From d4fc7e405f672c684088ba84e4531e1916d46700 Mon Sep 17 00:00:00 2001 From: archive Date: Wed, 29 Aug 2001 00:00:00 +0000 Subject: [PATCH] as released 2001-08-29 --- Network/delta.lst | 39 +- cl_dll/GameStudioModelRenderer.cpp | 1 - cl_dll/cdll_int.cpp | 88 +- cl_dll/cl_dll.dsp | 153 +- cl_dll/cl_dll.dsw | 37 - cl_dll/cl_util.h | 10 +- cl_dll/death.cpp | 2 + cl_dll/entity.cpp | 46 +- cl_dll/ev_hldm.cpp | 795 +- cl_dll/ev_hldm.h | 2 +- cl_dll/health.cpp | 5 +- cl_dll/hl/hl_baseentity.cpp | 103 +- cl_dll/hl/hl_events.cpp | 25 +- cl_dll/hl/hl_objects.cpp | 57 +- cl_dll/hl/hl_weapons.cpp | 510 +- cl_dll/hud.cpp | 63 +- cl_dll/hud.h | 55 +- cl_dll/hud_msg.cpp | 12 +- cl_dll/hud_redraw.cpp | 1 + cl_dll/hud_spectator.cpp | 1179 ++ cl_dll/hud_spectator.h | 113 + cl_dll/input.cpp | 80 +- cl_dll/message.cpp | 5 +- cl_dll/mssccprj.scc | 5 - cl_dll/overview.cpp | 160 + cl_dll/overview.h | 31 + {common => cl_dll}/r_studioint.h | 0 cl_dll/saytext.cpp | 6 + cl_dll/soundsystem.cpp | 162 + cl_dll/statusbar.cpp | 19 +- cl_dll/tf_defs.h | 2 + cl_dll/tri.cpp | 2 + cl_dll/vgui_ClassMenu.cpp | 11 +- cl_dll/vgui_CustomObjects.cpp | 33 +- cl_dll/vgui_MOTDWindow.cpp | 11 +- cl_dll/vgui_SchemeManager.cpp | 2 - cl_dll/vgui_ScorePanel.cpp | 1100 +- cl_dll/vgui_ScorePanel.h | 327 +- cl_dll/vgui_TeamFortressViewport.cpp | 152 +- cl_dll/vgui_TeamFortressViewport.h | 14 +- cl_dll/vgui_teammenu.cpp | 7 +- cl_dll/view.cpp | 295 +- common/beamdef.h | 2 +- common/cl_entity.h | 2 +- common/con_nprint.h | 2 +- common/const.h | 22 +- common/crc.h | 3 +- common/cvardef.h | 2 +- common/demo_api.h | 2 +- common/director_cmds.h | 31 + common/dlight.h | 2 +- common/engine_launcher_api.h | 4 +- common/entity_state.h | 6 +- common/entity_types.h | 2 +- common/event_args.h | 1 - common/event_flags.h | 2 +- common/exefuncs.h | 2 +- common/hltv.h | 37 + common/in_buttons.h | 2 +- common/interface.cpp | 142 + common/interface.h | 123 + common/itrackeruser.h | 46 + common/ivoicetweak.h | 35 + common/netadr.h | 4 +- common/nowin.h | 9 + common/particledef.h | 8 +- common/pmtrace.h | 2 +- common/qfont.h | 2 +- common/r_efx.h | 5 +- common/ref_params.h | 8 +- common/screenfade.h | 3 +- common/studio_event.h | 2 +- common/triangleapi.h | 3 +- common/usercmd.h | 2 +- common/weaponinfo.h | 2 +- dlls/AI_BaseNPC_Schedule.cpp | 1514 ++ dlls/Makefile | 67 +- dlls/WXDEBUG.CPP | 395 + dlls/activity.h | 2 +- dlls/activitymap.h | 2 +- dlls/aflock.cpp | 910 ++ dlls/agrunt.cpp | 1177 ++ dlls/airtank.cpp | 2 +- dlls/animating.cpp | 21 +- dlls/animation.cpp | 10 +- dlls/animation.h | 2 +- dlls/apache.cpp | 1050 ++ dlls/barnacle.cpp | 428 + dlls/barney.cpp | 841 ++ dlls/basemonster.h | 349 +- dlls/bigmomma.cpp | 1251 ++ dlls/bloater.cpp | 219 + dlls/bmodels.cpp | 2 +- dlls/bullsquid.cpp | 1275 ++ dlls/buttons.cpp | 2 +- dlls/cbase.cpp | 24 +- dlls/cbase.h | 36 +- dlls/cdll_dll.h | 2 +- dlls/client.cpp | 157 +- dlls/client.h | 2 +- dlls/combat.cpp | 118 +- dlls/controller.cpp | 1427 ++ dlls/crossbow.cpp | 156 +- dlls/crowbar.cpp | 76 +- dlls/decals.h | 2 +- dlls/defaultai.cpp | 1232 ++ dlls/defaultai.h | 98 + dlls/doors.cpp | 2 +- dlls/doors.h | 2 +- dlls/effects.cpp | 16 +- dlls/effects.h | 2 +- dlls/egon.cpp | 225 +- dlls/enginecallback.h | 10 +- dlls/explode.cpp | 2 +- dlls/explode.h | 2 +- dlls/extdll.h | 54 +- dlls/flyingmonster.cpp | 281 + dlls/flyingmonster.h | 53 + dlls/func_break.cpp | 4 +- dlls/func_break.h | 2 +- dlls/func_tank.cpp | 5 +- dlls/game.cpp | 15 +- dlls/game.h | 11 +- dlls/gamerules.cpp | 14 +- dlls/gamerules.h | 3 +- dlls/gargantua.cpp | 1368 ++ dlls/gauss.cpp | 232 +- dlls/genericmonster.cpp | 140 + dlls/ggrenade.cpp | 2 +- dlls/globals.cpp | 2 +- dlls/glock.cpp | 325 + dlls/gman.cpp | 237 + dlls/h_ai.cpp | 7 +- dlls/h_battery.cpp | 2 +- dlls/h_cine.cpp | 241 + dlls/h_cycler.cpp | 2 +- dlls/h_export.cpp | 28 +- dlls/handgrenade.cpp | 74 +- dlls/hassassin.cpp | 1015 ++ dlls/headcrab.cpp | 555 + dlls/healthkit.cpp | 7 +- dlls/hgrunt.cpp | 2517 ++++ dlls/{mp.def => hl.def} | 2 +- dlls/{mp.dsp => hl.dsp} | 323 +- dlls/hl.mak | 17750 ++++++++++++++++++++++++ dlls/hlgl.def | 15 + dlls/hornet.cpp | 17 +- dlls/hornet.h | 2 +- dlls/hornetgun.cpp | 90 +- dlls/houndeye.cpp | 1304 ++ dlls/ichthyosaur.cpp | 1108 ++ dlls/islave.cpp | 866 ++ dlls/items.cpp | 7 +- dlls/items.h | 2 +- dlls/leech.cpp | 723 + dlls/lights.cpp | 4 +- dlls/maprules.cpp | 2 +- dlls/maprules.h | 2 +- dlls/monsterevent.h | 2 +- dlls/monstermaker.cpp | 292 + dlls/monsters.cpp | 3448 +++++ dlls/monsters.h | 105 +- dlls/monsterstate.cpp | 234 + dlls/mortar.cpp | 2 +- dlls/mp5.cpp | 109 +- dlls/mpstubb.cpp | 2 +- dlls/multiplay_gamerules.cpp | 233 +- dlls/nihilanth.cpp | 1836 +++ dlls/nodes.cpp | 3640 +++++ dlls/nodes.h | 348 +- dlls/osprey.cpp | 805 ++ dlls/pathcorner.cpp | 2 +- dlls/plane.cpp | 3 +- dlls/plane.h | 2 +- dlls/plats.cpp | 2 +- dlls/player.cpp | 577 +- dlls/player.h | 21 +- dlls/playermonster.cpp | 115 + dlls/python.cpp | 93 +- dlls/rat.cpp | 98 + dlls/roach.cpp | 460 + dlls/rpg.cpp | 204 +- dlls/satchel.cpp | 108 +- dlls/saverestore.h | 3 +- dlls/schedule.cpp | 1514 ++ dlls/schedule.h | 269 +- dlls/scientist.cpp | 1428 ++ dlls/scripted.cpp | 1260 ++ dlls/scripted.h | 107 + dlls/scriptevent.h | 2 +- dlls/shotgun.cpp | 168 +- dlls/singleplay_gamerules.cpp | 2 +- dlls/skill.cpp | 2 +- dlls/skill.h | 2 +- dlls/sound.cpp | 12 +- dlls/soundent.cpp | 2 +- dlls/soundent.h | 2 +- dlls/spectator.cpp | 2 +- dlls/spectator.h | 2 +- dlls/squad.h | 13 + dlls/squadmonster.cpp | 623 + dlls/squadmonster.h | 120 + dlls/squeakgrenade.cpp | 61 +- dlls/stats.cpp | 149 + dlls/subs.cpp | 2 +- dlls/talkmonster.cpp | 1472 ++ dlls/talkmonster.h | 171 +- dlls/teamplay_gamerules.cpp | 43 +- dlls/teamplay_gamerules.h | 2 +- dlls/tempmonster.cpp | 117 + dlls/tentacle.cpp | 1044 ++ dlls/trains.h | 2 +- dlls/triggers.cpp | 2 +- dlls/tripmine.cpp | 74 +- dlls/turret.cpp | 1305 ++ dlls/util.cpp | 18 +- dlls/util.h | 36 +- dlls/vector.h | 2 +- dlls/weapons.cpp | 83 +- dlls/weapons.h | 533 +- dlls/world.cpp | 2 +- dlls/wpn_shared/hl_wpn_glock.cpp | 47 +- dlls/wxdebug.h | 137 + dlls/xen.cpp | 2 +- dlls/zombie.cpp | 346 + engine/{Anorms.h => anorms.h} | 0 engine/cdll_int.h | 44 +- engine/custom.h | 2 +- engine/eiface.h | 5 + engine/keydefs.h | 3 +- engine/{Progs.h => progs.h} | 0 engine/studio.h | 2 +- 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 | 201 + 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 | 246 + game_shared/voice_gamemgr.h | 75 + game_shared/voice_status.cpp | 861 ++ game_shared/voice_status.h | 225 + game_shared/voice_vgui_tweakdlg.cpp | 289 + game_shared/voice_vgui_tweakdlg.h | 25 + pm_shared/pm_debug.c | 5 +- pm_shared/pm_debug.h | 4 +- pm_shared/pm_defs.h | 3 +- pm_shared/pm_info.h | 4 +- pm_shared/pm_materials.h | 4 +- pm_shared/pm_math.c | 80 +- pm_shared/pm_shared.c | 179 +- pm_shared/pm_shared.h | 7 + utils/bspinfo/mssccprj.scc | 5 - utils/common/cmdlib.c | 18 + utils/common/cmdlib.h | 1 + utils/makels/makels.mak | 212 + utils/makels/mssccprj.scc | 5 - utils/makevfont/StdAfx.cpp | 8 - utils/makevfont/StdAfx.h | 23 - utils/makevfont/fileimage.cpp | 198 - utils/makevfont/fileimage.h | 85 - utils/makevfont/fontfiles.pl | 99 - utils/makevfont/makevfont.cpp | 378 - utils/makevfont/makevfont.dsp | 123 - utils/makevfont/vfontdata.cpp | 77 - utils/makevfont/vfontdata.h | 44 - utils/mkmovie/mssccprj.scc | 5 - utils/qbsp2/mssccprj.scc | 9 - utils/qcsg/mssccprj.scc | 5 - utils/qlumpy/mssccprj.scc | 5 - utils/qrad/mssccprj.scc | 5 - utils/readme.txt | 24 - utils/smdlexp/mssccprj.scc | 5 - utils/sprgen/mssccprj.scc | 5 - utils/studiomdl/mssccprj.scc | 5 - utils/studiomdl/studiomdl.c | 2 +- utils/vgui/include/VGUI_ImagePanel.h | 5 + utils/vgui/include/VGUI_InputSignal.h | 1 - utils/vgui/include/VGUI_Label.h | 5 + utils/vgui/include/VGUI_LineBorder.h | 2 + utils/vgui/lib/win32_vc6/vgui.lib | Bin 415712 -> 420978 bytes utils/visx2/mssccprj.scc | 5 - 295 files changed, 74734 insertions(+), 4076 deletions(-) delete mode 100644 cl_dll/cl_dll.dsw create mode 100644 cl_dll/hud_spectator.cpp create mode 100644 cl_dll/hud_spectator.h delete mode 100644 cl_dll/mssccprj.scc create mode 100644 cl_dll/overview.cpp create mode 100644 cl_dll/overview.h rename {common => cl_dll}/r_studioint.h (100%) create mode 100644 cl_dll/soundsystem.cpp create mode 100644 common/director_cmds.h create mode 100644 common/hltv.h create mode 100644 common/interface.cpp create mode 100644 common/interface.h create mode 100644 common/itrackeruser.h create mode 100644 common/ivoicetweak.h create mode 100644 common/nowin.h create mode 100644 dlls/AI_BaseNPC_Schedule.cpp create mode 100644 dlls/WXDEBUG.CPP create mode 100644 dlls/aflock.cpp create mode 100644 dlls/agrunt.cpp create mode 100644 dlls/apache.cpp create mode 100644 dlls/barnacle.cpp create mode 100644 dlls/barney.cpp create mode 100644 dlls/bigmomma.cpp create mode 100644 dlls/bloater.cpp create mode 100644 dlls/bullsquid.cpp create mode 100644 dlls/controller.cpp create mode 100644 dlls/defaultai.cpp create mode 100644 dlls/defaultai.h create mode 100644 dlls/flyingmonster.cpp create mode 100644 dlls/flyingmonster.h create mode 100644 dlls/gargantua.cpp create mode 100644 dlls/genericmonster.cpp create mode 100644 dlls/glock.cpp create mode 100644 dlls/gman.cpp create mode 100644 dlls/h_cine.cpp create mode 100644 dlls/hassassin.cpp create mode 100644 dlls/headcrab.cpp create mode 100644 dlls/hgrunt.cpp rename dlls/{mp.def => hl.def} (78%) rename dlls/{mp.dsp => hl.dsp} (60%) create mode 100644 dlls/hl.mak create mode 100644 dlls/hlgl.def create mode 100644 dlls/houndeye.cpp create mode 100644 dlls/ichthyosaur.cpp create mode 100644 dlls/islave.cpp create mode 100644 dlls/leech.cpp create mode 100644 dlls/monstermaker.cpp create mode 100644 dlls/monsters.cpp create mode 100644 dlls/monsterstate.cpp create mode 100644 dlls/nihilanth.cpp create mode 100644 dlls/nodes.cpp create mode 100644 dlls/osprey.cpp create mode 100644 dlls/playermonster.cpp create mode 100644 dlls/rat.cpp create mode 100644 dlls/roach.cpp create mode 100644 dlls/schedule.cpp create mode 100644 dlls/scientist.cpp create mode 100644 dlls/scripted.cpp create mode 100644 dlls/scripted.h create mode 100644 dlls/squad.h create mode 100644 dlls/squadmonster.cpp create mode 100644 dlls/squadmonster.h create mode 100644 dlls/stats.cpp create mode 100644 dlls/talkmonster.cpp create mode 100644 dlls/tempmonster.cpp create mode 100644 dlls/tentacle.cpp create mode 100644 dlls/turret.cpp create mode 100644 dlls/wxdebug.h create mode 100644 dlls/zombie.cpp rename engine/{Anorms.h => anorms.h} (100%) rename engine/{Progs.h => progs.h} (100%) 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 delete mode 100644 utils/bspinfo/mssccprj.scc create mode 100644 utils/makels/makels.mak delete mode 100644 utils/makels/mssccprj.scc delete mode 100644 utils/makevfont/StdAfx.cpp delete mode 100644 utils/makevfont/StdAfx.h delete mode 100644 utils/makevfont/fileimage.cpp delete mode 100644 utils/makevfont/fileimage.h delete mode 100644 utils/makevfont/fontfiles.pl delete mode 100644 utils/makevfont/makevfont.cpp delete mode 100644 utils/makevfont/makevfont.dsp delete mode 100644 utils/makevfont/vfontdata.cpp delete mode 100644 utils/makevfont/vfontdata.h delete mode 100644 utils/mkmovie/mssccprj.scc delete mode 100644 utils/qbsp2/mssccprj.scc delete mode 100644 utils/qcsg/mssccprj.scc delete mode 100644 utils/qlumpy/mssccprj.scc delete mode 100644 utils/qrad/mssccprj.scc delete mode 100644 utils/readme.txt delete mode 100644 utils/smdlexp/mssccprj.scc delete mode 100644 utils/sprgen/mssccprj.scc delete mode 100644 utils/studiomdl/mssccprj.scc delete mode 100644 utils/visx2/mssccprj.scc diff --git a/Network/delta.lst b/Network/delta.lst index b89b1c6..1334a8a 100644 --- a/Network/delta.lst +++ b/Network/delta.lst @@ -42,13 +42,35 @@ clientdata_t none DEFINE_DELTA( bInDuck, DT_INTEGER, 1, 1.0 ), DEFINE_DELTA( flSwimTime, DT_INTEGER, 10, 1.0 ), DEFINE_DELTA( waterjumptime, DT_INTEGER, 15, 1.0 ), - DEFINE_DELTA( waterlevel, DT_INTEGER, 2, 1.0 ) + DEFINE_DELTA( waterlevel, DT_INTEGER, 2, 1.0 ), + + DEFINE_DELTA( vuser1[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser1[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser1[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + + DEFINE_DELTA( vuser2[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser2[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser2[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + + DEFINE_DELTA( vuser3[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser3[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser3[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + + DEFINE_DELTA( vuser4[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser4[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + DEFINE_DELTA( vuser4[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), + + DEFINE_DELTA( fuser1, DT_SIGNED | DT_FLOAT, 22, 128.0 ), + DEFINE_DELTA( fuser2, DT_SIGNED | DT_FLOAT, 2, 128.0 ), + DEFINE_DELTA( fuser3, DT_SIGNED | DT_FLOAT, 2, 128.0 ), + DEFINE_DELTA( fuser4, DT_SIGNED | DT_FLOAT, 2, 128.0 ) } entity_state_t gamedll Entity_Encode { - DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ), - DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ), + // DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ), + DEFINE_DELTA( animtime, DT_TIMEWINDOW_BIG, 8, 100.0 ), + DEFINE_DELTA( frame, DT_FLOAT, 10, 4.0 ), DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), DEFINE_DELTA( angles[0], DT_ANGLE, 16, 1.0 ), DEFINE_DELTA( angles[1], DT_ANGLE, 16, 1.0 ), @@ -108,7 +130,8 @@ entity_state_t gamedll Entity_Encode entity_state_player_t gamedll Player_Encode { - DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ), + // DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ), + DEFINE_DELTA( animtime, DT_TIMEWINDOW_BIG, 8, 100.0 ), DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ), DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 18, 32.0 ), DEFINE_DELTA( angles[0], DT_ANGLE, 16, 1.0 ), @@ -216,7 +239,13 @@ weapon_data_t none DEFINE_DELTA( m_fAimedDamage, DT_FLOAT, 6, 0.1 ), DEFINE_DELTA( m_fInZoom, DT_INTEGER, 1, 1.0 ), DEFINE_DELTA( m_iWeaponState, DT_INTEGER, 2, 1.0 ), - DEFINE_DELTA( m_iId, DT_INTEGER, 5, 1.0 ) + DEFINE_DELTA( m_iId, DT_INTEGER, 5, 1.0 ), + DEFINE_DELTA( iuser1, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( iuser2, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( iuser3, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( fuser1, DT_SIGNED | DT_FLOAT, 22, 1000.0 ), + DEFINE_DELTA( fuser2, DT_SIGNED | DT_FLOAT, 22, 128.0 ), + DEFINE_DELTA( fuser3, DT_SIGNED | DT_FLOAT, 22, 128.0 ) } event_t none diff --git a/cl_dll/GameStudioModelRenderer.cpp b/cl_dll/GameStudioModelRenderer.cpp index 8a21ee6..1af9430 100644 --- a/cl_dll/GameStudioModelRenderer.cpp +++ b/cl_dll/GameStudioModelRenderer.cpp @@ -30,7 +30,6 @@ extern engine_studio_api_t IEngineStudio; // The renderer object, created on the stack. CGameStudioModelRenderer g_StudioRenderer; - /* ==================== CGameStudioModelRenderer diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 1070888..83d5d38 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -31,13 +31,19 @@ extern "C" #include #include "hud_servers.h" #include "vgui_int.h" +#include "interface.h" +#include "ITrackerUser.h" #define DLLEXPORT __declspec( dllexport ) + cl_enginefunc_t gEngfuncs; CHud gHUD; TeamFortressViewport *gViewPort = NULL; +HINTERFACEMODULE g_hTrackerModule = NULL; +ITrackerUser *g_pTrackerUser = NULL; + void InitInput (void); void EV_HookEvents( void ); void IN_Commands( void ); @@ -51,18 +57,20 @@ Called when the DLL is first loaded. */ extern "C" { -int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ); -int DLLEXPORT HUD_VidInit( void ); -int DLLEXPORT HUD_Init( void ); -int DLLEXPORT HUD_Redraw( float flTime, int intermission ); -int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime ); -int 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( 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 ); +int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ); +int DLLEXPORT HUD_VidInit( void ); +int DLLEXPORT HUD_Init( void ); +int DLLEXPORT HUD_Redraw( float flTime, int intermission ); +int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime ); +int 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( 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_DirectorEvent(unsigned char command, unsigned int firstObject, unsigned int secondObject, unsigned int flags); } /* @@ -139,17 +147,31 @@ int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) { gEngfuncs = *pEnginefuncs; - //!!! mwh UNDONE We need to think about our versioning strategy. Do we want to try to be compatible - // with previous versions, especially when we're only 'bonus' functionality? Should it be the engine - // that decides if the DLL is compliant? - if (iVersion != CLDLL_INTERFACE_VERSION) return 0; memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); EV_HookEvents(); + // get tracker interface, if any + char szDir[512]; + if (!gEngfuncs.COM_ExpandFilename("Bin/TrackerUI.dll", szDir, sizeof(szDir))) + { + g_pTrackerUser = NULL; + g_hTrackerModule = NULL; + return 1; + } + g_hTrackerModule = Sys_LoadModule(szDir); + CreateInterfaceFn trackerFactory = Sys_GetFactory(g_hTrackerModule); + if (!trackerFactory) + { + g_pTrackerUser = NULL; + g_hTrackerModule = NULL; + return 1; + } + + g_pTrackerUser = (ITrackerUser *)trackerFactory(TRACKERUSER_INTERFACE_VERSION, NULL); return 1; } @@ -188,7 +210,6 @@ int DLLEXPORT HUD_Init( void ) InitInput(); gHUD.Init(); Scheme_Init(); - return 1; } @@ -255,4 +276,35 @@ Called by engine every frame that client .dll is loaded void DLLEXPORT HUD_Frame( double time ) { ServersThink( time ); -} \ No newline at end of file + + GetClientVoiceMgr()->Frame(time); +} + + +/* +========================== +HUD_VoiceStatus + +Called when a player starts or stops talking. +========================== +*/ + +void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) +{ + GetClientVoiceMgr()->UpdateSpeakerStatus(entindex, bTalking); +} + +/* +========================== +HUD_DirectorEvent + +Called when a director event message was received +========================== +*/ + +void DLLEXPORT HUD_DirectorEvent(unsigned char command, unsigned int firstObject, unsigned int secondObject, unsigned int flags) +{ + gHUD.m_Spectator.DirectorEvent(command, firstObject, secondObject, flags); +} + + diff --git a/cl_dll/cl_dll.dsp b/cl_dll/cl_dll.dsp index a77d0dc..1c76e99 100644 --- a/cl_dll/cl_dll.dsp +++ b/cl_dll/cl_dll.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\utils\vgui\include" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Zi /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 BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -54,15 +54,6 @@ BSC32=bscmake.exe 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 /map /machine:I386 /out:".\Release\client.dll" -# Begin Custom Build - Copying to \quiver\valve\cl_dlls -TargetDir=.\Release -InputPath=.\Release\client.dll -SOURCE="$(InputPath)" - -"\quiver\valve\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\client.dll \quiver\valve\cl_dlls - -# End Custom Build !ELSEIF "$(CFG)" == "cl_dll - Win32 Debug" @@ -78,7 +69,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 /GX /ZI /Od /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\utils\vgui\include" /I "..\dlls" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /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\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" @@ -89,15 +80,6 @@ BSC32=bscmake.exe 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:".\Debug\client.dll" -# Begin Custom Build - Copying to \half-life\mp\cl_dlls -TargetDir=.\Debug -InputPath=.\Debug\client.dll -SOURCE="$(InputPath)" - -"\half-life\mp\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\client.dll \half-life\mp\cl_dlls - -# End Custom Build !ENDIF @@ -110,13 +92,33 @@ SOURCE="$(InputPath)" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" # Begin Group "hl" -# PROP Default_Filter "*.cpp" +# 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 @@ -135,6 +137,62 @@ SOURCE=.\hl\hl_weapons.cpp SOURCE=..\dlls\wpn_shared\hl_wpn_glock.cpp # End Source File +# Begin Source File + +SOURCE=..\dlls\hornetgun.cpp +# End Source File +# Begin Source File + +SOURCE=..\common\interface.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 +# Begin Source File + +SOURCE=..\game_shared\voice_vgui_tweakdlg.cpp +# End Source File # End Group # Begin Source File @@ -214,6 +272,10 @@ 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 @@ -238,6 +300,11 @@ 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 @@ -294,6 +361,10 @@ 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 @@ -310,10 +381,26 @@ 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 @@ -402,14 +489,26 @@ 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 @@ -482,6 +581,18 @@ 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 diff --git a/cl_dll/cl_dll.dsw b/cl_dll/cl_dll.dsw deleted file mode 100644 index d7d3ee1..0000000 --- a/cl_dll/cl_dll.dsw +++ /dev/null @@ -1,37 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "cl_dll"=.\cl_dll.dsp - Package Owner=<4> - -Package=<5> -{{{ - begin source code control - "$/GoldSrc/cl_dll", HGEBAAAA - . - end source code control -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ - begin source code control - "$/Sdk/Standard/cl_dll", UBZBAAAA - . - end source code control -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 4d48c80..52e0ab3 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -67,6 +67,14 @@ inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int fl // 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) ((x) * ((float)ScreenWidth / 640)) +#define YRES(y) ((y) * ((float)ScreenHeight / 480)) + +// 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) @@ -128,7 +136,7 @@ void ScaleColors( int &r, int &g, int &b, int a ); #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;} +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); diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 1566725..632205e 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -168,6 +168,8 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p if (gViewPort) gViewPort->DeathMsg( killer, victim ); + gHUD.m_Spectator.DeathMessage(victim); + for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) { if ( rgDeathNoticeList[i].iId == 0 ) diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index 6af73f6..f2e8ea8 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -12,6 +12,7 @@ #include "pm_defs.h" #include "pmtrace.h" + #define DLLEXPORT __declspec( dllexport ) void Game_AddObjects( void ); @@ -50,6 +51,17 @@ int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *mode default: break; } + // each frame every entity passes this function, so the overview hooks it to filter the overview entities + if (gEngfuncs.IsSpectateOnly()) + { + gHUD.m_Spectator.AddOverviewEntity( type, ent, modelname ); + + if ( ( gHUD.m_Spectator.m_iMainMode == MAIN_IN_EYE || + gHUD.m_Spectator.m_iInsetMode == INSET_IN_EYE ) && + ent->index == gHUD.m_Spectator.m_iObserverTarget ) + return 0; // don't draw the player we are following in eye + + } return 1; } @@ -71,6 +83,9 @@ void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const stru state->iuser1 = client->iuser1; state->iuser2 = client->iuser2; + // Duck prevention + state->iuser3 = client->iuser3; + // Fire prevention state->iuser4 = client->iuser4; } @@ -132,8 +147,11 @@ void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct { g_iPlayerClass = dst->playerclass; g_iTeamNumber = dst->team; + g_iUser1 = src->iuser1; g_iUser2 = src->iuser2; + g_iUser3 = src->iuser3; + } } @@ -175,9 +193,30 @@ void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct 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 ) ); } @@ -488,8 +527,11 @@ void DLLEXPORT HUD_CreateEntities( void ) Beams(); #endif + // Add in any game specific objects Game_AddObjects(); + + GetClientVoiceMgr()->CreateEntities(); } /* @@ -680,6 +722,7 @@ void DLLEXPORT HUD_TempEntUpdate ( 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++ ) @@ -922,4 +965,5 @@ cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) #else return NULL; #endif -} \ No newline at end of file +} + diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 7be5045..07dd372 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -37,6 +37,7 @@ 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 "C" { @@ -47,9 +48,21 @@ 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 ); } @@ -322,6 +335,7 @@ int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, flo return tracer; } + /* ================ FireBullets @@ -329,33 +343,41 @@ 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 *vecSpread, float flDistance, 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 ) { int i; pmtrace_t tr; int iShot; - vec3_t vecRight, vecUp; int tracer; - - VectorCopy( right, vecRight ); - VectorCopy( up, vecUp ); - - for ( iShot = 1; iShot <= cShots; iShot++ ) + + for ( iShot = 1; iShot <= cShots; iShot++ ) { vec3_t vecDir, vecEnd; - - // get circular gaussian spread - vec3_t spread; - do { - spread[0] = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); - spread[1] = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); - spread[2] = spread[0] * spread[0] + spread[1] *spread[1]; - } while (spread[2] > 1); - - for ( i = 0 ; i < 3; i++ ) + + float x, y, z; + //We randomize for the Shotgun. + if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) { - vecDir[i] = vecDirShooting[i] + spread[ 0 ] * vecSpread[ 0 ] * vecRight[ i ] + spread[ 1 ] * vecSpread[ 1 ] * up [ i ]; - vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + 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 ); @@ -378,13 +400,13 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int { default: case BULLET_PLAYER_9MM: - if ( !tracer ) - { - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); - EV_HLDM_DecalGunshot( &tr, iBulletType ); - } - break; + + 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 ); @@ -392,17 +414,15 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int } break; case BULLET_PLAYER_BUCKSHOT: - if ( !tracer ) - { - EV_HLDM_DecalGunshot( &tr, iBulletType ); - } + + EV_HLDM_DecalGunshot( &tr, iBulletType ); + break; case BULLET_PLAYER_357: - if ( !tracer ) - { - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); - EV_HLDM_DecalGunshot( &tr, iBulletType ); - } + + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + break; } @@ -412,6 +432,9 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int } } +//====================== +// GLOCK START +//====================== void EV_FireGlock1( event_args_t *args ) { int idx; @@ -420,15 +443,12 @@ void EV_FireGlock1( event_args_t *args ) vec3_t velocity; int empty; - int i; 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 ); @@ -443,6 +463,8 @@ void EV_FireGlock1( event_args_t *args ) { 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 ); @@ -455,17 +477,7 @@ void EV_FireGlock1( event_args_t *args ) VectorCopy( forward, vecAiming ); - for ( i = 0; i < 3; i++ ) - { - vecSpread[ i ] = flSpread; - } - - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, vecSpread, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1] ); - - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, -2.0 ); - } + 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 ) @@ -474,15 +486,13 @@ void EV_FireGlock2( event_args_t *args ) vec3_t origin; vec3_t angles; vec3_t velocity; - - int i; + vec3_t ShellVelocity; vec3_t ShellOrigin; int shell; vec3_t vecSrc, vecAiming; vec3_t vecSpread; vec3_t up, right, forward; - float flSpread = 0.1; idx = args->entindex; VectorCopy( args->origin, origin ); @@ -498,6 +508,8 @@ void EV_FireGlock2( event_args_t *args ) // 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 ); @@ -510,19 +522,16 @@ void EV_FireGlock2( event_args_t *args ) VectorCopy( forward, vecAiming ); - for ( i = 0; i < 3; i++ ) - { - vecSpread[ i ] = flSpread; - } - - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, vecSpread, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1] ); + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, -2.0 ); - } } +//====================== +// GLOCK END +//====================== +//====================== +// SHOTGUN START +//====================== void EV_FireShotGunDouble( event_args_t *args ) { int idx; @@ -530,7 +539,7 @@ void EV_FireShotGunDouble( event_args_t *args ) vec3_t angles; vec3_t velocity; - int i, j; + int j; vec3_t ShellVelocity; vec3_t ShellOrigin; int shell; @@ -553,6 +562,7 @@ void EV_FireShotGunDouble( event_args_t *args ) // 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++ ) @@ -567,25 +577,13 @@ void EV_FireShotGunDouble( event_args_t *args ) EV_GetGunPosition( args, vecSrc, origin ); VectorCopy( forward, vecAiming ); - if ( gEngfuncs.GetMaxClients() > 1 ) + if ( gEngfuncs.GetMaxClients() > 1 ) { - for ( i = 0; i < 3; i++ ) - { - vecSpread[0] = 0.17365; - vecSpread[1] = 0.04362; - vecSpread[2] = 0.00; - } - - EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, vecSpread, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-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, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] ); - } - - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, -10.0 ); + EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); } } @@ -596,7 +594,6 @@ void EV_FireShotGunSingle( event_args_t *args ) vec3_t angles; vec3_t velocity; - int i; vec3_t ShellVelocity; vec3_t ShellOrigin; int shell; @@ -619,6 +616,8 @@ void EV_FireShotGunSingle( event_args_t *args ) // 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 ); @@ -632,26 +631,20 @@ void EV_FireShotGunSingle( event_args_t *args ) if ( gEngfuncs.GetMaxClients() > 1 ) { - for ( i = 0; i < 3; i++ ) - { - vecSpread[0] = 0.08716; - vecSpread[1] = 0.04362; - vecSpread[2] = 0.00; - } - - EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, vecSpread, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-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, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] ); - } - - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, -5.0 ); + 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; @@ -680,6 +673,8 @@ void EV_FireMP5( event_args_t *args ) // 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 ); @@ -701,19 +696,48 @@ void EV_FireMP5( event_args_t *args ) if ( gEngfuncs.GetMaxClients() > 1 ) { - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-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, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1] ); - } - - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) ); + 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; @@ -740,6 +764,8 @@ void EV_FirePython( event_args_t *args ) // 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 ) ) @@ -756,14 +782,16 @@ void EV_FirePython( event_args_t *args ) VectorCopy( forward, vecAiming ); - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, &tracerCount[idx-1] ); - - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, -10.0 ); - } + 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 ) @@ -799,11 +827,6 @@ 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" ); - - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); - } } void EV_FireGauss( event_args_t *args ) @@ -841,9 +864,6 @@ void EV_FireGauss( event_args_t *args ) return; } - // Make sure we don't have a gauss spin event in the queue for this guy - gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" ); - // Con_Printf( "Firing gauss with %f\n", flDamage ); EV_GetGunPosition( args, vecSrc, origin ); @@ -882,10 +902,6 @@ void EV_FireGauss( event_args_t *args ) if ( tr.allsolid ) break; - pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); - if ( pEntity == NULL ) - break; - if (fFirstBeam) { if ( EV_IsLocal( idx ) ) @@ -929,6 +945,10 @@ void EV_FireGauss( event_args_t *args ) ); } + pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + if ( pEntity == NULL ) + break; + if ( pEntity->solid == SOLID_BSP ) { float n; @@ -937,7 +957,7 @@ 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 @@ -954,12 +974,11 @@ void EV_FireGauss( event_args_t *args ) 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, (int)(n * flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, - 255, 200 ); - } + 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 ) @@ -1078,6 +1097,530 @@ void EV_FireGauss( event_args_t *args ) } } } +//====================== +// 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 END +//====================== +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_NORMAL, -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 ) + { + 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 ); + + pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.075, 5, 0, 0.15, 5, 5, 25.5 ); + + if ( pBeam ) + pBeam->flags |= FBEAM_SINENOISE; + + pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.1, 2.5, 0, 0.15, 5, 5, 25.5 ); + } + } +} + +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 ) { @@ -1130,4 +1673,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 9857b34..15fdf1d 100644 --- a/cl_dll/ev_hldm.h +++ b/cl_dll/ev_hldm.h @@ -83,6 +83,6 @@ enum gauss_e { 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 *vecSpread, float flDistance, 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/health.cpp b/cl_dll/health.cpp index 3d9268e..191c30d 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -173,10 +173,7 @@ int CHudHealth::Draw(float flTime) int a = 0, x, y; int HealthWidth; -// if (m_iHealth <= 0) -// return 1; - - if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) + if ( (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || gEngfuncs.IsSpectateOnly() ) return 1; if ( !m_hSprite ) diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index 68934de..dc9f87c 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -27,6 +27,8 @@ This file contains "stubs" of class member implementations so that we can predic #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 ); @@ -91,24 +93,95 @@ 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; } @@ -118,16 +191,30 @@ int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, in 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 ) { } @@ -136,16 +223,26 @@ 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() { } @@ -157,8 +254,6 @@ void CBasePlayer::PlayerUse ( void ) { } void CBasePlayer::Jump() { } void CBasePlayer::Duck( ) { } int CBasePlayer::Classify ( void ) { return 0; } -void CBasePlayer :: PlayStepSound(int step, float fvol) { } -void CBasePlayer :: UpdateStepSound( void ) { } void CBasePlayer::PreThink(void) { } void CBasePlayer::CheckTimeBasedDamage() { } void CBasePlayer :: UpdateGeigerCounter( void ) { } @@ -247,4 +342,6 @@ 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 ) { } \ No newline at end of file +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 ){} diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp index 1302fb4..f8b010a 100644 --- a/cl_dll/hl/hl_events.cpp +++ b/cl_dll/hl/hl_events.cpp @@ -24,9 +24,22 @@ 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 ); } @@ -50,8 +63,18 @@ void Game_HookEvents( void ) 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 ); -} \ No newline at end of file + 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 179ab86..6c06b7a 100644 --- a/cl_dll/hl/hl_objects.cpp +++ b/cl_dll/hl/hl_objects.cpp @@ -16,6 +16,59 @@ #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 ); + + 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; + + if ( pBeam2 ) + pBeam2->target = tr.endpos; + +} + /* ===================== Game_AddObjects @@ -25,4 +78,6 @@ Add game specific, client-side objects here */ void Game_AddObjects( void ) { -} \ No newline at end of file + if ( pBeam && pBeam2 ) + UpdateBeams(); +} diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 242f8f0..1f9b9b7 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -45,8 +45,24 @@ static globalvars_t Globals; static CBasePlayerWeapon *g_pWpns[ 32 ]; +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; + /* ====================== @@ -68,6 +84,18 @@ void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) 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 @@ -96,133 +124,6 @@ void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) } } -/* -// FIXME: In order to predict animations client side, you'll need to work with the following code. -// It's not quite working, but it should be of use if you want -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pmodel - -// *label - -// Output : int -//----------------------------------------------------------------------------- -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; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *label - -// Output : int CBaseAnimating :: LookupSequence -//----------------------------------------------------------------------------- -int CBaseAnimating :: LookupSequence ( const char *label ) -{ - cl_entity_t *current; - - current = gEngfuncs.GetLocalPlayer(); - if ( !current || !current->model ) - return 0; - - return ::LookupSequence( (studiohdr_t *)IEngineStudio.Mod_Extradata( current->model ), label ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pmodel - -// *pev - -// *pflFrameRate - -// *pflGroundSpeed - -//----------------------------------------------------------------------------- -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; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pmodel - -// *pev - -// Output : int -//----------------------------------------------------------------------------- -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; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -//----------------------------------------------------------------------------- -void CBaseAnimating :: ResetSequenceInfo ( ) -{ - cl_entity_t *current; - - current = gEngfuncs.GetLocalPlayer(); - if ( !current || !current->model ) - return; - - void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata( current->model ); - - 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; -} -*/ /* ===================== CBaseEntity :: Killed @@ -242,7 +143,7 @@ CBasePlayerWeapon :: DefaultReload */ BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay ) { -#if 0 // FIXME, need to know primary ammo to get this right + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) return FALSE; @@ -250,7 +151,6 @@ BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay if (j == 0) return FALSE; -#endif m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; @@ -366,15 +266,49 @@ CBasePlayerWeapon::SendWeaponAnim Animate weapon model ===================== */ -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal ) +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) { m_pPlayer->pev->weaponanim = iAnim; - int body = 0; - 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 @@ -516,8 +450,8 @@ 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( ); } /* @@ -678,6 +612,55 @@ void HUD_InitClientWeapons( void ) // 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 ]; + } } /* @@ -707,9 +690,83 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? switch ( from->client.m_iId ) { - case WEAPON_GLOCK: - pWeapon = &g_Glock; - break; + 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. @@ -727,10 +784,23 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm 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 @@ -761,16 +831,31 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm 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 ]; } - // 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 ( 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 @@ -782,23 +867,6 @@ 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 ( to->client.health <= 0 && lasthealth > 0 ) - { - player.Killed( NULL, 0 ); - } - else if ( to->client.health > 0 && lasthealth <= 0 ) - { - player.Spawn(); - } - - lasthealth = to->client.health; - } - // Assume that we are not going to switch weapons to->client.m_iId = from->client.m_iId; @@ -830,18 +898,42 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm } } - // Copy in results of predcition code + // 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; + // Force a fixed anim down to viewmodel HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); } @@ -859,10 +951,18 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm } 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; @@ -870,13 +970,19 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm 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; - if ( pto->m_flPumpTime != -9999 ) + 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 ) { @@ -902,6 +1008,11 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm { 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 @@ -911,62 +1022,25 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm 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; } -// For storing predicted sequence and gaitsequence and origin/angles data -static int g_rseq = 0, g_gaitseq = 0; -static vec3_t g_clorg, g_clang; - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *seq - -// *gaitseq - -//----------------------------------------------------------------------------- -void Game_GetSequence( int *seq, int *gaitseq ) -{ - *seq = g_rseq; - *gaitseq = g_gaitseq; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : seq - -// gaitseq - -//----------------------------------------------------------------------------- -void Game_SetSequence( int seq, int gaitseq ) -{ - g_rseq = seq; - g_gaitseq = gaitseq; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : o - -// a - -//----------------------------------------------------------------------------- -void Game_SetOrientation( vec3_t o, vec3_t a ) -{ - g_clorg = o; - g_clang = a; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *o - -// *a - -//----------------------------------------------------------------------------- -void Game_GetOrientation( float *o, float *a ) -{ - int i; - - for ( i = 0; i < 3; i++ ) - { - o[ i ] = g_clorg[ i ]; - a[ i ] = g_clang[ i ]; - } -} /* ===================== @@ -983,11 +1057,8 @@ void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s { g_runfuncs = runfuncs; - // Only run post think stuff for glock for the sample - // implementation #if defined( CLIENT_WEAPONS ) - if ( cl_lw && cl_lw->value && - from->client.m_iId == WEAPON_GLOCK ) + if ( cl_lw && cl_lw->value ) { HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); } @@ -997,13 +1068,6 @@ void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s to->client.fov = g_lastFOV; } - // Store of final sequence, etc. for client side animation - if ( g_runfuncs ) - { - Game_SetSequence( to->playerstate.sequence, to->playerstate.gaitsequence ); - Game_SetOrientation( to->playerstate.origin, cmd->viewangles ); - } - // All games can use FOV state g_lastFOV = to->client.fov; } diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index 399b860..822e1f8 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -24,10 +24,59 @@ #include #include "parsemsg.h" #include "hud_servers.h" +#include "vgui_int.h" #include "vgui_TeamFortressViewport.h" #include "demo.h" #include "demo_api.h" +#include "vgui_scorepanel.h" + + + +class CHLVoiceStatusHelper : public IVoiceStatusHelper +{ +public: + virtual void GetPlayerTextColor(int entindex, int color[3]) + { + color[0] = color[1] = color[2] = 255; + + if( entindex >= 0 && entindex < sizeof(g_PlayerExtraInfo)/sizeof(g_PlayerExtraInfo[0]) ) + { + int iTeam = g_PlayerExtraInfo[entindex].teamnumber; + + if ( iTeam < 0 ) + { + iTeam = 0; + } + + iTeam = iTeam % iNumberOfTeamColors; + + color[0] = iTeamColors[iTeam][0]; + color[1] = iTeamColors[iTeam][1]; + color[2] = iTeamColors[iTeam][2]; + } + } + + virtual void UpdateCursorState() + { + gViewPort->UpdateCursorState(); + } + + virtual int GetAckIconHeight() + { + return ScreenHeight - gHUD.m_iFontHeight*3 - 6; + } + + virtual bool CanShowSpeakerLabels() + { + if( gViewPort && gViewPort->m_pScoreBoard ) + return !gViewPort->m_pScoreBoard->isVisible(); + else + return false; + } +}; +static CHLVoiceStatusHelper g_VoiceStatusHelper; + extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); @@ -245,6 +294,10 @@ void CHud :: Init( void ) // 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; @@ -284,6 +337,8 @@ void CHud :: Init( void ) m_AmmoSecondary.Init(); m_TextMessage.Init(); m_StatusIcons.Init(); + GetClientVoiceMgr()->Init(&g_VoiceStatusHelper, (vgui::Panel**)&gViewPort); + m_Spectator.Init(); m_SayText.Init(); m_Menu.Init(); @@ -431,6 +486,8 @@ void CHud :: VidInit( void ) m_AmmoSecondary.VidInit(); m_TextMessage.VidInit(); m_StatusIcons.VidInit(); + GetClientVoiceMgr()->VidInit(); + m_Spectator.VidInit(); } int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) @@ -544,10 +601,8 @@ int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) int newfov = READ_BYTE(); int def_fov = CVAR_GET_FLOAT( "default_fov" ); - int tfc = 0; - tfc = HUD_IsGame( "tfc" ); - - if ( tfc && cl_lw && cl_lw->value ) + //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). + if ( cl_lw && cl_lw->value ) return 1; g_lastFOV = newfov; diff --git a/cl_dll/hud.h b/cl_dll/hud.h index 171fdba..a781555 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -40,17 +40,26 @@ 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 1024 +#define MAX_MOTD_LENGTH 1536 // //----------------------------------------------------- @@ -61,6 +70,7 @@ 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;} @@ -76,6 +86,14 @@ struct HUDLIST { }; + +// +//----------------------------------------------------- +// +#include "..\game_shared\voice_status.h" +#include "hud_spectator.h" + + // //----------------------------------------------------- // @@ -236,6 +254,9 @@ protected: 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]; }; // @@ -273,13 +294,6 @@ private: }; */ -enum -{ - MAX_PLAYERS = 64, - MAX_TEAMS = 64, - MAX_TEAM_NAME = 16, -}; - struct extra_player_info_t { short frags; @@ -522,7 +536,7 @@ private: //----------------------------------------------------- // -typedef struct cvar_s cvar_t; + class CHud { @@ -580,20 +594,21 @@ public: int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array - CHudAmmo m_Ammo; - CHudHealth m_Health; - CHudGeiger m_Geiger; - CHudBattery m_Battery; - CHudTrain m_Train; - CHudFlashlight m_Flash; - CHudMessage m_Message; - CHudStatusBar m_StatusBar; + CHudAmmo m_Ammo; + CHudHealth m_Health; + 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; + CHudSayText m_SayText; + CHudMenu m_Menu; CHudAmmoSecondary m_AmmoSecondary; CHudTextMessage m_TextMessage; CHudStatusIcons m_StatusIcons; + CHudSpectator m_Spectator; void Init( void ); void VidInit( void ); @@ -612,6 +627,7 @@ public: void _cdecl MsgFunc_InitHUD( 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; @@ -638,4 +654,5 @@ 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_msg.cpp b/cl_dll/hud_msg.cpp index c0199ad..8936b54 100644 --- a/cl_dll/hud_msg.cpp +++ b/cl_dll/hud_msg.cpp @@ -19,7 +19,14 @@ #include "hud.h" #include "cl_util.h" #include "parsemsg.h" +#include "r_efx.h" +#define MAX_CLIENTS 32 + +#if !defined( _TFC ) +extern BEAM *pBeam; +extern BEAM *pBeam2; +#endif /// USER-DEFINED SERVER MESSAGE HANDLERS int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) @@ -56,6 +63,10 @@ void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) pList->p->InitHUDData(); pList = pList->pNext; } +#if !defined( _TFC ) + //Probably not a good place to put this. + pBeam = pBeam2 = NULL; +#endif } @@ -102,4 +113,3 @@ int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) this->m_StatusIcons.DisableIcon("dmg_concuss"); return 1; } - diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index 280707d..b5e135a 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -108,6 +108,7 @@ int CHud :: Redraw( float flTime, int intermission ) else if ( !m_iIntermission && intermission ) { gViewPort->HideCommandMenu(); + gViewPort->HideVGUIMenu(); gViewPort->ShowScoreBoard(); // Take a screenshot if the client's got the cvar set diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp new file mode 100644 index 0000000..be97fa1 --- /dev/null +++ b/cl_dll/hud_spectator.cpp @@ -0,0 +1,1179 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "vgui_TeamFortressViewport.h" +#include "hltv.h" + +#include "pm_shared.h" +#include "entity_types.h" + +// these are included for the math functions +#include "com_model.h" +#include "studio_util.h" + +#pragma warning(disable: 4244) + + +extern "C" unsigned int uiDirectorFlags; // from pm_shared.c +extern "C" float vecNewViewOrigin[3]; +extern "C" float vecNewViewAngles[3]; +extern "C" int iHasNewViewOrigin; +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 vec3_t v_angles; + +void SpectatorMode(void) +{ + if ( !gEngfuncs.IsSpectateOnly() ) + { + gEngfuncs.Con_Printf( "specmode only in HLTV mode available.\n" ); + return; + } + + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: specmode < modenumber >\n" ); + return; + } + + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), INSET_OFF ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudSpectator::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + m_flNextObserverInput = 0.0f; + m_iObserverTarget = 0; + m_zoomDelta = 0.0f; + m_moveDelta = 0.0f; + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + m_iMainMode = 0; + m_iInsetMode = 0; + + m_drawnames = gEngfuncs.pfnRegisterVariable( "cl_drawnames", "1", FCVAR_ARCHIVE ); + gEngfuncs.pfnAddCommand ("specmode", SpectatorMode ); + + 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; + } +} + +//----------------------------------------------------------------------------- +// SetSpectatorStartPosition(): +// Get valid map position and 'beam' spectator to this position +//----------------------------------------------------------------------------- + +void CHudSpectator::SetSpectatorStartPosition() +{ + float position[3] = {0,0,0}; + + cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model + + if ( pEnt ) + { + char *data; + char keyname[256]; + int n; + char token[1024]; + + + for ( data = gEngfuncs.COM_ParseFile( pEnt->model->entities, token) ; // cl.worldmodel->entities + *data && *token != '}'; + data = gEngfuncs.COM_ParseFile(data, token) ) // TODO check this for null pointer crashes + { + + if (token[0] != '{') + return; + + while (1) + { + // parse key + data = gEngfuncs.COM_ParseFile(data, token); + if (token[0] == '}') + break; + if (!data) + return; + + 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) + return; + + if (token[0] == '}') + return; + + if (!strcmp(keyname,"classname")) + { + if (!strcmp(token,"info_player_start")) + { + // origin should already be in SpectatorPos + break; + } + }; + + if (!strcmp(keyname,"origin")) + { + UTIL_StringToVector(position, token); + + }; + + } // while (1) + } + } + + VectorCopy ( position, vJumpOrigin ); + VectorCopy ( position, vecNewViewOrigin ); + + iHasNewViewOrigin = 1; + iJumpSpectator = 1; +} + +//----------------------------------------------------------------------------- +// 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 red, green, blue; + + // if user pressed zoom, aplly changes + if ( m_zoomDelta != 0.0f && m_iMainMode != MAIN_ROAMING ) + { + 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 && m_iMainMode != MAIN_ROAMING ) + { + vec3_t right; + AngleVectors(m_mapAngles, 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 ( m_iMainMode != MAIN_MAP_FREE ) + return 1; + + if ( !m_drawnames->value ) + return 1; + + // make sure we have player info + gViewPort->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_iInsetMode != 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; + } + + // hack in some team colors + switch (g_PlayerExtraInfo[i+1].teamnumber) + { + // blue and red teams are swapped in CS and TFC + case 2 : red = 1.0f; green = 0.4f; blue = 0.4f; break; // Team Red + case 1 : red = 0.4f; green = 0.4f; blue = 1.0f; break; // Team Blue + default : red = 0.8f; green = 0.8f; blue = 0.8f; break; // Unkown Team, grey + } + + // 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( red, green, blue ); + DrawConsoleString( m_vPlayerPos[i][0]-lx,m_vPlayerPos[i][1], string); + + } + + return 1; +} + + + +void CHudSpectator::DirectorEvent(unsigned char command, unsigned int firstObject, unsigned int secondObject, unsigned int flags) +{ + switch ( command ) + { + case HLTV_ACTIVE : // we are connected to a proxy or listening to a multicast stream + // now we have to do some things clientside, since the proxy doesn't know our mod + g_iPlayerClass = 0; + g_iTeamNumber = 0; + iJumpSpectator = 0; + m_iMainMode = m_iInsetMode = 0; + m_iObserverTarget = m_lastPrimaryObject = m_lastSecondaryObject = 0; + m_flNextObserverInput = 0.0f; + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + SetModes(MAIN_CHASE_FREE, INSET_OFF); + ParseOverviewFile(); + LoadMapSprites(); + SetSpectatorStartPosition(); + break; + + case HLTV_CAMERA : if ( g_iUser1 == OBS_DIRECTED ) + { + m_iObserverTarget = g_iUser2 = firstObject; + g_iUser3 = secondObject; + } + + m_lastPrimaryObject = firstObject; + m_lastSecondaryObject = secondObject; + uiDirectorFlags = flags; + // gEngfuncs.Con_Printf("Director Camera: %i %i\n", firstObject, secondObject); + break; + + default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorEvent: unknown director command.\n"); + } +} + +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; + if ( m_iObserverTarget ) + iStart = m_iObserverTarget; + else + iStart = 1; + + + m_iObserverTarget = 0; + + int iCurrent = iStart; + + int iDir = bReverse ? -1 : 1; + + // make sure we have player info + gViewPort->GetAllPlayersInfo(); + + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > MAX_PLAYERS) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = MAX_PLAYERS; + + cl_entity_t *pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); + + if ( !IsActivePlayer( pEnt ) ) + continue; + + // MOD AUTHORS: Add checks on target here. + + m_iObserverTarget = iCurrent; + break; + + } while ( iCurrent != iStart ); + + // Did we find a target? + if ( m_iObserverTarget ) + { + // Store the target in pev so the physics DLL can get to it + if ( m_iMainMode != MAIN_ROAMING ) + { + g_iUser2 = m_iObserverTarget; + g_iUser3 = 0; + } + + gEngfuncs.Con_Printf("Now Tracking %s\n", g_PlayerInfoList[m_iObserverTarget].name ); + } + else + { + gEngfuncs.Con_Printf( "No observer targets.\n" ); + } +} + +void CHudSpectator::HandleButtonsDown( int ButtonPressed ) +{ + double time = gEngfuncs.GetClientTime(); + int newMainMode = m_iMainMode; + int newInsetMode = m_iInsetMode; + + + // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); + + // Slow down mouse clicks + if ( m_flNextObserverInput > time || gEngfuncs.IsSpectateOnly()!=1 ) + return; + + // changing target or chase mode not in overviewmode without inset window + + // Jump changes main window modes + if ( ButtonPressed & IN_JUMP ) + { + newMainMode+=1; + if (newMainMode > MAIN_MAP_FREE ) + newMainMode = MAIN_CHASE_FREE; // Main window can't be turned off + } + + // Duck changes inset window mode + if ( ButtonPressed & IN_DUCK ) + { + newInsetMode+=1; + if ( newInsetMode > INSET_MAP_FREE ) + newInsetMode = INSET_OFF; // inset window can be turned off + } + + // Attack moves to the next player + if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) + { + // in any mode change now from directed to users mode + g_iUser1 = OBS_CHASE_FREE; // leave directed sub mode + + FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); + + if ( m_iMainMode == MAIN_ROAMING && m_iObserverTarget ) + { + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( m_iObserverTarget ); + VectorCopy ( ent->origin, vJumpOrigin ); + VectorCopy ( ent->angles, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + + } + + } + + 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; + + if ( newMainMode != m_iMainMode || newInsetMode != m_iInsetMode ) + SetModes(newMainMode, newInsetMode); + + m_flNextObserverInput = time + 0.2; +} + +void CHudSpectator::HandleButtonsUp( int ButtonPressed ) +{ + if ( gEngfuncs.IsSpectateOnly() != 1 ) + return; + + 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) +{ + char string[32]; + static wrect_t crosshairRect; + + if ( iNewMainMode < MAIN_CHASE_LOCKED || iNewMainMode > MAIN_MAP_FREE ) + { + gEngfuncs.Con_Printf("Invalid spectator mode.\n"); + return; + } + + // Just abort if we're changing to the mode we're already in + if (iNewInsetMode != m_iInsetMode) + { + m_iInsetMode = iNewInsetMode; + sprintf(string, "%c#Spec_Mode_Inset%d", HUD_PRINTCENTER, m_iInsetMode); + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + + // main modes ettings will override inset window settings + if ( iNewMainMode != m_iMainMode ) + { + switch ( iNewMainMode ) + { + case MAIN_CHASE_FREE : g_iUser1 = OBS_DIRECTED; + break; + + case MAIN_ROAMING : g_iUser1 = OBS_ROAMING; + + if ( m_iMainMode == MAIN_CHASE_FREE ) + { + VectorCopy ( vecNewViewOrigin, vJumpOrigin ); + VectorCopy ( vecNewViewAngles, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + + if ( m_iMainMode == MAIN_IN_EYE ) + { + V_GetInEyePos( m_iObserverTarget, vJumpOrigin, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + + g_iUser2 = m_iObserverTarget = 0; + g_iUser3 = 0; + break; + + case MAIN_IN_EYE : g_iUser1 = OBS_DIRECTED; + break; + + case MAIN_MAP_FREE : g_iUser1 = OBS_DIRECTED; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + } + + m_iMainMode = iNewMainMode; + sprintf(string, "%c#Spec_Mode%d", HUD_PRINTCENTER, m_iMainMode); + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + + if ( g_iUser1 == OBS_DIRECTED && m_iObserverTarget == 0 ) + { + // choose last Director object if still available + if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) + { + g_iUser2 = m_iObserverTarget = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + } + + // enable or disable crosshair + if ( m_iMainMode == MAIN_ROAMING || m_iMainMode == MAIN_IN_EYE ) + { + crosshairRect.left = 24; + crosshairRect.top = 0; + crosshairRect.right = 48; + crosshairRect.bottom = 24; + + SetCrosshair( m_hCrosshair, crosshairRect, 255, 255, 255 ); + } + else + { + memset( &crosshairRect,0,sizeof(crosshairRect) ); + SetCrosshair( 0, crosshairRect, 0, 0, 0 ); + } + + } + + // disallow same inset mode as main mode: + + if ( ( m_iMainMode != MAIN_MAP_FREE ) && ( m_iInsetMode == INSET_CHASE_FREE || m_iInsetMode == INSET_IN_EYE ) ) + { + // both would show in World picures + SetModes( m_iMainMode, INSET_MAP_FREE ); + } + + if ( ( m_iMainMode == MAIN_MAP_FREE ) && ( m_iInsetMode == INSET_MAP_FREE ) ) + { + // both would show map views + SetModes( m_iMainMode, INSET_OFF ); + } + gViewPort->UpdateSpectatorMenu(); + +} + +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(levelname, gEngfuncs.pfnGetLevelName() + 5); + levelname[strlen(levelname)-4] = 0; + + sprintf(filename, "overviews/%s.txt", levelname ); + + pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); + + if (!pfile) + { + gEngfuncs.Con_Printf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); + return false; + } + else + { + 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++; + + } + } + } + + 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 - m_mapAngles[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::GetMapPosition( float * returnvec ) +{ + vec3_t forward; + vec3_t zScaledTarget; + + zScaledTarget[0] = m_mapOrigin[0]; + zScaledTarget[1] = m_mapOrigin[1]; + zScaledTarget[2] = m_mapOrigin[2] * (( 90.0f - m_mapAngles[0] ) / 90.0f ); + + + AngleVectors(m_mapAngles, forward, NULL, NULL); + + VectorNormalize(forward); + VectorScale(forward, -( 4096.0f / m_mapZoom ), forward ); + + VectorAdd( zScaledTarget, forward, returnvec ) +} + + +void CHudSpectator::DrawOverviewEntities() +{ + int i,ir,ig,ib; + struct model_s *hSpriteModel; + vec3_t origin,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 - m_mapAngles[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_iInsetMode == INSET_OFF ) + return; + + if ( m_iInsetMode == INSET_IN_EYE ) + { + V_GetInEyePos(m_iObserverTarget, vecNewViewOrigin, vecNewViewAngles ); + } + + // draw camera sprite + + x = vecNewViewOrigin[0]; + y = vecNewViewOrigin[1]; + z = vecNewViewOrigin[2]; + + 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(vecNewViewAngles, 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 (); + +} + +extern void VectorAngles( const float *forward, float *angles ); +extern "C" void NormalizeAngles( float *angles ); + + +void CHudSpectator::DrawOverview() +{ + // don't draw it in developer mode + if ( gEngfuncs.IsSpectateOnly() != 1) + return; + + // Only draw the overview if Map Mode is selected for this view + if ( m_iDrawCycle == 0 && m_iMainMode != MAIN_MAP_FREE ) + return; + + if ( m_iDrawCycle == 1 && m_iInsetMode != 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 +} diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h new file mode 100644 index 0000000..1c994a9 --- /dev/null +++ b/cl_dll/hud_spectator.h @@ -0,0 +1,113 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SPECTATOR_H +#define SPECTATOR_H +#pragma once + +#include "cl_entity.h" + +#define MAIN_CHASE_LOCKED 1 +#define MAIN_CHASE_FREE 2 +#define MAIN_ROAMING 3 +#define MAIN_IN_EYE 4 +#define MAIN_MAP_FREE 5 + + +#define INSET_OFF 0 +#define INSET_CHASE_FREE 1 +#define INSET_IN_EYE 2 +#define INSET_MAP_FREE 3 + + +#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 { + 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: + 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 DirectorEvent(unsigned char command, unsigned int firstObject, unsigned int secondObject, unsigned int flags); + void SetSpectatorStartPosition(); + int Init(); + int VidInit(); + + int Draw(float flTime); + + int m_iMainMode; + int m_iInsetMode; + int m_iDrawCycle; + overviewInfo_t m_OverviewData; + overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; + int m_iObserverTarget; + + float m_mapZoom; // zoom the user currently uses + vec3_t m_mapOrigin; // origin where user rotates around + vec3_t m_mapAngles; // cuurent map view angles + +private: + cvar_t * m_drawnames; + 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; + 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/input.cpp b/cl_dll/input.cpp index 1119fb7..fd840c8 100644 --- a/cl_dll/input.cpp +++ b/cl_dll/input.cpp @@ -22,6 +22,7 @@ extern "C" #include "vgui_TeamFortressViewport.h" + extern "C" { struct kbutton_s DLLEXPORT *KB_Find( const char *name ); @@ -391,18 +392,57 @@ 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);} -void IN_ForwardUp(void) {KeyUp(&in_forward);} -void IN_BackDown(void) {KeyDown(&in_back);} -void IN_BackUp(void) {KeyUp(&in_back);} + +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);} -void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} -void IN_MoverightDown(void) {KeyDown(&in_moveright);} -void IN_MoverightUp(void) {KeyUp(&in_moveright);} +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);} @@ -410,18 +450,30 @@ 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); __CmdFunc_InputPlayerSpecial(); + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 ); } void IN_Attack2Up(void) {KeyUp(&in_attack2);} void IN_UseDown (void) {KeyDown(&in_use);} void IN_UseUp (void) {KeyUp(&in_use);} -void IN_JumpDown (void) {KeyDown(&in_jump);} +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);} +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);} @@ -433,6 +485,7 @@ void IN_GraphUp(void) {KeyUp(&in_graph);} void IN_AttackDown(void) { KeyDown( &in_attack ); + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); } void IN_AttackUp(void) @@ -672,6 +725,10 @@ void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int activ // cmd->buttons = CL_ButtonBits( 1 ); + // If they're in a modal dialog, ignore the attack button. + if(GetClientVoiceMgr()->IsInSquelchMode()) + cmd->buttons &= ~IN_ATTACK; + // Using joystick? if ( in_joystick->value ) { @@ -697,6 +754,7 @@ void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int activ { VectorCopy( oldangles, cmd->viewangles ); } + } /* @@ -956,4 +1014,4 @@ void ShutdownInput (void) void DLLEXPORT HUD_Shutdown( void ) { ShutdownInput(); -} \ No newline at end of file +} diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index 8404e43..cb9ba05 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -462,10 +462,11 @@ void CHudMessage::MessageAdd( const char *pName, float time ) { return; } + // get rid of any other messages in same location (only one displays at a time) - else if ( abs( tempMessage->y - m_pMessages[j]->y ) < 1 ) + if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) { - if ( abs( tempMessage->x - m_pMessages[j]->x ) < 1 ) + if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) { m_pMessages[j] = NULL; } diff --git a/cl_dll/mssccprj.scc b/cl_dll/mssccprj.scc deleted file mode 100644 index bad9ab2..0000000 --- a/cl_dll/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[cl_dll.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/cl_dll", UBZBAAAA diff --git a/cl_dll/overview.cpp b/cl_dll/overview.cpp new file mode 100644 index 0000000..5d24816 --- /dev/null +++ b/cl_dll/overview.cpp @@ -0,0 +1,160 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "vgui_TeamFortressViewport.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) +{ + // only draw in overview mode + if (!gEngfuncs.Overview_GetOverviewState()) + return 1; + + // make sure we have player info + gViewPort->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); + } + } + + 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 0000000..e87de10 --- /dev/null +++ b/cl_dll/overview.h @@ -0,0 +1,31 @@ +//========= Copyright © 1996-2001, 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/common/r_studioint.h b/cl_dll/r_studioint.h similarity index 100% rename from common/r_studioint.h rename to cl_dll/r_studioint.h diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index f7cb992..ae546d3 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -57,6 +57,8 @@ int CHudSayText :: Init( void ) CVAR_CREATE( "hud_saytext_time", "5", 0 ); + m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission + return 1; } @@ -164,7 +166,11 @@ int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) { if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + { + // Print it straight to the console + ConsolePrint( pszBuf ); return; + } // find an empty string slot for ( int i = 0; i < MAX_LINES; i++ ) diff --git a/cl_dll/soundsystem.cpp b/cl_dll/soundsystem.cpp new file mode 100644 index 0000000..f2f0022 --- /dev/null +++ b/cl_dll/soundsystem.cpp @@ -0,0 +1,162 @@ +//======== (C) Copyright 1999, 2000 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/statusbar.cpp b/cl_dll/statusbar.cpp index 6b2f28a..ec19d60 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -31,6 +31,9 @@ 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 ); @@ -54,12 +57,18 @@ int CHudStatusBar :: VidInit( void ) void CHudStatusBar :: Reset( void ) { + int i = 0; + m_iFlags &= ~HUD_ACTIVE; // start out inactive - for ( int 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 ); 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 ) @@ -133,11 +142,13 @@ void CHudStatusBar :: ParseStatusString( int line_num ) 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 ); @@ -166,7 +177,10 @@ 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; } @@ -192,6 +206,9 @@ int CHudStatusBar :: Draw( float fTime ) 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] ); } diff --git a/cl_dll/tf_defs.h b/cl_dll/tf_defs.h index 38e0f9f..52b4342 100644 --- a/cl_dll/tf_defs.h +++ b/cl_dll/tf_defs.h @@ -1129,6 +1129,8 @@ float already_chosen_map; #define MENU_REFRESH_RATE 25 +#define MENU_VOICETWEAK 50 + //============================ // Timer Types #define TF_TIMER_ANY 0 diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp index 99a975d..0a90ad0 100644 --- a/cl_dll/tri.cpp +++ b/cl_dll/tri.cpp @@ -94,6 +94,8 @@ Non-transparent triangles-- add them here void DLLEXPORT HUD_DrawNormalTriangles( void ) { + gHUD.m_Spectator.DrawOverview(); + #if defined( TEST_IT ) // Draw_Triangles(); #endif diff --git a/cl_dll/vgui_ClassMenu.cpp b/cl_dll/vgui_ClassMenu.cpp index 0c1ca7a..5799274 100644 --- a/cl_dll/vgui_ClassMenu.cpp +++ b/cl_dll/vgui_ClassMenu.cpp @@ -198,9 +198,11 @@ CClassMenuPanel::CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide // Open up the Class Briefing File sprintf(sz, "classes/short_%s.txt", sTFClassSelection[i]); char *cText = "Class Description not available."; - char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + char *pfile = (char *)gEngfuncs.COM_LoadFile( sz, 5, NULL ); if (pfile) + { cText = pfile; + } // Create the Text info window TextPanel *pTextWindow = new TextPanel(cText, textOffs, CLASSMENU_WINDOW_TEXT_Y, (CLASSMENU_WINDOW_SIZE_X - textOffs)-5, CLASSMENU_WINDOW_SIZE_Y - CLASSMENU_WINDOW_TEXT_Y); @@ -215,7 +217,7 @@ CClassMenuPanel::CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide int wide,tall; pTextWindow->getTextImage()->getTextSizeWrapped( wide,tall); pTextWindow->setSize(wide,tall); - //pTextWindow->setBorder(new LineBorder()); + int xx,yy; pTextWindow->getPos(xx,yy); int maxX=xx+wide; @@ -318,7 +320,10 @@ void CClassMenuPanel::Update() m_pPlayers[i]->setText( sz ); // Set the text color to the teamcolor - m_pPlayers[i]->setFgColor( iTeamColors[g_iTeamNumber][0], iTeamColors[g_iTeamNumber][1], iTeamColors[g_iTeamNumber][2], 0 ); + m_pPlayers[i]->setFgColor( iTeamColors[g_iTeamNumber % iNumberOfTeamColors][0], + iTeamColors[g_iTeamNumber % iNumberOfTeamColors][1], + iTeamColors[g_iTeamNumber % iNumberOfTeamColors][2], + 0 ); // set the graphic to be the team pick for ( int team = 0; team < MAX_TEAMS; team++ ) diff --git a/cl_dll/vgui_CustomObjects.cpp b/cl_dll/vgui_CustomObjects.cpp index ce8cfad..701ad33 100644 --- a/cl_dll/vgui_CustomObjects.cpp +++ b/cl_dll/vgui_CustomObjects.cpp @@ -32,6 +32,7 @@ #include "vgui_int.h" #include "vgui_TeamFortressViewport.h" #include "vgui_ServerBrowser.h" +#include "..\game_shared\vgui_LoadTGA.h" // Arrow filenames char *sArrowFilenames[] = @@ -42,20 +43,31 @@ char *sArrowFilenames[] = "arrowrt", }; +// Get the name of TGA file, without a gamedir +char *GetTGANameForRes(const char *pszName) +{ + int i; + char sz[256]; + static char gd[256]; + if (ScreenWidth < 640) + i = 320; + else + i = 640; + sprintf(sz, pszName, i); + sprintf(gd, "gfx/vgui/%s.tga", sz); + return gd; +} + //----------------------------------------------------------------------------- // Purpose: Loads a .tga file and returns a pointer to the VGUI tga object //----------------------------------------------------------------------------- -BitmapTGA *LoadTGA( const char* pImageName ) +BitmapTGA *LoadTGAForRes( const char* pImageName ) { BitmapTGA *pTGA; char sz[256]; sprintf(sz, "%%d_%s", pImageName); - - // Load the Image - FileInputStream* fis = new FileInputStream( GetVGUITGAName(sz), false ); - pTGA = new BitmapTGA(fis,true); - fis->close(); + pTGA = vgui_LoadTGA(GetTGANameForRes(sz)); return pTGA; } @@ -283,14 +295,14 @@ int ClassButton::IsNotValid() CImageLabel::CImageLabel( const char* pImageName,int x,int y ) : Label( "", x,y ) { setContentFitted(true); - m_pTGA = LoadTGA(pImageName); + m_pTGA = LoadTGAForRes(pImageName); setImage( m_pTGA ); } CImageLabel::CImageLabel( const char* pImageName,int x,int y,int wide,int tall ) : Label( "", x,y,wide,tall ) { setContentFitted(true); - m_pTGA = LoadTGA(pImageName); + m_pTGA = LoadTGAForRes(pImageName); setImage( m_pTGA ); } @@ -328,7 +340,7 @@ CTFScrollButton::CTFScrollButton(int iArrow, const char* text,int x,int y,int wi setFgColor(Scheme::sc_primary1); // Load in the arrow - m_pTGA = LoadTGA( sArrowFilenames[iArrow] ); + m_pTGA = LoadTGAForRes( sArrowFilenames[iArrow] ); setImage( m_pTGA ); // Highlight signal @@ -338,6 +350,9 @@ CTFScrollButton::CTFScrollButton(int iArrow, const char* text,int x,int y,int wi void CTFScrollButton::paint( void ) { + if (!m_pTGA) + return; + // draw armed button text in white if ( isArmed() ) { diff --git a/cl_dll/vgui_MOTDWindow.cpp b/cl_dll/vgui_MOTDWindow.cpp index ef4b606..7a47a68 100644 --- a/cl_dll/vgui_MOTDWindow.cpp +++ b/cl_dll/vgui_MOTDWindow.cpp @@ -104,6 +104,7 @@ CMessageWindowPanel::CMessageWindowPanel( const char *szMOTD, const char *szTitl // Create the Scroll panel ScrollPanel *pScrollPanel = new CTFScrollPanel( iXPos + XRES(16), iYPos + MOTD_TITLE_Y*2 + YRES(16), iXSize - XRES(32), iYSize - (YRES(48) + BUTTON_SIZE_Y*2) ); pScrollPanel->setParent(this); + //force the scrollbars on so clientClip will take them in account after the validate pScrollPanel->setScrollBarAutoVisible(false, false); pScrollPanel->setScrollBarVisible(true, true); @@ -120,13 +121,19 @@ CMessageWindowPanel::CMessageWindowPanel( const char *szMOTD, const char *szTitl pSchemes->getBgColor( hMOTDText, r, g, b, a ); pText->setBgColor( r, g, b, a ); pText->setText(szMOTD); - pText->setSize(pScrollPanel->getClientClip()->getWide()-2, 5000); // Get the total size of the MOTD text and resize the text panel int iScrollSizeX, iScrollSizeY; + + // First, set the size so that the client's wdith is correct at least because the + // width is critical for getting the "wrapped" size right. + // You'll see a horizontal scroll bar if there is a single word that won't wrap in the + // specified width. + pText->getTextImage()->setSize(pScrollPanel->getClientClip()->getWide(), pScrollPanel->getClientClip()->getTall()); pText->getTextImage()->getTextSizeWrapped( iScrollSizeX, iScrollSizeY ); + + // Now resize the textpanel to fit the scrolled size pText->setSize( iScrollSizeX , iScrollSizeY ); - //pText->setBorder(new LineBorder()); //turn the scrollbars back into automode pScrollPanel->setScrollBarAutoVisible(true, true); diff --git a/cl_dll/vgui_SchemeManager.cpp b/cl_dll/vgui_SchemeManager.cpp index 0c09b6b..3c03aea 100644 --- a/cl_dll/vgui_SchemeManager.cpp +++ b/cl_dll/vgui_SchemeManager.cpp @@ -397,8 +397,6 @@ buildDefaultFont: { sprintf(fontFilename, "gfx\\vgui\\fonts\\%d_%s.tga", m_xRes, m_pSchemeList[i].schemeName); pFontData = gEngfuncs.COM_LoadFile( fontFilename, 5, &fontFileLength ); - if(!pFontData) - gEngfuncs.Con_Printf("Missing bitmap font: %s\n", fontFilename); } m_pSchemeList[i].font = new vgui::Font( diff --git a/cl_dll/vgui_ScorePanel.cpp b/cl_dll/vgui_ScorePanel.cpp index d431eb9..c287db6 100644 --- a/cl_dll/vgui_ScorePanel.cpp +++ b/cl_dll/vgui_ScorePanel.cpp @@ -26,6 +26,11 @@ #include "cl_entity.h" #include "vgui_TeamFortressViewport.h" #include "vgui_ScorePanel.h" +#include "..\game_shared\vgui_helpers.h" +#include "..\game_shared\vgui_loadtga.h" + +#include "ITrackerUser.h" +extern ITrackerUser *g_pTrackerUser; 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 @@ -36,333 +41,209 @@ int HUD_IsGame( const char *game ); int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ); // Scoreboard dimensions -#define SBOARD_TITLE_SIZE_Y YRES(24) -#define SBOARD_HEADER_SIZE_Y YRES(40) -#define SBOARD_TABLE_X XRES(16) -#define SBOARD_TABLE_Y (SBOARD_TITLE_SIZE_Y + SBOARD_HEADER_SIZE_Y) +#define SBOARD_TITLE_SIZE_Y YRES(22) -#define SBOARD_TEAM_CELL_SIZE_Y YRES(20) -#define SBOARD_CELL_SIZE_Y YRES(13) +#define X_BORDER XRES(4) // Column sizes -#define CSIZE_NAME XRES(140) -#define CSIZE_CLASS CSIZE_NAME + XRES(64) -#define CSIZE_KILLS CSIZE_CLASS + XRES(60) -#define CSIZE_DEATHS CSIZE_KILLS + XRES(64) +class SBColumnInfo +{ +public: + char *m_pTitle; // If null, ignore, if starts with #, it's localized, otherwise use the string directly. + int m_Width; // Based on 640 width. Scaled to fit other resolutions. + Label::Alignment m_Alignment; +}; + +// grid size is marked out for 640x480 screen + +SBColumnInfo g_ColumnInfo[NUM_COLUMNS] = +{ + {NULL, 24, Label::a_east}, // tracker column + {NULL, 140, Label::a_east}, // name + {NULL, 56, Label::a_east}, // class + {"#SCORE", 40, Label::a_east}, + {"#DEATHS", 46, Label::a_east}, + {"#LATENCY", 46, Label::a_east}, + {"#VOICE", 40, Label::a_east}, + {NULL, 2, Label::a_east}, // blank column to take up the slack +}; -#define SMALL_CSIZE_NAME XRES(124) -#define SMALL_CSIZE_CLASS SMALL_CSIZE_NAME + XRES(60) -#define SMALL_CSIZE_KILLS SMALL_CSIZE_CLASS + XRES(64) -#define SMALL_CSIZE_DEATHS SMALL_CSIZE_KILLS + XRES(70) #define TEAM_NO 0 #define TEAM_YES 1 -#define TEAM_UNASSIGNED 2 -#define TEAM_SPECTATORS 3 +#define TEAM_SPECTATORS 2 +#define TEAM_BLANK 3 -// Team Colors used in the scoreboard -int ScoreColorsBG[5][3] = -{ - { 0, 0, 0 }, - { 66, 114, 247 }, - { 220, 51, 38 }, - { 236, 212, 48 }, - { 68, 199, 42 }, -}; - -int ScoreColorsFG[5][3] = -{ - { 255, 255, 255 }, - { 170, 193, 251 }, - { 215, 151, 146 }, - { 227, 203, 46 }, - { 143, 215, 142 }, -}; //----------------------------------------------------------------------------- -// Purpose: Set different cell heights for Teams and Players +// ScorePanel::HitTestPanel. //----------------------------------------------------------------------------- -int ScoreTablePanel::getCellTall(int row) -{ - if ( m_iIsATeam[row] ) - return SBOARD_TEAM_CELL_SIZE_Y; - return SBOARD_CELL_SIZE_Y; +void ScorePanel::HitTestPanel::internalMousePressed(MouseCode code) +{ + for(int i=0;i<_inputSignalDar.getCount();i++) + { + _inputSignalDar[i]->mousePressed(code,this); + } } -//----------------------------------------------------------------------------- -// Purpose: Render each of the cells in the Table -//----------------------------------------------------------------------------- -Panel* ScoreTablePanel::getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) -{ - char sz[128]; - hud_player_info_t *pl_info = NULL; - team_info_t *team_info = NULL; - if ( m_iIsATeam[row] == TEAM_YES ) - { - // Get the team's data - team_info = &g_TeamInfo[ m_iSortedRows[row] ]; - - // White text for team names - m_pLabel->setFgColor(Scheme::sc_white); - - // Set background color - m_pLabel->setBgColor( ScoreColorsBG[ team_info->teamnumber ][0], ScoreColorsBG[ team_info->teamnumber ][1], ScoreColorsBG[ team_info->teamnumber ][2], 128 ); - } - else if ( m_iIsATeam[row] == TEAM_UNASSIGNED || m_iIsATeam[row] == TEAM_SPECTATORS ) - { - // White text for team names - m_pLabel->setFgColor(Scheme::sc_white); - - // Set background color - m_pLabel->setBgColor( 0,0,0, 255 ); - } - else - { - // Grey text for player names - m_pLabel->setFgColor( ScoreColorsFG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][0], ScoreColorsFG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][1], ScoreColorsFG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][2], 128 ); - - // Get the player's data - pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; - - // Set background color - if ( pl_info->thisplayer ) // if it is their name, draw it a different color - { - // Highlight this player - m_pLabel->setFgColor(Scheme::sc_white); - m_pLabel->setBgColor( ScoreColorsBG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][0], ScoreColorsBG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][1], ScoreColorsBG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][2], 196 ); - } - else if ( m_iSortedRows[row] == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) - { - // Killer's name - m_pLabel->setBgColor( 255,0,0, 255 - ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); - } - else - { - m_pLabel->setBgColor( 0,0,0, 255 ); - } - } - - // Align - if (column <= 1) - { - if ( m_iIsATeam[row] ) - m_pLabel->setContentAlignment( vgui::Label::a_southwest ); - else - m_pLabel->setContentAlignment( vgui::Label::a_west ); - } - else - { - if ( m_iIsATeam[row] ) - m_pLabel->setContentAlignment( vgui::Label::a_south ); - else - m_pLabel->setContentAlignment( vgui::Label::a_center ); - } - - // Fill out with the correct data - if ( m_iIsATeam[row] ) - { - int i; - char sz2[128]; - strcpy(sz, ""); - - switch (column) - { - case 0: - if ( m_iIsATeam[row] == TEAM_UNASSIGNED ) - { - sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Unassigned" ) ); - } - else if ( m_iIsATeam[row] == TEAM_SPECTATORS ) - { - sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ) ); - } - else - { - sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( team_info->name ) ); - } - - // Uppercase it - for (i = 0; i < (int)strlen(sz2); i++) - { - if ( *(sz2 + i) ) - sz[i] = toupper( *(sz2 + i) ); - } - sz[i] = '\0'; - - // Append the number of players - if ( m_iIsATeam[row] == TEAM_YES ) - { - if (team_info->players == 1) - sprintf(sz, "%s (1 player)", sz ); - else - sprintf(sz, "%s (%d players)", sz, team_info->players ); - } - break; - case 1: - // No class for teams - break; - case 2: - if ( m_iIsATeam[row] == TEAM_YES ) - sprintf(sz, "%d", team_info->frags ); - break; - case 3: - if ( m_iIsATeam[row] == TEAM_YES ) - sprintf(sz, "%d", team_info->deaths ); - break; - case 4: - if ( m_iIsATeam[row] == TEAM_YES ) - sprintf(sz, "%d", team_info->ping ); - break; - default: - break; - } - - m_pLabel->setText(sz); - } - else - { - bool bShowClass = false; - - switch (column) - { - case 0: - sprintf(sz, " %s", pl_info->name); - break; - case 1: - // No class for other team's members (unless allied or spectator) - if ( gViewPort && EV_TFC_IsAllyTeam( g_iTeamNumber, g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) ) - bShowClass = true; - // Don't show classes if this client hasnt picked a team yet - if ( g_iTeamNumber == 0 ) - bShowClass = false; - if ( g_iUser1 ) - bShowClass = true; - - if (bShowClass) - { - // Only print Civilian if this team are all civilians - bool bNoClass = false; - if ( g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass == 0 ) - { - if ( gViewPort->GetValidClasses( g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) != -1 ) - bNoClass = true; - } - - if (bNoClass) - sprintf(sz, ""); - else - sprintf( sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[ g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass ] ) ); - } - else - { - strcpy(sz, ""); - } - break; - case 2: - sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].frags ); - break; - case 3: - sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].deaths ); - break; - case 4: - sprintf(sz, "%d", g_PlayerInfoList[ m_iSortedRows[row] ].ping ); - break; - default: - strcpy(sz, ""); - } - - m_pLabel->setText(sz); - } - - return m_pLabel; -} //----------------------------------------------------------------------------- // Purpose: Create the ScoreBoard panel //----------------------------------------------------------------------------- ScorePanel::ScorePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) { - setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0) ) ); - setBgColor( 0,0,0, 100 ); + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); + Font *tfont = pSchemes->getFont(hTitleScheme); + Font *smallfont = pSchemes->getFont(hSmallScheme); - m_pTitleLabel = new Label( " SCORES", 0,0, wide, SBOARD_TITLE_SIZE_Y ); - m_pTitleLabel->setBgColor( Scheme::sc_primary2 ); - m_pTitleLabel->setFgColor( Scheme::sc_primary1 ); - m_pTitleLabel->setContentAlignment( vgui::Label::a_west ); - m_pTitleLabel->setParent(this); + setBgColor(0, 0, 0, 96); + m_pCurrentHighlightLabel = NULL; + m_iHighlightRow = -1; - _headerPanel = new HeaderPanel( SBOARD_TABLE_X, SBOARD_TITLE_SIZE_Y, wide - (SBOARD_TABLE_X * 2), SBOARD_HEADER_SIZE_Y); - _headerPanel->setParent(this); + m_pTrackerIcon = NULL; + m_pTrackerIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardtracker.tga"); - // BUGBUG: This isn't working. gHUD.m_Teamplay hasn't been initialized yet. - if ( gHUD.m_Teamplay ) - _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#TEAMS" ), true) ); - else - _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#PLAYERS" ), true) ); + // Initialize the top title. + m_TitleLabel.setFont(tfont); + m_TitleLabel.setText(""); + m_TitleLabel.setBgColor( 0, 0, 0, 255 ); + m_TitleLabel.setFgColor( Scheme::sc_primary1 ); + m_TitleLabel.setContentAlignment( vgui::Label::a_west ); - if ( HUD_IsGame( "tfc" ) ) - _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#CLASS" ), true) ); - else - _headerPanel->addSectionPanel( new CLabelHeader("", true) ); + LineBorder *border = new LineBorder(Color(60, 60, 60, 128)); + setBorder(border); + setPaintBorderEnabled(true); - _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#SCORE" )) ); - _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#DEATHS")) ); - _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#LATENCY")) ); - _headerPanel->setBgColor( 0,0,0, 255 ); - - // Need to special case 400x300, because the titles just wont fit otherwise - if ( ScreenWidth == 400 ) + int xpos = g_ColumnInfo[0].m_Width + 3; + if (ScreenWidth >= 640) { - _headerPanel->setSliderPos( 0, SMALL_CSIZE_NAME ); - _headerPanel->setSliderPos( 1, SMALL_CSIZE_CLASS ); - _headerPanel->setSliderPos( 2, SMALL_CSIZE_KILLS ); - _headerPanel->setSliderPos( 3, SMALL_CSIZE_DEATHS ); - _headerPanel->setSliderPos( 4, wide - (SBOARD_TABLE_X * 2) - 1 ); + // only expand column size for res greater than 640 + xpos = XRES(xpos); } - else + m_TitleLabel.setBounds(xpos, 4, wide, SBOARD_TITLE_SIZE_Y); + m_TitleLabel.setContentFitted(false); + m_TitleLabel.setParent(this); + + // Setup the header (labels like "name", "class", etc..). + m_HeaderGrid.SetDimensions(NUM_COLUMNS, 1); + m_HeaderGrid.SetSpacing(0, 0); + + for(int i=0; i < NUM_COLUMNS; i++) { - _headerPanel->setSliderPos( 0, CSIZE_NAME ); - _headerPanel->setSliderPos( 1, CSIZE_CLASS ); - _headerPanel->setSliderPos( 2, CSIZE_KILLS ); - _headerPanel->setSliderPos( 3, CSIZE_DEATHS ); - _headerPanel->setSliderPos( 4, wide - (SBOARD_TABLE_X * 2) - 1 ); + if (g_ColumnInfo[i].m_pTitle && g_ColumnInfo[i].m_pTitle[0] == '#') + m_HeaderLabels[i].setText(CHudTextMessage::BufferedLocaliseTextString(g_ColumnInfo[i].m_pTitle)); + else if(g_ColumnInfo[i].m_pTitle) + m_HeaderLabels[i].setText(g_ColumnInfo[i].m_pTitle); + + int xwide = g_ColumnInfo[i].m_Width; + if (ScreenWidth >= 640) + { + xwide = XRES(xwide); + } + else if (ScreenWidth == 400) + { + // hack to make 400x300 resolution scoreboard fit + if (i == 1) + { + // reduces size of player name cell + xwide -= 28; + } + else if (i == 0) + { + // tracker icon cell + xwide -= 8; + } + } + + m_HeaderGrid.SetColumnWidth(i, xwide); + m_HeaderGrid.SetEntry(i, 0, &m_HeaderLabels[i]); + + m_HeaderLabels[i].setBgColor(0,0,0,255); + m_HeaderLabels[i].setBgColor(0,0,0,255); + m_HeaderLabels[i].setFgColor(Scheme::sc_primary1); + m_HeaderLabels[i].setFont(smallfont); + m_HeaderLabels[i].setContentAlignment(g_ColumnInfo[i].m_Alignment); + + int yres = 12; + if (ScreenHeight >= 480) + { + yres = YRES(yres); + } + m_HeaderLabels[i].setSize(50, yres); } - _tablePanel = new ScoreTablePanel(SBOARD_TABLE_X, SBOARD_TABLE_Y, wide - (SBOARD_TABLE_X * 2), tall - SBOARD_TABLE_Y, NUM_COLUMNS); - _tablePanel->setParent(this); - _tablePanel->setHeaderPanel(_headerPanel); - _tablePanel->setBgColor( 0,0,0, 255 ); + // Set the width of the last column to be the remaining space. + int ex, ey, ew, eh; + m_HeaderGrid.GetEntryBox(NUM_COLUMNS - 2, 0, ex, ey, ew, eh); + m_HeaderGrid.SetColumnWidth(NUM_COLUMNS - 1, (wide - X_BORDER) - (ex + ew)); + + m_HeaderGrid.AutoSetRowHeights(); + m_HeaderGrid.setBounds(X_BORDER, SBOARD_TITLE_SIZE_Y, wide - X_BORDER*2, m_HeaderGrid.GetRowHeight(0)); + m_HeaderGrid.setParent(this); + m_HeaderGrid.setBgColor(0,0,0,255); + + + // Now setup the listbox with the actual player data in it. + int headerX, headerY, headerWidth, headerHeight; + m_HeaderGrid.getBounds(headerX, headerY, headerWidth, headerHeight); + m_PlayerList.setBounds(headerX, headerY+headerHeight, headerWidth, tall - headerY - headerHeight - 6); + m_PlayerList.setBgColor(0,0,0,255); + m_PlayerList.setParent(this); + + for(int row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + + pGridRow->SetDimensions(NUM_COLUMNS, 1); + + for(int col=0; col < NUM_COLUMNS; col++) + { + m_PlayerEntries[col][row].setContentFitted(false); + m_PlayerEntries[col][row].setRow(row); + m_PlayerEntries[col][row].addInputSignal(this); + pGridRow->SetEntry(col, 0, &m_PlayerEntries[col][row]); + } + + pGridRow->setBgColor(0,0,0,255); +// pGridRow->SetSpacing(2, 0); + pGridRow->SetSpacing(0, 0); + pGridRow->CopyColumnWidths(&m_HeaderGrid); + pGridRow->AutoSetRowHeights(); + pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); + pGridRow->RepositionContents(); + + m_PlayerList.AddItem(pGridRow); + } + + + // Add the hit test panel. It is invisible and traps mouse clicks so we can go into squelch mode. + m_HitTestPanel.setBgColor(0,0,0,255); + m_HitTestPanel.setParent(this); + m_HitTestPanel.setBounds(0, 0, wide, tall); + m_HitTestPanel.addInputSignal(this); Initialize(); } + //----------------------------------------------------------------------------- // Purpose: Called each time a new level is started. //----------------------------------------------------------------------------- void ScorePanel::Initialize( void ) { // Clear out scoreboard data - _tablePanel->m_iLastKilledBy = 0; - _tablePanel->m_fLastKillTime = 0; + m_iLastKilledBy = 0; + m_fLastKillTime = 0; m_iPlayerNum = 0; m_iNumTeams = 0; memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); memset( g_TeamInfo, 0, sizeof g_TeamInfo ); } -//----------------------------------------------------------------------------- -// Purpose: Set the size of the header and table when this panel's size changes -//----------------------------------------------------------------------------- -void ScorePanel::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - - _headerPanel->setBounds(0,0,wide,SBOARD_HEADER_SIZE_Y); - _tablePanel->setBounds(0,20,wide,tall - SBOARD_HEADER_SIZE_Y); -} - //----------------------------------------------------------------------------- // Purpose: Recalculate the internal scoreboard data //----------------------------------------------------------------------------- @@ -372,19 +253,19 @@ void ScorePanel::Update() if (gViewPort->m_szServerName) { char sz[MAX_SERVERNAME_LENGTH + 16]; - sprintf(sz, " SCORES: %s", gViewPort->m_szServerName ); - m_pTitleLabel->setText(sz); + sprintf(sz, "%s", gViewPort->m_szServerName ); + m_TitleLabel.setText(sz); } - _tablePanel->m_iRows = 0; + m_iRows = 0; gViewPort->GetAllPlayersInfo(); // Clear out sorts - for (int i = 0; i < MAX_PLAYERS; i++) + for (int i = 0; i < NUM_ROWS; i++) { - _tablePanel->m_iSortedRows[i] = 0; - _tablePanel->m_iIsATeam[i] = TEAM_NO; - _tablePanel->m_bHasBeenSorted[i] = false; + m_iSortedRows[i] = 0; + m_iIsATeam[i] = TEAM_NO; + m_bHasBeenSorted[i] = false; } // If it's not teamplay, sort all the players. Otherwise, sort the teams. @@ -392,6 +273,11 @@ void ScorePanel::Update() SortPlayers( 0, NULL ); else SortTeams(); + + // set scrollbar range + m_PlayerList.SetScrollRange(m_iRows); + + FillGrid(); } //----------------------------------------------------------------------------- @@ -482,20 +368,17 @@ void ScorePanel::SortTeams() break; // Put this team in the sorted list - _tablePanel->m_iSortedRows[ _tablePanel->m_iRows ] = best_team; - _tablePanel->m_iIsATeam[ _tablePanel->m_iRows ] = TEAM_YES; + m_iSortedRows[ m_iRows ] = best_team; + m_iIsATeam[ m_iRows ] = TEAM_YES; g_TeamInfo[best_team].already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get sorted again - _tablePanel->m_iRows++; + m_iRows++; // Now sort all the players on this team SortPlayers( 0, g_TeamInfo[best_team].name ); } - // Now add all the spectators + // Add all the players who aren't in a team yet into spectators SortPlayers( TEAM_SPECTATORS, NULL ); - - // Now add all the players who aren't in a team yet - SortPlayers( TEAM_UNASSIGNED, NULL ); } //----------------------------------------------------------------------------- @@ -515,11 +398,11 @@ void ScorePanel::SortPlayers( int iTeam, char *team ) for ( int i = 1; i < MAX_PLAYERS; i++ ) { - if ( _tablePanel->m_bHasBeenSorted[i] == false && g_PlayerInfoList[i].name && g_PlayerExtraInfo[i].frags >= highest_frags ) + if ( m_bHasBeenSorted[i] == false && g_PlayerInfoList[i].name && g_PlayerExtraInfo[i].frags >= highest_frags ) { cl_entity_t *ent = gEngfuncs.GetEntityByIndex( i ); - if ( ent && ((iTeam == TEAM_SPECTATORS && g_IsSpectator[i] != 0) || (iTeam != TEAM_SPECTATORS && !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)))) ) + if ( ent && !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)) ) { extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) @@ -538,16 +421,21 @@ void ScorePanel::SortPlayers( int iTeam, char *team ) // If we haven't created the Team yet, do it first if (!bCreatedTeam && iTeam) { - _tablePanel->m_iIsATeam[ _tablePanel->m_iRows ] = iTeam; - _tablePanel->m_iRows++; + m_iIsATeam[ m_iRows ] = iTeam; + m_iRows++; bCreatedTeam = true; } // Put this player in the sorted list - _tablePanel->m_iSortedRows[ _tablePanel->m_iRows ] = best_player; - _tablePanel->m_bHasBeenSorted[ best_player ] = true; - _tablePanel->m_iRows++; + m_iSortedRows[ m_iRows ] = best_player; + m_bHasBeenSorted[ best_player ] = true; + m_iRows++; + } + + if (team) + { + m_iIsATeam[m_iRows++] = TEAM_BLANK; } } @@ -611,6 +499,352 @@ void ScorePanel::RebuildTeams() Update(); } + +void ScorePanel::FillGrid() +{ + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + SchemeHandle_t hScheme = pSchemes->getSchemeHandle("Scoreboard Text"); + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); + + Font *sfont = pSchemes->getFont(hScheme); + Font *tfont = pSchemes->getFont(hTitleScheme); + Font *smallfont = pSchemes->getFont(hSmallScheme); + + // update highlight position + int x, y; + getApp()->getCursorPos(x, y); + cursorMoved(x, y, this); + + // remove highlight row if we're not in squelch mode + if (!GetClientVoiceMgr()->IsInSquelchMode()) + { + m_iHighlightRow = -1; + } + + bool bNextRowIsGap = false; + + for(int row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + pGridRow->SetRowUnderline(0, false, 0, 0, 0, 0, 0); + + if(row >= m_iRows) + { + for(int col=0; col < NUM_COLUMNS; col++) + m_PlayerEntries[col][row].setVisible(false); + + continue; + } + + bool bRowIsGap = false; + if (bNextRowIsGap) + { + bNextRowIsGap = false; + bRowIsGap = true; + } + + for(int col=0; col < NUM_COLUMNS; col++) + { + CLabelHeader *pLabel = &m_PlayerEntries[col][row]; + + pLabel->setVisible(true); + pLabel->setText2(""); + pLabel->setImage(NULL); + pLabel->setFont(sfont); + pLabel->setTextOffset(0, 0); + + int rowheight = 13; + if (ScreenHeight > 480) + { + rowheight = YRES(rowheight); + } + else + { + // more tweaking, make sure icons fit at low res + rowheight = 15; + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setBgColor(0, 0, 0, 255); + + char sz[128]; + hud_player_info_t *pl_info = NULL; + team_info_t *team_info = NULL; + + if (m_iIsATeam[row] == TEAM_BLANK) + { + pLabel->setText(" "); + continue; + } + else if ( m_iIsATeam[row] == TEAM_YES ) + { + // Get the team's data + team_info = &g_TeamInfo[ m_iSortedRows[row] ]; + + // team color text for team names + pLabel->setFgColor( iTeamColors[team_info->teamnumber % iNumberOfTeamColors][0], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][1], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][2], + 0 ); + + // different height for team header rows + rowheight = 20; + if (ScreenHeight >= 480) + { + rowheight = YRES(rowheight); + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setFont(tfont); + + pGridRow->SetRowUnderline( 0, + true, + YRES(3), + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][0], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][1], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][2], + 0 ); + } + else if ( m_iIsATeam[row] == TEAM_SPECTATORS ) + { + // grey text for spectators + pLabel->setFgColor(100, 100, 100, 0); + + // different height for team header rows + rowheight = 20; + if (ScreenHeight >= 480) + { + rowheight = YRES(rowheight); + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setFont(tfont); + + pGridRow->SetRowUnderline(0, true, YRES(3), 100, 100, 100, 0); + } + else + { + // team color text for player names + pLabel->setFgColor( iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][0], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][1], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][2], + 0 ); + + // Get the player's data + pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; + + // Set background color + if ( pl_info->thisplayer ) // if it is their name, draw it a different color + { + // Highlight this player + pLabel->setFgColor(Scheme::sc_white); + pLabel->setBgColor( iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][0], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][1], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][2], + 196 ); + } + else if ( m_iSortedRows[row] == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) + { + // Killer's name + pLabel->setBgColor( 255,0,0, 255 - ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); + } + } + + // Align + if (col == COLUMN_NAME || col == COLUMN_CLASS) + { + pLabel->setContentAlignment( vgui::Label::a_west ); + } + else if (col == COLUMN_TRACKER) + { + pLabel->setContentAlignment( vgui::Label::a_center ); + } + else + { + pLabel->setContentAlignment( vgui::Label::a_east ); + } + + // Fill out with the correct data + strcpy(sz, ""); + if ( m_iIsATeam[row] ) + { + char sz2[128]; + + switch (col) + { + case COLUMN_NAME: + if ( m_iIsATeam[row] == TEAM_SPECTATORS ) + { + sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ) ); + } + else + { + sprintf( sz2, gViewPort->GetTeamName(team_info->teamnumber) ); + } + + strcpy(sz, sz2); + + // Append the number of players + if ( m_iIsATeam[row] == TEAM_YES ) + { + if (team_info->players == 1) + { + sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player" ) ); + } + else + { + sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player_plural" ) ); + } + + pLabel->setText2(sz2); + pLabel->setFont2(smallfont); + } + break; + case COLUMN_VOICE: + break; + case COLUMN_CLASS: + break; + case COLUMN_KILLS: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->frags ); + break; + case COLUMN_DEATHS: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->deaths ); + break; + case COLUMN_LATENCY: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->ping ); + break; + default: + break; + } + } + else + { + bool bShowClass = false; + + switch (col) + { + case COLUMN_NAME: + /* + if (g_pTrackerUser) + { + int playerSlot = m_iSortedRows[row]; + int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); + const char *trackerName = g_pTrackerUser->GetUserName(trackerID); + if (trackerName && *trackerName) + { + sprintf(sz, " (%s)", trackerName); + pLabel->setText2(sz); + } + } + */ + sprintf(sz, "%s ", pl_info->name); + break; + case COLUMN_VOICE: + sz[0] = 0; + // in HLTV mode allow spectator to turn on/off commentator voice + if (!pl_info->thisplayer || gEngfuncs.IsSpectateOnly() ) + { + GetClientVoiceMgr()->UpdateSpeakerImage(pLabel, m_iSortedRows[row]); + } + break; + case COLUMN_CLASS: + // No class for other team's members (unless allied or spectator) + if ( gViewPort && EV_TFC_IsAllyTeam( g_iTeamNumber, g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) ) + bShowClass = true; + // Don't show classes if this client hasnt picked a team yet + if ( g_iTeamNumber == 0 ) + bShowClass = false; +#ifdef _TFC + // in TFC show all classes in spectator mode + if ( g_iUser1 ) + bShowClass = true; +#endif + + if (bShowClass) + { + // Only print Civilian if this team are all civilians + bool bNoClass = false; + if ( g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass == 0 ) + { + if ( gViewPort->GetValidClasses( g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) != -1 ) + bNoClass = true; + } + + if (bNoClass) + sprintf(sz, ""); + else + sprintf( sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[ g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass ] ) ); + } + else + { + strcpy(sz, ""); + } + break; + + case COLUMN_TRACKER: + if (g_pTrackerUser) + { + int playerSlot = m_iSortedRows[row]; + int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); + + if (g_pTrackerUser->IsFriend(trackerID) && trackerID != g_pTrackerUser->GetTrackerID()) + { + pLabel->setImage(m_pTrackerIcon); + pLabel->setFgColorAsImageColor(false); + m_pTrackerIcon->setColor(Color(255, 255, 255, 0)); + } + } + break; + +#ifdef _TFC + case COLUMN_KILLS: + if (g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber) + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].frags ); + break; + case COLUMN_DEATHS: + if (g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber) + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].deaths ); + break; + case COLUMN_LATENCY: + if (g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber) + sprintf(sz, "%d", g_PlayerInfoList[ m_iSortedRows[row] ].ping ); + break; +#else + case COLUMN_KILLS: + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].frags ); + break; + case COLUMN_DEATHS: + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].deaths ); + break; + case COLUMN_LATENCY: + sprintf(sz, "%d", g_PlayerInfoList[ m_iSortedRows[row] ].ping ); + break; +#endif + default: + break; + } + } + + pLabel->setText(sz); + } + } + + for(row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + + pGridRow->AutoSetRowHeights(); + pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); + pGridRow->RepositionContents(); + } + + // hack, for the thing to resize + m_PlayerList.getSize(x, y); + m_PlayerList.setSize(x, y); +} + + //----------------------------------------------------------------------------- // Purpose: Setup highlights for player names in scoreboard //----------------------------------------------------------------------------- @@ -619,11 +853,269 @@ void ScorePanel::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 ) { - _tablePanel->m_iLastKilledBy = killer ? killer : m_iPlayerNum; - _tablePanel->m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds + 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 ) - _tablePanel->m_iLastKilledBy = m_iPlayerNum; + m_iLastKilledBy = m_iPlayerNum; } } + +void ScorePanel::Open( void ) +{ + RebuildTeams(); + setVisible(true); + m_HitTestPanel.setVisible(true); +} + + +void ScorePanel::mousePressed(MouseCode code, Panel* panel) +{ + if(gHUD.m_iIntermission) + return; + + if (!GetClientVoiceMgr()->IsInSquelchMode()) + { + GetClientVoiceMgr()->StartSquelchMode(); + m_HitTestPanel.setVisible(false); + } + else if (m_iHighlightRow >= 0) + { + // mouse has been pressed, toggle mute state + int iPlayer = m_iSortedRows[m_iHighlightRow]; + if (iPlayer > 0) + { + // print text message + hud_player_info_t *pl_info = &g_PlayerInfoList[iPlayer]; + + if (pl_info && pl_info->name && pl_info->name[0]) + { + char string[256]; + if (GetClientVoiceMgr()->IsPlayerBlocked(iPlayer)) + { + char string1[1024]; + + // remove mute + GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, false); + + sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Unmuted" ), pl_info->name ); + sprintf( string, "%c** %s\n", HUD_PRINTTALK, string1 ); + + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + else + { + char string1[1024]; + char string2[1024]; + + // mute the player + GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, true); + + sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Muted" ), pl_info->name ); + sprintf( string2, CHudTextMessage::BufferedLocaliseTextString( "#No_longer_hear_that_player" ) ); + sprintf( string, "%c** %s %s\n", HUD_PRINTTALK, string1, string2 ); + + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + } + } + } +} + +void ScorePanel::cursorMoved(int x, int y, Panel *panel) +{ + if (GetClientVoiceMgr()->IsInSquelchMode()) + { + // look for which cell the mouse is currently over + for (int i = 0; i < NUM_ROWS; i++) + { + int row, col; + if (m_PlayerGrids[i].getCellAtPoint(x, y, row, col)) + { + MouseOverCell(i, col); + return; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handles mouse movement over a cell +// Input : row - +// col - +//----------------------------------------------------------------------------- +void ScorePanel::MouseOverCell(int row, int col) +{ + CLabelHeader *label = &m_PlayerEntries[col][row]; + + // clear the previously highlighted label + if (m_pCurrentHighlightLabel != label) + { + m_pCurrentHighlightLabel = NULL; + m_iHighlightRow = -1; + } + if (!label) + return; + + // don't act on teams + if (m_iIsATeam[row] != TEAM_NO) + return; + + // don't act on disconnected players or ourselves + hud_player_info_t *pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; + if (!pl_info->name || !pl_info->name[0]) + return; + + if (pl_info->thisplayer && !gEngfuncs.IsSpectateOnly() ) + return; + + // only act on audible players + if (!GetClientVoiceMgr()->IsPlayerAudible(m_iSortedRows[row])) + return; + + // setup the new highlight + m_pCurrentHighlightLabel = label; + m_iHighlightRow = row; +} + +//----------------------------------------------------------------------------- +// Purpose: Label paint functions - take into account current highligh status +//----------------------------------------------------------------------------- +void CLabelHeader::paintBackground() +{ + Color oldBg; + getBgColor(oldBg); + + if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) + { + setBgColor(134, 91, 19, 0); + } + + Panel::paintBackground(); + + setBgColor(oldBg); +} + + +//----------------------------------------------------------------------------- +// Purpose: Label paint functions - take into account current highligh status +//----------------------------------------------------------------------------- +void CLabelHeader::paint() +{ + Color oldFg; + getFgColor(oldFg); + + if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) + { + setFgColor(255, 255, 255, 0); + } + + // draw text + int x, y, iwide, itall; + getTextSize(iwide, itall); + calcAlignment(iwide, itall, x, y); + _dualImage->setPos(x, y); + + int x1, y1; + _dualImage->GetImage(1)->getPos(x1, y1); + _dualImage->GetImage(1)->setPos(_gap, y1); + + _dualImage->doPaint(this); + + // get size of the panel and the image + if (_image) + { + _image->getSize(iwide, itall); + calcAlignment(iwide, itall, x, y); + _image->setPos(x, y); + _image->doPaint(this); + } + + setFgColor(oldFg[0], oldFg[1], oldFg[2], oldFg[3]); +} + + +void CLabelHeader::calcAlignment(int iwide, int itall, int &x, int &y) +{ + // calculate alignment ourselves, since vgui is so broken + int wide, tall; + getSize(wide, tall); + + x = 0, y = 0; + + // align left/right + switch (_contentAlignment) + { + // left + case Label::a_northwest: + case Label::a_west: + case Label::a_southwest: + { + x = 0; + break; + } + + // center + case Label::a_north: + case Label::a_center: + case Label::a_south: + { + x = (wide - iwide) / 2; + break; + } + + // right + case Label::a_northeast: + case Label::a_east: + case Label::a_southeast: + { + x = wide - iwide; + break; + } + } + + // top/down + switch (_contentAlignment) + { + // top + case Label::a_northwest: + case Label::a_north: + case Label::a_northeast: + { + y = 0; + break; + } + + // center + case Label::a_west: + case Label::a_center: + case Label::a_east: + { + y = (tall - itall) / 2; + break; + } + + // south + case Label::a_southwest: + case Label::a_south: + case Label::a_southeast: + { + y = tall - itall; + break; + } + } + +// don't clip to Y +// if (y < 0) +// { +// y = 0; +// } + if (x < 0) + { + x = 0; + } + + x += _offset[0]; + y += _offset[1]; +} diff --git a/cl_dll/vgui_ScorePanel.h b/cl_dll/vgui_ScorePanel.h index 89cb340..d718ec7 100644 --- a/cl_dll/vgui_ScorePanel.h +++ b/cl_dll/vgui_ScorePanel.h @@ -7,116 +7,301 @@ #include #include #include +#include +#include "..\game_shared\vgui_listbox.h" -#define MAX_SCORES 10 +#include + +#define MAX_SCORES 10 +#define MAX_SCOREBOARD_TEAMS 5 // Scoreboard cells -#define NUM_COLUMNS 5 -#define NUM_ROWS (MAX_PLAYERS + MAX_TEAMS) - -// Scoreboard positions -#define SBOARD_INDENT_X XRES(104) -#define SBOARD_INDENT_Y YRES(40) +#define COLUMN_TRACKER 0 +#define COLUMN_NAME 1 +#define COLUMN_CLASS 2 +#define COLUMN_KILLS 3 +#define COLUMN_DEATHS 4 +#define COLUMN_LATENCY 5 +#define COLUMN_VOICE 6 +#define COLUMN_BLANK 7 +#define NUM_COLUMNS 8 +#define NUM_ROWS (MAX_PLAYERS + (MAX_SCOREBOARD_TEAMS * 2)) using namespace vgui; +class CTextImage2 : public Image +{ +public: + CTextImage2() + { + _image[0] = new TextImage(""); + _image[1] = new TextImage(""); + } + + ~CTextImage2() + { + delete _image[0]; + delete _image[1]; + } + + TextImage *GetImage(int image) + { + return _image[image]; + } + + void getSize(int &wide, int &tall) + { + int w1, w2, t1, t2; + _image[0]->getTextSize(w1, t1); + _image[1]->getTextSize(w2, t2); + + wide = w1 + w2; + tall = max(t1, t2); + setSize(wide, tall); + } + + void doPaint(Panel *panel) + { + _image[0]->doPaint(panel); + _image[1]->doPaint(panel); + } + + void setPos(int x, int y) + { + _image[0]->setPos(x, y); + + int swide, stall; + _image[0]->getSize(swide, stall); + + int wide, tall; + _image[1]->getSize(wide, tall); + _image[1]->setPos(x + wide, y + (stall * 0.9) - tall); + } + + void setColor(Color color) + { + _image[0]->setColor(color); + } + + void setColor2(Color color) + { + _image[1]->setColor(color); + } + +private: + TextImage *_image[2]; + +}; + //----------------------------------------------------------------------------- // Purpose: Custom label for cells in the Scoreboard's Table Header //----------------------------------------------------------------------------- class CLabelHeader : public Label { -private: - void Init( void ) - { - setFont( Scheme::sf_primary1 ); - setFgColor( Scheme::sc_primary1 ); - setBgColor( 0,0,0, 255 ); - } public: - - CLabelHeader(const char* text,int x,int y,int wide,int tall) : Label(text,x,y,wide,tall) + CLabelHeader() : Label("") { - Init(); + _dualImage = new CTextImage2(); + _dualImage->setColor2(Color(255, 170, 0, 0)); + _row = -2; + _useFgColorAsImageColor = true; + _offset[0] = 0; + _offset[1] = 0; } - CLabelHeader(const char* text, bool bAlignLeft = false) : Label(text) + ~CLabelHeader() { - Init(); - - if (bAlignLeft) - setContentAlignment(Label::a_west); + delete _dualImage; } + + void setRow(int row) + { + _row = row; + } + + void setFgColorAsImageColor(bool state) + { + _useFgColorAsImageColor = state; + } + + virtual void setText(int textBufferLen, const char* text) + { + _dualImage->GetImage(0)->setText(text); + + // calculate the text size + Font *font = _dualImage->GetImage(0)->getFont(); + _gap = 0; + for (const char *ch = text; *ch != 0; ch++) + { + int a, b, c; + font->getCharABCwide(*ch, a, b, c); + _gap += (a + b + c); + } + + _gap += XRES(5); + } + + virtual void setText(const char* text) + { + // strip any non-alnum characters from the end + char buf[512]; + strcpy(buf, text); + + int len = strlen(buf); + while (len && isspace(buf[--len])) + { + buf[len] = 0; + } + + CLabelHeader::setText(0, buf); + } + + void setText2(const char *text) + { + _dualImage->GetImage(1)->setText(text); + } + + void getTextSize(int &wide, int &tall) + { + _dualImage->getSize(wide, tall); + } + + void setFgColor(int r,int g,int b,int a) + { + Label::setFgColor(r,g,b,a); + Color color(r,g,b,a); + _dualImage->setColor(color); + _dualImage->setColor2(color); + if (_image && _useFgColorAsImageColor) + { + _image->setColor(color); + } + repaint(); + } + + void setFgColor(Scheme::SchemeColor sc) + { + Label::setFgColor(sc); + _dualImage->setColor(sc); + } + + void setFont(Font *font) + { + _dualImage->GetImage(0)->setFont(font); + } + + void setFont2(Font *font) + { + _dualImage->GetImage(1)->setFont(font); + } + + // this adjust the absolute position of the text after alignment is calculated + void setTextOffset(int x, int y) + { + _offset[0] = x; + _offset[1] = y; + } + + void paint(); + void paintBackground(); + void calcAlignment(int iwide, int itall, int &x, int &y); + +private: + CTextImage2 *_dualImage; + int _row; + int _gap; + int _offset[2]; + bool _useFgColorAsImageColor; }; -//----------------------------------------------------------------------------- -// Purpose: Custom Table for the scoreboard -//----------------------------------------------------------------------------- -class ScoreTablePanel : public TablePanel -{ -private: - TextGrid *_textGrid; - Label *m_pLabel; +class ScoreTablePanel; -public: - int m_iRows; - int m_iSortedRows[NUM_ROWS]; - int m_iIsATeam[NUM_ROWS]; - bool m_bHasBeenSorted[MAX_PLAYERS]; - int m_iLastKilledBy; - int m_fLastKillTime; - -public: - ScoreTablePanel(int x,int y,int wide,int tall,int columnCount) : TablePanel(x,y,wide,tall,columnCount) - { - setCellEditingEnabled(false); - - m_pLabel = new Label( "", 0, 0, wide, tall ); - m_pLabel->setFont( Scheme::sf_primary2 ); - } - virtual int getRowCount() - { - return m_iRows; - } - virtual Panel* startCellEditing(int column,int row) - { - return null; - } - virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected); - virtual int getCellTall(int row); -}; +#include "..\game_shared\vgui_grid.h" +#include "..\game_shared\vgui_defaultinputsignal.h" //----------------------------------------------------------------------------- // Purpose: Scoreboard back panel //----------------------------------------------------------------------------- -class ScorePanel : public Panel +class ScorePanel : public Panel, public vgui::CDefaultInputSignal { private: - HeaderPanel *_headerPanel; - ScoreTablePanel *_tablePanel; - Label *m_pTitleLabel; + // Default panel implementation doesn't forward mouse messages when there is no cursor and we need them. + class HitTestPanel : public Panel + { + public: + virtual void internalMousePressed(MouseCode code); + }; + + +private: + + Label m_TitleLabel; + + // Here is how these controls are arranged hierarchically. + // m_HeaderGrid + // m_HeaderLabels + + // m_PlayerGridScroll + // m_PlayerGrid + // m_PlayerEntries + + CGrid m_HeaderGrid; + CLabelHeader m_HeaderLabels[NUM_COLUMNS]; // Labels above the + CLabelHeader *m_pCurrentHighlightLabel; + int m_iHighlightRow; + + vgui::CListBox m_PlayerList; + CGrid m_PlayerGrids[NUM_ROWS]; // The grid with player and team info. + CLabelHeader m_PlayerEntries[NUM_COLUMNS][NUM_ROWS]; // Labels for the grid entries. + + ScorePanel::HitTestPanel m_HitTestPanel; + + CLabelHeader* GetPlayerEntry(int x, int y) {return &m_PlayerEntries[x][y];} + + vgui::BitmapTGA *m_pTrackerIcon; + public: - int m_iNumTeams; - int m_iPlayerNum; - int m_iShowscoresHeld; + + int m_iNumTeams; + int m_iPlayerNum; + int m_iShowscoresHeld; + + int m_iRows; + int m_iSortedRows[NUM_ROWS]; + int m_iIsATeam[NUM_ROWS]; + bool m_bHasBeenSorted[MAX_PLAYERS]; + int m_iLastKilledBy; + int m_fLastKillTime; + public: + ScorePanel(int x,int y,int wide,int tall); - virtual void setSize(int wide,int tall); void Update( void ); + void SortTeams( void ); void SortPlayers( int iTeam, char *team ); void RebuildTeams( void ); + + void FillGrid(); + void DeathMsg( int killer, int victim ); void Initialize( void ); - void Open( void ) - { - RebuildTeams(); - setVisible(true); - } + void Open( void ); + + void MouseOverCell(int row, int col); + +// InputSignal overrides. +public: + + virtual void mousePressed(MouseCode code, Panel* panel); + virtual void cursorMoved(int x, int y, Panel *panel); + + friend CLabelHeader; }; -#endif \ No newline at end of file +#endif diff --git a/cl_dll/vgui_TeamFortressViewport.cpp b/cl_dll/vgui_TeamFortressViewport.cpp index d755fd1..b9f16f1 100644 --- a/cl_dll/vgui_TeamFortressViewport.cpp +++ b/cl_dll/vgui_TeamFortressViewport.cpp @@ -44,6 +44,7 @@ #include "camera.h" #include "in_defs.h" #include "parsemsg.h" +#include "pm_shared.h" #include "../engine/keydefs.h" #include "demo.h" #include "demo_api.h" @@ -59,6 +60,19 @@ int g_iPlayerClass; int g_iTeamNumber; int g_iUser1; int g_iUser2; +int g_iUser3; + +// Scoreboard positions +#define SBOARD_INDENT_X XRES(104) +#define SBOARD_INDENT_Y YRES(40) + +// low-res scoreboard indents +#define SBOARD_INDENT_X_512 30 +#define SBOARD_INDENT_Y_512 30 + +#define SBOARD_INDENT_X_400 0 +#define SBOARD_INDENT_Y_400 20 + void IN_ResetMouse( void ); extern CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ); @@ -66,15 +80,17 @@ extern CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *s using namespace vgui; // Team Colors +int iNumberOfTeamColors = 5; int iTeamColors[5][3] = { - { 255, 255, 255 }, - { 66, 115, 247 }, - { 220, 51, 38 }, - { 240, 135, 0 }, - { 115, 240, 115 }, + { 255, 170, 0 }, // HL orange (default) + { 125, 165, 210 }, // Blue + { 200, 90, 70 }, // Red + { 225, 205, 45 }, // Yellow + { 145, 215, 140 }, // Green }; + // Used for Class specific buttons char *sTFClasses[] = { @@ -470,9 +486,6 @@ TeamFortressViewport::TeamFortressViewport(int x,int y,int wide,int tall) : Pane m_pCurrentMenu = NULL; m_pCurrentCommandMenu = NULL; - CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE ); // 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 - Initialize(); addInputSignal( new CViewPortInputHandler ); @@ -595,7 +608,7 @@ void TeamFortressViewport::CreateCommandMenu( void ) m_pCommandMenus[0]->setParent(this); m_pCommandMenus[0]->setVisible(false); m_iNumMenus = 1; - m_iCurrentTeamNumber = m_iUser1 = m_iUser2 = 0; + m_iCurrentTeamNumber = m_iUser1 = m_iUser2 = m_iUser3 = 0; // Read Command Menu from the txt file char token[1024]; @@ -1227,6 +1240,9 @@ void TeamFortressViewport::HideScoreBoard( void ) if (m_pScoreBoard) { m_pScoreBoard->setVisible(false); + + GetClientVoiceMgr()->StopSquelchMode(); + UpdateCursorState(); } } @@ -1276,26 +1292,61 @@ void TeamFortressViewport::UpdateCommandMenu() void TeamFortressViewport::UpdateSpectatorMenu() { - char sz[64]; + char helpString1[128]; + char helpString2[128]; + int mode; + + m_iUser1 = g_iUser1; + m_iUser2 = g_iUser2; + m_iUser3 = g_iUser3; if (!m_pSpectatorMenu) return; - if (m_iUser1) + if ( gEngfuncs.IsSpectateOnly() ) + { + mode = gHUD.m_Spectator.m_iMainMode; // spec mode is set client side + + sprintf(helpString2, "#Spec_Only_Help"); + } + else + { + // spec mode is given by server + mode = m_iUser1; + // set normal help text + sprintf(helpString2, "#Spec_Help" ); + } + + if ( mode && ( gEngfuncs.IsSpectateOnly() != 2) ) // don't draw in dev_overview mode { m_pSpectatorMenu->setVisible( true ); - if (m_iUser2 > 0) + // check if we're locked onto a target, show the player's name + if ( (m_iUser2 > 0) && (m_iUser2 <= gEngfuncs.GetMaxClients()) ) { - // Locked onto a target, show the player's name - sprintf(sz, "#Spec_Mode%d : %s", m_iUser1, g_PlayerInfoList[ m_iUser2 ].name); - m_pSpectatorLabel->setText( CHudTextMessage::BufferedLocaliseTextString( sz ) ); + // Locked onto a target, show the player's name + + + if ( g_PlayerInfoList[ m_iUser2 ].name != NULL ) + sprintf(helpString1, "#Spec_Mode%d : %s", mode, g_PlayerInfoList[ m_iUser2 ].name ); + + else + sprintf(helpString1, "#Spec_Mode%d", mode ); } else { - sprintf(sz, "#Spec_Mode%d", m_iUser1); - m_pSpectatorLabel->setText( CHudTextMessage::BufferedLocaliseTextString( sz ) ); + sprintf(helpString1, "#Spec_Mode%d", mode); } + + if ( m_iUser1 == OBS_DIRECTED ) + { + char tempString[128]; + sprintf(tempString, "#Directed %s", helpString1); + strcpy( helpString1, tempString ); + } + + m_pSpectatorLabel->setText( CHudTextMessage::BufferedLocaliseTextString( helpString1 ) ); + m_pSpectatorHelpLabel->setText( CHudTextMessage::BufferedLocaliseTextString( helpString2 ) ); } else { @@ -1306,7 +1357,19 @@ void TeamFortressViewport::UpdateSpectatorMenu() //====================================================================== void TeamFortressViewport::CreateScoreBoard( void ) { - m_pScoreBoard = new ScorePanel(SBOARD_INDENT_X,SBOARD_INDENT_Y, ScreenWidth - (SBOARD_INDENT_X * 2), ScreenHeight - (SBOARD_INDENT_Y * 2)); + int xdent = SBOARD_INDENT_X, ydent = SBOARD_INDENT_Y; + if (ScreenWidth == 512) + { + xdent = SBOARD_INDENT_X_512; + ydent = SBOARD_INDENT_Y_512; + } + else if (ScreenWidth == 400) + { + xdent = SBOARD_INDENT_X_400; + ydent = SBOARD_INDENT_Y_400; + } + + m_pScoreBoard = new ScorePanel(xdent, ydent, ScreenWidth - (xdent * 2), ScreenHeight - (ydent * 2)); m_pScoreBoard->setParent(this); m_pScoreBoard->setVisible(false); } @@ -1462,6 +1525,12 @@ void TeamFortressViewport::ShowVGUIMenu( int iMenu ) if ( gEngfuncs.pDemoAPI->IsPlayingback() ) return; + // Don't open any menus except the MOTD during intermission + // MOTD needs to be accepted because it's sent down to the client + // after map change, before intermission's turned off + if ( gHUD.m_iIntermission && iMenu != MENU_INTRO ) + return; + // Don't create one if it's already in the list if (m_pCurrentMenu) { @@ -1509,6 +1578,7 @@ void TeamFortressViewport::ShowVGUIMenu( int iMenu ) pNewMenu->SetMenuID( iMenu ); pNewMenu->SetActive( true ); + pNewMenu->setParent(this); // See if another menu is visible, and if so, cache this one for display once the other one's finished if (m_pCurrentMenu) @@ -1649,16 +1719,16 @@ void TeamFortressViewport::CreateSpectatorMenu() m_pSpectatorLabel->setContentAlignment( vgui::Label::a_north ); // Create the Help - Label *pLabel = new Label( CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help" ), 0, YRES(25), ScreenWidth, YRES(15) ); - pLabel->setParent( m_pSpectatorMenu ); - pLabel->setFont( pSchemes->getFont(hHelpText) ); + m_pSpectatorHelpLabel = new Label( CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help" ), 0, YRES(25), ScreenWidth, YRES(15) ); + m_pSpectatorHelpLabel->setParent( m_pSpectatorMenu ); + m_pSpectatorHelpLabel->setFont( pSchemes->getFont(hHelpText) ); pSchemes->getFgColor( hHelpText, r, g, b, a ); - pLabel->setFgColor( r, g, b, a ); + m_pSpectatorHelpLabel->setFgColor( r, g, b, a ); pSchemes->getBgColor( hHelpText, r, g, b, a ); - pLabel->setBgColor( r, g, b, 255 ); - pLabel->setContentAlignment( vgui::Label::a_north ); + m_pSpectatorHelpLabel->setBgColor( r, g, b, 255 ); + m_pSpectatorHelpLabel->setContentAlignment( vgui::Label::a_north ); - pLabel = new Label( CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help2" ), 0, YRES(40), ScreenWidth, YRES(20) ); + Label *pLabel = new Label( CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help2" ), 0, YRES(40), ScreenWidth, YRES(20) ); pLabel->setParent( m_pSpectatorMenu ); pLabel->setFont( pSchemes->getFont(hHelpText) ); pSchemes->getFgColor( hHelpText, r, g, b, a ); @@ -1666,6 +1736,7 @@ void TeamFortressViewport::CreateSpectatorMenu() pSchemes->getBgColor( hHelpText, r, g, b, a ); pLabel->setBgColor( r, g, b, 255 ); pLabel->setContentAlignment( vgui::Label::a_center ); + } //====================================================================================== @@ -1686,7 +1757,7 @@ void TeamFortressViewport::UpdateOnPlayerInfo() void TeamFortressViewport::UpdateCursorState() { // Need cursor if any VGUI window is up - if ( m_pCurrentMenu || m_pTeamMenu->isVisible() || m_pServerBrowser->isVisible() ) + if ( m_pCurrentMenu || m_pTeamMenu->isVisible() || m_pServerBrowser->isVisible() || GetClientVoiceMgr()->IsInSquelchMode() ) { g_iVisibleMouse = true; App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); @@ -1727,6 +1798,13 @@ void TeamFortressViewport::GetAllPlayersInfo( void ) void TeamFortressViewport::paintBackground() { + if (m_pScoreBoard) + { + int x, y; + getApp()->getCursorPos(x, y); + m_pScoreBoard->cursorMoved(x, y, m_pScoreBoard); + } + // See if the command menu is visible and needs recalculating due to some external change if ( g_iTeamNumber != m_iCurrentTeamNumber ) { @@ -1748,10 +1826,9 @@ void TeamFortressViewport::paintBackground() } // See if the Spectator Menu needs to be update + // no update if only second target (m_iUser3) changes if ( g_iUser1 != m_iUser1 || g_iUser2 != m_iUser2 ) { - m_iUser1 = g_iUser1; - m_iUser2 = g_iUser2; UpdateSpectatorMenu(); } @@ -1932,9 +2009,13 @@ int TeamFortressViewport::MsgFunc_TeamNames(const char *pszName, int iSize, void if (m_pTeamButtons[i]) m_pTeamButtons[i]->setText( m_sTeamNames[teamNum] ); - // Set the disguise buttons - if (m_pDisguiseButtons[i]) - m_pDisguiseButtons[i]->setText( m_sTeamNames[teamNum] ); + // range check this value...m_pDisguiseButtons[5]; + if ( teamNum < 5 ) + { + // Set the disguise buttons + if ( m_pDisguiseButtons[teamNum] ) + m_pDisguiseButtons[teamNum]->setText( m_sTeamNames[teamNum] ); + } } // Update the Team Menu @@ -1995,7 +2076,10 @@ int TeamFortressViewport::MsgFunc_MOTD( const char *pszName, int iSize, void *pb BEGIN_READ( pbuf, iSize ); m_iGotAllMOTD = READ_BYTE(); - strncat( m_szMOTD, READ_STRING(), sizeof(m_szMOTD) - strlen(m_szMOTD) ); + + int roomInArray = sizeof(m_szMOTD) - strlen(m_szMOTD) - 1; + + strncat( m_szMOTD, READ_STRING(), roomInArray >= 0 ? roomInArray : 0 ); m_szMOTD[ sizeof(m_szMOTD)-1 ] = '\0'; if ( m_iGotAllMOTD ) @@ -2052,6 +2136,10 @@ int TeamFortressViewport::MsgFunc_ScoreInfo( const char *pszName, int iSize, voi g_PlayerExtraInfo[cl].playerclass = playerclass; g_PlayerExtraInfo[cl].teamnumber = teamnumber; + //Dont go bellow 0! + if ( g_PlayerExtraInfo[cl].teamnumber < 0 ) + g_PlayerExtraInfo[cl].teamnumber = 0; + UpdateOnPlayerInfo(); } diff --git a/cl_dll/vgui_TeamFortressViewport.h b/cl_dll/vgui_TeamFortressViewport.h index 61257fa..177f778 100644 --- a/cl_dll/vgui_TeamFortressViewport.h +++ b/cl_dll/vgui_TeamFortressViewport.h @@ -45,21 +45,18 @@ class CClassMenuPanel; class CTeamMenuPanel; char* GetVGUITGAName(const char *pszName); -BitmapTGA *LoadTGA( const char* pImageName ); +BitmapTGA *LoadTGAForRes(const char* pImageName); void ScaleColors( int &r, int &g, int &b, int a ); extern char *sTFClassSelection[]; extern int sTFValidClassInts[]; extern char *sLocalisedClasses[]; extern int iTeamColors[5][3]; +extern int iNumberOfTeamColors; #define MAX_SERVERNAME_LENGTH 32 -// Use this to set any co-ords in 640x480 space -#define XRES(x) (x * ((float)ScreenWidth / 640)) -#define YRES(y) (y * ((float)ScreenHeight / 480)) - // Command Menu positions -#define MAX_MENUS 40 +#define MAX_MENUS 80 #define MAX_BUTTONS 100 #define BUTTON_SIZE_Y YRES(30) @@ -268,6 +265,7 @@ private: int m_iCurrentPlayerClass; int m_iUser1; int m_iUser2; + int m_iUser3; // VGUI Menus void CreateTeamMenu( void ); @@ -295,6 +293,7 @@ private: // Spectator "menu" CTransparentPanel *m_pSpectatorMenu; Label *m_pSpectatorLabel; + Label *m_pSpectatorHelpLabel; int m_iAllowSpectators; // Data for specific sections of the Command Menu @@ -385,6 +384,7 @@ public: virtual void paintBackground(); CSchemeManager *GetSchemeManager( void ) { return &m_SchemeManager; } + ScorePanel *GetScoreBoard( void ) { return m_pScoreBoard; } void *operator new( size_t stAllocateBlock ); @@ -1252,4 +1252,4 @@ public: } }; -#endif \ No newline at end of file +#endif diff --git a/cl_dll/vgui_teammenu.cpp b/cl_dll/vgui_teammenu.cpp index 9edbfca..af04734 100644 --- a/cl_dll/vgui_teammenu.cpp +++ b/cl_dll/vgui_teammenu.cpp @@ -100,7 +100,7 @@ CTeamMenuPanel::CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,i pSchemes->getBgColor( hTeamWindowText, r, g, b, a ); m_pBriefing->setBgColor( r, g, b, a ); - m_pBriefing->setText("Map Description not available."); + m_pBriefing->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Map_Description_not_available") ); // Team Menu buttons for (int i = 1; i <= 5; i++) @@ -132,7 +132,10 @@ CTeamMenuPanel::CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,i m_pTeamInfoPanel[i] = new TextPanel("", TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_INFO_Y, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_Y ); m_pTeamInfoPanel[i]->setParent( m_pTeamWindow ); m_pTeamInfoPanel[i]->setFont( pSchemes->getFont(hTeamInfoText) ); - m_pTeamInfoPanel[i]->setFgColor( iTeamColors[i][0], iTeamColors[i][1], iTeamColors[i][2], 0 ); + m_pTeamInfoPanel[i]->setFgColor( iTeamColors[i % iNumberOfTeamColors][0], + iTeamColors[i % iNumberOfTeamColors][1], + iTeamColors[i % iNumberOfTeamColors][2], + 0 ); m_pTeamInfoPanel[i]->setBgColor( 0,0,0, 255 ); } diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index df282f6..7435497 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -16,6 +16,7 @@ #include "screenfade.h" #include "shake.h" + // Spectator Mode extern "C" { @@ -39,6 +40,8 @@ extern "C" void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); int PM_GetInfo( int ent ); + void InterpolateAngles( float *start, float *end, float *output, float frac ); + float AngleBetweenVectors( float * v1, float * v2 ); } @@ -84,6 +87,7 @@ 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 ) { @@ -110,7 +114,7 @@ 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; @@ -139,7 +143,7 @@ void V_InterpolateAngles( float *start, float *end, float *output, float 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 ) @@ -563,13 +567,14 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) frac = min( 1.0, frac ); // interpolate angles - V_InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], pparams->cl_viewangles, frac ); + InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], pparams->cl_viewangles, frac ); VectorCopy( pparams->cl_viewangles, vecNewViewAngles ); } } } + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); gEngfuncs.V_CalcShake(); @@ -871,6 +876,284 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) lasttime = pparams->time; v_origin = pparams->vieworg; + +} +void V_GetInEyePos(int entity, float *origin, float * angles ) +{ + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( entity ); + + if ( !ent ) + return; + + if ( !ent->player || g_PlayerInfoList[entity].name == NULL ) + return; + + VectorCopy ( ent->origin, origin ); + VectorCopy ( ent->angles, angles ); + + angles[0]*=-M_PI; + + 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 +} + +/* +================== +V_CalcSpectatorRefdef + +================== +*/ +void V_CalcSpectatorRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + vec3_t angles; + static viewinterp_t ViewInterp; + + static float lasttime; + + static float lastang[3]; + static float lastorg[3]; + + vec3_t delta; + + + // 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(); + + + // refresh position + VectorCopy ( pparams->simorg, pparams->vieworg ); + + // done all the spectator smoothing only once in the first frame + + // Observer angle capturing and smoothing + if ( iHasNewViewOrigin ) + { + // Get the angles from the physics code + VectorCopy( vecNewViewOrigin, pparams->vieworg ); + } + else + { + // otherwise copy normal vieworigin into vecNewViewOrigin + VectorCopy( pparams->vieworg, vecNewViewOrigin ); + } + + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + // Observer angle capturing and smoothing + if ( iHasNewViewAngles ) + { + // Get the angles from the physics code + VectorCopy( vecNewViewAngles, pparams->viewangles ); + } + else + { + // otherwise copy normal viewangle into vewNewViewAngles + VectorCopy( pparams->viewangles, vecNewViewAngles); + } + + // do the smoothing only once per frame + if (pparams->nextView == 0) + { + // smooth angles + + VectorSubtract( pparams->viewangles, lastang, delta ); + if ( Length( delta ) != 0.0f ) + { + VectorCopy( pparams->viewangles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); + ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentAngle++; + VectorCopy( pparams->viewangles, lastang ); + } + + if ( cl_vsmoothing && cl_vsmoothing->value && ( iIsSpectator & SPEC_SMOOTH_ANGLES ) ) + { + int foundidx; + int i; + float t; + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentAngle - 1 - i; + if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + double dt; + float da; + vec3_t v1,v2; + + AngleVectors( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], v1, NULL, NULL ); + AngleVectors( ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v2, NULL, NULL ); + da = AngleBetweenVectors( v1, v2 ); + + dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; + + if ( dt > 0.0 && ( da < 22.5f) ) + { + double frac; + + frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + + // interpolate angles + InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], vecNewViewAngles, frac ); + VectorCopy( vecNewViewAngles, pparams->viewangles ); + } + } + } + + // smooth origin + + VectorSubtract( pparams->vieworg, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( pparams->vieworg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( pparams->vieworg, lastorg ); + } + + if ( cl_vsmoothing && cl_vsmoothing->value && ( iIsSpectator & SPEC_SMOOTH_ORIGIN ) ) + { + int foundidx; + int i; + float t; + + 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->vieworg, delta, pparams->vieworg ); + VectorCopy( pparams->vieworg, vecNewViewOrigin ); + } + } + } + } + } + + + + + lasttime = pparams->time; + + view->model = NULL; + + if ( pparams->nextView == 0 ) + { + // first renderer cycle + + switch (gHUD.m_Spectator.m_iMainMode) + { + case MAIN_MAP_FREE : pparams->onlyClientDraw = true; + + angles = pparams->cl_viewangles; + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + + VectorCopy ( angles, gHUD.m_Spectator.m_mapAngles ); + + gHUD.m_Spectator.GetMapPosition( pparams->vieworg ); + VectorCopy ( angles, pparams->viewangles ); + break; + + case MAIN_IN_EYE : V_GetInEyePos( gHUD.m_Spectator.m_iObserverTarget, + pparams->vieworg, pparams->viewangles ); + + break; + + default : pparams->onlyClientDraw = false; + break; + } + + if ( gHUD.m_Spectator.m_iInsetMode != INSET_OFF ) + pparams->nextView = 1; // force a second renderer view + + gHUD.m_Spectator.m_iDrawCycle = 0; + + } + else + { + // second renderer cycle + + // 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->onlyClientDraw = false; + + // override some settings in certain modes + switch (gHUD.m_Spectator.m_iInsetMode) + { + case INSET_MAP_FREE : pparams->onlyClientDraw = true; + + angles = pparams->cl_viewangles; + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + + VectorCopy ( angles, gHUD.m_Spectator.m_mapAngles ); + + gHUD.m_Spectator.GetMapPosition( pparams->vieworg ); + + VectorCopy ( angles, pparams->viewangles ); + break; + + case INSET_IN_EYE : V_GetInEyePos( gHUD.m_Spectator.m_iObserverTarget, + pparams->vieworg, pparams->viewangles ); + + break; + } + + gHUD.m_Spectator.m_iDrawCycle = 1; + } + + v_angles = pparams->viewangles; + v_origin = pparams->vieworg; } void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) @@ -880,6 +1163,10 @@ void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) { V_CalcIntermissionRefdef ( pparams ); } + else if ( pparams->spectator ) + { + V_CalcSpectatorRefdef ( pparams ); + } else if ( !pparams->paused ) { V_CalcNormalRefdef ( pparams ); @@ -1036,4 +1323,4 @@ void V_Move( int mx, int my ) } } -#endif \ No newline at end of file +#endif diff --git a/common/beamdef.h b/common/beamdef.h index ad87648..48ac07b 100644 --- a/common/beamdef.h +++ b/common/beamdef.h @@ -59,4 +59,4 @@ struct beam_s struct particle_s *particles; }; -#endif \ No newline at end of file +#endif diff --git a/common/cl_entity.h b/common/cl_entity.h index 931267d..902c067 100644 --- a/common/cl_entity.h +++ b/common/cl_entity.h @@ -112,4 +112,4 @@ struct cl_entity_s colorVec cvFloorColor; }; -#endif // !CL_ENTITYH \ No newline at end of file +#endif // !CL_ENTITYH diff --git a/common/con_nprint.h b/common/con_nprint.h index fc9280a..5128d87 100644 --- a/common/con_nprint.h +++ b/common/con_nprint.h @@ -28,4 +28,4 @@ typedef struct con_nprint_s void Con_NPrintf( int idx, char *fmt, ... ); void Con_NXPrintf( struct con_nprint_s *info, char *fmt, ... ); -#endif \ No newline at end of file +#endif diff --git a/common/const.h b/common/const.h index 7b12ca8..9ebf665 100644 --- a/common/const.h +++ b/common/const.h @@ -43,7 +43,7 @@ #define FL_IMMUNE_SLIME (1<<18) #define FL_IMMUNE_LAVA (1<<19) -//#define FL_ARCHIVE_OVERRIDE (1<<20) // NOT USED +#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 @@ -347,7 +347,17 @@ // 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) @@ -550,6 +560,8 @@ // 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 @@ -559,6 +571,7 @@ #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 @@ -594,9 +607,10 @@ #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_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 diff --git a/common/crc.h b/common/crc.h index 9852d00..f2f69ab 100644 --- a/common/crc.h +++ b/common/crc.h @@ -34,7 +34,8 @@ CRC32_t CRC32_Final(CRC32_t pulCRC); void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len); void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); int CRC_File(CRC32_t *crcvalue, char *pszFileName); -unsigned char COM_BlockSequenceCRCByte(unsigned char *base, int length, int sequence); + +unsigned char COM_BlockSequenceCRCByte (unsigned char *base, int length, int sequence); void MD5Init(MD5Context_t *context); void MD5Update(MD5Context_t *context, unsigned char const *buf, diff --git a/common/cvardef.h b/common/cvardef.h index a4cf7a4..2d599a3 100644 --- a/common/cvardef.h +++ b/common/cvardef.h @@ -33,4 +33,4 @@ typedef struct cvar_s float value; struct cvar_s *next; } cvar_t; -#endif \ No newline at end of file +#endif diff --git a/common/demo_api.h b/common/demo_api.h index df98608..f87d5ee 100644 --- a/common/demo_api.h +++ b/common/demo_api.h @@ -28,4 +28,4 @@ typedef struct demo_api_s extern demo_api_t demoapi; -#endif \ No newline at end of file +#endif diff --git a/common/director_cmds.h b/common/director_cmds.h new file mode 100644 index 0000000..850ddab --- /dev/null +++ b/common/director_cmds.h @@ -0,0 +1,31 @@ +// director_cmds.h +// sub commands for svc_director + +#define DRC_ACTIVE 0 // tells client that he's an spectator and will get director command +#define DRC_STATUS 1 // send status infos about proxy +#define DRC_CAMERA 2 // set the actual director camera position +#define DRC_EVENT 3 // informs the dircetor about ann important game event + + +#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) + + + +// commands of the director API function CallDirectorProc(...) + +#define DRCAPI_NOP 0 // no operation +#define DRCAPI_ACTIVE 1 // de/acivates director mode in engine +#define DRCAPI_STATUS 2 // request proxy information +#define DRCAPI_SETCAM 3 // set camera n to given position and angle +#define DRCAPI_GETCAM 4 // request camera n position and angle +#define DRCAPI_DIRPLAY 5 // set director time and play with normal speed +#define DRCAPI_DIRFREEZE 6 // freeze directo at this time +#define DRCAPI_SETVIEWMODE 7 // overview or 4 cameras +#define DRCAPI_SETOVERVIEWPARAMS 8 // sets parameter for overview mode +#define DRCAPI_SETFOCUS 9 // set the camera which has the input focus +#define DRCAPI_GETTARGETS 10 // queries engine for player list +#define DRCAPI_SETVIEWPOINTS 11 // gives engine all waypoints + + diff --git a/common/dlight.h b/common/dlight.h index 287bc33..0f5d74a 100644 --- a/common/dlight.h +++ b/common/dlight.h @@ -30,4 +30,4 @@ typedef struct qboolean dark; // subtracts light instead of adding } dlight_t; -#endif \ No newline at end of file +#endif diff --git a/common/engine_launcher_api.h b/common/engine_launcher_api.h index 0b63260..fef1a65 100644 --- a/common/engine_launcher_api.h +++ b/common/engine_launcher_api.h @@ -86,6 +86,7 @@ typedef struct engine_api_s void ( *QGL_D3DShared ) ( struct tagD3DGlobals *d3dGShared ); int ( WINAPI *glSwapBuffers ) ( HDC dc ); + void ( *DirectorProc ) ( unsigned int cmd, void * params ); #else // NOT USED IN LINUX!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void ( *GL_Init ) ( void ); @@ -93,9 +94,10 @@ typedef struct engine_api_s void ( *GL_Shutdown ) ( void ); void ( *QGL_D3DShared ) ( void ); void ( *glSwapBuffers ) ( void ); + void ( *DirectorProc ) ( void ); // LINUX #endif } engine_api_t; -#endif // ENGINE_LAUNCHER_APIH \ No newline at end of file +#endif // ENGINE_LAUNCHER_APIH diff --git a/common/entity_state.h b/common/entity_state.h index b68df87..e3d7018 100644 --- a/common/entity_state.h +++ b/common/entity_state.h @@ -49,9 +49,9 @@ struct entity_state_s short solid; int effects; float scale; - - byte eflags; + byte eflags; + // Render information int rendermode; int renderamt; @@ -190,4 +190,4 @@ typedef struct local_state_s weapon_data_t weapondata[ 32 ]; } local_state_t; -#endif // !ENTITY_STATEH \ No newline at end of file +#endif // !ENTITY_STATEH diff --git a/common/entity_types.h b/common/entity_types.h index b084409..856a61b 100644 --- a/common/entity_types.h +++ b/common/entity_types.h @@ -23,4 +23,4 @@ // BMODEL or SPRITE that was split across BSP nodes #define ET_FRAGMENTED 4 -#endif // !ENTITY_TYPESH \ No newline at end of file +#endif // !ENTITY_TYPESH diff --git a/common/event_args.h b/common/event_args.h index 335adb3..acbe8c3 100644 --- a/common/event_args.h +++ b/common/event_args.h @@ -48,4 +48,3 @@ typedef struct event_args_s } event_args_t; #endif - diff --git a/common/event_flags.h b/common/event_flags.h index 166ff68..9e1aa54 100644 --- a/common/event_flags.h +++ b/common/event_flags.h @@ -44,4 +44,4 @@ // Only issue event client side ( from shared code ) #define FEV_CLIENT (1<<6) -#endif \ No newline at end of file +#endif diff --git a/common/exefuncs.h b/common/exefuncs.h index de5d47a..6162083 100644 --- a/common/exefuncs.h +++ b/common/exefuncs.h @@ -38,4 +38,4 @@ typedef struct exefuncs_s void (*unused25)(void); } exefuncs_t; -#endif \ No newline at end of file +#endif diff --git a/common/hltv.h b/common/hltv.h new file mode 100644 index 0000000..b653e39 --- /dev/null +++ b/common/hltv.h @@ -0,0 +1,37 @@ +// hltv.h +// all shared consts between server, clients and proxy + +#define TYPE_CLIENT 0 // client is a normal HL client (default) +#define TYPE_PROXY 1 // client is another proxy +#define TYPE_DIRECTOR 2 // client is a director +#define TYPE_COMMENTATOR 3 // client is a commentator + + +#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director command +#define HLTV_STATUS 1 // send status infos about proxy +#define HLTV_CAMERA 2 // set the actual director camera position +#define HLTV_EVENT 3 // informs the dircetor about ann important game event + + +#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) + + + +// commands of the director API function CallDirectorProc(...) + +#define DRCAPI_NOP 0 // no operation +#define DRCAPI_ACTIVE 1 // de/acivates director mode in engine +#define DRCAPI_STATUS 2 // request proxy information +#define DRCAPI_SETCAM 3 // set camera n to given position and angle +#define DRCAPI_GETCAM 4 // request camera n position and angle +#define DRCAPI_DIRTIME 5 // set director time +#define DRCAPI_DIRSCALE 6 // set time scale +#define DRCAPI_SETVIEWMODE 7 // overview or 4 cameras +#define DRCAPI_SETOVERVIEWPARAMS 8 // sets parameter for overview mode +#define DRCAPI_SETFOCUS 9 // set the camera which has the input focus +#define DRCAPI_GETTARGETS 10 // queries engine for player list +#define DRCAPI_SETVIEWPOINTS 11 // gives engine all waypoints + + diff --git a/common/in_buttons.h b/common/in_buttons.h index 7d4eb00..1894b0a 100644 --- a/common/in_buttons.h +++ b/common/in_buttons.h @@ -35,4 +35,4 @@ #define IN_ALT1 (1 << 14) #define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down -#endif // IN_BUTTONS_H \ No newline at end of file +#endif // IN_BUTTONS_H diff --git a/common/interface.cpp b/common/interface.cpp new file mode 100644 index 0000000..3bae10e --- /dev/null +++ b/common/interface.cpp @@ -0,0 +1,142 @@ + +#include +#include +#include "interface.h" + +#ifndef _WIN32 // LINUX +#include +#endif + + +// ------------------------------------------------------------------------------------ // +// InterfaceReg. +// ------------------------------------------------------------------------------------ // +InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; + + +InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : + m_pName(pName) +{ + m_CreateFn = fn; + m_pNext = s_pInterfaceRegs; + s_pInterfaceRegs = this; +} + + + +// ------------------------------------------------------------------------------------ // +// CreateInterface. +// ------------------------------------------------------------------------------------ // +EXPORT_FUNCTION IBaseInterface *CreateInterface( const char *pName, int *pReturnCode ) +{ + InterfaceReg *pCur; + + for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) + { + if(strcmp(pCur->m_pName, pName) == 0) + { + if ( pReturnCode ) + { + *pReturnCode = IFACE_OK; + } + return pCur->m_CreateFn(); + } + } + + if ( pReturnCode ) + { + *pReturnCode = IFACE_FAILED; + } + return NULL; +} + + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#endif + + +#ifdef _WIN32 +HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) +{ + return (HINTERFACEMODULE)LoadLibrary(pModuleName); +} + +#else // LINUX +HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) +{ + // Linux dlopen() doesn't look in the current directory for libraries. + // We tell it to, so people don't have to 'install' libraries as root. + + char szCwd[1024]; + char szAbsoluteLibFilename[1024]; + + getcwd( szCwd, sizeof( szCwd ) ); + if ( szCwd[ strlen( szCwd ) - 1 ] == '/' ) + szCwd[ strlen( szCwd ) - 1 ] = 0; + + sprintf( szAbsoluteLibFilename, "%s/%s", szCwd, pModuleName ); + + return (HINTERFACEMODULE)dlopen( szAbsoluteLibFilename, RTLD_NOW ); +} + +#endif + + +#ifdef _WIN32 +void Sys_FreeModule(HINTERFACEMODULE hModule) +{ + if(!hModule) + return; + + FreeLibrary((HMODULE)hModule); +} + +#else // LINUX +void Sys_FreeModule(HINTERFACEMODULE hModule) +{ + if(!hModule) + return; + + dlclose( (void *)hModule ); +} + +#endif + + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of this module +// Output : interface_instance_t +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactoryThis( void ) +{ + return CreateInterface; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of the named module +// Input : *pModuleName - name of the module +// Output : interface_instance_t - instance of that module +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) +{ + if(!hModule) + return NULL; + + return (CreateInterfaceFn)GetProcAddress((HMODULE)hModule, CREATEINTERFACE_PROCNAME); +} + +#else // LINUX +CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) +{ + if(!hModule) + return NULL; + + return dlsym( (void *)hModule, CREATEINTERFACE_PROCNAME ); +} + +#endif diff --git a/common/interface.h b/common/interface.h new file mode 100644 index 0000000..8099662 --- /dev/null +++ b/common/interface.h @@ -0,0 +1,123 @@ + +// This header defines the interface convention used in the valve engine. +// To make an interface and expose it: +// 1. Derive from IBaseInterface. +// 2. The interface must be ALL pure virtuals, and have no data members. +// 3. Define a name for it. +// 4. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE. + +// Versioning +// There are two versioning cases that are handled by this: +// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, +// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. +// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface +// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and +// expose it for the old interface. + +#ifndef INTERFACE_H +#define INTERFACE_H + +#ifdef __cplusplus + +// All interfaces derive from this. +class IBaseInterface +{ +public: + + virtual ~IBaseInterface() {} +}; + + +#define CREATEINTERFACE_PROCNAME "CreateInterface" +typedef IBaseInterface* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); + + +typedef IBaseInterface* (*InstantiateInterfaceFn)(); + + +// Used internally to register classes. +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char *pName); + +public: + + InstantiateInterfaceFn m_CreateFn; + const char *m_pName; + + InterfaceReg *m_pNext; // For the global list. + static InterfaceReg *s_pInterfaceRegs; +}; + + +// Use this to expose an interface that can have multiple instances. +// e.g.: +// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) +// This will expose a class called CInterfaceImp that implements IInterface (a pure class) +// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) +// +// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") +// so that each component can use these names/vtables to communicate +// +// A single class can support multiple interfaces through multiple inheritance +// +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + static InterfaceReg __g_Create##className##_reg(functionName, versionName); + +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + static IBaseInterface* __Create##className##_interface() {return (interfaceName *)new className;}\ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); + +// Use this to expose a singleton interface with a global variable you've created. +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + static IBaseInterface* __Create##className##interfaceName##_interface() {return (interfaceName *)&globalVarName;}\ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); + +// Use this to expose a singleton interface. This creates the global variable for you automatically. +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + static className __g_##className##_singleton;\ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) + + +#ifdef WIN32 + #define EXPORT_FUNCTION __declspec(dllexport) +#else + #define EXPORT_FUNCTION +#endif + + +// This function is automatically exported and allows you to access any interfaces exposed with the above macros. +// if pReturnCode is set, it will return one of the following values +// extend this for other error conditions/code +enum +{ + IFACE_OK = 0, + IFACE_FAILED +}; + + +extern "C" +{ + EXPORT_FUNCTION IBaseInterface* CreateInterface(const char *pName, int *pReturnCode); +}; + + +// Handle to an interface (HInterfaceModule_t* is just there for type safety). +typedef struct HInterfaceModule_t* HINTERFACEMODULE; + + +// Use these to load and unload a module. +extern HINTERFACEMODULE Sys_LoadModule(const char *pModuleName); +extern void Sys_FreeModule(HINTERFACEMODULE hModule); + +// Use these to get the factory function from either a loaded module or the current module. +extern CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ); +extern CreateInterfaceFn Sys_GetFactoryThis( void ); + +#endif // __cplusplus + +#endif + + + diff --git a/common/itrackeruser.h b/common/itrackeruser.h new file mode 100644 index 0000000..5ba185c --- /dev/null +++ b/common/itrackeruser.h @@ -0,0 +1,46 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef ITRACKERUSER_H +#define ITRACKERUSER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: Interface to accessing information about tracker users +//----------------------------------------------------------------------------- +class ITrackerUser : public IBaseInterface +{ +public: + // returns true if the interface is ready for use + virtual bool IsValid() = 0; + + // returns the tracker ID of the current user + virtual int GetTrackerID() = 0; + + // returns information about a user + // information may not be known about some users, "" will be returned + virtual const char *GetUserName(int trackerID) = 0; + virtual const char *GetFirstName(int trackerID) = 0; + virtual const char *GetLastName(int trackerID) = 0; + virtual const char *GetEmail(int trackerID) = 0; + + // returns true if friendID is a friend of the current user + // ie. the current is authorized to see when the friend is online + virtual bool IsFriend(int friendID) = 0; + + // requests authorization from a user + virtual void RequestAuthorizationFromUser(int potentialFriendID) = 0; +}; + +#define TRACKERUSER_INTERFACE_VERSION "TrackerUser001" + + +#endif // ITRACKERUSER_H diff --git a/common/ivoicetweak.h b/common/ivoicetweak.h new file mode 100644 index 0000000..9c39a5f --- /dev/null +++ b/common/ivoicetweak.h @@ -0,0 +1,35 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef IVOICETWEAK_H +#define IVOICETWEAK_H +#ifdef _WIN32 +#pragma once +#endif + +// 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)(); // Returns 0 on error. + void (*EndVoiceTweakMode)(); + + // Get/set control values. + void (*SetControlFloat)(VoiceTweakControl iControl, float value); + float (*GetControlFloat)(VoiceTweakControl iControl); +} IVoiceTweak; + + +#endif // IVOICETWEAK_H diff --git a/common/netadr.h b/common/netadr.h index 94925a9..5d29524 100644 --- a/common/netadr.h +++ b/common/netadr.h @@ -26,7 +26,7 @@ typedef enum NA_BROADCAST, NA_IP, NA_IPX, - NA_BROADCAST_IPX + NA_BROADCAST_IPX, } netadrtype_t; typedef struct netadr_s @@ -37,4 +37,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/nowin.h b/common/nowin.h new file mode 100644 index 0000000..315ac83 --- /dev/null +++ b/common/nowin.h @@ -0,0 +1,9 @@ + +#ifndef INC_NOWIN_H +#define INC_NOWIN_H +#ifndef _WIN32 + +#include + +#endif //!_WIN32 +#endif //INC_NOWIN_H \ No newline at end of file diff --git a/common/particledef.h b/common/particledef.h index 15ba6db..823f4fd 100644 --- a/common/particledef.h +++ b/common/particledef.h @@ -47,11 +47,11 @@ typedef struct particle_s ptype_t type; void (*deathfunc)( struct particle_s *particle ); - // For pt_clientcusttom, we'll call this function each frame + // for pt_clientcusttom, we'll call this function each frame void (*callback)( struct particle_s *particle, float frametime ); - - // for deathfunc, etc. + + // For deathfunc, etc. unsigned char context; } particle_t; -#endif \ No newline at end of file +#endif diff --git a/common/pmtrace.h b/common/pmtrace.h index 657649d..071185f 100644 --- a/common/pmtrace.h +++ b/common/pmtrace.h @@ -40,4 +40,4 @@ struct pmtrace_s int hitgroup; }; -#endif \ No newline at end of file +#endif diff --git a/common/qfont.h b/common/qfont.h index fc2a7de..3989001 100644 --- a/common/qfont.h +++ b/common/qfont.h @@ -37,4 +37,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 e8881bd..436128c 100644 --- a/common/r_efx.h +++ b/common/r_efx.h @@ -14,7 +14,9 @@ ****/ #if !defined ( R_EFXH ) #define R_EFXH +#ifdef _WIN32 #pragma once +#endif // particle_t #if !defined( PARTICLEDEFH ) @@ -187,8 +189,9 @@ struct efx_api_s 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. }; extern efx_api_t efx; -#endif \ No newline at end of file +#endif diff --git a/common/ref_params.h b/common/ref_params.h index d9db414..974fcc7 100644 --- a/common/ref_params.h +++ b/common/ref_params.h @@ -64,6 +64,12 @@ typedef struct ref_params_s // 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 } ref_params_t; -#endif // !REF_PARAMSH \ No newline at end of file +#endif // !REF_PARAMSH diff --git a/common/screenfade.h b/common/screenfade.h index 3e08dca..3560e73 100644 --- a/common/screenfade.h +++ b/common/screenfade.h @@ -8,9 +8,10 @@ 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 // !SCREENFADEH \ No newline at end of file +#endif // !SCREENFADEH diff --git a/common/studio_event.h b/common/studio_event.h index ffec2cf..8fae6f5 100644 --- a/common/studio_event.h +++ b/common/studio_event.h @@ -26,4 +26,4 @@ typedef struct mstudioevent_s char options[64]; } mstudioevent_t; -#endif // STUDIO_EVENTH \ No newline at end of file +#endif // STUDIO_EVENTH diff --git a/common/triangleapi.h b/common/triangleapi.h index a89918f..c4adebb 100644 --- a/common/triangleapi.h +++ b/common/triangleapi.h @@ -49,6 +49,7 @@ typedef struct triangleapi_s 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. } triangleapi_t; -#endif // !TRIANGLEAPIH \ No newline at end of file +#endif // !TRIANGLEAPIH diff --git a/common/usercmd.h b/common/usercmd.h index 09644ac..5f9bf82 100644 --- a/common/usercmd.h +++ b/common/usercmd.h @@ -38,4 +38,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/weaponinfo.h b/common/weaponinfo.h index 6f526c2..39ee193 100644 --- a/common/weaponinfo.h +++ b/common/weaponinfo.h @@ -49,4 +49,4 @@ typedef struct weapon_data_s float fuser4; } weapon_data_t; -#endif \ No newline at end of file +#endif diff --git a/dlls/AI_BaseNPC_Schedule.cpp b/dlls/AI_BaseNPC_Schedule.cpp new file mode 100644 index 0000000..2b6058e --- /dev/null +++ b/dlls/AI_BaseNPC_Schedule.cpp @@ -0,0 +1,1514 @@ +/*** +* +* 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. +* +* 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/Makefile b/dlls/Makefile index 9203566..1681f92 100644 --- a/dlls/Makefile +++ b/dlls/Makefile @@ -1,10 +1,10 @@ # -# Half-Life StandardSDK 2.0 mp_i386.so Makefile for i386 Linux +# Half-Life Full SDK 2.2 hl_i386.so Makefile for x86 Linux # -# April 2000 by Leon Hartwig (jehannum@planethalflife.com) +# August 2001 by Leon Hartwig (hartwig@valvesoftware.com) # -DLLNAME=mp +DLLNAME=hl ARCH=i386 @@ -12,27 +12,32 @@ ARCH=i386 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 +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 -m486 -O2 -ffast-math -funroll-loops \ - -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \ - -malign-jumps=2 -malign-functions=2 +#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 -I../common -I../pm_shared +INCLUDEDIRS=-I. -I$(ENGINE_SRCDIR) -I$(COMMON_SRCDIR) -I$(PM_SHARED_SRCDIR) -I$(GAME_SHARED_SRCDIR) LDFLAGS= @@ -53,69 +58,111 @@ $(DLL_OBJDIR)/%.o: $(DLL_SRCDIR)/%.cpp $(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)/mpstubb.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 @@ -126,6 +173,7 @@ $(DLLNAME)_$(ARCH).$(SHLIBEXT) : neat $(OBJ) neat: -mkdir $(DLL_OBJDIR) -mkdir $(WPN_SHARED_OBJDIR) + -mkdir $(GAME_SHARED_OBJDIR) -mkdir $(PM_SHARED_OBJDIR) clean: -rm -f $(OBJ) @@ -133,5 +181,6 @@ clean: 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 0000000..d3902d6 --- /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 index cb2e7e1..b44de8b 100644 --- a/dlls/activity.h +++ b/dlls/activity.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/activitymap.h b/dlls/activitymap.h index 606f6f1..b02c666 100644 --- a/dlls/activitymap.h +++ b/dlls/activitymap.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp new file mode 100644 index 0000000..46cbb3c --- /dev/null +++ b/dlls/aflock.cpp @@ -0,0 +1,910 @@ +/*** +* +* 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. +* +* 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; + 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( 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 0000000..5c60c45 --- /dev/null +++ b/dlls/agrunt.cpp @@ -0,0 +1,1177 @@ +/*** +* +* 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. +* +* 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; + + 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 0bbde7f..5559222 100644 --- a/dlls/airtank.cpp +++ b/dlls/airtank.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/animating.cpp b/dlls/animating.cpp index 3f97a41..51517d2 100644 --- a/dlls/animating.cpp +++ b/dlls/animating.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -295,13 +295,18 @@ void CBaseAnimating :: SetSequenceBox( void ) transformed.y = xvector.y*base.x + yvector.y*base.y; transformed.z = base.z; - for ( int l = 0; l < 3; l++ ) - { - if (transformed[l] < rmin[l]) - rmin[l] = transformed[l]; - if (transformed[l] > rmax[l]) - rmax[l] = transformed[l]; - } + 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; } } } diff --git a/dlls/animation.cpp b/dlls/animation.cpp index 91998d0..a9dc60d 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -16,7 +16,11 @@ #include #include -typedef bool BOOL; +#include "../common/nowin.h" + +typedef int BOOL; +#define TRUE 1 +#define FALSE 0 // hack into header files that we can ship typedef int qboolean; @@ -29,8 +33,6 @@ typedef unsigned char byte; #include "studio.h" -#include "../engine/studio.h" - #ifndef ACTIVITY_H #include "activity.h" #endif diff --git a/dlls/animation.h b/dlls/animation.h index 5dc0dd5..db6898a 100644 --- a/dlls/animation.h +++ b/dlls/animation.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/apache.cpp b/dlls/apache.cpp new file mode 100644 index 0000000..86c8259 --- /dev/null +++ b/dlls/apache.cpp @@ -0,0 +1,1050 @@ +/*** +* +* 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. +* +* 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; + 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( 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) + { + 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( 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 0000000..75fbc29 --- /dev/null +++ b/dlls/barnacle.cpp @@ -0,0 +1,428 @@ +/*** +* +* 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. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// barnacle - stationary ceiling mounted 'fishing' monster +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + +#define BARNACLE_BODY_HEIGHT 44 // how 'tall' the barnacle's model is. +#define BARNACLE_PULL_SPEED 8 +#define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them. + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define BARNACLE_AE_PUKEGIB 2 + +class CBarnacle : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + CBaseEntity *TongueTouchEnt ( float *pflLength ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void EXPORT BarnacleThink ( void ); + void EXPORT WaitTillDead ( void ); + void Killed( entvars_t *pevAttacker, int iGib ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + float m_flAltitude; + float m_flKillVictimTime; + int m_cGibs;// barnacle loads up on gibs each time it kills something. + BOOL m_fTongueExtended; + BOOL m_fLiftingPrey; + float m_flTongueAdj; +}; +LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ); + +TYPEDESCRIPTION CBarnacle::m_SaveData[] = +{ + DEFINE_FIELD( CBarnacle, m_flAltitude, FIELD_FLOAT ), + DEFINE_FIELD( CBarnacle, m_flKillVictimTime, FIELD_TIME ), + DEFINE_FIELD( CBarnacle, m_cGibs, FIELD_INTEGER ),// barnacle loads up on gibs each time it kills something. + DEFINE_FIELD( CBarnacle, m_fTongueExtended, FIELD_BOOLEAN ), + DEFINE_FIELD( CBarnacle, m_fLiftingPrey, FIELD_BOOLEAN ), + DEFINE_FIELD( CBarnacle, m_flTongueAdj, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ); + + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CBarnacle :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case BARNACLE_AE_PUKEGIB: + CGib::SpawnRandomGibs( pev, 1, 1 ); + break; + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CBarnacle :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/barnacle.mdl"); + UTIL_SetSize( pev, Vector(-16, -16, -32), Vector(16, 16, 0) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_NONE; + pev->takedamage = DAMAGE_AIM; + m_bloodColor = BLOOD_COLOR_RED; + pev->effects = EF_INVLIGHT; // take light from the ceiling + pev->health = 25; + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_flKillVictimTime = 0; + m_cGibs = 0; + m_fLiftingPrey = FALSE; + m_flTongueAdj = -100; + + InitBoneControllers(); + + SetActivity ( ACT_IDLE ); + + SetThink ( BarnacleThink ); + pev->nextthink = gpGlobals->time + 0.5; + + UTIL_SetOrigin ( pev, pev->origin ); +} + +int CBarnacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + if ( bitsDamageType & DMG_CLUB ) + { + flDamage = pev->health; + } + + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +//========================================================= +//========================================================= +void CBarnacle :: BarnacleThink ( void ) +{ + CBaseEntity *pTouchEnt; + CBaseMonster *pVictim; + float flLength; + + pev->nextthink = gpGlobals->time + 0.1; + + if ( m_hEnemy != 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(); + 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 new file mode 100644 index 0000000..6589bd3 --- /dev/null +++ b/dlls/barney.cpp @@ -0,0 +1,841 @@ +/*** +* +* 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. +* +* 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 ); + } + + 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 d0894e4..358a7c1 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -1,94 +1,339 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. +* 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: - Activity m_Activity;// what the monster is doing (animation) - Activity m_IdealActivity;// monster should switch to this activity - int m_LastHitGroup; // the last body region that took damage - int m_bitsDamageType; // what types of damage has monster (player) taken - BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; - MONSTERSTATE m_MonsterState;// monster's current state - MONSTERSTATE m_IdealMonsterState;// monster should change to this state - int m_afConditions; - int m_afMemory; - float m_flNextAttack; // cannot attack again until this time - EHANDLE m_hEnemy; // the entity that the monster is fighting. - EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach - float m_flFieldOfView;// width of monster's field of view ( dot product ) - int m_bloodColor; // color of blood particless - Vector m_HackedGunPos; // HACK until we can query end of gun + 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 ); - void MakeIdealYaw( Vector vecTarget ); +// 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 ); - virtual BOOL HasHumanGibs( void ); - virtual BOOL HasAlienGibs( void ); - virtual void FadeMonster( void ); // Called instead of GibMonster() when gibs are disabled - virtual void GibMonster( void ); + 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 BecomeDead( void ); + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual void GibMonster( void ); BOOL ShouldGibMonster( int iGib ); void CallGibMonster( void ); - virtual BOOL ShouldFadeOnDeath( void ); - BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. - virtual int IRelationship ( CBaseEntity *pTarget ); + 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 ); - float DamageForce( float damage ); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual void PainSound ( void ) { return; }; 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; } - 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; } + 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; } - // This will stop animation until you call ResetSequenceInfo() at some point in the future - inline void StopAnimation( void ) { pev->framerate = 0; } - - virtual void ReportAIState( void ); - virtual void MonsterInitDead( void ); // Call after animation/pose is set up - void EXPORT CorpseFallThink( void ); - - virtual void Look ( int iDistance );// basic sight function for monsters - virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack - CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); - 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 - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ); - virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); } + BOOL ExitScriptedSequence( ); + BOOL CineCleanup( ); + CBaseEntity* DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. }; -#endif + +#endif // BASEMONSTER_H diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp new file mode 100644 index 0000000..b493ea3 --- /dev/null +++ b/dlls/bigmomma.cpp @@ -0,0 +1,1251 @@ +/*** +* +* 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. +* +* 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 0000000..f5bc67e --- /dev/null +++ b/dlls/bloater.cpp @@ -0,0 +1,219 @@ +/*** +* +* 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. +* +* 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 75258f6..f0dadac 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp new file mode 100644 index 0000000..cd9ee88 --- /dev/null +++ b/dlls/bullsquid.cpp @@ -0,0 +1,1275 @@ +/*** +* +* 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. +* +* 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 index f7ae613..cb8ec9b 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index 0da11db..d1f2635 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -21,12 +21,12 @@ #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 ); -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ); - extern Vector VecBModelOrigin( entvars_t* pevBModel ); extern DLL_GLOBAL Vector g_vecAttackDir; extern DLL_GLOBAL int g_iSkillLevel; @@ -73,7 +73,7 @@ static DLL_FUNCTIONS gFunctionTable = 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 @@ -97,6 +97,9 @@ static DLL_FUNCTIONS gFunctionTable = static void SetObjectCollisionBox( entvars_t *pev ); +#ifndef _WIN32 +extern "C" { +#endif int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) { if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) @@ -121,6 +124,11 @@ int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) return TRUE; } +#ifndef _WIN32 +} +#endif + + int DispatchSpawn( edict_t *pent ) { CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); @@ -631,17 +639,17 @@ void SetObjectCollisionBox( entvars_t *pev ) max = 0; for (i=0 ; i<3 ; i++) { - v = fabs( pev->mins[i]); + v = fabs( ((float *)pev->mins)[i]); if (v > max) max = v; - v = fabs( pev->maxs[i]); + v = fabs( ((float *)pev->maxs)[i]); if (v > max) max = v; } for (i=0 ; i<3 ; i++) { - pev->absmin[i] = pev->origin[i] - max; - pev->absmax[i] = pev->origin[i] + max; + ((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max; + ((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max; } } else diff --git a/dlls/cbase.h b/dlls/cbase.h index cf7976a..ce4cd36 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -54,7 +54,7 @@ CBaseEntity #ifdef _WIN32 #define EXPORT _declspec( dllexport ) #else -#define EXPORT +#define EXPORT /* */ #endif extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); @@ -240,6 +240,7 @@ public: 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; } @@ -250,16 +251,6 @@ public: int IsDormant( void ); BOOL IsLockedByMaster( void ) { return FALSE; } -#ifdef _DEBUG - static CBaseEntity *Instance( edict_t *pent ) - { - if ( !pent ) - pent = ENT(0); - CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent); - ASSERT(pEnt!=NULL); - return pEnt; - } -#else static CBaseEntity *Instance( edict_t *pent ) { if ( !pent ) @@ -267,7 +258,6 @@ public: CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent); return pEnt; } -#endif static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); } static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); } @@ -292,10 +282,8 @@ public: #ifdef _DEBUG void FunctionCheck( void *pFunction, char *name ) { -#ifdef _WIN32 if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) ) ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction ); -#endif // _WIN32 } BASEPTR ThinkSet( BASEPTR func, char *name ) @@ -349,6 +337,24 @@ public: 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; }; diff --git a/dlls/cdll_dll.h b/dlls/cdll_dll.h index ef0e066..619324b 100644 --- a/dlls/cdll_dll.h +++ b/dlls/cdll_dll.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/client.cpp b/dlls/client.cpp index 973fae4..ae32625 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -32,6 +32,7 @@ #include "client.h" #include "soundent.h" #include "gamerules.h" +#include "game.h" #include "customentity.h" #include "weapons.h" #include "weaponinfo.h" @@ -47,7 +48,10 @@ 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 @@ -189,7 +193,7 @@ void ClientPutInServer( edict_t *pEntity ) 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; @@ -309,6 +313,34 @@ void Host_Say( edict_t *pEntity, int teamonly ) // 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><%u><%s>\" %s \"%s\"\n", + STRING( pEntity->v.netname ), + GETPLAYERUSERID( pEntity ), + GETPLAYERWONID( pEntity ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pEntity ), "model" ), + temp, + p ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%u><%i>\" %s \"%s\"\n", + STRING( pEntity->v.netname ), + GETPLAYERUSERID( pEntity ), + GETPLAYERWONID( pEntity ), + GETPLAYERUSERID( pEntity ), + temp, + p ); + } } @@ -384,7 +416,15 @@ void ClientCommand( edict_t *pEntity ) else { // tell the user they entered an unknown command - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pcmd ) ); + 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 ) ); } } @@ -407,6 +447,22 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) // 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 ); @@ -414,7 +470,25 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) WRITE_STRING( text ); MESSAGE_END(); - UTIL_LogPrintf( "\"%s<%i>\" changed name to \"%s<%i>\"\n", STRING( pEntity->v.netname ), GETPLAYERUSERID( pEntity ), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ), GETPLAYERUSERID( pEntity ) ); + // team match? + if ( g_teamplay ) + { + UTIL_LogPrintf( "\"%s<%i><%u><%s>\" changed name to \"%s\"\n", + STRING( pEntity->v.netname ), + GETPLAYERUSERID( pEntity ), + GETPLAYERWONID( pEntity ), + g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ), + g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%u><%i>\" changed name to \"%s\"\n", + STRING( pEntity->v.netname ), + GETPLAYERUSERID( pEntity ), + GETPLAYERWONID( pEntity ), + GETPLAYERUSERID( pEntity ), + g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + } } g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); @@ -435,16 +509,6 @@ void ServerDeactivate( void ) // Peform any shutdown operations here... // - #ifdef PERSISTENCE_SAMPLE - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBasePlayer *pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( i ); - if(pPlayer && pPlayer->IsPlayer()) - { - pPlayer->m_PersistenceInfo.SendInfo(); - } - } - #endif } void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) @@ -542,8 +606,7 @@ void StartFrame( void ) if ( g_fGameOver ) return; - gpGlobals->teamplay = CVAR_GET_FLOAT("teamplay"); - g_iSkillLevel = CVAR_GET_FLOAT("skill"); + gpGlobals->teamplay = teamplay.value; g_ulFrameCount++; } @@ -665,7 +728,7 @@ void ClientPrecache( void ) /* =============== -const char *GetGameDescription() +GetGameDescription Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2 =============== @@ -780,7 +843,6 @@ void SpectatorThink( edict_t *pEntity ) pPlayer->SpectatorThink( ); } - //////////////////////////////////////////////////////// // PAS and PVS routines for client messaging // @@ -810,6 +872,13 @@ void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pv pView = pViewEntity; } + if ( pClient->v.flags & FL_PROXY ) + { + *pvs = NULL; // the spectator proxy sees + *pas = NULL; // and hears everything + return; + } + org = pView->v.origin + pView->v.view_ofs; if ( pView->v.flags & FL_DUCKING ) { @@ -946,6 +1015,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h 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; @@ -964,9 +1034,9 @@ 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->renderfx = ent->v.renderfx; - state->rendercolor.r = ent->v.rendercolor[0]; - state->rendercolor.g = ent->v.rendercolor[1]; - state->rendercolor.b = ent->v.rendercolor[2]; + 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 ) @@ -1005,7 +1075,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h state->gravity = ent->v.gravity; // state->team = ent->v.team; -// state->playerclass = ent->v.playerclass; +// state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; state->health = ent->v.health; } @@ -1033,9 +1103,9 @@ void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, st // render information baseline->rendermode = (byte)entity->v.rendermode; baseline->renderamt = (byte)entity->v.renderamt; - baseline->rendercolor.r = (byte)entity->v.rendercolor[0]; - baseline->rendercolor.g = (byte)entity->v.rendercolor[1]; - baseline->rendercolor.b = (byte)entity->v.rendercolor[2]; + 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 ) @@ -1114,7 +1184,6 @@ 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; @@ -1361,7 +1430,7 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) if ( II.iId >= 0 && II.iId < 32 ) { item = &info[ II.iId ]; - + item->m_iId = II.iId; item->m_iClip = gun->m_iClip; @@ -1369,6 +1438,16 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) 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; @@ -1395,6 +1474,7 @@ void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clien 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; @@ -1428,6 +1508,17 @@ void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clien 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 ) { @@ -1440,6 +1531,17 @@ void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clien 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; + } } } } @@ -1604,4 +1706,3 @@ int AllowLagCompensation( void ) { return 0; } - diff --git a/dlls/client.h b/dlls/client.h index 5c254c2..5c7a7e6 100644 --- a/dlls/client.h +++ b/dlls/client.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 0246fa3..4fad50c 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -898,6 +898,7 @@ 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 ) { @@ -1364,6 +1365,8 @@ void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector 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 ) @@ -1377,9 +1380,6 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting if ( pevAttacker == NULL ) pevAttacker = pev; // the default attacker is ourselves - // 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); ClearMultiDamage(); gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB; @@ -1419,8 +1419,6 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting tracer = 1; switch( iBulletType ) { - case BULLET_PLAYER_MP5: - break; case BULLET_MONSTER_MP5: case BULLET_MONSTER_9MM: case BULLET_MONSTER_12MM: @@ -1452,23 +1450,6 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting 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_MONSTER_9MM: pEntity->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET); @@ -1513,6 +1494,97 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting } +/* +================ +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) diff --git a/dlls/controller.cpp b/dlls/controller.cpp new file mode 100644 index 0000000..955d923 --- /dev/null +++ b/dlls/controller.cpp @@ -0,0 +1,1427 @@ +/*** +* +* 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. +* +* 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) + { + 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( 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) + { + 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 4eb2631..84a448d 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -23,6 +23,7 @@ #include "player.h" #include "gamerules.h" +#ifndef CLIENT_DLL #define BOLT_AIR_VELOCITY 2000 #define BOLT_WATER_VELOCITY 1000 @@ -217,7 +218,7 @@ void CCrossbowBolt::ExplodeThink( void ) UTIL_Remove(this); } - +#endif enum crossbow_e { CROSSBOW_IDLE1 = 0, // full @@ -234,27 +235,6 @@ enum crossbow_e { CROSSBOW_HOLSTER2, // empty }; - -class CCrossbow : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( ) { return 3; } - int GetItemInfo(ItemInfo *p); - - void FireBolt( void ); - void FireSniperBolt( void ); - void PrimaryAttack( void ); - void SecondaryAttack( void ); - int AddToPlayer( CBasePlayer *pPlayer ); - BOOL Deploy( ); - void Holster( int skiplocal = 0 ); - void Reload( void ); - void WeaponIdle( void ); - - int m_fInZoom; // don't save this -}; LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ); void CCrossbow::Spawn( ) @@ -290,6 +270,9 @@ void CCrossbow::Precache( void ) 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" ); } @@ -335,7 +318,12 @@ void CCrossbow::Holster( int skiplocal /* = 0 */ ) void CCrossbow::PrimaryAttack( void ) { + +#ifdef CLIENT_DLL + if ( m_fInZoom && bIsMultiplayer() ) +#else if ( m_fInZoom && g_pGameRules->IsMultiplayer() ) +#endif { FireSniperBolt(); return; @@ -347,7 +335,7 @@ void CCrossbow::PrimaryAttack( void ) // this function only gets called in multiplayer void CCrossbow::FireSniperBolt() { - m_flNextPrimaryAttack = gpGlobals->time + 0.75; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; if (m_iClip == 0) { @@ -360,18 +348,14 @@ void CCrossbow::FireSniperBolt() m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_iClip--; - // make twang sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/xbow_fire1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF)); + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif - if (m_iClip) - { - 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)); - SendWeaponAnim( CROSSBOW_FIRE1 ); - } - else if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0) - { - SendWeaponAnim( CROSSBOW_FIRE3 ); - } + 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 ); @@ -383,47 +367,14 @@ void CCrossbow::FireSniperBolt() UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr); +#ifndef CLIENT_DLL if ( tr.pHit->v.takedamage ) { - switch( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND( tr.pHit, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break; - case 1: - EMIT_SOUND( tr.pHit, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break; - } - ClearMultiDamage( ); CBaseEntity::Instance(tr.pHit)->TraceAttack(m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); ApplyMultiDamage( pev, m_pPlayer->pev ); } - else - { - // create a bolt - CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); - pBolt->pev->origin = tr.vecEndPos - vecDir * 10; - pBolt->pev->angles = UTIL_VecToAngles( vecDir ); - pBolt->pev->solid = SOLID_NOT; - pBolt->SetTouch( NULL ); - pBolt->SetThink( SUB_Remove ); - - EMIT_SOUND( pBolt->edict(), CHAN_WEAPON, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM ); - - if (UTIL_PointContents(tr.vecEndPos) != CONTENTS_WATER) - { - UTIL_Sparks( tr.vecEndPos ); - } - - if ( FClassnameIs( tr.pHit, "worldspawn" ) ) - { - // let the bolt sit around for a while if it hit static architecture - pBolt->pev->nextthink = gpGlobals->time + 5.0; - } - else - { - pBolt->pev->nextthink = gpGlobals->time; - } - } +#endif } void CCrossbow::FireBolt() @@ -440,32 +391,26 @@ void CCrossbow::FireBolt() m_iClip--; - // make twang sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/xbow_fire1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF)); + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif - if (m_iClip) - { - - 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)); - SendWeaponAnim( CROSSBOW_FIRE1 ); - } - else if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0) - { - SendWeaponAnim( CROSSBOW_FIRE3 ); - } + 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 ); - - // Vector vecSrc = pev->origin + gpGlobals->v_up * 16 + gpGlobals->v_forward * 20 + gpGlobals->v_right * 4; + anglesAim.x = -anglesAim.x; Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; Vector vecDir = gpGlobals->v_forward; - //CBaseEntity *pBolt = CBaseEntity::Create( "crossbow_bolt", vecSrc, anglesAim, m_pPlayer->edict() ); +#ifndef CLIENT_DLL CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); pBolt->pev->origin = vecSrc; pBolt->pev->angles = anglesAim; @@ -482,49 +427,52 @@ void CCrossbow::FireBolt() 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 = gpGlobals->time + 0.75; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - m_flNextSecondaryAttack = gpGlobals->time + 0.75; if (m_iClip != 0) - m_flTimeWeaponIdle = gpGlobals->time + 5.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; else - m_flTimeWeaponIdle = 0.75; - - m_pPlayer->pev->punchangle.x -= 2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; } void CCrossbow::SecondaryAttack() { - if (m_fInZoom) + if ( m_pPlayer->pev->fov != 0 ) { - m_pPlayer->m_iFOV = 0; // 0 means reset to default fov + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov m_fInZoom = 0; } - else + else if ( m_pPlayer->pev->fov != 20 ) { - m_pPlayer->m_iFOV = 20; + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 20; m_fInZoom = 1; } - pev->nextthink = gpGlobals->time + 0.1; - m_flNextSecondaryAttack = gpGlobals->time + 1.0; + pev->nextthink = UTIL_WeaponTimeBase() + 0.1; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; } void CCrossbow::Reload( void ) { - if ( m_fInZoom ) + if ( m_pPlayer->ammo_bolts <= 0 ) + return; + + 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)); } @@ -537,9 +485,9 @@ void CCrossbow::WeaponIdle( void ) ResetEmptySound( ); - if (m_flTimeWeaponIdle < gpGlobals->time) + if ( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.75) { if (m_iClip) @@ -550,19 +498,19 @@ void CCrossbow::WeaponIdle( void ) { SendWeaponAnim( CROSSBOW_IDLE2 ); } - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else { if (m_iClip) { SendWeaponAnim( CROSSBOW_FIDGET1 ); - m_flTimeWeaponIdle = gpGlobals->time + 90.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; } else { SendWeaponAnim( CROSSBOW_FIDGET2 ); - m_flTimeWeaponIdle = gpGlobals->time + 80.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 30.0; } } } diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 77b74c7..69d9d10 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -26,23 +26,6 @@ #define CROWBAR_BODYHIT_VOLUME 128 #define CROWBAR_WALLHIT_VOLUME 512 -class CCrowbar : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 1; } - void EXPORT SwingAgain( void ); - void EXPORT Smack( void ); - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - int Swing( int fFirst ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - int m_iSwing; - TraceResult m_trHit; -}; LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ); @@ -82,6 +65,8 @@ void CCrowbar::Precache( void ) 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) @@ -192,6 +177,7 @@ int CCrowbar::Swing( int fFirst ) 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 ); @@ -205,36 +191,26 @@ int CCrowbar::Swing( int fFirst ) 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 - switch( (m_iSwing++) % 3 ) - { - case 0: - SendWeaponAnim( CROWBAR_ATTACK1MISS ); break; - case 1: - SendWeaponAnim( CROWBAR_ATTACK2MISS ); break; - case 2: - SendWeaponAnim( CROWBAR_ATTACK3MISS ); break; - } - m_flNextPrimaryAttack = gpGlobals->time + 0.5; - // play wiff or swish sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xF)); - + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); } } else { - // hit - fDidHit = TRUE; - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - switch( ((m_iSwing++) % 2) + 1 ) { case 0: @@ -247,9 +223,16 @@ int CCrowbar::Swing( int fFirst ) // 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 < gpGlobals->time) || 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 ); @@ -261,8 +244,6 @@ int CCrowbar::Swing( int fFirst ) } ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - m_flNextPrimaryAttack = gpGlobals->time + 0.25; - // play thwack, smack, or dong sound float flVol = 1.0; int fHitWorld = TRUE; @@ -310,22 +291,25 @@ int CCrowbar::Swing( int fFirst ) switch( RANDOM_LONG(0,1) ) { case 0: - //UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "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: - //UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "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; } + + // delay the decal a bit + m_trHit = tr; } - // delay the decal a bit - m_trHit = tr; - SetThink( Smack ); - pev->nextthink = gpGlobals->time + 0.2; - 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 index addf929..bfb3ed5 100644 --- a/dlls/decals.h +++ b/dlls/decals.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/defaultai.cpp b/dlls/defaultai.cpp new file mode 100644 index 0000000..fd74789 --- /dev/null +++ b/dlls/defaultai.cpp @@ -0,0 +1,1232 @@ +/*** +* +* 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. +* +* 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 0000000..23754e6 --- /dev/null +++ b/dlls/defaultai.h @@ -0,0 +1,98 @@ +/*** +* +* 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. +* +* 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 1f1471b..5877252 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/doors.h b/dlls/doors.h index 51fc896..a4e7b62 100644 --- a/dlls/doors.h +++ b/dlls/doors.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 4a5bc98..1994112 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -669,14 +669,18 @@ void CLightning::StrikeThink( void ) 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 ( pev->spawnflags & SF_BEAM_RING) - { - // don't work - return; - } if ( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd { CBaseEntity *pTemp; diff --git a/dlls/effects.h b/dlls/effects.h index e7e9fe4..9b5430b 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/egon.cpp b/dlls/egon.cpp index dc5a705..24244e2 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -35,7 +35,6 @@ #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, @@ -50,90 +49,8 @@ enum egon_e { EGON_HOLSTER }; - -class CEgon : public CBasePlayerWeapon -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 4; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - - void CreateEffect( void ); - void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ); - void DestroyEffect( void ); - - void EndAttack( void ); - void Attack( void ); - void PrimaryAttack( void ); - void WeaponIdle( void ); - static int g_fireAnims1[]; - static int g_fireAnims2[]; - - float m_flAmmoUseTime;// since we use < 1 point of ammo per update, we subtract ammo on a timer. - - float GetPulseInterval( void ); - float GetDischargeInterval( void ); - - void Fire( const Vector &vecOrigSrc, const Vector &vecDir ); - - BOOL HasAmmo( void ) - { - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - return FALSE; - return TRUE; - } - - void 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; - } - - enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; - enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; - -private: - float m_shootTime; - CBeam *m_pBeam; - CBeam *m_pNoise; - CSprite *m_pSprite; - EGON_FIRESTATE m_fireState; - EGON_FIREMODE m_fireMode; - float m_shakeTime; - BOOL m_deployed; -}; - LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ); -int CEgon::g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; -int CEgon::g_fireAnims2[] = { EGON_ALTFIRECYCLE }; - - -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 ); - - void CEgon::Spawn( ) { Precache( ); @@ -163,12 +80,16 @@ void CEgon::Precache( void ) 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" ); } @@ -189,11 +110,9 @@ int CEgon::AddToPlayer( CBasePlayer *pPlayer ) void CEgon::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - // m_flTimeWeaponIdle = gpGlobals->time + UTIL_RandomFloat ( 10, 15 ); SendWeaponAnim( EGON_HOLSTER ); - if ( m_fireState != FIRE_OFF ) - EndAttack(); + EndAttack(); } int CEgon::GetItemInfo(ItemInfo *p) @@ -213,39 +132,42 @@ int CEgon::GetItemInfo(ItemInfo *p) return 1; } - -//#define EGON_PULSE_INTERVAL 0.25 -//#define EGON_DISCHARGE_INTERVAL 0.5 - #define EGON_PULSE_INTERVAL 0.1 #define EGON_DISCHARGE_INTERVAL 0.1 float CEgon::GetPulseInterval( void ) { - if ( g_pGameRules->IsMultiplayer() ) - { - return 0.1; - } - return EGON_PULSE_INTERVAL; } float CEgon::GetDischargeInterval( void ) { - if ( g_pGameRules->IsMultiplayer() ) - { - return 0.1; - } - 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_pPlayer->pev->waterlevel == 3 ) { - if ( m_pBeam ) + + if ( m_fireState != FIRE_OFF || m_pBeam ) { EndAttack(); } @@ -260,34 +182,33 @@ void CEgon::Attack( void ) 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 = gpGlobals->time + 0.25; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; PlayEmptySound( ); return; } m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. - SendWeaponAnim( g_fireAnims1[ RANDOM_LONG(0,ARRAYSIZE(g_fireAnims1)-1) ] ); + 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 = gpGlobals->time + 0.1; - m_shootTime = gpGlobals->time + 2; - - if ( m_fireMode == FIRE_WIDE ) - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); - } - else - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); - } + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; + pev->fuser1 = UTIL_WeaponTimeBase() + 2; pev->dmgtime = gpGlobals->time + GetPulseInterval(); m_fireState = FIRE_CHARGE; @@ -298,25 +219,17 @@ void CEgon::Attack( void ) { Fire( vecSrc, vecAiming ); m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - - if ( m_shootTime != 0 && gpGlobals->time > m_shootTime ) + + if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) { - if ( m_fireMode == FIRE_WIDE ) - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); - } - else - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); - } - - m_shootTime = 0; + 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_fireState = FIRE_OFF; - m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + 1.0; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; } } @@ -347,6 +260,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) if (tr.fAllSolid) return; +#ifndef CLIENT_DLL CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); if (pEntity == NULL) @@ -364,11 +278,15 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) } } + +#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 @@ -400,10 +318,12 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) 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 @@ -449,6 +369,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) m_shakeTime = gpGlobals->time + 1.5; } } +#endif timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval(); break; } @@ -465,6 +386,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ) { +#ifndef CLIENT_DLL if ( !m_pBeam ) { CreateEffect(); @@ -486,11 +408,15 @@ 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(); m_pBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 40 ); @@ -498,6 +424,8 @@ void CEgon::CreateEffect( void ) 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() ); @@ -505,11 +433,15 @@ void CEgon::CreateEffect( void ) 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 ) { @@ -525,11 +457,15 @@ void CEgon::CreateEffect( void ) 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 ); @@ -548,9 +484,12 @@ void CEgon::DestroyEffect( void ) UTIL_Remove( m_pSprite ); m_pSprite = NULL; } +#endif + } + void CEgon::WeaponIdle( void ) { ResetEmptySound( ); @@ -559,9 +498,8 @@ void CEgon::WeaponIdle( void ) return; if ( m_fireState != FIRE_OFF ) - EndAttack(); - - + EndAttack(); + int iAnim; float flRand = RANDOM_FLOAT(0,1); @@ -569,12 +507,12 @@ void CEgon::WeaponIdle( void ) if ( flRand <= 0.5 ) { iAnim = EGON_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT(10,15); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else { iAnim = EGON_FIDGET1; - m_flTimeWeaponIdle = gpGlobals->time + 3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; } SendWeaponAnim( iAnim ); @@ -585,11 +523,18 @@ void CEgon::WeaponIdle( void ) void CEgon::EndAttack( void ) { - STOP_SOUND( ENT(m_pPlayer->pev), CHAN_STATIC, EGON_SOUND_RUN ); - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100); + 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; - m_flTimeWeaponIdle = gpGlobals->time + 2.0; - m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + 0.5; + DestroyEffect(); } diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index 12fe603..84c131d 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -55,9 +55,7 @@ extern enginefuncs_t g_engfuncs; #define TRACE_HULL (*g_engfuncs.pfnTraceHull) #define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) #define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) -#ifndef SERVER_EXECUTE - #define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) -#endif +#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) #define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) #define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) #define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) @@ -69,6 +67,7 @@ extern enginefuncs_t g_engfuncs; #define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final) #define RANDOM_LONG (*g_engfuncs.pfnRandomLong) #define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) +#define GETPLAYERWONID (*g_engfuncs.pfnGetPlayerWONId) 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); @@ -87,6 +86,7 @@ inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NU #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) @@ -126,8 +126,6 @@ inline void *GET_PRIVATE( edict_t *pent ) #define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities) #define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) -#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer) - #define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) #define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) diff --git a/dlls/explode.cpp b/dlls/explode.cpp index a4c6c51..c6146d6 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/explode.h b/dlls/explode.h index 22434f2..26d08aa 100644 --- a/dlls/explode.h +++ b/dlls/explode.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/extdll.h b/dlls/extdll.h index f16452a..28e8df9 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -32,46 +32,36 @@ #pragma warning(disable : 4514) // unreferenced inline function removed #pragma warning(disable : 4100) // unreferenced formal parameter -#ifdef _WIN32 // Prevent tons of unused windows definitions +#ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #define NOWINRES #define NOSERVICE #define NOMCX #define NOIME -#include "WINDOWS.H" - -// Misc C-runtime library headers -#include "STDIO.H" -#include "STDLIB.H" -#include "MATH.H" - -#else -#include -#include -#include -#include -#include -#include -#include - -#define MAX_PATH PATH_MAX -#define ULONG ulong +#include "windows.h" +#else // _WIN32 #define FALSE 0 -#define TRUE 1 - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -#define itoa(a,b,c) sprintf(b, "%d", a) - +#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; // diff --git a/dlls/flyingmonster.cpp b/dlls/flyingmonster.cpp new file mode 100644 index 0000000..892418e --- /dev/null +++ b/dlls/flyingmonster.cpp @@ -0,0 +1,281 @@ +/*** +* +* 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. +* +* 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 0000000..7c1f12e --- /dev/null +++ b/dlls/flyingmonster.h @@ -0,0 +1,53 @@ +/*** +* +* 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. +* +* 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 60c8c9e..fbd41c8 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -161,7 +161,7 @@ void CBreakable::Spawn( void ) { pev->playerclass = 1; } - + SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. SetTouch( BreakTouch ); diff --git a/dlls/func_break.h b/dlls/func_break.h index 41a31a7..f478036 100644 --- a/dlls/func_break.h +++ b/dlls/func_break.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index bdbb9ff..648f830 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -353,12 +353,13 @@ BOOL CFuncTank :: StartControl( CBasePlayer *pController ) ALERT( at_console, "using TANK!\n"); - // Holster player's weapon 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; diff --git a/dlls/game.cpp b/dlls/game.cpp index 9789b29..ddc0f3b 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -17,11 +17,7 @@ #include "util.h" #include "game.h" - cvar_t displaysoundlist = {"displaysoundlist","0"}; -cvar_t mapcyclefile = {"mapcyclefile","mapcycle.txt"}; -cvar_t servercfgfile = {"servercfgfile","server.cfg"}; -cvar_t lservercfgfile = {"lservercfgfile","listenserver.cfg"}; // multiplayer server rules cvar_t fragsleft = {"mp_fragsleft","0", FCVAR_SERVER | FCVAR_UNLOGGED }; // Don't spam console/log files/users with this changing @@ -43,6 +39,9 @@ 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; @@ -454,14 +453,12 @@ cvar_t sk_player_leg3 = { "sk_player_leg3","1" }; 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 (&mapcyclefile); - CVAR_REGISTER (&servercfgfile); - CVAR_REGISTER (&lservercfgfile); CVAR_REGISTER (&teamplay); CVAR_REGISTER (&fraglimit); @@ -482,6 +479,8 @@ void GameDLLInit( void ) 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"}; diff --git a/dlls/game.h b/dlls/game.h index 2e0d03a..2536b02 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -20,23 +20,22 @@ extern void GameDLLInit( void ); extern cvar_t displaysoundlist; -extern cvar_t mapcyclefile; -extern cvar_t servercfgfile; -extern cvar_t lservercfgfile; // multiplayer server rules +extern cvar_t teamplay; extern cvar_t fraglimit; extern cvar_t timelimit; -extern cvar_t friendlyfir; +extern cvar_t friendlyfire; extern cvar_t falldamage; extern cvar_t weaponstay; -extern cvar_t forcerespaw; +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; diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index 188cba4..629d228 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -24,15 +24,17 @@ #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 gmsgScoreInfo; extern int gmsgMOTD; +int g_teamplay = 0; + //========================================================= //========================================================= BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry ) @@ -113,6 +115,7 @@ void CGameRules::RefreshSkillData ( void ) int iSkill; iSkill = (int)CVAR_GET_FLOAT("skill"); + g_iSkillLevel = iSkill; if ( iSkill < 1 ) { @@ -313,23 +316,28 @@ CGameRules *InstallGameRules( void ) if ( !gpGlobals->deathmatch ) { // generic half-life + g_teamplay = 0; return new CHalfLifeRules; } else { - if ( CVAR_GET_FLOAT( "mp_teamplay" ) > 0 ) + 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 27dc43d..8f3d6d4 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -292,6 +292,7 @@ public: 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 ); diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp new file mode 100644 index 0000000..5d572fe --- /dev/null +++ b/dlls/gargantua.cpp @@ -0,0 +1,1368 @@ +/*** +* +* 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. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#ifndef OEM_BUILD + +//========================================================= +// Gargantua +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "nodes.h" +#include "monsters.h" +#include "schedule.h" +#include "customentity.h" +#include "weapons.h" +#include "effects.h" +#include "soundent.h" +#include "decals.h" +#include "explode.h" +#include "func_break.h" + +//========================================================= +// Gargantua Monster +//========================================================= +const float GARG_ATTACKDIST = 80.0; + +// Garg animation events +#define GARG_AE_SLASH_LEFT 1 +//#define GARG_AE_BEAM_ATTACK_RIGHT 2 // No longer used +#define GARG_AE_LEFT_FOOT 3 +#define GARG_AE_RIGHT_FOOT 4 +#define GARG_AE_STOMP 5 +#define GARG_AE_BREATHE 6 + + +// Gargantua is immune to any damage but this +#define GARG_DAMAGE (DMG_ENERGYBEAM|DMG_CRUSH|DMG_MORTAR|DMG_BLAST) +#define GARG_EYE_SPRITE_NAME "sprites/gargeye1.spr" +#define GARG_BEAM_SPRITE_NAME "sprites/xbeam3.spr" +#define GARG_BEAM_SPRITE2 "sprites/xbeam3.spr" +#define GARG_STOMP_SPRITE_NAME "sprites/gargeye1.spr" +#define GARG_STOMP_BUZZ_SOUND "weapons/mine_charge.wav" +#define GARG_FLAME_LENGTH 330 +#define GARG_GIB_MODEL "models/metalplategibs.mdl" + +#define ATTN_GARG (ATTN_NORM) + +#define STOMP_SPRITE_COUNT 10 + +int gStompSprite = 0, gGargGibModel = 0; +void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ); + +class CSmoker; + +// Spiral Effect +class CSpiral : public CBaseEntity +{ +public: + void Spawn( void ); + void Think( void ); + int ObjectCaps( void ) { return FCAP_DONT_SAVE; } + static CSpiral *Create( const Vector &origin, float height, float radius, float duration ); +}; +LINK_ENTITY_TO_CLASS( streak_spiral, CSpiral ); + + +class CStomp : public CBaseEntity +{ +public: + void Spawn( void ); + void Think( void ); + static CStomp *StompCreate( const Vector &origin, const Vector &end, float speed ); + +private: +// UNDONE: re-use this sprite list instead of creating new ones all the time +// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ]; +}; + +LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ); +CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed ) +{ + CStomp *pStomp = GetClassPtr( (CStomp *)NULL ); + + pStomp->pev->origin = origin; + Vector dir = (end - origin); + pStomp->pev->scale = dir.Length(); + pStomp->pev->movedir = dir.Normalize(); + pStomp->pev->speed = speed; + pStomp->Spawn(); + + return pStomp; +} + +void CStomp::Spawn( void ) +{ + pev->nextthink = gpGlobals->time; + pev->classname = MAKE_STRING("garg_stomp"); + pev->dmgtime = gpGlobals->time; + + pev->framerate = 30; + pev->model = MAKE_STRING(GARG_STOMP_SPRITE_NAME); + pev->rendermode = kRenderTransTexture; + pev->renderamt = 0; + EMIT_SOUND_DYN( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND, 1, ATTN_NORM, 0, PITCH_NORM * 0.55); +} + + +#define STOMP_INTERVAL 0.025 + +void CStomp::Think( void ) +{ + TraceResult tr; + + pev->nextthink = gpGlobals->time + 0.1; + + // Do damage for this frame + Vector vecStart = pev->origin; + vecStart.z += 30; + Vector vecEnd = vecStart + (pev->movedir * pev->speed * gpGlobals->frametime); + + UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); + + if ( tr.pHit && tr.pHit != pev->owner ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + entvars_t *pevOwner = pev; + if ( pev->owner ) + pevOwner = VARS(pev->owner); + + if ( pEntity ) + pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC ); + } + + // Accelerate the effect + pev->speed = pev->speed + (gpGlobals->frametime) * pev->framerate; + pev->framerate = pev->framerate + (gpGlobals->frametime) * 1500; + + // Move and spawn trails + while ( gpGlobals->time - pev->dmgtime > STOMP_INTERVAL ) + { + pev->origin = pev->origin + pev->movedir * pev->speed * STOMP_INTERVAL; + for ( int i = 0; i < 2; i++ ) + { + CSprite *pSprite = CSprite::SpriteCreate( GARG_STOMP_SPRITE_NAME, pev->origin, TRUE ); + if ( pSprite ) + { + UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,500), ignore_monsters, edict(), &tr ); + pSprite->pev->origin = tr.vecEndPos; + pSprite->pev->velocity = Vector(RANDOM_FLOAT(-200,200),RANDOM_FLOAT(-200,200),175); + // pSprite->AnimateAndDie( RANDOM_FLOAT( 8.0, 12.0 ) ); + pSprite->pev->nextthink = gpGlobals->time + 0.3; + pSprite->SetThink( 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 index 18fac1e..09b798f 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -41,65 +41,15 @@ enum gauss_e { GAUSS_DRAW }; -class CGauss : public CBasePlayerWeapon -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 4; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - void WeaponIdle( void ); - - int m_fInAttack; - float m_flStartCharge; - float m_flPlayAftershock; - void StartFire( void ); - void Fire( Vector vecOrigSrc, Vector vecDirShooting, float flDamage ); - float GetFullChargeTime( void ); - int m_iBalls; - int m_iGlow; - int m_iBeam; - int m_iSoundState; // don't save this - - float m_flNextAmmoBurn;// while charging, when to absorb another unit of player's ammo? - - // was this weapon just fired primary or secondary? - // we need to know so we can pick the right set of effects. - BOOL m_fPrimaryFire; - -private: - unsigned short m_usGaussFire; - unsigned short m_usGaussSpin; -}; - LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); - -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 ); - - float CGauss::GetFullChargeTime( void ) { +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else if ( g_pGameRules->IsMultiplayer() ) +#endif { return 1.5; } @@ -170,34 +120,34 @@ int CGauss::GetItemInfo(ItemInfo *p) 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_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 ); + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - // m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + SendWeaponAnim( GAUSS_HOLSTER ); m_fInAttack = 0; - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); } void CGauss::PrimaryAttack() { // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) + if ( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound( ); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->time + 0.15; + 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( ); m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; @@ -205,21 +155,20 @@ void CGauss::PrimaryAttack() } m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - m_fPrimaryFire = TRUE; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 2; StartFire(); m_fInAttack = 0; - m_flTimeWeaponIdle = gpGlobals->time + 1.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_pPlayer->pev->waterlevel == 3 ) { if ( m_fInAttack != 0 ) { @@ -232,13 +181,13 @@ void CGauss::SecondaryAttack() PlayEmptySound( ); } - m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->time + 0.5; + 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); m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; @@ -248,23 +197,24 @@ void CGauss::SecondaryAttack() m_fPrimaryFire = FALSE; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin - m_flNextAmmoBurn = gpGlobals->time; + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase(); // spin up m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; SendWeaponAnim( GAUSS_SPINUP ); m_fInAttack = 1; - m_flTimeWeaponIdle = gpGlobals->time + 0.5; - m_flStartCharge = gpGlobals->time; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; + m_pPlayer->m_flStartCharge = gpGlobals->time; + m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime(); - PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); + 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 < gpGlobals->time) + if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) { SendWeaponAnim( GAUSS_SPIN ); m_fInAttack = 2; @@ -272,65 +222,71 @@ void CGauss::SecondaryAttack() } else { - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0 ) - { - // out of ammo! force the gun to fire - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = gpGlobals->time + 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 ( gpGlobals->time > m_flNextAmmoBurn && m_flNextAmmoBurn != -1 ) + if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) { - if ( g_pGameRules->IsMultiplayer() ) +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_flNextAmmoBurn = gpGlobals->time + 0.1; + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.1; } else { m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_flNextAmmoBurn = gpGlobals->time + 0.3; + 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 ( gpGlobals->time - m_flStartCharge >= GetFullChargeTime() ) + if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) { // don't eat any more ammo after gun is fully charged. - m_flNextAmmoBurn = -1; + m_pPlayer->m_flNextAmmoBurn = 1000; } - int pitch = (gpGlobals->time - m_flStartCharge) * (150/GetFullChargeTime()) + 100; - if (pitch > 250) - pitch = 250; + 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) + if ( m_iSoundState == 0 ) ALERT( at_console, "sound state %d\n", m_iSoundState ); - PLAYBACK_EVENT_FULL( 0, 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 ); + 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 = gpGlobals->time + 0.1; - if (m_flStartCharge < gpGlobals->time - 10) + // 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 = gpGlobals->time + 1.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! @@ -353,25 +309,30 @@ void CGauss::StartFire( void ) Vector vecAiming = gpGlobals->v_forward; Vector vecSrc = m_pPlayer->GetGunPosition( ); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; - if (gpGlobals->time - m_flStartCharge > GetFullChargeTime()) + if ( gpGlobals->time - m_pPlayer->m_flStartCharge > GetFullChargeTime() ) { flDamage = 200; } else { - flDamage = 200 * ((gpGlobals->time - m_flStartCharge) / GetFullChargeTime() ); + 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_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 ) @@ -379,17 +340,19 @@ void CGauss::StartFire( void ) m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5; } - if ( !g_pGameRules->IsDeathmatch() ) + 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_flPlayAftershock = gpGlobals->time + RANDOM_FLOAT(0.3, 0.8); + m_pPlayer->m_flPlayAftershock = gpGlobals->time + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.3, 0.8 ); Fire( vecSrc, vecAiming, flDamage ); } @@ -411,21 +374,23 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) pentIgnore = ENT( m_pPlayer->pev ); // The main firing event is sent unreliably so it won't be delayed. - PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); + 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_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 1 ); - /* - ALERT( at_console, "%f %f %f\n%f %f %f\n", + 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 ); - */ + 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) { nMaxHits--; @@ -441,17 +406,14 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) if (pEntity == NULL) break; - if (fFirstBeam) + if ( fFirstBeam ) { m_pPlayer->pev->effects |= EF_MUZZLEFLASH; fFirstBeam = 0; + nTotal += 26; } - else - { - nTotal += 26; - } - + if (pEntity->pev->takedamage) { ClearMultiDamage(); @@ -459,8 +421,6 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); } - // ALERT( at_console, "%s\n", STRING( pEntity->pev->classname )); - if ( pEntity->ReflectGauss() ) { float n; @@ -484,10 +444,8 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) // explode a bit m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST ); - nTotal += 13; - - nTotal += 21; - + nTotal += 34; + // lose energy if (n == 0) n = 0.1; flDamage = flDamage * (1 - n); @@ -518,11 +476,13 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) 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 @@ -533,8 +493,11 @@ 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 ); + nTotal += 53; + vecSrc = beam_tr.vecEndPos + vecDir; } } @@ -547,6 +510,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) else { //ALERT( at_console, "blocked solid\n" ); + flDamage = 0; } @@ -558,6 +522,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) pentIgnore = ENT( pEntity->pev ); } } +#endif // ALERT( at_console, "%d bytes\n", nTotal ); } @@ -569,7 +534,7 @@ void CGauss::WeaponIdle( void ) ResetEmptySound( ); // play aftershock static discharge - if (m_flPlayAftershock && m_flPlayAftershock < gpGlobals->time) + if ( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) { switch (RANDOM_LONG(0,3)) { @@ -578,17 +543,17 @@ void CGauss::WeaponIdle( void ) 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_flPlayAftershock = 0.0; + m_pPlayer->m_flPlayAftershock = 0.0; } - if (m_flTimeWeaponIdle > gpGlobals->time) + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) return; if (m_fInAttack != 0) { StartFire(); m_fInAttack = 0; - m_flTimeWeaponIdle = gpGlobals->time + 2.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; } else { @@ -597,17 +562,17 @@ void CGauss::WeaponIdle( void ) if (flRand <= 0.5) { iAnim = GAUSS_IDLE; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else if (flRand <= 0.75) { iAnim = GAUSS_IDLE2; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else { iAnim = GAUSS_FIDGET; - m_flTimeWeaponIdle = gpGlobals->time + 3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; } return; @@ -616,6 +581,11 @@ void CGauss::WeaponIdle( void ) } } + + + + + class CGaussAmmo : public CBasePlayerAmmo { void Spawn( void ) @@ -641,4 +611,4 @@ class CGaussAmmo : public CBasePlayerAmmo }; LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); -#endif \ No newline at end of file +#endif diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp new file mode 100644 index 0000000..1c8c6ee --- /dev/null +++ b/dlls/genericmonster.cpp @@ -0,0 +1,140 @@ +/*** +* +* 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. +* +* 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 502a7dc..c85c324 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/globals.cpp b/dlls/globals.cpp index b4432e9..b5c734b 100644 --- a/dlls/globals.cpp +++ b/dlls/globals.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/glock.cpp b/dlls/glock.cpp new file mode 100644 index 0000000..ae2485b --- /dev/null +++ b/dlls/glock.cpp @@ -0,0 +1,325 @@ +/*** +* +* 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. +* +****/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" + +enum glock_e { + GLOCK_IDLE1 = 0, + GLOCK_IDLE2, + GLOCK_IDLE3, + GLOCK_SHOOT, + GLOCK_SHOOT_EMPTY, + GLOCK_RELOAD, + GLOCK_RELOAD_NOT_EMPTY, + GLOCK_DRAW, + GLOCK_HOLSTER, + GLOCK_ADD_SILENCER +}; + +class CGlock : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 2; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ); + BOOL Deploy( void ); + void Reload( void ); + void WeaponIdle( void ); + +private: + int m_iShell; + + + unsigned short m_usFireGlock1; + unsigned short m_usFireGlock2; +}; +LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); +LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); + + +void CGlock::Spawn( ) +{ + pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names + Precache( ); + m_iId = WEAPON_GLOCK; + SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); + + m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CGlock::Precache( void ) +{ + PRECACHE_MODEL("models/v_9mmhandgun.mdl"); + PRECACHE_MODEL("models/w_9mmhandgun.mdl"); + PRECACHE_MODEL("models/p_9mmhandgun.mdl"); + + m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell + + PRECACHE_SOUND("items/9mmclip1.wav"); + PRECACHE_SOUND("items/9mmclip2.wav"); + + PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun + + m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); + m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); +} + +int CGlock::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "9mm"; + p->iMaxAmmo1 = _9MM_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = GLOCK_MAX_CLIP; + p->iSlot = 1; + p->iPosition = 0; + p->iFlags = 0; + p->iId = m_iId = WEAPON_GLOCK; + p->iWeight = GLOCK_WEIGHT; + + return 1; +} + +BOOL CGlock::Deploy( ) +{ + // pev->body = 1; + return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded" ); +} + +void CGlock::SecondaryAttack( void ) +{ + GlockFire( 0.1, 0.2, FALSE ); +} + +void CGlock::PrimaryAttack( void ) +{ + GlockFire( 0.01, 0.3, TRUE ); +} + +void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) +{ + if (m_iClip <= 0) + { + if (m_fFireOnEmpty) + { + PlayEmptySound(); + m_flNextPrimaryAttack = gpGlobals->time + 0.2; + } + + return; + } + + m_iClip--; + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + +#if defined ( OLD_WEAPONS ) + if (m_iClip != 0) + SendWeaponAnim( GLOCK_SHOOT ); + else + SendWeaponAnim( GLOCK_SHOOT_EMPTY ); +#endif + + if ( fUseAutoAim ) + { + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock1, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); + } + else + { + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); + } + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + +#if defined ( OLD_WEAPONS ) + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + + Vector vecShellVelocity = m_pPlayer->pev->velocity + + gpGlobals->v_right * RANDOM_FLOAT(50,70) + + gpGlobals->v_up * RANDOM_FLOAT(100,150) + + gpGlobals->v_forward * 25; + EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); +#endif + + // silenced + if (pev->body == 1) + { + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; +#if defined ( OLD_WEAPONS ) + switch(RANDOM_LONG(0,1)) + { + case 0: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); + break; + case 1: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); + break; + } +#endif + } + else + { + // non-silenced + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; +#if defined ( OLD_WEAPONS ) + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); +#endif + } + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming; + + if ( fUseAutoAim ) + { + vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + } + else + { + vecAiming = gpGlobals->v_forward; + } + + m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + flCycleTime; + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + +#if defined ( OLD_WEAPONS ) + m_pPlayer->pev->punchangle.x -= 2; +#endif +} + + +void CGlock::Reload( void ) +{ + int iResult; + + if (m_iClip == 0) + iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); + else + iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); + + if (iResult) + { + m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + } +} + + + +void CGlock::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + if (m_flTimeWeaponIdle > gpGlobals->time) + return; + + // only idle if the slid isn't back + if (m_iClip != 0) + { + int iAnim; + float flRand = RANDOM_FLOAT(0, 1); + if (flRand <= 0.3 + 0 * 0.75) + { + iAnim = GLOCK_IDLE3; + m_flTimeWeaponIdle = gpGlobals->time + 49.0 / 16; + } + else if (flRand <= 0.6 + 0 * 0.875) + { + iAnim = GLOCK_IDLE1; + m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 16.0; + } + else + { + iAnim = GLOCK_IDLE2; + m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0; + } + SendWeaponAnim( iAnim ); + } +} + + + + + + + + +class CGlockAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_9mmclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); +LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); + + + + + + + + + + + + + + + diff --git a/dlls/gman.cpp b/dlls/gman.cpp new file mode 100644 index 0000000..a45d6a4 --- /dev/null +++ b/dlls/gman.cpp @@ -0,0 +1,237 @@ +/*** +* +* 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. +* +* 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 1fb1963..b821474 100644 --- a/dlls/h_ai.cpp +++ b/dlls/h_ai.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -23,6 +23,7 @@ #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 @@ -83,7 +84,7 @@ Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, f Vector vecScale; Vector vecGrenadeVel; Vector vecTemp; - float flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj; + float flGravity = g_psv_gravity->value * flGravityAdj; if (vecSpot2.z - vecSpot1.z > 500) { @@ -163,7 +164,7 @@ Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, f // Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj ) { - float flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj; + float flGravity = g_psv_gravity->value * flGravityAdj; Vector vecGrenadeVel = (vecSpot2 - vecSpot1); diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index 7e24e11..de31953 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/h_cine.cpp b/dlls/h_cine.cpp new file mode 100644 index 0000000..948cfde --- /dev/null +++ b/dlls/h_cine.cpp @@ -0,0 +1,241 @@ +/*** +* +* 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. +* +* 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 index 85a0f40..a68252e 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/h_export.cpp b/dlls/h_export.cpp index 01257a7..f7bb3f9 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -25,8 +25,13 @@ #include "cbase.h" +// Holds engine functionality callbacks +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + #ifdef _WIN32 + // Required DLL entry point BOOL WINAPI DllMain( HINSTANCE hinstDLL, @@ -41,21 +46,24 @@ BOOL WINAPI DllMain( } return TRUE; } -#endif -// Holds engine functionality callbacks -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; - -#ifdef _WIN32 void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -#else -extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -#endif { 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 index 6ebe79e..e991dc8 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -35,22 +35,6 @@ enum handgrenade_e { }; -class CHandGrenade : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 5; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - BOOL Deploy( void ); - BOOL CanHolster( void ); - void Holster( int skiplocal = 0 ); - void WeaponIdle( void ); - float m_flStartThrow; - float m_flReleaseThrow; -}; LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade ); @@ -60,7 +44,9 @@ void CHandGrenade::Spawn( ) 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; @@ -108,7 +94,8 @@ BOOL CHandGrenade::CanHolster( void ) 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 ); } @@ -125,36 +112,36 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) 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; SendWeaponAnim( HANDGRENADE_PINPULL ); - m_flTimeWeaponIdle = gpGlobals->time + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; } } void CHandGrenade::WeaponIdle( void ) { - if (m_flReleaseThrow == 0) - m_flReleaseThrow = gpGlobals->time; + if ( m_flReleaseThrow == 0 && m_flStartThrow ) + m_flReleaseThrow = gpGlobals->time; - if (m_flTimeWeaponIdle > gpGlobals->time) + 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) - angThrow.x = -10 + angThrow.x * ((90 - 10) / 90.0); + if ( angThrow.x < 0 ) + angThrow.x = -10 + angThrow.x * ( ( 90 - 10 ) / 90.0 ); else - angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0); + angThrow.x = -10 + angThrow.x * ( ( 90 + 10 ) / 90.0 ); - float flVel = (90 - angThrow.x) * 4; - if (flVel > 500) + float flVel = ( 90 - angThrow.x ) * 4; + if ( flVel > 500 ) flVel = 500; UTIL_MakeVectors( angThrow ); @@ -170,11 +157,11 @@ void CHandGrenade::WeaponIdle( void ) 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 ); } @@ -186,27 +173,28 @@ void CHandGrenade::WeaponIdle( void ) // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + m_flReleaseThrow = 0; m_flStartThrow = 0; - m_flNextPrimaryAttack = gpGlobals->time + 0.5; - m_flTimeWeaponIdle = gpGlobals->time + 0.5; + 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 // animation, weapon idle will automatically retire the weapon for us. - m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->time + 0.5;// ensure that the animation can finish playing + m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;// ensure that the animation can finish playing } 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 ); } @@ -216,24 +204,24 @@ void CHandGrenade::WeaponIdle( void ) return; } - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); m_flReleaseThrow = -1; return; } - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.75) { iAnim = HANDGRENADE_IDLE; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );// how long till we do this again. + 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 = gpGlobals->time + 75.0 / 30.0; + 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 0000000..cf62d50 --- /dev/null +++ b/dlls/hassassin.cpp @@ -0,0 +1,1015 @@ +/*** +* +* 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. +* +* 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 0000000..1a42602 --- /dev/null +++ b/dlls/headcrab.cpp @@ -0,0 +1,555 @@ +/*** +* +* 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. +* +* 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 ( 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 d5055d9..44ac14d 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -68,6 +68,11 @@ void CHealthKit::Precache( void ) 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 ); diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp new file mode 100644 index 0000000..ae28426 --- /dev/null +++ b/dlls/hgrunt.cpp @@ -0,0 +1,2517 @@ +/*** +* +* 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. +* +* 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/mp.def b/dlls/hl.def similarity index 78% rename from dlls/mp.def rename to dlls/hl.def index 5ae6f18..c009191 100644 --- a/dlls/mp.def +++ b/dlls/hl.def @@ -1,4 +1,4 @@ -LIBRARY mp +LIBRARY hl EXPORTS GiveFnptrsToDll @1 SECTIONS diff --git a/dlls/mp.dsp b/dlls/hl.dsp similarity index 60% rename from dlls/mp.dsp rename to dlls/hl.dsp index c792505..ca69abc 100644 --- a/dlls/mp.dsp +++ b/dlls/hl.dsp @@ -1,36 +1,37 @@ -# Microsoft Developer Studio Project File - Name="mp" - Package Owner=<4> +# 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=mp - Win32 Release +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 "mp.mak". +!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 "mp.mak" CFG="mp - Win32 Release" +!MESSAGE NMAKE /f "hl.mak" CFG="hl - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "mp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mp - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") +!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 Germany" (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 ""$/SDKSrc/Public/dlls", NVGBAAAA" +# PROP Scc_ProjName ""$/GoldSrc/dlls", ELEBAAAA" # PROP Scc_LocalPath "." -CPP=xicl6.exe +CPP=cl.exe MTL=midl.exe RSC=rc.exe -!IF "$(CFG)" == "mp - Win32 Release" +!IF "$(CFG)" == "hl - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -39,12 +40,11 @@ RSC=rc.exe # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".\Releasemp" -# PROP Intermediate_Dir ".\Releasemp" +# PROP Output_Dir ".\Releasehl" +# PROP Intermediate_Dir ".\Releasehl" # 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 /GX /Zi /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\\" /I "..\common\gamedb" /I "..\common\persistence" /I "..\common\persistance\sample" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /D "PERSISTENCE_SAMPLE" /YX /FD /c -# SUBTRACT 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" /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" @@ -52,35 +52,26 @@ RSC=rc.exe BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo -LINK32=xilink6.exe +LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\mp.def" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\hl.def" # SUBTRACT LINK32 /profile -# Begin Custom Build - Copying to \half-life\mp\dlls -TargetPath=.\Releasemp\mp.dll -TargetName=mp -InputPath=.\Releasemp\mp.dll -SOURCE="$(InputPath)" -"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetPath) \half-life\mp\dlls - -# End Custom Build - -!ELSEIF "$(CFG)" == "mp - Win32 Debug" +!ELSEIF "$(CFG)" == "hl - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir ".\mp___Win" -# PROP BASE Intermediate_Dir ".\mp___Win" +# 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 ".\debugmp" -# PROP Intermediate_Dir ".\debugmp" +# PROP Output_Dir ".\debughl" +# PROP Intermediate_Dir ".\debughl" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\\" /I "..\common\gamedb" /I "..\common\persistence" /I "..\common\persistance\sample" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /D "PERSISTENCE_SAMPLE" /FR /YX /FD /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" @@ -88,36 +79,53 @@ SOURCE="$(InputPath)" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo -LINK32=xilink6.exe +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:".\mp.def" /implib:".\Debug\mp.lib" +# ADD LINK32 user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\hl.def" /implib:".\Debug\hl.lib" # SUBTRACT LINK32 /profile -# Begin Custom Build - Copying to \half-life\mp\dlls -TargetPath=.\debugmp\mp.dll -TargetName=mp -InputPath=.\debugmp\mp.dll -SOURCE="$(InputPath)" -"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetPath) \half-life\mp\dlls - -# End Custom Build - -!ELSEIF "$(CFG)" == "mp - Win32 Profile" +!ELSEIF "$(CFG)" == "hl - Win32 Germany" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\mp___Win" -# PROP BASE Intermediate_Dir ".\mp___Win" +# 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 ".\Profilemp" -# PROP Intermediate_Dir ".\Profilemp" +# PROP Output_Dir ".\Germany" +# PROP Intermediate_Dir ".\Germany" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /FR /YX /c +# ADD CPP /nologo /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 "GERMANY" /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 /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 odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /def:".\hl.def" +# SUBTRACT LINK32 /profile + +!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 ".\Profilehl" +# PROP Intermediate_Dir ".\Profilehl" # 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 /GX /Zi /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\\" /I "..\common\gamedb" /I "..\common\persistence" /I "..\common\persistance\sample" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /D "PERSISTENCE_SAMPLE" /YX /FD /c +# 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" /YX /FD /c # SUBTRACT CPP /Fr # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -126,39 +134,32 @@ SOURCE="$(InputPath)" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo -LINK32=xilink6.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:".\mp.def" +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:".\mp.def" -# Begin Custom Build - Copying to \half-life\mp\dlls -TargetDir=.\Profilemp -InputPath=.\Profilemp\mp.dll -SOURCE="$(InputPath)" - -BuildCmds= \ - copy $(TargetDir)\mp.dll \half-life\mp\dlls \ - copy $(TargetDir)\mp.map \half-life\mp\dlls \ - - -"\half-life\mp\dlls\mp.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) - -"\half-life\mp\dlls\mp.map" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) -# End Custom Build +# 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" !ENDIF # Begin Target -# Name "mp - Win32 Release" -# Name "mp - Win32 Debug" -# Name "mp - Win32 Profile" +# Name "hl - Win32 Release" +# Name "hl - Win32 Debug" +# Name "hl - Win32 Germany" +# 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 @@ -171,10 +172,34 @@ 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 @@ -191,6 +216,10 @@ 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 @@ -199,6 +228,10 @@ 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 @@ -215,6 +248,10 @@ 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 @@ -231,10 +268,18 @@ 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 @@ -243,6 +288,10 @@ SOURCE=.\globals.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 @@ -251,6 +300,10 @@ 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 @@ -263,10 +316,22 @@ 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=.\wpn_shared\hl_wpn_glock.cpp # End Source File # Begin Source File @@ -279,7 +344,15 @@ SOURCE=.\hornetgun.cpp # End Source File # Begin Source File -SOURCE=..\common\interface.cpp +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 @@ -287,6 +360,10 @@ 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 @@ -295,6 +372,18 @@ 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 @@ -303,19 +392,23 @@ SOURCE=.\mp5.cpp # End Source File # Begin Source File -SOURCE=.\mpstubb.cpp -# End Source File -# Begin Source File - SOURCE=.\multiplay_gamerules.cpp # End Source File # Begin Source File -SOURCE=.\pathcorner.cpp +SOURCE=.\nihilanth.cpp # End Source File # Begin Source File -SOURCE=.\persistencehelpers.cpp +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 @@ -347,6 +440,14 @@ 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 @@ -355,6 +456,18 @@ 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 @@ -379,6 +492,10 @@ 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 @@ -387,10 +504,22 @@ 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 @@ -399,10 +528,18 @@ 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 @@ -413,6 +550,10 @@ SOURCE=.\world.cpp SOURCE=.\xen.cpp # End Source File +# Begin Source File + +SOURCE=.\zombie.cpp +# End Source File # End Group # Begin Group "Header Files" @@ -451,6 +592,10 @@ 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 @@ -459,6 +604,10 @@ 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 @@ -471,11 +620,11 @@ SOURCE=.\extdll.h # End Source File # Begin Source File -SOURCE=.\func_break.h +SOURCE=.\flyingmonster.h # End Source File # Begin Source File -SOURCE=.\game.h +SOURCE=.\func_break.h # End Source File # Begin Source File @@ -491,10 +640,6 @@ SOURCE=.\items.h # End Source File # Begin Source File -SOURCE=.\maprules.h -# End Source File -# Begin Source File - SOURCE=.\monsterevent.h # End Source File # Begin Source File @@ -547,6 +692,10 @@ 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 @@ -563,6 +712,10 @@ 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 diff --git a/dlls/hl.mak b/dlls/hl.mak new file mode 100644 index 0000000..8a56e08 --- /dev/null +++ b/dlls/hl.mak @@ -0,0 +1,17750 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +!IF "$(CFG)" == "" +CFG=hl - Win32 Release +!MESSAGE No configuration specified. Defaulting to hl - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "hl - Win32 Release" && "$(CFG)" != "hl - Win32 Debug" &&\ + "$(CFG)" != "hl - Win32 Germany" && "$(CFG)" != "hl - Win32 Profile" &&\ + "$(CFG)" != "hl - Win32 HLDEMO Release" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!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 Germany" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "hl - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "hl - Win32 HLDEMO Release" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "hl - Win32 Profile" +MTL=mktyplib.exe +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "hl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Releasehl" +# PROP Intermediate_Dir "Releasehl" +# PROP Target_Dir "" +OUTDIR=.\Releasehl +INTDIR=.\Releasehl +# Begin Custom Macros +TargetName=hl +# End Custom Macros + +ALL : "$(OUTDIR)\hl.dll" ".\hl" + +CLEAN : + -@erase "$(INTDIR)\aflock.obj" + -@erase "$(INTDIR)\agrunt.obj" + -@erase "$(INTDIR)\airtank.obj" + -@erase "$(INTDIR)\animating.obj" + -@erase "$(INTDIR)\animation.obj" + -@erase "$(INTDIR)\apache.obj" + -@erase "$(INTDIR)\barnacle.obj" + -@erase "$(INTDIR)\barney.obj" + -@erase "$(INTDIR)\bigmomma.obj" + -@erase "$(INTDIR)\bloater.obj" + -@erase "$(INTDIR)\bmodels.obj" + -@erase "$(INTDIR)\bullsquid.obj" + -@erase "$(INTDIR)\buttons.obj" + -@erase "$(INTDIR)\cbase.obj" + -@erase "$(INTDIR)\client.obj" + -@erase "$(INTDIR)\combat.obj" + -@erase "$(INTDIR)\controller.obj" + -@erase "$(INTDIR)\crossbow.obj" + -@erase "$(INTDIR)\crowbar.obj" + -@erase "$(INTDIR)\defaultai.obj" + -@erase "$(INTDIR)\doors.obj" + -@erase "$(INTDIR)\effects.obj" + -@erase "$(INTDIR)\egon.obj" + -@erase "$(INTDIR)\explode.obj" + -@erase "$(INTDIR)\flyingmonster.obj" + -@erase "$(INTDIR)\func_break.obj" + -@erase "$(INTDIR)\func_tank.obj" + -@erase "$(INTDIR)\game.obj" + -@erase "$(INTDIR)\gamerules.obj" + -@erase "$(INTDIR)\gargantua.obj" + -@erase "$(INTDIR)\gauss.obj" + -@erase "$(INTDIR)\genericmonster.obj" + -@erase "$(INTDIR)\ggrenade.obj" + -@erase "$(INTDIR)\globals.obj" + -@erase "$(INTDIR)\glock.obj" + -@erase "$(INTDIR)\gman.obj" + -@erase "$(INTDIR)\h_ai.obj" + -@erase "$(INTDIR)\h_battery.obj" + -@erase "$(INTDIR)\h_cine.obj" + -@erase "$(INTDIR)\h_cycler.obj" + -@erase "$(INTDIR)\h_export.obj" + -@erase "$(INTDIR)\handgrenade.obj" + -@erase "$(INTDIR)\hassassin.obj" + -@erase "$(INTDIR)\headcrab.obj" + -@erase "$(INTDIR)\healthkit.obj" + -@erase "$(INTDIR)\hgrunt.obj" + -@erase "$(INTDIR)\hornet.obj" + -@erase "$(INTDIR)\hornetgun.obj" + -@erase "$(INTDIR)\houndeye.obj" + -@erase "$(INTDIR)\ichthyosaur.obj" + -@erase "$(INTDIR)\islave.obj" + -@erase "$(INTDIR)\items.obj" + -@erase "$(INTDIR)\leech.obj" + -@erase "$(INTDIR)\lights.obj" + -@erase "$(INTDIR)\maprules.obj" + -@erase "$(INTDIR)\monstermaker.obj" + -@erase "$(INTDIR)\monsters.obj" + -@erase "$(INTDIR)\monsterstate.obj" + -@erase "$(INTDIR)\mortar.obj" + -@erase "$(INTDIR)\mp5.obj" + -@erase "$(INTDIR)\multiplay_gamerules.obj" + -@erase "$(INTDIR)\nihilanth.obj" + -@erase "$(INTDIR)\nodes.obj" + -@erase "$(INTDIR)\osprey.obj" + -@erase "$(INTDIR)\pathcorner.obj" + -@erase "$(INTDIR)\plane.obj" + -@erase "$(INTDIR)\plats.obj" + -@erase "$(INTDIR)\player.obj" + -@erase "$(INTDIR)\pm_debug.obj" + -@erase "$(INTDIR)\pm_math.obj" + -@erase "$(INTDIR)\pm_shared.obj" + -@erase "$(INTDIR)\python.obj" + -@erase "$(INTDIR)\rat.obj" + -@erase "$(INTDIR)\roach.obj" + -@erase "$(INTDIR)\rpg.obj" + -@erase "$(INTDIR)\satchel.obj" + -@erase "$(INTDIR)\schedule.obj" + -@erase "$(INTDIR)\scientist.obj" + -@erase "$(INTDIR)\scripted.obj" + -@erase "$(INTDIR)\shotgun.obj" + -@erase "$(INTDIR)\singleplay_gamerules.obj" + -@erase "$(INTDIR)\skill.obj" + -@erase "$(INTDIR)\sound.obj" + -@erase "$(INTDIR)\soundent.obj" + -@erase "$(INTDIR)\spectator.obj" + -@erase "$(INTDIR)\squadmonster.obj" + -@erase "$(INTDIR)\squeakgrenade.obj" + -@erase "$(INTDIR)\subs.obj" + -@erase "$(INTDIR)\talkmonster.obj" + -@erase "$(INTDIR)\teamplay_gamerules.obj" + -@erase "$(INTDIR)\tempmonster.obj" + -@erase "$(INTDIR)\tentacle.obj" + -@erase "$(INTDIR)\triggers.obj" + -@erase "$(INTDIR)\tripmine.obj" + -@erase "$(INTDIR)\turret.obj" + -@erase "$(INTDIR)\util.obj" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(INTDIR)\weapons.obj" + -@erase "$(INTDIR)\world.obj" + -@erase "$(INTDIR)\WXDEBUG.OBJ" + -@erase "$(INTDIR)\xen.obj" + -@erase "$(INTDIR)\zombie.obj" + -@erase "$(OUTDIR)\hl.dll" + -@erase "$(OUTDIR)\hl.exp" + -@erase "$(OUTDIR)\hl.lib" + -@erase "$(OUTDIR)\hl.map" + -@erase "$(OUTDIR)\hl.pdb" + -@erase ".\hl" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /I "..\common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /YX /c +# SUBTRACT CPP /Fr +CPP_PROJ=/nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /I "..\common" /D\ + "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D\ + "VALVE_DLL" /Fp"$(INTDIR)/hl.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Releasehl/ +CPP_SBRS=.\. +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/hl.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\hl.def" +# SUBTRACT LINK32 /profile +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\ + /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)/hl.pdb"\ + /map:"$(INTDIR)/hl.map" /debug /machine:I386 /def:".\hl.def"\ + /out:"$(OUTDIR)/hl.dll" /implib:"$(OUTDIR)/hl.lib" +LINK32_OBJS= \ + "$(INTDIR)\aflock.obj" \ + "$(INTDIR)\agrunt.obj" \ + "$(INTDIR)\airtank.obj" \ + "$(INTDIR)\animating.obj" \ + "$(INTDIR)\animation.obj" \ + "$(INTDIR)\apache.obj" \ + "$(INTDIR)\barnacle.obj" \ + "$(INTDIR)\barney.obj" \ + "$(INTDIR)\bigmomma.obj" \ + "$(INTDIR)\bloater.obj" \ + "$(INTDIR)\bmodels.obj" \ + "$(INTDIR)\bullsquid.obj" \ + "$(INTDIR)\buttons.obj" \ + "$(INTDIR)\cbase.obj" \ + "$(INTDIR)\client.obj" \ + "$(INTDIR)\combat.obj" \ + "$(INTDIR)\controller.obj" \ + "$(INTDIR)\crossbow.obj" \ + "$(INTDIR)\crowbar.obj" \ + "$(INTDIR)\defaultai.obj" \ + "$(INTDIR)\doors.obj" \ + "$(INTDIR)\effects.obj" \ + "$(INTDIR)\egon.obj" \ + "$(INTDIR)\explode.obj" \ + "$(INTDIR)\flyingmonster.obj" \ + "$(INTDIR)\func_break.obj" \ + "$(INTDIR)\func_tank.obj" \ + "$(INTDIR)\game.obj" \ + "$(INTDIR)\gamerules.obj" \ + "$(INTDIR)\gargantua.obj" \ + "$(INTDIR)\gauss.obj" \ + "$(INTDIR)\genericmonster.obj" \ + "$(INTDIR)\ggrenade.obj" \ + "$(INTDIR)\globals.obj" \ + "$(INTDIR)\glock.obj" \ + "$(INTDIR)\gman.obj" \ + "$(INTDIR)\h_ai.obj" \ + "$(INTDIR)\h_battery.obj" \ + "$(INTDIR)\h_cine.obj" \ + "$(INTDIR)\h_cycler.obj" \ + "$(INTDIR)\h_export.obj" \ + "$(INTDIR)\handgrenade.obj" \ + "$(INTDIR)\hassassin.obj" \ + "$(INTDIR)\headcrab.obj" \ + "$(INTDIR)\healthkit.obj" \ + "$(INTDIR)\hgrunt.obj" \ + "$(INTDIR)\hornet.obj" \ + "$(INTDIR)\hornetgun.obj" \ + "$(INTDIR)\houndeye.obj" \ + "$(INTDIR)\ichthyosaur.obj" \ + "$(INTDIR)\islave.obj" \ + "$(INTDIR)\items.obj" \ + "$(INTDIR)\leech.obj" \ + "$(INTDIR)\lights.obj" \ + "$(INTDIR)\maprules.obj" \ + "$(INTDIR)\monstermaker.obj" \ + "$(INTDIR)\monsters.obj" \ + "$(INTDIR)\monsterstate.obj" \ + "$(INTDIR)\mortar.obj" \ + "$(INTDIR)\mp5.obj" \ + "$(INTDIR)\multiplay_gamerules.obj" \ + "$(INTDIR)\nihilanth.obj" \ + "$(INTDIR)\nodes.obj" \ + "$(INTDIR)\osprey.obj" \ + "$(INTDIR)\pathcorner.obj" \ + "$(INTDIR)\plane.obj" \ + "$(INTDIR)\plats.obj" \ + "$(INTDIR)\player.obj" \ + "$(INTDIR)\pm_debug.obj" \ + "$(INTDIR)\pm_math.obj" \ + "$(INTDIR)\pm_shared.obj" \ + "$(INTDIR)\python.obj" \ + "$(INTDIR)\rat.obj" \ + "$(INTDIR)\roach.obj" \ + "$(INTDIR)\rpg.obj" \ + "$(INTDIR)\satchel.obj" \ + "$(INTDIR)\schedule.obj" \ + "$(INTDIR)\scientist.obj" \ + "$(INTDIR)\scripted.obj" \ + "$(INTDIR)\shotgun.obj" \ + "$(INTDIR)\singleplay_gamerules.obj" \ + "$(INTDIR)\skill.obj" \ + "$(INTDIR)\sound.obj" \ + "$(INTDIR)\soundent.obj" \ + "$(INTDIR)\spectator.obj" \ + "$(INTDIR)\squadmonster.obj" \ + "$(INTDIR)\squeakgrenade.obj" \ + "$(INTDIR)\subs.obj" \ + "$(INTDIR)\talkmonster.obj" \ + "$(INTDIR)\teamplay_gamerules.obj" \ + "$(INTDIR)\tempmonster.obj" \ + "$(INTDIR)\tentacle.obj" \ + "$(INTDIR)\triggers.obj" \ + "$(INTDIR)\tripmine.obj" \ + "$(INTDIR)\turret.obj" \ + "$(INTDIR)\util.obj" \ + "$(INTDIR)\weapons.obj" \ + "$(INTDIR)\world.obj" \ + "$(INTDIR)\WXDEBUG.OBJ" \ + "$(INTDIR)\xen.obj" \ + "$(INTDIR)\zombie.obj" + +"$(OUTDIR)\hl.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +# Begin Custom Build +TargetPath=.\Releasehl\hl.dll +TargetName=hl +InputPath=.\Releasehl\hl.dll +SOURCE=$(InputPath) + +"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetPath) u:\quiver\valve\dlls + +# End Custom Build + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "hl___Win" +# PROP BASE Intermediate_Dir "hl___Win" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "debughl" +# PROP Intermediate_Dir "debughl" +# PROP Target_Dir "" +OUTDIR=.\debughl +INTDIR=.\debughl + +ALL : "$(OUTDIR)\hl.dll" "$(OUTDIR)\hl.bsc" "..\..\valve\dlls\hl.dll" + +CLEAN : + -@erase "$(INTDIR)\aflock.obj" + -@erase "$(INTDIR)\aflock.sbr" + -@erase "$(INTDIR)\agrunt.obj" + -@erase "$(INTDIR)\agrunt.sbr" + -@erase "$(INTDIR)\airtank.obj" + -@erase "$(INTDIR)\airtank.sbr" + -@erase "$(INTDIR)\animating.obj" + -@erase "$(INTDIR)\animating.sbr" + -@erase "$(INTDIR)\animation.obj" + -@erase "$(INTDIR)\animation.sbr" + -@erase "$(INTDIR)\apache.obj" + -@erase "$(INTDIR)\apache.sbr" + -@erase "$(INTDIR)\barnacle.obj" + -@erase "$(INTDIR)\barnacle.sbr" + -@erase "$(INTDIR)\barney.obj" + -@erase "$(INTDIR)\barney.sbr" + -@erase "$(INTDIR)\bigmomma.obj" + -@erase "$(INTDIR)\bigmomma.sbr" + -@erase "$(INTDIR)\bloater.obj" + -@erase "$(INTDIR)\bloater.sbr" + -@erase "$(INTDIR)\bmodels.obj" + -@erase "$(INTDIR)\bmodels.sbr" + -@erase "$(INTDIR)\bullsquid.obj" + -@erase "$(INTDIR)\bullsquid.sbr" + -@erase "$(INTDIR)\buttons.obj" + -@erase "$(INTDIR)\buttons.sbr" + -@erase "$(INTDIR)\cbase.obj" + -@erase "$(INTDIR)\cbase.sbr" + -@erase "$(INTDIR)\client.obj" + -@erase "$(INTDIR)\client.sbr" + -@erase "$(INTDIR)\combat.obj" + -@erase "$(INTDIR)\combat.sbr" + -@erase "$(INTDIR)\controller.obj" + -@erase "$(INTDIR)\controller.sbr" + -@erase "$(INTDIR)\crossbow.obj" + -@erase "$(INTDIR)\crossbow.sbr" + -@erase "$(INTDIR)\crowbar.obj" + -@erase "$(INTDIR)\crowbar.sbr" + -@erase "$(INTDIR)\defaultai.obj" + -@erase "$(INTDIR)\defaultai.sbr" + -@erase "$(INTDIR)\doors.obj" + -@erase "$(INTDIR)\doors.sbr" + -@erase "$(INTDIR)\effects.obj" + -@erase "$(INTDIR)\effects.sbr" + -@erase "$(INTDIR)\egon.obj" + -@erase "$(INTDIR)\egon.sbr" + -@erase "$(INTDIR)\explode.obj" + -@erase "$(INTDIR)\explode.sbr" + -@erase "$(INTDIR)\flyingmonster.obj" + -@erase "$(INTDIR)\flyingmonster.sbr" + -@erase "$(INTDIR)\func_break.obj" + -@erase "$(INTDIR)\func_break.sbr" + -@erase "$(INTDIR)\func_tank.obj" + -@erase "$(INTDIR)\func_tank.sbr" + -@erase "$(INTDIR)\game.obj" + -@erase "$(INTDIR)\game.sbr" + -@erase "$(INTDIR)\gamerules.obj" + -@erase "$(INTDIR)\gamerules.sbr" + -@erase "$(INTDIR)\gargantua.obj" + -@erase "$(INTDIR)\gargantua.sbr" + -@erase "$(INTDIR)\gauss.obj" + -@erase "$(INTDIR)\gauss.sbr" + -@erase "$(INTDIR)\genericmonster.obj" + -@erase "$(INTDIR)\genericmonster.sbr" + -@erase "$(INTDIR)\ggrenade.obj" + -@erase "$(INTDIR)\ggrenade.sbr" + -@erase "$(INTDIR)\globals.obj" + -@erase "$(INTDIR)\globals.sbr" + -@erase "$(INTDIR)\glock.obj" + -@erase "$(INTDIR)\glock.sbr" + -@erase "$(INTDIR)\gman.obj" + -@erase "$(INTDIR)\gman.sbr" + -@erase "$(INTDIR)\h_ai.obj" + -@erase "$(INTDIR)\h_ai.sbr" + -@erase "$(INTDIR)\h_battery.obj" + -@erase "$(INTDIR)\h_battery.sbr" + -@erase "$(INTDIR)\h_cine.obj" + -@erase "$(INTDIR)\h_cine.sbr" + -@erase "$(INTDIR)\h_cycler.obj" + -@erase "$(INTDIR)\h_cycler.sbr" + -@erase "$(INTDIR)\h_export.obj" + -@erase "$(INTDIR)\h_export.sbr" + -@erase "$(INTDIR)\handgrenade.obj" + -@erase "$(INTDIR)\handgrenade.sbr" + -@erase "$(INTDIR)\hassassin.obj" + -@erase "$(INTDIR)\hassassin.sbr" + -@erase "$(INTDIR)\headcrab.obj" + -@erase "$(INTDIR)\headcrab.sbr" + -@erase "$(INTDIR)\healthkit.obj" + -@erase "$(INTDIR)\healthkit.sbr" + -@erase "$(INTDIR)\hgrunt.obj" + -@erase "$(INTDIR)\hgrunt.sbr" + -@erase "$(INTDIR)\hornet.obj" + -@erase "$(INTDIR)\hornet.sbr" + -@erase "$(INTDIR)\hornetgun.obj" + -@erase "$(INTDIR)\hornetgun.sbr" + -@erase "$(INTDIR)\houndeye.obj" + -@erase "$(INTDIR)\houndeye.sbr" + -@erase "$(INTDIR)\ichthyosaur.obj" + -@erase "$(INTDIR)\ichthyosaur.sbr" + -@erase "$(INTDIR)\islave.obj" + -@erase "$(INTDIR)\islave.sbr" + -@erase "$(INTDIR)\items.obj" + -@erase "$(INTDIR)\items.sbr" + -@erase "$(INTDIR)\leech.obj" + -@erase "$(INTDIR)\leech.sbr" + -@erase "$(INTDIR)\lights.obj" + -@erase "$(INTDIR)\lights.sbr" + -@erase "$(INTDIR)\maprules.obj" + -@erase "$(INTDIR)\maprules.sbr" + -@erase "$(INTDIR)\monstermaker.obj" + -@erase "$(INTDIR)\monstermaker.sbr" + -@erase "$(INTDIR)\monsters.obj" + -@erase "$(INTDIR)\monsters.sbr" + -@erase "$(INTDIR)\monsterstate.obj" + -@erase "$(INTDIR)\monsterstate.sbr" + -@erase "$(INTDIR)\mortar.obj" + -@erase "$(INTDIR)\mortar.sbr" + -@erase "$(INTDIR)\mp5.obj" + -@erase "$(INTDIR)\mp5.sbr" + -@erase "$(INTDIR)\multiplay_gamerules.obj" + -@erase "$(INTDIR)\multiplay_gamerules.sbr" + -@erase "$(INTDIR)\nihilanth.obj" + -@erase "$(INTDIR)\nihilanth.sbr" + -@erase "$(INTDIR)\nodes.obj" + -@erase "$(INTDIR)\nodes.sbr" + -@erase "$(INTDIR)\osprey.obj" + -@erase "$(INTDIR)\osprey.sbr" + -@erase "$(INTDIR)\pathcorner.obj" + -@erase "$(INTDIR)\pathcorner.sbr" + -@erase "$(INTDIR)\plane.obj" + -@erase "$(INTDIR)\plane.sbr" + -@erase "$(INTDIR)\plats.obj" + -@erase "$(INTDIR)\plats.sbr" + -@erase "$(INTDIR)\player.obj" + -@erase "$(INTDIR)\player.sbr" + -@erase "$(INTDIR)\pm_debug.obj" + -@erase "$(INTDIR)\pm_debug.sbr" + -@erase "$(INTDIR)\pm_math.obj" + -@erase "$(INTDIR)\pm_math.sbr" + -@erase "$(INTDIR)\pm_shared.obj" + -@erase "$(INTDIR)\pm_shared.sbr" + -@erase "$(INTDIR)\python.obj" + -@erase "$(INTDIR)\python.sbr" + -@erase "$(INTDIR)\rat.obj" + -@erase "$(INTDIR)\rat.sbr" + -@erase "$(INTDIR)\roach.obj" + -@erase "$(INTDIR)\roach.sbr" + -@erase "$(INTDIR)\rpg.obj" + -@erase "$(INTDIR)\rpg.sbr" + -@erase "$(INTDIR)\satchel.obj" + -@erase "$(INTDIR)\satchel.sbr" + -@erase "$(INTDIR)\schedule.obj" + -@erase "$(INTDIR)\schedule.sbr" + -@erase "$(INTDIR)\scientist.obj" + -@erase "$(INTDIR)\scientist.sbr" + -@erase "$(INTDIR)\scripted.obj" + -@erase "$(INTDIR)\scripted.sbr" + -@erase "$(INTDIR)\shotgun.obj" + -@erase "$(INTDIR)\shotgun.sbr" + -@erase "$(INTDIR)\singleplay_gamerules.obj" + -@erase "$(INTDIR)\singleplay_gamerules.sbr" + -@erase "$(INTDIR)\skill.obj" + -@erase "$(INTDIR)\skill.sbr" + -@erase "$(INTDIR)\sound.obj" + -@erase "$(INTDIR)\sound.sbr" + -@erase "$(INTDIR)\soundent.obj" + -@erase "$(INTDIR)\soundent.sbr" + -@erase "$(INTDIR)\spectator.obj" + -@erase "$(INTDIR)\spectator.sbr" + -@erase "$(INTDIR)\squadmonster.obj" + -@erase "$(INTDIR)\squadmonster.sbr" + -@erase "$(INTDIR)\squeakgrenade.obj" + -@erase "$(INTDIR)\squeakgrenade.sbr" + -@erase "$(INTDIR)\subs.obj" + -@erase "$(INTDIR)\subs.sbr" + -@erase "$(INTDIR)\talkmonster.obj" + -@erase "$(INTDIR)\talkmonster.sbr" + -@erase "$(INTDIR)\teamplay_gamerules.obj" + -@erase "$(INTDIR)\teamplay_gamerules.sbr" + -@erase "$(INTDIR)\tempmonster.obj" + -@erase "$(INTDIR)\tempmonster.sbr" + -@erase "$(INTDIR)\tentacle.obj" + -@erase "$(INTDIR)\tentacle.sbr" + -@erase "$(INTDIR)\triggers.obj" + -@erase "$(INTDIR)\triggers.sbr" + -@erase "$(INTDIR)\tripmine.obj" + -@erase "$(INTDIR)\tripmine.sbr" + -@erase "$(INTDIR)\turret.obj" + -@erase "$(INTDIR)\turret.sbr" + -@erase "$(INTDIR)\util.obj" + -@erase "$(INTDIR)\util.sbr" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(INTDIR)\weapons.obj" + -@erase "$(INTDIR)\weapons.sbr" + -@erase "$(INTDIR)\world.obj" + -@erase "$(INTDIR)\world.sbr" + -@erase "$(INTDIR)\WXDEBUG.OBJ" + -@erase "$(INTDIR)\WXDEBUG.SBR" + -@erase "$(INTDIR)\xen.obj" + -@erase "$(INTDIR)\xen.sbr" + -@erase "$(INTDIR)\zombie.obj" + -@erase "$(INTDIR)\zombie.sbr" + -@erase "$(OUTDIR)\hl.bsc" + -@erase "$(OUTDIR)\hl.dll" + -@erase "$(OUTDIR)\hl.ilk" + -@erase "$(OUTDIR)\hl.pdb" + -@erase "..\..\valve\dlls\hl.dll" + -@erase ".\Debug\hl.exp" + -@erase ".\Debug\hl.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# 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 /GX /Zi /Od /I "..\engine" /I "..\common" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /FR /YX /c +CPP_PROJ=/nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /I "..\engine" /I "..\common" /D\ + "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D\ + "VALVE_DLL" /FR"$(INTDIR)/" /Fp"$(INTDIR)/hl.pch" /YX /Fo"$(INTDIR)/"\ + /Fd"$(INTDIR)/" /c +CPP_OBJS=.\debughl/ +CPP_SBRS=.\debughl/ +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /win32 +MTL_PROJ=/nologo /D "_DEBUG" /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 +BSC32_FLAGS=/nologo /o"$(OUTDIR)/hl.bsc" +BSC32_SBRS= \ + "$(INTDIR)\aflock.sbr" \ + "$(INTDIR)\agrunt.sbr" \ + "$(INTDIR)\airtank.sbr" \ + "$(INTDIR)\animating.sbr" \ + "$(INTDIR)\animation.sbr" \ + "$(INTDIR)\apache.sbr" \ + "$(INTDIR)\barnacle.sbr" \ + "$(INTDIR)\barney.sbr" \ + "$(INTDIR)\bigmomma.sbr" \ + "$(INTDIR)\bloater.sbr" \ + "$(INTDIR)\bmodels.sbr" \ + "$(INTDIR)\bullsquid.sbr" \ + "$(INTDIR)\buttons.sbr" \ + "$(INTDIR)\cbase.sbr" \ + "$(INTDIR)\client.sbr" \ + "$(INTDIR)\combat.sbr" \ + "$(INTDIR)\controller.sbr" \ + "$(INTDIR)\crossbow.sbr" \ + "$(INTDIR)\crowbar.sbr" \ + "$(INTDIR)\defaultai.sbr" \ + "$(INTDIR)\doors.sbr" \ + "$(INTDIR)\effects.sbr" \ + "$(INTDIR)\egon.sbr" \ + "$(INTDIR)\explode.sbr" \ + "$(INTDIR)\flyingmonster.sbr" \ + "$(INTDIR)\func_break.sbr" \ + "$(INTDIR)\func_tank.sbr" \ + "$(INTDIR)\game.sbr" \ + "$(INTDIR)\gamerules.sbr" \ + "$(INTDIR)\gargantua.sbr" \ + "$(INTDIR)\gauss.sbr" \ + "$(INTDIR)\genericmonster.sbr" \ + "$(INTDIR)\ggrenade.sbr" \ + "$(INTDIR)\globals.sbr" \ + "$(INTDIR)\glock.sbr" \ + "$(INTDIR)\gman.sbr" \ + "$(INTDIR)\h_ai.sbr" \ + "$(INTDIR)\h_battery.sbr" \ + "$(INTDIR)\h_cine.sbr" \ + "$(INTDIR)\h_cycler.sbr" \ + "$(INTDIR)\h_export.sbr" \ + "$(INTDIR)\handgrenade.sbr" \ + "$(INTDIR)\hassassin.sbr" \ + "$(INTDIR)\headcrab.sbr" \ + "$(INTDIR)\healthkit.sbr" \ + "$(INTDIR)\hgrunt.sbr" \ + "$(INTDIR)\hornet.sbr" \ + "$(INTDIR)\hornetgun.sbr" \ + "$(INTDIR)\houndeye.sbr" \ + "$(INTDIR)\ichthyosaur.sbr" \ + "$(INTDIR)\islave.sbr" \ + "$(INTDIR)\items.sbr" \ + "$(INTDIR)\leech.sbr" \ + "$(INTDIR)\lights.sbr" \ + "$(INTDIR)\maprules.sbr" \ + "$(INTDIR)\monstermaker.sbr" \ + "$(INTDIR)\monsters.sbr" \ + "$(INTDIR)\monsterstate.sbr" \ + "$(INTDIR)\mortar.sbr" \ + "$(INTDIR)\mp5.sbr" \ + "$(INTDIR)\multiplay_gamerules.sbr" \ + "$(INTDIR)\nihilanth.sbr" \ + "$(INTDIR)\nodes.sbr" \ + "$(INTDIR)\osprey.sbr" \ + "$(INTDIR)\pathcorner.sbr" \ + "$(INTDIR)\plane.sbr" \ + "$(INTDIR)\plats.sbr" \ + "$(INTDIR)\player.sbr" \ + "$(INTDIR)\pm_debug.sbr" \ + "$(INTDIR)\pm_math.sbr" \ + "$(INTDIR)\pm_shared.sbr" \ + "$(INTDIR)\python.sbr" \ + "$(INTDIR)\rat.sbr" \ + "$(INTDIR)\roach.sbr" \ + "$(INTDIR)\rpg.sbr" \ + "$(INTDIR)\satchel.sbr" \ + "$(INTDIR)\schedule.sbr" \ + "$(INTDIR)\scientist.sbr" \ + "$(INTDIR)\scripted.sbr" \ + "$(INTDIR)\shotgun.sbr" \ + "$(INTDIR)\singleplay_gamerules.sbr" \ + "$(INTDIR)\skill.sbr" \ + "$(INTDIR)\sound.sbr" \ + "$(INTDIR)\soundent.sbr" \ + "$(INTDIR)\spectator.sbr" \ + "$(INTDIR)\squadmonster.sbr" \ + "$(INTDIR)\squeakgrenade.sbr" \ + "$(INTDIR)\subs.sbr" \ + "$(INTDIR)\talkmonster.sbr" \ + "$(INTDIR)\teamplay_gamerules.sbr" \ + "$(INTDIR)\tempmonster.sbr" \ + "$(INTDIR)\tentacle.sbr" \ + "$(INTDIR)\triggers.sbr" \ + "$(INTDIR)\tripmine.sbr" \ + "$(INTDIR)\turret.sbr" \ + "$(INTDIR)\util.sbr" \ + "$(INTDIR)\weapons.sbr" \ + "$(INTDIR)\world.sbr" \ + "$(INTDIR)\WXDEBUG.SBR" \ + "$(INTDIR)\xen.sbr" \ + "$(INTDIR)\zombie.sbr" + +"$(OUTDIR)\hl.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\hl.def" /implib:"Debug/hl.lib" +# SUBTRACT LINK32 /profile +LINK32_FLAGS=user32.lib advapi32.lib /nologo /subsystem:windows /dll\ + /incremental:yes /pdb:"$(OUTDIR)/hl.pdb" /debug /machine:I386 /def:".\hl.def"\ + /out:"$(OUTDIR)/hl.dll" /implib:"Debug/hl.lib" +LINK32_OBJS= \ + "$(INTDIR)\aflock.obj" \ + "$(INTDIR)\agrunt.obj" \ + "$(INTDIR)\airtank.obj" \ + "$(INTDIR)\animating.obj" \ + "$(INTDIR)\animation.obj" \ + "$(INTDIR)\apache.obj" \ + "$(INTDIR)\barnacle.obj" \ + "$(INTDIR)\barney.obj" \ + "$(INTDIR)\bigmomma.obj" \ + "$(INTDIR)\bloater.obj" \ + "$(INTDIR)\bmodels.obj" \ + "$(INTDIR)\bullsquid.obj" \ + "$(INTDIR)\buttons.obj" \ + "$(INTDIR)\cbase.obj" \ + "$(INTDIR)\client.obj" \ + "$(INTDIR)\combat.obj" \ + "$(INTDIR)\controller.obj" \ + "$(INTDIR)\crossbow.obj" \ + "$(INTDIR)\crowbar.obj" \ + "$(INTDIR)\defaultai.obj" \ + "$(INTDIR)\doors.obj" \ + "$(INTDIR)\effects.obj" \ + "$(INTDIR)\egon.obj" \ + "$(INTDIR)\explode.obj" \ + "$(INTDIR)\flyingmonster.obj" \ + "$(INTDIR)\func_break.obj" \ + "$(INTDIR)\func_tank.obj" \ + "$(INTDIR)\game.obj" \ + "$(INTDIR)\gamerules.obj" \ + "$(INTDIR)\gargantua.obj" \ + "$(INTDIR)\gauss.obj" \ + "$(INTDIR)\genericmonster.obj" \ + "$(INTDIR)\ggrenade.obj" \ + "$(INTDIR)\globals.obj" \ + "$(INTDIR)\glock.obj" \ + "$(INTDIR)\gman.obj" \ + "$(INTDIR)\h_ai.obj" \ + "$(INTDIR)\h_battery.obj" \ + "$(INTDIR)\h_cine.obj" \ + "$(INTDIR)\h_cycler.obj" \ + "$(INTDIR)\h_export.obj" \ + "$(INTDIR)\handgrenade.obj" \ + "$(INTDIR)\hassassin.obj" \ + "$(INTDIR)\headcrab.obj" \ + "$(INTDIR)\healthkit.obj" \ + "$(INTDIR)\hgrunt.obj" \ + "$(INTDIR)\hornet.obj" \ + "$(INTDIR)\hornetgun.obj" \ + "$(INTDIR)\houndeye.obj" \ + "$(INTDIR)\ichthyosaur.obj" \ + "$(INTDIR)\islave.obj" \ + "$(INTDIR)\items.obj" \ + "$(INTDIR)\leech.obj" \ + "$(INTDIR)\lights.obj" \ + "$(INTDIR)\maprules.obj" \ + "$(INTDIR)\monstermaker.obj" \ + "$(INTDIR)\monsters.obj" \ + "$(INTDIR)\monsterstate.obj" \ + "$(INTDIR)\mortar.obj" \ + "$(INTDIR)\mp5.obj" \ + "$(INTDIR)\multiplay_gamerules.obj" \ + "$(INTDIR)\nihilanth.obj" \ + "$(INTDIR)\nodes.obj" \ + "$(INTDIR)\osprey.obj" \ + "$(INTDIR)\pathcorner.obj" \ + "$(INTDIR)\plane.obj" \ + "$(INTDIR)\plats.obj" \ + "$(INTDIR)\player.obj" \ + "$(INTDIR)\pm_debug.obj" \ + "$(INTDIR)\pm_math.obj" \ + "$(INTDIR)\pm_shared.obj" \ + "$(INTDIR)\python.obj" \ + "$(INTDIR)\rat.obj" \ + "$(INTDIR)\roach.obj" \ + "$(INTDIR)\rpg.obj" \ + "$(INTDIR)\satchel.obj" \ + "$(INTDIR)\schedule.obj" \ + "$(INTDIR)\scientist.obj" \ + "$(INTDIR)\scripted.obj" \ + "$(INTDIR)\shotgun.obj" \ + "$(INTDIR)\singleplay_gamerules.obj" \ + "$(INTDIR)\skill.obj" \ + "$(INTDIR)\sound.obj" \ + "$(INTDIR)\soundent.obj" \ + "$(INTDIR)\spectator.obj" \ + "$(INTDIR)\squadmonster.obj" \ + "$(INTDIR)\squeakgrenade.obj" \ + "$(INTDIR)\subs.obj" \ + "$(INTDIR)\talkmonster.obj" \ + "$(INTDIR)\teamplay_gamerules.obj" \ + "$(INTDIR)\tempmonster.obj" \ + "$(INTDIR)\tentacle.obj" \ + "$(INTDIR)\triggers.obj" \ + "$(INTDIR)\tripmine.obj" \ + "$(INTDIR)\turret.obj" \ + "$(INTDIR)\util.obj" \ + "$(INTDIR)\weapons.obj" \ + "$(INTDIR)\world.obj" \ + "$(INTDIR)\WXDEBUG.OBJ" \ + "$(INTDIR)\xen.obj" \ + "$(INTDIR)\zombie.obj" + +"$(OUTDIR)\hl.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +# Begin Custom Build - Copying to \quiver\valve\dlls +TargetDir=.\debughl +InputPath=.\debughl\hl.dll +SOURCE=$(InputPath) + +"\quiver\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll \quiver\valve\dlls + +# End Custom Build + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +# 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 "Germany" +# PROP Intermediate_Dir "Germany" +# PROP Target_Dir "" +OUTDIR=.\Germany +INTDIR=.\Germany + +ALL : "$(OUTDIR)\hl.dll" "$(OUTDIR)\hl.bsc" "..\..\valve\Germandlls\hl.dll" + +CLEAN : + -@erase "$(INTDIR)\aflock.obj" + -@erase "$(INTDIR)\aflock.sbr" + -@erase "$(INTDIR)\agrunt.obj" + -@erase "$(INTDIR)\agrunt.sbr" + -@erase "$(INTDIR)\airtank.obj" + -@erase "$(INTDIR)\airtank.sbr" + -@erase "$(INTDIR)\animating.obj" + -@erase "$(INTDIR)\animating.sbr" + -@erase "$(INTDIR)\animation.obj" + -@erase "$(INTDIR)\animation.sbr" + -@erase "$(INTDIR)\apache.obj" + -@erase "$(INTDIR)\apache.sbr" + -@erase "$(INTDIR)\barnacle.obj" + -@erase "$(INTDIR)\barnacle.sbr" + -@erase "$(INTDIR)\barney.obj" + -@erase "$(INTDIR)\barney.sbr" + -@erase "$(INTDIR)\bigmomma.obj" + -@erase "$(INTDIR)\bigmomma.sbr" + -@erase "$(INTDIR)\bloater.obj" + -@erase "$(INTDIR)\bloater.sbr" + -@erase "$(INTDIR)\bmodels.obj" + -@erase "$(INTDIR)\bmodels.sbr" + -@erase "$(INTDIR)\bullsquid.obj" + -@erase "$(INTDIR)\bullsquid.sbr" + -@erase "$(INTDIR)\buttons.obj" + -@erase "$(INTDIR)\buttons.sbr" + -@erase "$(INTDIR)\cbase.obj" + -@erase "$(INTDIR)\cbase.sbr" + -@erase "$(INTDIR)\client.obj" + -@erase "$(INTDIR)\client.sbr" + -@erase "$(INTDIR)\combat.obj" + -@erase "$(INTDIR)\combat.sbr" + -@erase "$(INTDIR)\controller.obj" + -@erase "$(INTDIR)\controller.sbr" + -@erase "$(INTDIR)\crossbow.obj" + -@erase "$(INTDIR)\crossbow.sbr" + -@erase "$(INTDIR)\crowbar.obj" + -@erase "$(INTDIR)\crowbar.sbr" + -@erase "$(INTDIR)\defaultai.obj" + -@erase "$(INTDIR)\defaultai.sbr" + -@erase "$(INTDIR)\doors.obj" + -@erase "$(INTDIR)\doors.sbr" + -@erase "$(INTDIR)\effects.obj" + -@erase "$(INTDIR)\effects.sbr" + -@erase "$(INTDIR)\egon.obj" + -@erase "$(INTDIR)\egon.sbr" + -@erase "$(INTDIR)\explode.obj" + -@erase "$(INTDIR)\explode.sbr" + -@erase "$(INTDIR)\flyingmonster.obj" + -@erase "$(INTDIR)\flyingmonster.sbr" + -@erase "$(INTDIR)\func_break.obj" + -@erase "$(INTDIR)\func_break.sbr" + -@erase "$(INTDIR)\func_tank.obj" + -@erase "$(INTDIR)\func_tank.sbr" + -@erase "$(INTDIR)\game.obj" + -@erase "$(INTDIR)\game.sbr" + -@erase "$(INTDIR)\gamerules.obj" + -@erase "$(INTDIR)\gamerules.sbr" + -@erase "$(INTDIR)\gargantua.obj" + -@erase "$(INTDIR)\gargantua.sbr" + -@erase "$(INTDIR)\gauss.obj" + -@erase "$(INTDIR)\gauss.sbr" + -@erase "$(INTDIR)\genericmonster.obj" + -@erase "$(INTDIR)\genericmonster.sbr" + -@erase "$(INTDIR)\ggrenade.obj" + -@erase "$(INTDIR)\ggrenade.sbr" + -@erase "$(INTDIR)\globals.obj" + -@erase "$(INTDIR)\globals.sbr" + -@erase "$(INTDIR)\glock.obj" + -@erase "$(INTDIR)\glock.sbr" + -@erase "$(INTDIR)\gman.obj" + -@erase "$(INTDIR)\gman.sbr" + -@erase "$(INTDIR)\h_ai.obj" + -@erase "$(INTDIR)\h_ai.sbr" + -@erase "$(INTDIR)\h_battery.obj" + -@erase "$(INTDIR)\h_battery.sbr" + -@erase "$(INTDIR)\h_cine.obj" + -@erase "$(INTDIR)\h_cine.sbr" + -@erase "$(INTDIR)\h_cycler.obj" + -@erase "$(INTDIR)\h_cycler.sbr" + -@erase "$(INTDIR)\h_export.obj" + -@erase "$(INTDIR)\h_export.sbr" + -@erase "$(INTDIR)\handgrenade.obj" + -@erase "$(INTDIR)\handgrenade.sbr" + -@erase "$(INTDIR)\hassassin.obj" + -@erase "$(INTDIR)\hassassin.sbr" + -@erase "$(INTDIR)\headcrab.obj" + -@erase "$(INTDIR)\headcrab.sbr" + -@erase "$(INTDIR)\healthkit.obj" + -@erase "$(INTDIR)\healthkit.sbr" + -@erase "$(INTDIR)\hgrunt.obj" + -@erase "$(INTDIR)\hgrunt.sbr" + -@erase "$(INTDIR)\hornet.obj" + -@erase "$(INTDIR)\hornet.sbr" + -@erase "$(INTDIR)\hornetgun.obj" + -@erase "$(INTDIR)\hornetgun.sbr" + -@erase "$(INTDIR)\houndeye.obj" + -@erase "$(INTDIR)\houndeye.sbr" + -@erase "$(INTDIR)\ichthyosaur.obj" + -@erase "$(INTDIR)\ichthyosaur.sbr" + -@erase "$(INTDIR)\islave.obj" + -@erase "$(INTDIR)\islave.sbr" + -@erase "$(INTDIR)\items.obj" + -@erase "$(INTDIR)\items.sbr" + -@erase "$(INTDIR)\leech.obj" + -@erase "$(INTDIR)\leech.sbr" + -@erase "$(INTDIR)\lights.obj" + -@erase "$(INTDIR)\lights.sbr" + -@erase "$(INTDIR)\maprules.obj" + -@erase "$(INTDIR)\maprules.sbr" + -@erase "$(INTDIR)\monstermaker.obj" + -@erase "$(INTDIR)\monstermaker.sbr" + -@erase "$(INTDIR)\monsters.obj" + -@erase "$(INTDIR)\monsters.sbr" + -@erase "$(INTDIR)\monsterstate.obj" + -@erase "$(INTDIR)\monsterstate.sbr" + -@erase "$(INTDIR)\mortar.obj" + -@erase "$(INTDIR)\mortar.sbr" + -@erase "$(INTDIR)\mp5.obj" + -@erase "$(INTDIR)\mp5.sbr" + -@erase "$(INTDIR)\multiplay_gamerules.obj" + -@erase "$(INTDIR)\multiplay_gamerules.sbr" + -@erase "$(INTDIR)\nihilanth.obj" + -@erase "$(INTDIR)\nihilanth.sbr" + -@erase "$(INTDIR)\nodes.obj" + -@erase "$(INTDIR)\nodes.sbr" + -@erase "$(INTDIR)\osprey.obj" + -@erase "$(INTDIR)\osprey.sbr" + -@erase "$(INTDIR)\pathcorner.obj" + -@erase "$(INTDIR)\pathcorner.sbr" + -@erase "$(INTDIR)\plane.obj" + -@erase "$(INTDIR)\plane.sbr" + -@erase "$(INTDIR)\plats.obj" + -@erase "$(INTDIR)\plats.sbr" + -@erase "$(INTDIR)\player.obj" + -@erase "$(INTDIR)\player.sbr" + -@erase "$(INTDIR)\pm_debug.obj" + -@erase "$(INTDIR)\pm_debug.sbr" + -@erase "$(INTDIR)\pm_math.obj" + -@erase "$(INTDIR)\pm_math.sbr" + -@erase "$(INTDIR)\pm_shared.obj" + -@erase "$(INTDIR)\pm_shared.sbr" + -@erase "$(INTDIR)\python.obj" + -@erase "$(INTDIR)\python.sbr" + -@erase "$(INTDIR)\rat.obj" + -@erase "$(INTDIR)\rat.sbr" + -@erase "$(INTDIR)\roach.obj" + -@erase "$(INTDIR)\roach.sbr" + -@erase "$(INTDIR)\rpg.obj" + -@erase "$(INTDIR)\rpg.sbr" + -@erase "$(INTDIR)\satchel.obj" + -@erase "$(INTDIR)\satchel.sbr" + -@erase "$(INTDIR)\schedule.obj" + -@erase "$(INTDIR)\schedule.sbr" + -@erase "$(INTDIR)\scientist.obj" + -@erase "$(INTDIR)\scientist.sbr" + -@erase "$(INTDIR)\scripted.obj" + -@erase "$(INTDIR)\scripted.sbr" + -@erase "$(INTDIR)\shotgun.obj" + -@erase "$(INTDIR)\shotgun.sbr" + -@erase "$(INTDIR)\singleplay_gamerules.obj" + -@erase "$(INTDIR)\singleplay_gamerules.sbr" + -@erase "$(INTDIR)\skill.obj" + -@erase "$(INTDIR)\skill.sbr" + -@erase "$(INTDIR)\sound.obj" + -@erase "$(INTDIR)\sound.sbr" + -@erase "$(INTDIR)\soundent.obj" + -@erase "$(INTDIR)\soundent.sbr" + -@erase "$(INTDIR)\spectator.obj" + -@erase "$(INTDIR)\spectator.sbr" + -@erase "$(INTDIR)\squadmonster.obj" + -@erase "$(INTDIR)\squadmonster.sbr" + -@erase "$(INTDIR)\squeakgrenade.obj" + -@erase "$(INTDIR)\squeakgrenade.sbr" + -@erase "$(INTDIR)\subs.obj" + -@erase "$(INTDIR)\subs.sbr" + -@erase "$(INTDIR)\talkmonster.obj" + -@erase "$(INTDIR)\talkmonster.sbr" + -@erase "$(INTDIR)\teamplay_gamerules.obj" + -@erase "$(INTDIR)\teamplay_gamerules.sbr" + -@erase "$(INTDIR)\tempmonster.obj" + -@erase "$(INTDIR)\tempmonster.sbr" + -@erase "$(INTDIR)\tentacle.obj" + -@erase "$(INTDIR)\tentacle.sbr" + -@erase "$(INTDIR)\triggers.obj" + -@erase "$(INTDIR)\triggers.sbr" + -@erase "$(INTDIR)\tripmine.obj" + -@erase "$(INTDIR)\tripmine.sbr" + -@erase "$(INTDIR)\turret.obj" + -@erase "$(INTDIR)\turret.sbr" + -@erase "$(INTDIR)\util.obj" + -@erase "$(INTDIR)\util.sbr" + -@erase "$(INTDIR)\weapons.obj" + -@erase "$(INTDIR)\weapons.sbr" + -@erase "$(INTDIR)\world.obj" + -@erase "$(INTDIR)\world.sbr" + -@erase "$(INTDIR)\WXDEBUG.OBJ" + -@erase "$(INTDIR)\WXDEBUG.SBR" + -@erase "$(INTDIR)\xen.obj" + -@erase "$(INTDIR)\xen.sbr" + -@erase "$(INTDIR)\zombie.obj" + -@erase "$(INTDIR)\zombie.sbr" + -@erase "$(OUTDIR)\hl.bsc" + -@erase "$(OUTDIR)\hl.dll" + -@erase "$(OUTDIR)\hl.exp" + -@erase "$(OUTDIR)\hl.lib" + -@erase "..\..\valve\Germandlls\hl.dll" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /FR /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\engine" /I "..\common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "GERMANY" /FR /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "..\engine" /I "..\common" /D "NDEBUG" /D\ + "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D\ + "GERMANY" /FR"$(INTDIR)/" /Fp"$(INTDIR)/hl.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Germany/ +CPP_SBRS=.\Germany/ +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/hl.bsc" +BSC32_SBRS= \ + "$(INTDIR)\aflock.sbr" \ + "$(INTDIR)\agrunt.sbr" \ + "$(INTDIR)\airtank.sbr" \ + "$(INTDIR)\animating.sbr" \ + "$(INTDIR)\animation.sbr" \ + "$(INTDIR)\apache.sbr" \ + "$(INTDIR)\barnacle.sbr" \ + "$(INTDIR)\barney.sbr" \ + "$(INTDIR)\bigmomma.sbr" \ + "$(INTDIR)\bloater.sbr" \ + "$(INTDIR)\bmodels.sbr" \ + "$(INTDIR)\bullsquid.sbr" \ + "$(INTDIR)\buttons.sbr" \ + "$(INTDIR)\cbase.sbr" \ + "$(INTDIR)\client.sbr" \ + "$(INTDIR)\combat.sbr" \ + "$(INTDIR)\controller.sbr" \ + "$(INTDIR)\crossbow.sbr" \ + "$(INTDIR)\crowbar.sbr" \ + "$(INTDIR)\defaultai.sbr" \ + "$(INTDIR)\doors.sbr" \ + "$(INTDIR)\effects.sbr" \ + "$(INTDIR)\egon.sbr" \ + "$(INTDIR)\explode.sbr" \ + "$(INTDIR)\flyingmonster.sbr" \ + "$(INTDIR)\func_break.sbr" \ + "$(INTDIR)\func_tank.sbr" \ + "$(INTDIR)\game.sbr" \ + "$(INTDIR)\gamerules.sbr" \ + "$(INTDIR)\gargantua.sbr" \ + "$(INTDIR)\gauss.sbr" \ + "$(INTDIR)\genericmonster.sbr" \ + "$(INTDIR)\ggrenade.sbr" \ + "$(INTDIR)\globals.sbr" \ + "$(INTDIR)\glock.sbr" \ + "$(INTDIR)\gman.sbr" \ + "$(INTDIR)\h_ai.sbr" \ + "$(INTDIR)\h_battery.sbr" \ + "$(INTDIR)\h_cine.sbr" \ + "$(INTDIR)\h_cycler.sbr" \ + "$(INTDIR)\h_export.sbr" \ + "$(INTDIR)\handgrenade.sbr" \ + "$(INTDIR)\hassassin.sbr" \ + "$(INTDIR)\headcrab.sbr" \ + "$(INTDIR)\healthkit.sbr" \ + "$(INTDIR)\hgrunt.sbr" \ + "$(INTDIR)\hornet.sbr" \ + "$(INTDIR)\hornetgun.sbr" \ + "$(INTDIR)\houndeye.sbr" \ + "$(INTDIR)\ichthyosaur.sbr" \ + "$(INTDIR)\islave.sbr" \ + "$(INTDIR)\items.sbr" \ + "$(INTDIR)\leech.sbr" \ + "$(INTDIR)\lights.sbr" \ + "$(INTDIR)\maprules.sbr" \ + "$(INTDIR)\monstermaker.sbr" \ + "$(INTDIR)\monsters.sbr" \ + "$(INTDIR)\monsterstate.sbr" \ + "$(INTDIR)\mortar.sbr" \ + "$(INTDIR)\mp5.sbr" \ + "$(INTDIR)\multiplay_gamerules.sbr" \ + "$(INTDIR)\nihilanth.sbr" \ + "$(INTDIR)\nodes.sbr" \ + "$(INTDIR)\osprey.sbr" \ + "$(INTDIR)\pathcorner.sbr" \ + "$(INTDIR)\plane.sbr" \ + "$(INTDIR)\plats.sbr" \ + "$(INTDIR)\player.sbr" \ + "$(INTDIR)\pm_debug.sbr" \ + "$(INTDIR)\pm_math.sbr" \ + "$(INTDIR)\pm_shared.sbr" \ + "$(INTDIR)\python.sbr" \ + "$(INTDIR)\rat.sbr" \ + "$(INTDIR)\roach.sbr" \ + "$(INTDIR)\rpg.sbr" \ + "$(INTDIR)\satchel.sbr" \ + "$(INTDIR)\schedule.sbr" \ + "$(INTDIR)\scientist.sbr" \ + "$(INTDIR)\scripted.sbr" \ + "$(INTDIR)\shotgun.sbr" \ + "$(INTDIR)\singleplay_gamerules.sbr" \ + "$(INTDIR)\skill.sbr" \ + "$(INTDIR)\sound.sbr" \ + "$(INTDIR)\soundent.sbr" \ + "$(INTDIR)\spectator.sbr" \ + "$(INTDIR)\squadmonster.sbr" \ + "$(INTDIR)\squeakgrenade.sbr" \ + "$(INTDIR)\subs.sbr" \ + "$(INTDIR)\talkmonster.sbr" \ + "$(INTDIR)\teamplay_gamerules.sbr" \ + "$(INTDIR)\tempmonster.sbr" \ + "$(INTDIR)\tentacle.sbr" \ + "$(INTDIR)\triggers.sbr" \ + "$(INTDIR)\tripmine.sbr" \ + "$(INTDIR)\turret.sbr" \ + "$(INTDIR)\util.sbr" \ + "$(INTDIR)\weapons.sbr" \ + "$(INTDIR)\world.sbr" \ + "$(INTDIR)\WXDEBUG.SBR" \ + "$(INTDIR)\xen.sbr" \ + "$(INTDIR)\zombie.sbr" + +"$(OUTDIR)\hl.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +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 /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 odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /def:".\hl.def" +# SUBTRACT LINK32 /profile +LINK32_FLAGS=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 /incremental:no\ + /pdb:"$(OUTDIR)/hl.pdb" /machine:I386 /def:".\hl.def" /out:"$(OUTDIR)/hl.dll"\ + /implib:"$(OUTDIR)/hl.lib" +LINK32_OBJS= \ + "$(INTDIR)\aflock.obj" \ + "$(INTDIR)\agrunt.obj" \ + "$(INTDIR)\airtank.obj" \ + "$(INTDIR)\animating.obj" \ + "$(INTDIR)\animation.obj" \ + "$(INTDIR)\apache.obj" \ + "$(INTDIR)\barnacle.obj" \ + "$(INTDIR)\barney.obj" \ + "$(INTDIR)\bigmomma.obj" \ + "$(INTDIR)\bloater.obj" \ + "$(INTDIR)\bmodels.obj" \ + "$(INTDIR)\bullsquid.obj" \ + "$(INTDIR)\buttons.obj" \ + "$(INTDIR)\cbase.obj" \ + "$(INTDIR)\client.obj" \ + "$(INTDIR)\combat.obj" \ + "$(INTDIR)\controller.obj" \ + "$(INTDIR)\crossbow.obj" \ + "$(INTDIR)\crowbar.obj" \ + "$(INTDIR)\defaultai.obj" \ + "$(INTDIR)\doors.obj" \ + "$(INTDIR)\effects.obj" \ + "$(INTDIR)\egon.obj" \ + "$(INTDIR)\explode.obj" \ + "$(INTDIR)\flyingmonster.obj" \ + "$(INTDIR)\func_break.obj" \ + "$(INTDIR)\func_tank.obj" \ + "$(INTDIR)\game.obj" \ + "$(INTDIR)\gamerules.obj" \ + "$(INTDIR)\gargantua.obj" \ + "$(INTDIR)\gauss.obj" \ + "$(INTDIR)\genericmonster.obj" \ + "$(INTDIR)\ggrenade.obj" \ + "$(INTDIR)\globals.obj" \ + "$(INTDIR)\glock.obj" \ + "$(INTDIR)\gman.obj" \ + "$(INTDIR)\h_ai.obj" \ + "$(INTDIR)\h_battery.obj" \ + "$(INTDIR)\h_cine.obj" \ + "$(INTDIR)\h_cycler.obj" \ + "$(INTDIR)\h_export.obj" \ + "$(INTDIR)\handgrenade.obj" \ + "$(INTDIR)\hassassin.obj" \ + "$(INTDIR)\headcrab.obj" \ + "$(INTDIR)\healthkit.obj" \ + "$(INTDIR)\hgrunt.obj" \ + "$(INTDIR)\hornet.obj" \ + "$(INTDIR)\hornetgun.obj" \ + "$(INTDIR)\houndeye.obj" \ + "$(INTDIR)\ichthyosaur.obj" \ + "$(INTDIR)\islave.obj" \ + "$(INTDIR)\items.obj" \ + "$(INTDIR)\leech.obj" \ + "$(INTDIR)\lights.obj" \ + "$(INTDIR)\maprules.obj" \ + "$(INTDIR)\monstermaker.obj" \ + "$(INTDIR)\monsters.obj" \ + "$(INTDIR)\monsterstate.obj" \ + "$(INTDIR)\mortar.obj" \ + "$(INTDIR)\mp5.obj" \ + "$(INTDIR)\multiplay_gamerules.obj" \ + "$(INTDIR)\nihilanth.obj" \ + "$(INTDIR)\nodes.obj" \ + "$(INTDIR)\osprey.obj" \ + "$(INTDIR)\pathcorner.obj" \ + "$(INTDIR)\plane.obj" \ + "$(INTDIR)\plats.obj" \ + "$(INTDIR)\player.obj" \ + "$(INTDIR)\pm_debug.obj" \ + "$(INTDIR)\pm_math.obj" \ + "$(INTDIR)\pm_shared.obj" \ + "$(INTDIR)\python.obj" \ + "$(INTDIR)\rat.obj" \ + "$(INTDIR)\roach.obj" \ + "$(INTDIR)\rpg.obj" \ + "$(INTDIR)\satchel.obj" \ + "$(INTDIR)\schedule.obj" \ + "$(INTDIR)\scientist.obj" \ + "$(INTDIR)\scripted.obj" \ + "$(INTDIR)\shotgun.obj" \ + "$(INTDIR)\singleplay_gamerules.obj" \ + "$(INTDIR)\skill.obj" \ + "$(INTDIR)\sound.obj" \ + "$(INTDIR)\soundent.obj" \ + "$(INTDIR)\spectator.obj" \ + "$(INTDIR)\squadmonster.obj" \ + "$(INTDIR)\squeakgrenade.obj" \ + "$(INTDIR)\subs.obj" \ + "$(INTDIR)\talkmonster.obj" \ + "$(INTDIR)\teamplay_gamerules.obj" \ + "$(INTDIR)\tempmonster.obj" \ + "$(INTDIR)\tentacle.obj" \ + "$(INTDIR)\triggers.obj" \ + "$(INTDIR)\tripmine.obj" \ + "$(INTDIR)\turret.obj" \ + "$(INTDIR)\util.obj" \ + "$(INTDIR)\weapons.obj" \ + "$(INTDIR)\world.obj" \ + "$(INTDIR)\WXDEBUG.OBJ" \ + "$(INTDIR)\xen.obj" \ + "$(INTDIR)\zombie.obj" + +"$(OUTDIR)\hl.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +# Begin Custom Build - Copying to \quiver\valve\dlls +TargetDir=.\Germany +InputPath=.\Germany\hl.dll +SOURCE=$(InputPath) + +"\quiver\valve\Germandlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll \quiver\valve\Germandlls + +# 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 "Profilehl" +# PROP Intermediate_Dir "Profilehl" +# PROP Target_Dir "" +OUTDIR=.\Profilehl +INTDIR=.\Profilehl + +ALL : "$(OUTDIR)\hl.dll" "..\..\valve\dlls\hl.dll" "..\..\valve\dlls\hl.map" + +CLEAN : + -@erase "$(INTDIR)\aflock.obj" + -@erase "$(INTDIR)\agrunt.obj" + -@erase "$(INTDIR)\airtank.obj" + -@erase "$(INTDIR)\animating.obj" + -@erase "$(INTDIR)\animation.obj" + -@erase "$(INTDIR)\apache.obj" + -@erase "$(INTDIR)\barnacle.obj" + -@erase "$(INTDIR)\barney.obj" + -@erase "$(INTDIR)\bigmomma.obj" + -@erase "$(INTDIR)\bloater.obj" + -@erase "$(INTDIR)\bmodels.obj" + -@erase "$(INTDIR)\bullsquid.obj" + -@erase "$(INTDIR)\buttons.obj" + -@erase "$(INTDIR)\cbase.obj" + -@erase "$(INTDIR)\client.obj" + -@erase "$(INTDIR)\combat.obj" + -@erase "$(INTDIR)\controller.obj" + -@erase "$(INTDIR)\crossbow.obj" + -@erase "$(INTDIR)\crowbar.obj" + -@erase "$(INTDIR)\defaultai.obj" + -@erase "$(INTDIR)\doors.obj" + -@erase "$(INTDIR)\effects.obj" + -@erase "$(INTDIR)\egon.obj" + -@erase "$(INTDIR)\explode.obj" + -@erase "$(INTDIR)\flyingmonster.obj" + -@erase "$(INTDIR)\func_break.obj" + -@erase "$(INTDIR)\func_tank.obj" + -@erase "$(INTDIR)\game.obj" + -@erase "$(INTDIR)\gamerules.obj" + -@erase "$(INTDIR)\gargantua.obj" + -@erase "$(INTDIR)\gauss.obj" + -@erase "$(INTDIR)\genericmonster.obj" + -@erase "$(INTDIR)\ggrenade.obj" + -@erase "$(INTDIR)\globals.obj" + -@erase "$(INTDIR)\glock.obj" + -@erase "$(INTDIR)\gman.obj" + -@erase "$(INTDIR)\h_ai.obj" + -@erase "$(INTDIR)\h_battery.obj" + -@erase "$(INTDIR)\h_cine.obj" + -@erase "$(INTDIR)\h_cycler.obj" + -@erase "$(INTDIR)\h_export.obj" + -@erase "$(INTDIR)\handgrenade.obj" + -@erase "$(INTDIR)\hassassin.obj" + -@erase "$(INTDIR)\headcrab.obj" + -@erase "$(INTDIR)\healthkit.obj" + -@erase "$(INTDIR)\hgrunt.obj" + -@erase "$(INTDIR)\hornet.obj" + -@erase "$(INTDIR)\hornetgun.obj" + -@erase "$(INTDIR)\houndeye.obj" + -@erase "$(INTDIR)\ichthyosaur.obj" + -@erase "$(INTDIR)\islave.obj" + -@erase "$(INTDIR)\items.obj" + -@erase "$(INTDIR)\leech.obj" + -@erase "$(INTDIR)\lights.obj" + -@erase "$(INTDIR)\maprules.obj" + -@erase "$(INTDIR)\monstermaker.obj" + -@erase "$(INTDIR)\monsters.obj" + -@erase "$(INTDIR)\monsterstate.obj" + -@erase "$(INTDIR)\mortar.obj" + -@erase "$(INTDIR)\mp5.obj" + -@erase "$(INTDIR)\multiplay_gamerules.obj" + -@erase "$(INTDIR)\nihilanth.obj" + -@erase "$(INTDIR)\nodes.obj" + -@erase "$(INTDIR)\osprey.obj" + -@erase "$(INTDIR)\pathcorner.obj" + -@erase "$(INTDIR)\plane.obj" + -@erase "$(INTDIR)\plats.obj" + -@erase "$(INTDIR)\player.obj" + -@erase "$(INTDIR)\pm_debug.obj" + -@erase "$(INTDIR)\pm_math.obj" + -@erase "$(INTDIR)\pm_shared.obj" + -@erase "$(INTDIR)\python.obj" + -@erase "$(INTDIR)\rat.obj" + -@erase "$(INTDIR)\roach.obj" + -@erase "$(INTDIR)\rpg.obj" + -@erase "$(INTDIR)\satchel.obj" + -@erase "$(INTDIR)\schedule.obj" + -@erase "$(INTDIR)\scientist.obj" + -@erase "$(INTDIR)\scripted.obj" + -@erase "$(INTDIR)\shotgun.obj" + -@erase "$(INTDIR)\singleplay_gamerules.obj" + -@erase "$(INTDIR)\skill.obj" + -@erase "$(INTDIR)\sound.obj" + -@erase "$(INTDIR)\soundent.obj" + -@erase "$(INTDIR)\spectator.obj" + -@erase "$(INTDIR)\squadmonster.obj" + -@erase "$(INTDIR)\squeakgrenade.obj" + -@erase "$(INTDIR)\subs.obj" + -@erase "$(INTDIR)\talkmonster.obj" + -@erase "$(INTDIR)\teamplay_gamerules.obj" + -@erase "$(INTDIR)\tempmonster.obj" + -@erase "$(INTDIR)\tentacle.obj" + -@erase "$(INTDIR)\triggers.obj" + -@erase "$(INTDIR)\tripmine.obj" + -@erase "$(INTDIR)\turret.obj" + -@erase "$(INTDIR)\util.obj" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(INTDIR)\weapons.obj" + -@erase "$(INTDIR)\world.obj" + -@erase "$(INTDIR)\WXDEBUG.OBJ" + -@erase "$(INTDIR)\xen.obj" + -@erase "$(INTDIR)\zombie.obj" + -@erase "$(OUTDIR)\hl.dll" + -@erase "$(OUTDIR)\hl.exp" + -@erase "$(OUTDIR)\hl.lib" + -@erase "..\..\valve\dlls\hl.dll" + -@erase "..\..\valve\dlls\hl.map" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# 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 /GX /Zi /O2 /I "..\engine" /I "..\common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /YX /c +# SUBTRACT CPP /Fr +CPP_PROJ=/nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /I "..\common" /D\ + "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D\ + "VALVE_DLL" /Fp"$(INTDIR)/hl.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Profilehl/ +CPP_SBRS=.\. +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/hl.bsc" +BSC32_SBRS= \ + +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" +LINK32_FLAGS=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"\ + /out:"$(OUTDIR)/hl.dll" /implib:"$(OUTDIR)/hl.lib" +LINK32_OBJS= \ + "$(INTDIR)\aflock.obj" \ + "$(INTDIR)\agrunt.obj" \ + "$(INTDIR)\airtank.obj" \ + "$(INTDIR)\animating.obj" \ + "$(INTDIR)\animation.obj" \ + "$(INTDIR)\apache.obj" \ + "$(INTDIR)\barnacle.obj" \ + "$(INTDIR)\barney.obj" \ + "$(INTDIR)\bigmomma.obj" \ + "$(INTDIR)\bloater.obj" \ + "$(INTDIR)\bmodels.obj" \ + "$(INTDIR)\bullsquid.obj" \ + "$(INTDIR)\buttons.obj" \ + "$(INTDIR)\cbase.obj" \ + "$(INTDIR)\client.obj" \ + "$(INTDIR)\combat.obj" \ + "$(INTDIR)\controller.obj" \ + "$(INTDIR)\crossbow.obj" \ + "$(INTDIR)\crowbar.obj" \ + "$(INTDIR)\defaultai.obj" \ + "$(INTDIR)\doors.obj" \ + "$(INTDIR)\effects.obj" \ + "$(INTDIR)\egon.obj" \ + "$(INTDIR)\explode.obj" \ + "$(INTDIR)\flyingmonster.obj" \ + "$(INTDIR)\func_break.obj" \ + "$(INTDIR)\func_tank.obj" \ + "$(INTDIR)\game.obj" \ + "$(INTDIR)\gamerules.obj" \ + "$(INTDIR)\gargantua.obj" \ + "$(INTDIR)\gauss.obj" \ + "$(INTDIR)\genericmonster.obj" \ + "$(INTDIR)\ggrenade.obj" \ + "$(INTDIR)\globals.obj" \ + "$(INTDIR)\glock.obj" \ + "$(INTDIR)\gman.obj" \ + "$(INTDIR)\h_ai.obj" \ + "$(INTDIR)\h_battery.obj" \ + "$(INTDIR)\h_cine.obj" \ + "$(INTDIR)\h_cycler.obj" \ + "$(INTDIR)\h_export.obj" \ + "$(INTDIR)\handgrenade.obj" \ + "$(INTDIR)\hassassin.obj" \ + "$(INTDIR)\headcrab.obj" \ + "$(INTDIR)\healthkit.obj" \ + "$(INTDIR)\hgrunt.obj" \ + "$(INTDIR)\hornet.obj" \ + "$(INTDIR)\hornetgun.obj" \ + "$(INTDIR)\houndeye.obj" \ + "$(INTDIR)\ichthyosaur.obj" \ + "$(INTDIR)\islave.obj" \ + "$(INTDIR)\items.obj" \ + "$(INTDIR)\leech.obj" \ + "$(INTDIR)\lights.obj" \ + "$(INTDIR)\maprules.obj" \ + "$(INTDIR)\monstermaker.obj" \ + "$(INTDIR)\monsters.obj" \ + "$(INTDIR)\monsterstate.obj" \ + "$(INTDIR)\mortar.obj" \ + "$(INTDIR)\mp5.obj" \ + "$(INTDIR)\multiplay_gamerules.obj" \ + "$(INTDIR)\nihilanth.obj" \ + "$(INTDIR)\nodes.obj" \ + "$(INTDIR)\osprey.obj" \ + "$(INTDIR)\pathcorner.obj" \ + "$(INTDIR)\plane.obj" \ + "$(INTDIR)\plats.obj" \ + "$(INTDIR)\player.obj" \ + "$(INTDIR)\pm_debug.obj" \ + "$(INTDIR)\pm_math.obj" \ + "$(INTDIR)\pm_shared.obj" \ + "$(INTDIR)\python.obj" \ + "$(INTDIR)\rat.obj" \ + "$(INTDIR)\roach.obj" \ + "$(INTDIR)\rpg.obj" \ + "$(INTDIR)\satchel.obj" \ + "$(INTDIR)\schedule.obj" \ + "$(INTDIR)\scientist.obj" \ + "$(INTDIR)\scripted.obj" \ + "$(INTDIR)\shotgun.obj" \ + "$(INTDIR)\singleplay_gamerules.obj" \ + "$(INTDIR)\skill.obj" \ + "$(INTDIR)\sound.obj" \ + "$(INTDIR)\soundent.obj" \ + "$(INTDIR)\spectator.obj" \ + "$(INTDIR)\squadmonster.obj" \ + "$(INTDIR)\squeakgrenade.obj" \ + "$(INTDIR)\subs.obj" \ + "$(INTDIR)\talkmonster.obj" \ + "$(INTDIR)\teamplay_gamerules.obj" \ + "$(INTDIR)\tempmonster.obj" \ + "$(INTDIR)\tentacle.obj" \ + "$(INTDIR)\triggers.obj" \ + "$(INTDIR)\tripmine.obj" \ + "$(INTDIR)\turret.obj" \ + "$(INTDIR)\util.obj" \ + "$(INTDIR)\weapons.obj" \ + "$(INTDIR)\world.obj" \ + "$(INTDIR)\WXDEBUG.OBJ" \ + "$(INTDIR)\xen.obj" \ + "$(INTDIR)\zombie.obj" + +"$(OUTDIR)\hl.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +# Begin Custom Build - Copying to \quiver\valve\dlls +TargetDir=.\Profilehl +InputPath=.\Profilehl\hl.dll +SOURCE=$(InputPath) + +BuildCmds= \ + copy $(TargetDir)\hl.dll \quiver\valve\dlls \ + copy $(TargetDir)\hl.map \quiver\valve\dlls \ + + +"\quiver\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"\quiver\valve\dlls\hl.map" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +# 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 "HLDEMO" +# PROP Intermediate_Dir "HLDEMO" +# PROP Target_Dir "" +OUTDIR=.\HLDEMO +INTDIR=.\HLDEMO +# Begin Custom Macros +TargetName=hl +# End Custom Macros + +ALL : "$(OUTDIR)\hl.dll" ".\hl" + +CLEAN : + -@erase "$(INTDIR)\aflock.obj" + -@erase "$(INTDIR)\agrunt.obj" + -@erase "$(INTDIR)\airtank.obj" + -@erase "$(INTDIR)\animating.obj" + -@erase "$(INTDIR)\animation.obj" + -@erase "$(INTDIR)\apache.obj" + -@erase "$(INTDIR)\barnacle.obj" + -@erase "$(INTDIR)\barney.obj" + -@erase "$(INTDIR)\bigmomma.obj" + -@erase "$(INTDIR)\bloater.obj" + -@erase "$(INTDIR)\bmodels.obj" + -@erase "$(INTDIR)\bullsquid.obj" + -@erase "$(INTDIR)\buttons.obj" + -@erase "$(INTDIR)\cbase.obj" + -@erase "$(INTDIR)\client.obj" + -@erase "$(INTDIR)\combat.obj" + -@erase "$(INTDIR)\controller.obj" + -@erase "$(INTDIR)\crossbow.obj" + -@erase "$(INTDIR)\crowbar.obj" + -@erase "$(INTDIR)\defaultai.obj" + -@erase "$(INTDIR)\doors.obj" + -@erase "$(INTDIR)\effects.obj" + -@erase "$(INTDIR)\egon.obj" + -@erase "$(INTDIR)\explode.obj" + -@erase "$(INTDIR)\flyingmonster.obj" + -@erase "$(INTDIR)\func_break.obj" + -@erase "$(INTDIR)\func_tank.obj" + -@erase "$(INTDIR)\game.obj" + -@erase "$(INTDIR)\gamerules.obj" + -@erase "$(INTDIR)\gargantua.obj" + -@erase "$(INTDIR)\gauss.obj" + -@erase "$(INTDIR)\genericmonster.obj" + -@erase "$(INTDIR)\ggrenade.obj" + -@erase "$(INTDIR)\globals.obj" + -@erase "$(INTDIR)\glock.obj" + -@erase "$(INTDIR)\gman.obj" + -@erase "$(INTDIR)\h_ai.obj" + -@erase "$(INTDIR)\h_battery.obj" + -@erase "$(INTDIR)\h_cine.obj" + -@erase "$(INTDIR)\h_cycler.obj" + -@erase "$(INTDIR)\h_export.obj" + -@erase "$(INTDIR)\handgrenade.obj" + -@erase "$(INTDIR)\hassassin.obj" + -@erase "$(INTDIR)\headcrab.obj" + -@erase "$(INTDIR)\healthkit.obj" + -@erase "$(INTDIR)\hgrunt.obj" + -@erase "$(INTDIR)\hornet.obj" + -@erase "$(INTDIR)\hornetgun.obj" + -@erase "$(INTDIR)\houndeye.obj" + -@erase "$(INTDIR)\ichthyosaur.obj" + -@erase "$(INTDIR)\islave.obj" + -@erase "$(INTDIR)\items.obj" + -@erase "$(INTDIR)\leech.obj" + -@erase "$(INTDIR)\lights.obj" + -@erase "$(INTDIR)\maprules.obj" + -@erase "$(INTDIR)\monstermaker.obj" + -@erase "$(INTDIR)\monsters.obj" + -@erase "$(INTDIR)\monsterstate.obj" + -@erase "$(INTDIR)\mortar.obj" + -@erase "$(INTDIR)\mp5.obj" + -@erase "$(INTDIR)\multiplay_gamerules.obj" + -@erase "$(INTDIR)\nihilanth.obj" + -@erase "$(INTDIR)\nodes.obj" + -@erase "$(INTDIR)\osprey.obj" + -@erase "$(INTDIR)\pathcorner.obj" + -@erase "$(INTDIR)\plane.obj" + -@erase "$(INTDIR)\plats.obj" + -@erase "$(INTDIR)\player.obj" + -@erase "$(INTDIR)\pm_debug.obj" + -@erase "$(INTDIR)\pm_math.obj" + -@erase "$(INTDIR)\pm_shared.obj" + -@erase "$(INTDIR)\python.obj" + -@erase "$(INTDIR)\rat.obj" + -@erase "$(INTDIR)\roach.obj" + -@erase "$(INTDIR)\rpg.obj" + -@erase "$(INTDIR)\satchel.obj" + -@erase "$(INTDIR)\schedule.obj" + -@erase "$(INTDIR)\scientist.obj" + -@erase "$(INTDIR)\scripted.obj" + -@erase "$(INTDIR)\shotgun.obj" + -@erase "$(INTDIR)\singleplay_gamerules.obj" + -@erase "$(INTDIR)\skill.obj" + -@erase "$(INTDIR)\sound.obj" + -@erase "$(INTDIR)\soundent.obj" + -@erase "$(INTDIR)\spectator.obj" + -@erase "$(INTDIR)\squadmonster.obj" + -@erase "$(INTDIR)\squeakgrenade.obj" + -@erase "$(INTDIR)\subs.obj" + -@erase "$(INTDIR)\talkmonster.obj" + -@erase "$(INTDIR)\teamplay_gamerules.obj" + -@erase "$(INTDIR)\tempmonster.obj" + -@erase "$(INTDIR)\tentacle.obj" + -@erase "$(INTDIR)\triggers.obj" + -@erase "$(INTDIR)\tripmine.obj" + -@erase "$(INTDIR)\turret.obj" + -@erase "$(INTDIR)\util.obj" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(INTDIR)\weapons.obj" + -@erase "$(INTDIR)\world.obj" + -@erase "$(INTDIR)\WXDEBUG.OBJ" + -@erase "$(INTDIR)\xen.obj" + -@erase "$(INTDIR)\zombie.obj" + -@erase "$(OUTDIR)\hl.dll" + -@erase "$(OUTDIR)\hl.exp" + -@erase "$(OUTDIR)\hl.lib" + -@erase "$(OUTDIR)\hl.map" + -@erase "$(OUTDIR)\hl.pdb" + -@erase ".\hl" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# 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 /GX /Zi /O2 /I "..\engine" /I "..\common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "HLDEMO_BUILD" /YX /c +# SUBTRACT CPP /Fr +CPP_PROJ=/nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /I "..\common" /D\ + "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D\ + "VALVE_DLL" /D "HLDEMO_BUILD" /Fp"$(INTDIR)/hl.pch" /YX /Fo"$(INTDIR)/"\ + /Fd"$(INTDIR)/" /c +CPP_OBJS=.\HLDEMO/ +CPP_SBRS=.\. +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" /d "HLDEMO_BUILD" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/hl.bsc" +BSC32_SBRS= \ + +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 /map /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 /map /debug /machine:I386 /def:".\hl.def" +# SUBTRACT LINK32 /profile +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\ + /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)/hl.pdb"\ + /map:"$(INTDIR)/hl.map" /debug /machine:I386 /def:".\hl.def"\ + /out:"$(OUTDIR)/hl.dll" /implib:"$(OUTDIR)/hl.lib" +LINK32_OBJS= \ + "$(INTDIR)\aflock.obj" \ + "$(INTDIR)\agrunt.obj" \ + "$(INTDIR)\airtank.obj" \ + "$(INTDIR)\animating.obj" \ + "$(INTDIR)\animation.obj" \ + "$(INTDIR)\apache.obj" \ + "$(INTDIR)\barnacle.obj" \ + "$(INTDIR)\barney.obj" \ + "$(INTDIR)\bigmomma.obj" \ + "$(INTDIR)\bloater.obj" \ + "$(INTDIR)\bmodels.obj" \ + "$(INTDIR)\bullsquid.obj" \ + "$(INTDIR)\buttons.obj" \ + "$(INTDIR)\cbase.obj" \ + "$(INTDIR)\client.obj" \ + "$(INTDIR)\combat.obj" \ + "$(INTDIR)\controller.obj" \ + "$(INTDIR)\crossbow.obj" \ + "$(INTDIR)\crowbar.obj" \ + "$(INTDIR)\defaultai.obj" \ + "$(INTDIR)\doors.obj" \ + "$(INTDIR)\effects.obj" \ + "$(INTDIR)\egon.obj" \ + "$(INTDIR)\explode.obj" \ + "$(INTDIR)\flyingmonster.obj" \ + "$(INTDIR)\func_break.obj" \ + "$(INTDIR)\func_tank.obj" \ + "$(INTDIR)\game.obj" \ + "$(INTDIR)\gamerules.obj" \ + "$(INTDIR)\gargantua.obj" \ + "$(INTDIR)\gauss.obj" \ + "$(INTDIR)\genericmonster.obj" \ + "$(INTDIR)\ggrenade.obj" \ + "$(INTDIR)\globals.obj" \ + "$(INTDIR)\glock.obj" \ + "$(INTDIR)\gman.obj" \ + "$(INTDIR)\h_ai.obj" \ + "$(INTDIR)\h_battery.obj" \ + "$(INTDIR)\h_cine.obj" \ + "$(INTDIR)\h_cycler.obj" \ + "$(INTDIR)\h_export.obj" \ + "$(INTDIR)\handgrenade.obj" \ + "$(INTDIR)\hassassin.obj" \ + "$(INTDIR)\headcrab.obj" \ + "$(INTDIR)\healthkit.obj" \ + "$(INTDIR)\hgrunt.obj" \ + "$(INTDIR)\hornet.obj" \ + "$(INTDIR)\hornetgun.obj" \ + "$(INTDIR)\houndeye.obj" \ + "$(INTDIR)\ichthyosaur.obj" \ + "$(INTDIR)\islave.obj" \ + "$(INTDIR)\items.obj" \ + "$(INTDIR)\leech.obj" \ + "$(INTDIR)\lights.obj" \ + "$(INTDIR)\maprules.obj" \ + "$(INTDIR)\monstermaker.obj" \ + "$(INTDIR)\monsters.obj" \ + "$(INTDIR)\monsterstate.obj" \ + "$(INTDIR)\mortar.obj" \ + "$(INTDIR)\mp5.obj" \ + "$(INTDIR)\multiplay_gamerules.obj" \ + "$(INTDIR)\nihilanth.obj" \ + "$(INTDIR)\nodes.obj" \ + "$(INTDIR)\osprey.obj" \ + "$(INTDIR)\pathcorner.obj" \ + "$(INTDIR)\plane.obj" \ + "$(INTDIR)\plats.obj" \ + "$(INTDIR)\player.obj" \ + "$(INTDIR)\pm_debug.obj" \ + "$(INTDIR)\pm_math.obj" \ + "$(INTDIR)\pm_shared.obj" \ + "$(INTDIR)\python.obj" \ + "$(INTDIR)\rat.obj" \ + "$(INTDIR)\roach.obj" \ + "$(INTDIR)\rpg.obj" \ + "$(INTDIR)\satchel.obj" \ + "$(INTDIR)\schedule.obj" \ + "$(INTDIR)\scientist.obj" \ + "$(INTDIR)\scripted.obj" \ + "$(INTDIR)\shotgun.obj" \ + "$(INTDIR)\singleplay_gamerules.obj" \ + "$(INTDIR)\skill.obj" \ + "$(INTDIR)\sound.obj" \ + "$(INTDIR)\soundent.obj" \ + "$(INTDIR)\spectator.obj" \ + "$(INTDIR)\squadmonster.obj" \ + "$(INTDIR)\squeakgrenade.obj" \ + "$(INTDIR)\subs.obj" \ + "$(INTDIR)\talkmonster.obj" \ + "$(INTDIR)\teamplay_gamerules.obj" \ + "$(INTDIR)\tempmonster.obj" \ + "$(INTDIR)\tentacle.obj" \ + "$(INTDIR)\triggers.obj" \ + "$(INTDIR)\tripmine.obj" \ + "$(INTDIR)\turret.obj" \ + "$(INTDIR)\util.obj" \ + "$(INTDIR)\weapons.obj" \ + "$(INTDIR)\world.obj" \ + "$(INTDIR)\WXDEBUG.OBJ" \ + "$(INTDIR)\xen.obj" \ + "$(INTDIR)\zombie.obj" + +"$(OUTDIR)\hl.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +# Begin Custom Build +TargetPath=.\HLDEMO\hl.dll +TargetName=hl +InputPath=.\HLDEMO\hl.dll +SOURCE=$(InputPath) + +"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetPath) u:\quiver\valve\dlls + +# End Custom Build + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "hl - Win32 Release" +# Name "hl - Win32 Debug" +# Name "hl - Win32 Germany" +# Name "hl - Win32 Profile" +# Name "hl - Win32 HLDEMO Release" + +!IF "$(CFG)" == "hl - Win32 Release" + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\world.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_WORLD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\world.obj" : $(SOURCE) $(DEP_CPP_WORLD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_WORLD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\world.obj" : $(SOURCE) $(DEP_CPP_WORLD) "$(INTDIR)" + +"$(INTDIR)\world.sbr" : $(SOURCE) $(DEP_CPP_WORLD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_WORLD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\world.obj" : $(SOURCE) $(DEP_CPP_WORLD) "$(INTDIR)" + +"$(INTDIR)\world.sbr" : $(SOURCE) $(DEP_CPP_WORLD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_WORLD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\world.obj" : $(SOURCE) $(DEP_CPP_WORLD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_WORLD=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\world.obj" : $(SOURCE) $(DEP_CPP_WORLD) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\bmodels.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_BMODE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bmodels.obj" : $(SOURCE) $(DEP_CPP_BMODE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_BMODE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bmodels.obj" : $(SOURCE) $(DEP_CPP_BMODE) "$(INTDIR)" + +"$(INTDIR)\bmodels.sbr" : $(SOURCE) $(DEP_CPP_BMODE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_BMODE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bmodels.obj" : $(SOURCE) $(DEP_CPP_BMODE) "$(INTDIR)" + +"$(INTDIR)\bmodels.sbr" : $(SOURCE) $(DEP_CPP_BMODE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_BMODE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bmodels.obj" : $(SOURCE) $(DEP_CPP_BMODE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_BMODE=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\bmodels.obj" : $(SOURCE) $(DEP_CPP_BMODE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\buttons.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_BUTTO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\buttons.obj" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_BUTTO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\buttons.obj" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)" + +"$(INTDIR)\buttons.sbr" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_BUTTO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\buttons.obj" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)" + +"$(INTDIR)\buttons.sbr" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_BUTTO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\buttons.obj" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_BUTTO=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\buttons.obj" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\client.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_CLIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\entity_state.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\client.obj" : $(SOURCE) $(DEP_CPP_CLIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_CLIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\entity_state.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\client.obj" : $(SOURCE) $(DEP_CPP_CLIEN) "$(INTDIR)" + +"$(INTDIR)\client.sbr" : $(SOURCE) $(DEP_CPP_CLIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_CLIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\entity_state.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\client.obj" : $(SOURCE) $(DEP_CPP_CLIEN) "$(INTDIR)" + +"$(INTDIR)\client.sbr" : $(SOURCE) $(DEP_CPP_CLIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_CLIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\entity_state.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\client.obj" : $(SOURCE) $(DEP_CPP_CLIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_CLIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\entity_state.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\client.obj" : $(SOURCE) $(DEP_CPP_CLIEN) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\combat.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_COMBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\combat.obj" : $(SOURCE) $(DEP_CPP_COMBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_COMBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\combat.obj" : $(SOURCE) $(DEP_CPP_COMBA) "$(INTDIR)" + +"$(INTDIR)\combat.sbr" : $(SOURCE) $(DEP_CPP_COMBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_COMBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\combat.obj" : $(SOURCE) $(DEP_CPP_COMBA) "$(INTDIR)" + +"$(INTDIR)\combat.sbr" : $(SOURCE) $(DEP_CPP_COMBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_COMBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\combat.obj" : $(SOURCE) $(DEP_CPP_COMBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_COMBA=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\cvardef.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\combat.obj" : $(SOURCE) $(DEP_CPP_COMBA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\doors.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_DOORS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\doors.obj" : $(SOURCE) $(DEP_CPP_DOORS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_DOORS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\doors.obj" : $(SOURCE) $(DEP_CPP_DOORS) "$(INTDIR)" + +"$(INTDIR)\doors.sbr" : $(SOURCE) $(DEP_CPP_DOORS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_DOORS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\doors.obj" : $(SOURCE) $(DEP_CPP_DOORS) "$(INTDIR)" + +"$(INTDIR)\doors.sbr" : $(SOURCE) $(DEP_CPP_DOORS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_DOORS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\doors.obj" : $(SOURCE) $(DEP_CPP_DOORS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_DOORS=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\doors.obj" : $(SOURCE) $(DEP_CPP_DOORS) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\globals.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GLOBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\globals.obj" : $(SOURCE) $(DEP_CPP_GLOBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GLOBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\globals.obj" : $(SOURCE) $(DEP_CPP_GLOBA) "$(INTDIR)" + +"$(INTDIR)\globals.sbr" : $(SOURCE) $(DEP_CPP_GLOBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GLOBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\globals.obj" : $(SOURCE) $(DEP_CPP_GLOBA) "$(INTDIR)" + +"$(INTDIR)\globals.sbr" : $(SOURCE) $(DEP_CPP_GLOBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GLOBA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\globals.obj" : $(SOURCE) $(DEP_CPP_GLOBA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GLOBA=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + + +"$(INTDIR)\globals.obj" : $(SOURCE) $(DEP_CPP_GLOBA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\h_export.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_H_EXP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_export.obj" : $(SOURCE) $(DEP_CPP_H_EXP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_H_EXP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_export.obj" : $(SOURCE) $(DEP_CPP_H_EXP) "$(INTDIR)" + +"$(INTDIR)\h_export.sbr" : $(SOURCE) $(DEP_CPP_H_EXP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_H_EXP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_export.obj" : $(SOURCE) $(DEP_CPP_H_EXP) "$(INTDIR)" + +"$(INTDIR)\h_export.sbr" : $(SOURCE) $(DEP_CPP_H_EXP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_H_EXP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_export.obj" : $(SOURCE) $(DEP_CPP_H_EXP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_H_EXP=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\wxdebug.h"\ + + +"$(INTDIR)\h_export.obj" : $(SOURCE) $(DEP_CPP_H_EXP) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\lights.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_LIGHT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\lights.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_LIGHT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\lights.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + +"$(INTDIR)\lights.sbr" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_LIGHT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\lights.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + +"$(INTDIR)\lights.sbr" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_LIGHT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\lights.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_LIGHT=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\lights.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\monsters.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_MONST=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\monsters.obj" : $(SOURCE) $(DEP_CPP_MONST) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_MONST=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\monsters.obj" : $(SOURCE) $(DEP_CPP_MONST) "$(INTDIR)" + +"$(INTDIR)\monsters.sbr" : $(SOURCE) $(DEP_CPP_MONST) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_MONST=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\monsters.obj" : $(SOURCE) $(DEP_CPP_MONST) "$(INTDIR)" + +"$(INTDIR)\monsters.sbr" : $(SOURCE) $(DEP_CPP_MONST) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_MONST=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\monsters.obj" : $(SOURCE) $(DEP_CPP_MONST) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_MONST=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\monsters.obj" : $(SOURCE) $(DEP_CPP_MONST) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\monsters.h + +!IF "$(CFG)" == "hl - Win32 Release" + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\plats.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_PLATS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plats.obj" : $(SOURCE) $(DEP_CPP_PLATS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_PLATS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plats.obj" : $(SOURCE) $(DEP_CPP_PLATS) "$(INTDIR)" + +"$(INTDIR)\plats.sbr" : $(SOURCE) $(DEP_CPP_PLATS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_PLATS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plats.obj" : $(SOURCE) $(DEP_CPP_PLATS) "$(INTDIR)" + +"$(INTDIR)\plats.sbr" : $(SOURCE) $(DEP_CPP_PLATS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_PLATS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plats.obj" : $(SOURCE) $(DEP_CPP_PLATS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_PLATS=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + + +"$(INTDIR)\plats.obj" : $(SOURCE) $(DEP_CPP_PLATS) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\player.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_PLAYE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\player.obj" : $(SOURCE) $(DEP_CPP_PLAYE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_PLAYE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\player.obj" : $(SOURCE) $(DEP_CPP_PLAYE) "$(INTDIR)" + +"$(INTDIR)\player.sbr" : $(SOURCE) $(DEP_CPP_PLAYE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_PLAYE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\player.obj" : $(SOURCE) $(DEP_CPP_PLAYE) "$(INTDIR)" + +"$(INTDIR)\player.sbr" : $(SOURCE) $(DEP_CPP_PLAYE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_PLAYE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\player.obj" : $(SOURCE) $(DEP_CPP_PLAYE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_PLAYE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\player.obj" : $(SOURCE) $(DEP_CPP_PLAYE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\sound.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\sound.obj" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\sound.obj" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + +"$(INTDIR)\sound.sbr" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\sound.obj" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + +"$(INTDIR)\sound.sbr" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\sound.obj" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SOUND=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\sound.obj" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\subs.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SUBS_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\subs.obj" : $(SOURCE) $(DEP_CPP_SUBS_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SUBS_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\subs.obj" : $(SOURCE) $(DEP_CPP_SUBS_) "$(INTDIR)" + +"$(INTDIR)\subs.sbr" : $(SOURCE) $(DEP_CPP_SUBS_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SUBS_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\subs.obj" : $(SOURCE) $(DEP_CPP_SUBS_) "$(INTDIR)" + +"$(INTDIR)\subs.sbr" : $(SOURCE) $(DEP_CPP_SUBS_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SUBS_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\subs.obj" : $(SOURCE) $(DEP_CPP_SUBS_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SUBS_=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\subs.obj" : $(SOURCE) $(DEP_CPP_SUBS_) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\triggers.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_TRIGG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\triggers.obj" : $(SOURCE) $(DEP_CPP_TRIGG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_TRIGG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\triggers.obj" : $(SOURCE) $(DEP_CPP_TRIGG) "$(INTDIR)" + +"$(INTDIR)\triggers.sbr" : $(SOURCE) $(DEP_CPP_TRIGG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_TRIGG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\triggers.obj" : $(SOURCE) $(DEP_CPP_TRIGG) "$(INTDIR)" + +"$(INTDIR)\triggers.sbr" : $(SOURCE) $(DEP_CPP_TRIGG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_TRIGG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\triggers.obj" : $(SOURCE) $(DEP_CPP_TRIGG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_TRIGG=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + + +"$(INTDIR)\triggers.obj" : $(SOURCE) $(DEP_CPP_TRIGG) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_UTIL_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\util.obj" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_UTIL_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\util.obj" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" + +"$(INTDIR)\util.sbr" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_UTIL_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\util.obj" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" + +"$(INTDIR)\util.sbr" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_UTIL_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\util.obj" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_UTIL_=\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\util.obj" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util.h + +!IF "$(CFG)" == "hl - Win32 Release" + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\weapons.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_WEAPO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\weapons.obj" : $(SOURCE) $(DEP_CPP_WEAPO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_WEAPO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\weapons.obj" : $(SOURCE) $(DEP_CPP_WEAPO) "$(INTDIR)" + +"$(INTDIR)\weapons.sbr" : $(SOURCE) $(DEP_CPP_WEAPO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_WEAPO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\weapons.obj" : $(SOURCE) $(DEP_CPP_WEAPO) "$(INTDIR)" + +"$(INTDIR)\weapons.sbr" : $(SOURCE) $(DEP_CPP_WEAPO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_WEAPO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\weapons.obj" : $(SOURCE) $(DEP_CPP_WEAPO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_WEAPO=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\cvardef.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\weapons.obj" : $(SOURCE) $(DEP_CPP_WEAPO) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quiver\SRC\engine\eiface.h + +!IF "$(CFG)" == "hl - Win32 Release" + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quiver\src\engine\extdll.h + +!IF "$(CFG)" == "hl - Win32 Release" + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quiver\SRC\engine\const.h + +!IF "$(CFG)" == "hl - Win32 Release" + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\h_cine.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_H_CIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_cine.obj" : $(SOURCE) $(DEP_CPP_H_CIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_H_CIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_cine.obj" : $(SOURCE) $(DEP_CPP_H_CIN) "$(INTDIR)" + +"$(INTDIR)\h_cine.sbr" : $(SOURCE) $(DEP_CPP_H_CIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_H_CIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_cine.obj" : $(SOURCE) $(DEP_CPP_H_CIN) "$(INTDIR)" + +"$(INTDIR)\h_cine.sbr" : $(SOURCE) $(DEP_CPP_H_CIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_H_CIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_cine.obj" : $(SOURCE) $(DEP_CPP_H_CIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_H_CIN=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\h_cine.obj" : $(SOURCE) $(DEP_CPP_H_CIN) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\cbase.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_CBASE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\cbase.obj" : $(SOURCE) $(DEP_CPP_CBASE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_CBASE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\cbase.obj" : $(SOURCE) $(DEP_CPP_CBASE) "$(INTDIR)" + +"$(INTDIR)\cbase.sbr" : $(SOURCE) $(DEP_CPP_CBASE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_CBASE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\cbase.obj" : $(SOURCE) $(DEP_CPP_CBASE) "$(INTDIR)" + +"$(INTDIR)\cbase.sbr" : $(SOURCE) $(DEP_CPP_CBASE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_CBASE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\cbase.obj" : $(SOURCE) $(DEP_CPP_CBASE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_CBASE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\client.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\cbase.obj" : $(SOURCE) $(DEP_CPP_CBASE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\pathcorner.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_PATHC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\pathcorner.obj" : $(SOURCE) $(DEP_CPP_PATHC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_PATHC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\pathcorner.obj" : $(SOURCE) $(DEP_CPP_PATHC) "$(INTDIR)" + +"$(INTDIR)\pathcorner.sbr" : $(SOURCE) $(DEP_CPP_PATHC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_PATHC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\pathcorner.obj" : $(SOURCE) $(DEP_CPP_PATHC) "$(INTDIR)" + +"$(INTDIR)\pathcorner.sbr" : $(SOURCE) $(DEP_CPP_PATHC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_PATHC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\pathcorner.obj" : $(SOURCE) $(DEP_CPP_PATHC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_PATHC=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\trains.h"\ + ".\util.h"\ + + +"$(INTDIR)\pathcorner.obj" : $(SOURCE) $(DEP_CPP_PATHC) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\h_cycler.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_H_CYC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\h_cycler.obj" : $(SOURCE) $(DEP_CPP_H_CYC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_H_CYC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\h_cycler.obj" : $(SOURCE) $(DEP_CPP_H_CYC) "$(INTDIR)" + +"$(INTDIR)\h_cycler.sbr" : $(SOURCE) $(DEP_CPP_H_CYC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_H_CYC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\h_cycler.obj" : $(SOURCE) $(DEP_CPP_H_CYC) "$(INTDIR)" + +"$(INTDIR)\h_cycler.sbr" : $(SOURCE) $(DEP_CPP_H_CYC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_H_CYC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\h_cycler.obj" : $(SOURCE) $(DEP_CPP_H_CYC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_H_CYC=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\h_cycler.obj" : $(SOURCE) $(DEP_CPP_H_CYC) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\explode.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_EXPLO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\explode.obj" : $(SOURCE) $(DEP_CPP_EXPLO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_EXPLO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\explode.obj" : $(SOURCE) $(DEP_CPP_EXPLO) "$(INTDIR)" + +"$(INTDIR)\explode.sbr" : $(SOURCE) $(DEP_CPP_EXPLO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_EXPLO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\explode.obj" : $(SOURCE) $(DEP_CPP_EXPLO) "$(INTDIR)" + +"$(INTDIR)\explode.sbr" : $(SOURCE) $(DEP_CPP_EXPLO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_EXPLO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\explode.obj" : $(SOURCE) $(DEP_CPP_EXPLO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_EXPLO=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\explode.obj" : $(SOURCE) $(DEP_CPP_EXPLO) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\turret.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_TURRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\turret.obj" : $(SOURCE) $(DEP_CPP_TURRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_TURRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\turret.obj" : $(SOURCE) $(DEP_CPP_TURRE) "$(INTDIR)" + +"$(INTDIR)\turret.sbr" : $(SOURCE) $(DEP_CPP_TURRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_TURRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\turret.obj" : $(SOURCE) $(DEP_CPP_TURRE) "$(INTDIR)" + +"$(INTDIR)\turret.sbr" : $(SOURCE) $(DEP_CPP_TURRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_TURRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\turret.obj" : $(SOURCE) $(DEP_CPP_TURRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_TURRE=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\turret.obj" : $(SOURCE) $(DEP_CPP_TURRE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\func_break.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_FUNC_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\func_break.obj" : $(SOURCE) $(DEP_CPP_FUNC_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_FUNC_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\func_break.obj" : $(SOURCE) $(DEP_CPP_FUNC_) "$(INTDIR)" + +"$(INTDIR)\func_break.sbr" : $(SOURCE) $(DEP_CPP_FUNC_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_FUNC_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\func_break.obj" : $(SOURCE) $(DEP_CPP_FUNC_) "$(INTDIR)" + +"$(INTDIR)\func_break.sbr" : $(SOURCE) $(DEP_CPP_FUNC_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_FUNC_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\func_break.obj" : $(SOURCE) $(DEP_CPP_FUNC_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_FUNC_=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\func_break.obj" : $(SOURCE) $(DEP_CPP_FUNC_) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\effects.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_EFFEC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\effects.obj" : $(SOURCE) $(DEP_CPP_EFFEC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_EFFEC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\effects.obj" : $(SOURCE) $(DEP_CPP_EFFEC) "$(INTDIR)" + +"$(INTDIR)\effects.sbr" : $(SOURCE) $(DEP_CPP_EFFEC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_EFFEC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\effects.obj" : $(SOURCE) $(DEP_CPP_EFFEC) "$(INTDIR)" + +"$(INTDIR)\effects.sbr" : $(SOURCE) $(DEP_CPP_EFFEC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_EFFEC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\effects.obj" : $(SOURCE) $(DEP_CPP_EFFEC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_EFFEC=\ + "..\engine\customentity.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\effects.obj" : $(SOURCE) $(DEP_CPP_EFFEC) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\items.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_ITEMS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\items.obj" : $(SOURCE) $(DEP_CPP_ITEMS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_ITEMS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\items.obj" : $(SOURCE) $(DEP_CPP_ITEMS) "$(INTDIR)" + +"$(INTDIR)\items.sbr" : $(SOURCE) $(DEP_CPP_ITEMS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_ITEMS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\items.obj" : $(SOURCE) $(DEP_CPP_ITEMS) "$(INTDIR)" + +"$(INTDIR)\items.sbr" : $(SOURCE) $(DEP_CPP_ITEMS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_ITEMS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\items.obj" : $(SOURCE) $(DEP_CPP_ITEMS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_ITEMS=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\items.obj" : $(SOURCE) $(DEP_CPP_ITEMS) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\animation.cpp +DEP_CPP_ANIMA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\common\nowin.h"\ + "..\common\studio_event.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\studio.h"\ + "..\utils\common\mathlib.h"\ + ".\activity.h"\ + ".\activitymap.h"\ + ".\animation.h"\ + ".\enginecallback.h"\ + ".\monsterevent.h"\ + ".\scriptevent.h"\ + + +!IF "$(CFG)" == "hl - Win32 Release" + + +"$(INTDIR)\animation.obj" : $(SOURCE) $(DEP_CPP_ANIMA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + + +"$(INTDIR)\animation.obj" : $(SOURCE) $(DEP_CPP_ANIMA) "$(INTDIR)" + +"$(INTDIR)\animation.sbr" : $(SOURCE) $(DEP_CPP_ANIMA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + + +"$(INTDIR)\animation.obj" : $(SOURCE) $(DEP_CPP_ANIMA) "$(INTDIR)" + +"$(INTDIR)\animation.sbr" : $(SOURCE) $(DEP_CPP_ANIMA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + + +"$(INTDIR)\animation.obj" : $(SOURCE) $(DEP_CPP_ANIMA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + + +"$(INTDIR)\animation.obj" : $(SOURCE) $(DEP_CPP_ANIMA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\src\engine\progdefs.h + +!IF "$(CFG)" == "hl - Win32 Release" + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\nodes.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_NODES=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\nodes.obj" : $(SOURCE) $(DEP_CPP_NODES) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_NODES=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\nodes.obj" : $(SOURCE) $(DEP_CPP_NODES) "$(INTDIR)" + +"$(INTDIR)\nodes.sbr" : $(SOURCE) $(DEP_CPP_NODES) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_NODES=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\nodes.obj" : $(SOURCE) $(DEP_CPP_NODES) "$(INTDIR)" + +"$(INTDIR)\nodes.sbr" : $(SOURCE) $(DEP_CPP_NODES) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_NODES=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\nodes.obj" : $(SOURCE) $(DEP_CPP_NODES) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_NODES=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\doors.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\nodes.obj" : $(SOURCE) $(DEP_CPP_NODES) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\h_battery.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_H_BAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_battery.obj" : $(SOURCE) $(DEP_CPP_H_BAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_H_BAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_battery.obj" : $(SOURCE) $(DEP_CPP_H_BAT) "$(INTDIR)" + +"$(INTDIR)\h_battery.sbr" : $(SOURCE) $(DEP_CPP_H_BAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_H_BAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_battery.obj" : $(SOURCE) $(DEP_CPP_H_BAT) "$(INTDIR)" + +"$(INTDIR)\h_battery.sbr" : $(SOURCE) $(DEP_CPP_H_BAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_H_BAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_battery.obj" : $(SOURCE) $(DEP_CPP_H_BAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_H_BAT=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\h_battery.obj" : $(SOURCE) $(DEP_CPP_H_BAT) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\headcrab.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HEADC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\headcrab.obj" : $(SOURCE) $(DEP_CPP_HEADC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HEADC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\headcrab.obj" : $(SOURCE) $(DEP_CPP_HEADC) "$(INTDIR)" + +"$(INTDIR)\headcrab.sbr" : $(SOURCE) $(DEP_CPP_HEADC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HEADC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\headcrab.obj" : $(SOURCE) $(DEP_CPP_HEADC) "$(INTDIR)" + +"$(INTDIR)\headcrab.sbr" : $(SOURCE) $(DEP_CPP_HEADC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HEADC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\headcrab.obj" : $(SOURCE) $(DEP_CPP_HEADC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HEADC=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\headcrab.obj" : $(SOURCE) $(DEP_CPP_HEADC) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\houndeye.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\houndeye.obj" : $(SOURCE) $(DEP_CPP_HOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\houndeye.obj" : $(SOURCE) $(DEP_CPP_HOUND) "$(INTDIR)" + +"$(INTDIR)\houndeye.sbr" : $(SOURCE) $(DEP_CPP_HOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\houndeye.obj" : $(SOURCE) $(DEP_CPP_HOUND) "$(INTDIR)" + +"$(INTDIR)\houndeye.sbr" : $(SOURCE) $(DEP_CPP_HOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HOUND=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\houndeye.obj" : $(SOURCE) $(DEP_CPP_HOUND) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HOUND=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + + +"$(INTDIR)\houndeye.obj" : $(SOURCE) $(DEP_CPP_HOUND) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\hgrunt.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hgrunt.obj" : $(SOURCE) $(DEP_CPP_HGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hgrunt.obj" : $(SOURCE) $(DEP_CPP_HGRUN) "$(INTDIR)" + +"$(INTDIR)\hgrunt.sbr" : $(SOURCE) $(DEP_CPP_HGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hgrunt.obj" : $(SOURCE) $(DEP_CPP_HGRUN) "$(INTDIR)" + +"$(INTDIR)\hgrunt.sbr" : $(SOURCE) $(DEP_CPP_HGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hgrunt.obj" : $(SOURCE) $(DEP_CPP_HGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HGRUN=\ + "..\engine\customentity.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hgrunt.obj" : $(SOURCE) $(DEP_CPP_HGRUN) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\schedule.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SCHED=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\schedule.obj" : $(SOURCE) $(DEP_CPP_SCHED) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SCHED=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\schedule.obj" : $(SOURCE) $(DEP_CPP_SCHED) "$(INTDIR)" + +"$(INTDIR)\schedule.sbr" : $(SOURCE) $(DEP_CPP_SCHED) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SCHED=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\schedule.obj" : $(SOURCE) $(DEP_CPP_SCHED) "$(INTDIR)" + +"$(INTDIR)\schedule.sbr" : $(SOURCE) $(DEP_CPP_SCHED) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SCHED=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\schedule.obj" : $(SOURCE) $(DEP_CPP_SCHED) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SCHED=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + + +"$(INTDIR)\schedule.obj" : $(SOURCE) $(DEP_CPP_SCHED) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\monsterstate.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_MONSTE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monsterstate.obj" : $(SOURCE) $(DEP_CPP_MONSTE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_MONSTE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monsterstate.obj" : $(SOURCE) $(DEP_CPP_MONSTE) "$(INTDIR)" + +"$(INTDIR)\monsterstate.sbr" : $(SOURCE) $(DEP_CPP_MONSTE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_MONSTE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monsterstate.obj" : $(SOURCE) $(DEP_CPP_MONSTE) "$(INTDIR)" + +"$(INTDIR)\monsterstate.sbr" : $(SOURCE) $(DEP_CPP_MONSTE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_MONSTE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monsterstate.obj" : $(SOURCE) $(DEP_CPP_MONSTE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_MONSTE=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + + +"$(INTDIR)\monsterstate.obj" : $(SOURCE) $(DEP_CPP_MONSTE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\defaultai.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_DEFAU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\defaultai.obj" : $(SOURCE) $(DEP_CPP_DEFAU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_DEFAU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\defaultai.obj" : $(SOURCE) $(DEP_CPP_DEFAU) "$(INTDIR)" + +"$(INTDIR)\defaultai.sbr" : $(SOURCE) $(DEP_CPP_DEFAU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_DEFAU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\defaultai.obj" : $(SOURCE) $(DEP_CPP_DEFAU) "$(INTDIR)" + +"$(INTDIR)\defaultai.sbr" : $(SOURCE) $(DEP_CPP_DEFAU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_DEFAU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\defaultai.obj" : $(SOURCE) $(DEP_CPP_DEFAU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_DEFAU=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + + +"$(INTDIR)\defaultai.obj" : $(SOURCE) $(DEP_CPP_DEFAU) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\h_ai.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_H_AI_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_ai.obj" : $(SOURCE) $(DEP_CPP_H_AI_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_H_AI_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_ai.obj" : $(SOURCE) $(DEP_CPP_H_AI_) "$(INTDIR)" + +"$(INTDIR)\h_ai.sbr" : $(SOURCE) $(DEP_CPP_H_AI_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_H_AI_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_ai.obj" : $(SOURCE) $(DEP_CPP_H_AI_) "$(INTDIR)" + +"$(INTDIR)\h_ai.sbr" : $(SOURCE) $(DEP_CPP_H_AI_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_H_AI_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\h_ai.obj" : $(SOURCE) $(DEP_CPP_H_AI_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_H_AI_=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\h_ai.obj" : $(SOURCE) $(DEP_CPP_H_AI_) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\scripted.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SCRIP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scripted.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SCRIP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scripted.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + +"$(INTDIR)\scripted.sbr" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SCRIP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scripted.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + +"$(INTDIR)\scripted.sbr" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SCRIP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scripted.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SCRIP=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\scripted.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\barney.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_BARNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\barney.obj" : $(SOURCE) $(DEP_CPP_BARNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_BARNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\barney.obj" : $(SOURCE) $(DEP_CPP_BARNE) "$(INTDIR)" + +"$(INTDIR)\barney.sbr" : $(SOURCE) $(DEP_CPP_BARNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_BARNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\barney.obj" : $(SOURCE) $(DEP_CPP_BARNE) "$(INTDIR)" + +"$(INTDIR)\barney.sbr" : $(SOURCE) $(DEP_CPP_BARNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_BARNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\barney.obj" : $(SOURCE) $(DEP_CPP_BARNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_BARNE=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\barney.obj" : $(SOURCE) $(DEP_CPP_BARNE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\scientist.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SCIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scientist.obj" : $(SOURCE) $(DEP_CPP_SCIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SCIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scientist.obj" : $(SOURCE) $(DEP_CPP_SCIEN) "$(INTDIR)" + +"$(INTDIR)\scientist.sbr" : $(SOURCE) $(DEP_CPP_SCIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SCIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scientist.obj" : $(SOURCE) $(DEP_CPP_SCIEN) "$(INTDIR)" + +"$(INTDIR)\scientist.sbr" : $(SOURCE) $(DEP_CPP_SCIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SCIEN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\scientist.obj" : $(SOURCE) $(DEP_CPP_SCIEN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SCIEN=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + + +"$(INTDIR)\scientist.obj" : $(SOURCE) $(DEP_CPP_SCIEN) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\zombie.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_ZOMBI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\zombie.obj" : $(SOURCE) $(DEP_CPP_ZOMBI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_ZOMBI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\zombie.obj" : $(SOURCE) $(DEP_CPP_ZOMBI) "$(INTDIR)" + +"$(INTDIR)\zombie.sbr" : $(SOURCE) $(DEP_CPP_ZOMBI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_ZOMBI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\zombie.obj" : $(SOURCE) $(DEP_CPP_ZOMBI) "$(INTDIR)" + +"$(INTDIR)\zombie.sbr" : $(SOURCE) $(DEP_CPP_ZOMBI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_ZOMBI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\zombie.obj" : $(SOURCE) $(DEP_CPP_ZOMBI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_ZOMBI=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\zombie.obj" : $(SOURCE) $(DEP_CPP_ZOMBI) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\roach.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_ROACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\roach.obj" : $(SOURCE) $(DEP_CPP_ROACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_ROACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\roach.obj" : $(SOURCE) $(DEP_CPP_ROACH) "$(INTDIR)" + +"$(INTDIR)\roach.sbr" : $(SOURCE) $(DEP_CPP_ROACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_ROACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\roach.obj" : $(SOURCE) $(DEP_CPP_ROACH) "$(INTDIR)" + +"$(INTDIR)\roach.sbr" : $(SOURCE) $(DEP_CPP_ROACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_ROACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\roach.obj" : $(SOURCE) $(DEP_CPP_ROACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_ROACH=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + + +"$(INTDIR)\roach.obj" : $(SOURCE) $(DEP_CPP_ROACH) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\rat.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_RAT_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\rat.obj" : $(SOURCE) $(DEP_CPP_RAT_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_RAT_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\rat.obj" : $(SOURCE) $(DEP_CPP_RAT_C) "$(INTDIR)" + +"$(INTDIR)\rat.sbr" : $(SOURCE) $(DEP_CPP_RAT_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_RAT_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\rat.obj" : $(SOURCE) $(DEP_CPP_RAT_C) "$(INTDIR)" + +"$(INTDIR)\rat.sbr" : $(SOURCE) $(DEP_CPP_RAT_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_RAT_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\rat.obj" : $(SOURCE) $(DEP_CPP_RAT_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_RAT_C=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\rat.obj" : $(SOURCE) $(DEP_CPP_RAT_C) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\monstermaker.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_MONSTER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monstermaker.obj" : $(SOURCE) $(DEP_CPP_MONSTER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_MONSTER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monstermaker.obj" : $(SOURCE) $(DEP_CPP_MONSTER) "$(INTDIR)" + +"$(INTDIR)\monstermaker.sbr" : $(SOURCE) $(DEP_CPP_MONSTER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_MONSTER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monstermaker.obj" : $(SOURCE) $(DEP_CPP_MONSTER) "$(INTDIR)" + +"$(INTDIR)\monstermaker.sbr" : $(SOURCE) $(DEP_CPP_MONSTER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_MONSTER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\monstermaker.obj" : $(SOURCE) $(DEP_CPP_MONSTER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_MONSTER=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\monstermaker.obj" : $(SOURCE) $(DEP_CPP_MONSTER) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\bullsquid.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_BULLS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bullsquid.obj" : $(SOURCE) $(DEP_CPP_BULLS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_BULLS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bullsquid.obj" : $(SOURCE) $(DEP_CPP_BULLS) "$(INTDIR)" + +"$(INTDIR)\bullsquid.sbr" : $(SOURCE) $(DEP_CPP_BULLS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_BULLS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bullsquid.obj" : $(SOURCE) $(DEP_CPP_BULLS) "$(INTDIR)" + +"$(INTDIR)\bullsquid.sbr" : $(SOURCE) $(DEP_CPP_BULLS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_BULLS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bullsquid.obj" : $(SOURCE) $(DEP_CPP_BULLS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_BULLS=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + + +"$(INTDIR)\bullsquid.obj" : $(SOURCE) $(DEP_CPP_BULLS) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ichthyosaur.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_ICHTH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ichthyosaur.obj" : $(SOURCE) $(DEP_CPP_ICHTH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_ICHTH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ichthyosaur.obj" : $(SOURCE) $(DEP_CPP_ICHTH) "$(INTDIR)" + +"$(INTDIR)\ichthyosaur.sbr" : $(SOURCE) $(DEP_CPP_ICHTH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_ICHTH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ichthyosaur.obj" : $(SOURCE) $(DEP_CPP_ICHTH) "$(INTDIR)" + +"$(INTDIR)\ichthyosaur.sbr" : $(SOURCE) $(DEP_CPP_ICHTH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_ICHTH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ichthyosaur.obj" : $(SOURCE) $(DEP_CPP_ICHTH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_ICHTH=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + ".\wxdebug.h"\ + + +"$(INTDIR)\ichthyosaur.obj" : $(SOURCE) $(DEP_CPP_ICHTH) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\barnacle.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_BARNA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\barnacle.obj" : $(SOURCE) $(DEP_CPP_BARNA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_BARNA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\barnacle.obj" : $(SOURCE) $(DEP_CPP_BARNA) "$(INTDIR)" + +"$(INTDIR)\barnacle.sbr" : $(SOURCE) $(DEP_CPP_BARNA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_BARNA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\barnacle.obj" : $(SOURCE) $(DEP_CPP_BARNA) "$(INTDIR)" + +"$(INTDIR)\barnacle.sbr" : $(SOURCE) $(DEP_CPP_BARNA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_BARNA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\barnacle.obj" : $(SOURCE) $(DEP_CPP_BARNA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_BARNA=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\barnacle.obj" : $(SOURCE) $(DEP_CPP_BARNA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\hassassin.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HASSA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hassassin.obj" : $(SOURCE) $(DEP_CPP_HASSA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HASSA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hassassin.obj" : $(SOURCE) $(DEP_CPP_HASSA) "$(INTDIR)" + +"$(INTDIR)\hassassin.sbr" : $(SOURCE) $(DEP_CPP_HASSA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HASSA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hassassin.obj" : $(SOURCE) $(DEP_CPP_HASSA) "$(INTDIR)" + +"$(INTDIR)\hassassin.sbr" : $(SOURCE) $(DEP_CPP_HASSA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HASSA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hassassin.obj" : $(SOURCE) $(DEP_CPP_HASSA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HASSA=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hassassin.obj" : $(SOURCE) $(DEP_CPP_HASSA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\agrunt.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_AGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\agrunt.obj" : $(SOURCE) $(DEP_CPP_AGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_AGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\agrunt.obj" : $(SOURCE) $(DEP_CPP_AGRUN) "$(INTDIR)" + +"$(INTDIR)\agrunt.sbr" : $(SOURCE) $(DEP_CPP_AGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_AGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\agrunt.obj" : $(SOURCE) $(DEP_CPP_AGRUN) "$(INTDIR)" + +"$(INTDIR)\agrunt.sbr" : $(SOURCE) $(DEP_CPP_AGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_AGRUN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\agrunt.obj" : $(SOURCE) $(DEP_CPP_AGRUN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_AGRUN=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\agrunt.obj" : $(SOURCE) $(DEP_CPP_AGRUN) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\islave.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_ISLAV=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\islave.obj" : $(SOURCE) $(DEP_CPP_ISLAV) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_ISLAV=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\islave.obj" : $(SOURCE) $(DEP_CPP_ISLAV) "$(INTDIR)" + +"$(INTDIR)\islave.sbr" : $(SOURCE) $(DEP_CPP_ISLAV) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_ISLAV=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\islave.obj" : $(SOURCE) $(DEP_CPP_ISLAV) "$(INTDIR)" + +"$(INTDIR)\islave.sbr" : $(SOURCE) $(DEP_CPP_ISLAV) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_ISLAV=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\islave.obj" : $(SOURCE) $(DEP_CPP_ISLAV) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_ISLAV=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\islave.obj" : $(SOURCE) $(DEP_CPP_ISLAV) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\shotgun.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SHOTG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\shotgun.obj" : $(SOURCE) $(DEP_CPP_SHOTG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SHOTG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\shotgun.obj" : $(SOURCE) $(DEP_CPP_SHOTG) "$(INTDIR)" + +"$(INTDIR)\shotgun.sbr" : $(SOURCE) $(DEP_CPP_SHOTG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SHOTG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\shotgun.obj" : $(SOURCE) $(DEP_CPP_SHOTG) "$(INTDIR)" + +"$(INTDIR)\shotgun.sbr" : $(SOURCE) $(DEP_CPP_SHOTG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SHOTG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\shotgun.obj" : $(SOURCE) $(DEP_CPP_SHOTG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SHOTG=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\cvardef.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\shotgun.obj" : $(SOURCE) $(DEP_CPP_SHOTG) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\glock.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GLOCK=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\glock.obj" : $(SOURCE) $(DEP_CPP_GLOCK) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GLOCK=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\glock.obj" : $(SOURCE) $(DEP_CPP_GLOCK) "$(INTDIR)" + +"$(INTDIR)\glock.sbr" : $(SOURCE) $(DEP_CPP_GLOCK) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GLOCK=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\glock.obj" : $(SOURCE) $(DEP_CPP_GLOCK) "$(INTDIR)" + +"$(INTDIR)\glock.sbr" : $(SOURCE) $(DEP_CPP_GLOCK) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GLOCK=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\glock.obj" : $(SOURCE) $(DEP_CPP_GLOCK) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GLOCK=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\cvardef.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\glock.obj" : $(SOURCE) $(DEP_CPP_GLOCK) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mp5.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_MP5_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mp5.obj" : $(SOURCE) $(DEP_CPP_MP5_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_MP5_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mp5.obj" : $(SOURCE) $(DEP_CPP_MP5_C) "$(INTDIR)" + +"$(INTDIR)\mp5.sbr" : $(SOURCE) $(DEP_CPP_MP5_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_MP5_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mp5.obj" : $(SOURCE) $(DEP_CPP_MP5_C) "$(INTDIR)" + +"$(INTDIR)\mp5.sbr" : $(SOURCE) $(DEP_CPP_MP5_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_MP5_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mp5.obj" : $(SOURCE) $(DEP_CPP_MP5_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_MP5_C=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\cvardef.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mp5.obj" : $(SOURCE) $(DEP_CPP_MP5_C) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\python.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_PYTHO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\python.obj" : $(SOURCE) $(DEP_CPP_PYTHO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_PYTHO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\python.obj" : $(SOURCE) $(DEP_CPP_PYTHO) "$(INTDIR)" + +"$(INTDIR)\python.sbr" : $(SOURCE) $(DEP_CPP_PYTHO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_PYTHO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\python.obj" : $(SOURCE) $(DEP_CPP_PYTHO) "$(INTDIR)" + +"$(INTDIR)\python.sbr" : $(SOURCE) $(DEP_CPP_PYTHO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_PYTHO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\python.obj" : $(SOURCE) $(DEP_CPP_PYTHO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_PYTHO=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\cvardef.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsters.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\python.obj" : $(SOURCE) $(DEP_CPP_PYTHO) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\crowbar.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_CROWB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crowbar.obj" : $(SOURCE) $(DEP_CPP_CROWB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_CROWB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crowbar.obj" : $(SOURCE) $(DEP_CPP_CROWB) "$(INTDIR)" + +"$(INTDIR)\crowbar.sbr" : $(SOURCE) $(DEP_CPP_CROWB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_CROWB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crowbar.obj" : $(SOURCE) $(DEP_CPP_CROWB) "$(INTDIR)" + +"$(INTDIR)\crowbar.sbr" : $(SOURCE) $(DEP_CPP_CROWB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_CROWB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crowbar.obj" : $(SOURCE) $(DEP_CPP_CROWB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_CROWB=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crowbar.obj" : $(SOURCE) $(DEP_CPP_CROWB) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\gauss.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GAUSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gauss.obj" : $(SOURCE) $(DEP_CPP_GAUSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GAUSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gauss.obj" : $(SOURCE) $(DEP_CPP_GAUSS) "$(INTDIR)" + +"$(INTDIR)\gauss.sbr" : $(SOURCE) $(DEP_CPP_GAUSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GAUSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gauss.obj" : $(SOURCE) $(DEP_CPP_GAUSS) "$(INTDIR)" + +"$(INTDIR)\gauss.sbr" : $(SOURCE) $(DEP_CPP_GAUSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GAUSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gauss.obj" : $(SOURCE) $(DEP_CPP_GAUSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GAUSS=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\cvardef.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + "..\engine\shake.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gauss.obj" : $(SOURCE) $(DEP_CPP_GAUSS) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\rpg.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_RPG_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\rpg.obj" : $(SOURCE) $(DEP_CPP_RPG_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_RPG_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\rpg.obj" : $(SOURCE) $(DEP_CPP_RPG_C) "$(INTDIR)" + +"$(INTDIR)\rpg.sbr" : $(SOURCE) $(DEP_CPP_RPG_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_RPG_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\rpg.obj" : $(SOURCE) $(DEP_CPP_RPG_C) "$(INTDIR)" + +"$(INTDIR)\rpg.sbr" : $(SOURCE) $(DEP_CPP_RPG_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_RPG_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\rpg.obj" : $(SOURCE) $(DEP_CPP_RPG_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_RPG_C=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\rpg.obj" : $(SOURCE) $(DEP_CPP_RPG_C) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\soundent.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SOUNDE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\soundent.obj" : $(SOURCE) $(DEP_CPP_SOUNDE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SOUNDE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\soundent.obj" : $(SOURCE) $(DEP_CPP_SOUNDE) "$(INTDIR)" + +"$(INTDIR)\soundent.sbr" : $(SOURCE) $(DEP_CPP_SOUNDE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SOUNDE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\soundent.obj" : $(SOURCE) $(DEP_CPP_SOUNDE) "$(INTDIR)" + +"$(INTDIR)\soundent.sbr" : $(SOURCE) $(DEP_CPP_SOUNDE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SOUNDE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\soundent.obj" : $(SOURCE) $(DEP_CPP_SOUNDE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SOUNDE=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + + +"$(INTDIR)\soundent.obj" : $(SOURCE) $(DEP_CPP_SOUNDE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\gargantua.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GARGA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gargantua.obj" : $(SOURCE) $(DEP_CPP_GARGA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GARGA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gargantua.obj" : $(SOURCE) $(DEP_CPP_GARGA) "$(INTDIR)" + +"$(INTDIR)\gargantua.sbr" : $(SOURCE) $(DEP_CPP_GARGA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GARGA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gargantua.obj" : $(SOURCE) $(DEP_CPP_GARGA) "$(INTDIR)" + +"$(INTDIR)\gargantua.sbr" : $(SOURCE) $(DEP_CPP_GARGA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GARGA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gargantua.obj" : $(SOURCE) $(DEP_CPP_GARGA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GARGA=\ + "..\engine\customentity.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\func_break.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gargantua.obj" : $(SOURCE) $(DEP_CPP_GARGA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\crossbow.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_CROSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crossbow.obj" : $(SOURCE) $(DEP_CPP_CROSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_CROSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crossbow.obj" : $(SOURCE) $(DEP_CPP_CROSS) "$(INTDIR)" + +"$(INTDIR)\crossbow.sbr" : $(SOURCE) $(DEP_CPP_CROSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_CROSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crossbow.obj" : $(SOURCE) $(DEP_CPP_CROSS) "$(INTDIR)" + +"$(INTDIR)\crossbow.sbr" : $(SOURCE) $(DEP_CPP_CROSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_CROSS=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crossbow.obj" : $(SOURCE) $(DEP_CPP_CROSS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_CROSS=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\crossbow.obj" : $(SOURCE) $(DEP_CPP_CROSS) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\egon.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_EGON_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\egon.obj" : $(SOURCE) $(DEP_CPP_EGON_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_EGON_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\egon.obj" : $(SOURCE) $(DEP_CPP_EGON_) "$(INTDIR)" + +"$(INTDIR)\egon.sbr" : $(SOURCE) $(DEP_CPP_EGON_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_EGON_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\egon.obj" : $(SOURCE) $(DEP_CPP_EGON_) "$(INTDIR)" + +"$(INTDIR)\egon.sbr" : $(SOURCE) $(DEP_CPP_EGON_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_EGON_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\egon.obj" : $(SOURCE) $(DEP_CPP_EGON_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_EGON_=\ + "..\engine\customentity.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\egon.obj" : $(SOURCE) $(DEP_CPP_EGON_) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\bigmomma.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_BIGMO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\bigmomma.obj" : $(SOURCE) $(DEP_CPP_BIGMO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_BIGMO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\bigmomma.obj" : $(SOURCE) $(DEP_CPP_BIGMO) "$(INTDIR)" + +"$(INTDIR)\bigmomma.sbr" : $(SOURCE) $(DEP_CPP_BIGMO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_BIGMO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\bigmomma.obj" : $(SOURCE) $(DEP_CPP_BIGMO) "$(INTDIR)" + +"$(INTDIR)\bigmomma.sbr" : $(SOURCE) $(DEP_CPP_BIGMO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_BIGMO=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\bigmomma.obj" : $(SOURCE) $(DEP_CPP_BIGMO) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_BIGMO=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\bigmomma.obj" : $(SOURCE) $(DEP_CPP_BIGMO) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\flyingmonster.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_FLYIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\flyingmonster.obj" : $(SOURCE) $(DEP_CPP_FLYIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_FLYIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\flyingmonster.obj" : $(SOURCE) $(DEP_CPP_FLYIN) "$(INTDIR)" + +"$(INTDIR)\flyingmonster.sbr" : $(SOURCE) $(DEP_CPP_FLYIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_FLYIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\flyingmonster.obj" : $(SOURCE) $(DEP_CPP_FLYIN) "$(INTDIR)" + +"$(INTDIR)\flyingmonster.sbr" : $(SOURCE) $(DEP_CPP_FLYIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_FLYIN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\flyingmonster.obj" : $(SOURCE) $(DEP_CPP_FLYIN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_FLYIN=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\flyingmonster.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\flyingmonster.obj" : $(SOURCE) $(DEP_CPP_FLYIN) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ggrenade.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GGREN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ggrenade.obj" : $(SOURCE) $(DEP_CPP_GGREN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GGREN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ggrenade.obj" : $(SOURCE) $(DEP_CPP_GGREN) "$(INTDIR)" + +"$(INTDIR)\ggrenade.sbr" : $(SOURCE) $(DEP_CPP_GGREN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GGREN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ggrenade.obj" : $(SOURCE) $(DEP_CPP_GGREN) "$(INTDIR)" + +"$(INTDIR)\ggrenade.sbr" : $(SOURCE) $(DEP_CPP_GGREN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GGREN=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ggrenade.obj" : $(SOURCE) $(DEP_CPP_GGREN) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GGREN=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\ggrenade.obj" : $(SOURCE) $(DEP_CPP_GGREN) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\handgrenade.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HANDG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\handgrenade.obj" : $(SOURCE) $(DEP_CPP_HANDG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HANDG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\handgrenade.obj" : $(SOURCE) $(DEP_CPP_HANDG) "$(INTDIR)" + +"$(INTDIR)\handgrenade.sbr" : $(SOURCE) $(DEP_CPP_HANDG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HANDG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\handgrenade.obj" : $(SOURCE) $(DEP_CPP_HANDG) "$(INTDIR)" + +"$(INTDIR)\handgrenade.sbr" : $(SOURCE) $(DEP_CPP_HANDG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HANDG=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\handgrenade.obj" : $(SOURCE) $(DEP_CPP_HANDG) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HANDG=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\handgrenade.obj" : $(SOURCE) $(DEP_CPP_HANDG) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\satchel.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SATCH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\satchel.obj" : $(SOURCE) $(DEP_CPP_SATCH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SATCH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\satchel.obj" : $(SOURCE) $(DEP_CPP_SATCH) "$(INTDIR)" + +"$(INTDIR)\satchel.sbr" : $(SOURCE) $(DEP_CPP_SATCH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SATCH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\satchel.obj" : $(SOURCE) $(DEP_CPP_SATCH) "$(INTDIR)" + +"$(INTDIR)\satchel.sbr" : $(SOURCE) $(DEP_CPP_SATCH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SATCH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\satchel.obj" : $(SOURCE) $(DEP_CPP_SATCH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SATCH=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\satchel.obj" : $(SOURCE) $(DEP_CPP_SATCH) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\squeakgrenade.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SQUEA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\squeakgrenade.obj" : $(SOURCE) $(DEP_CPP_SQUEA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SQUEA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\squeakgrenade.obj" : $(SOURCE) $(DEP_CPP_SQUEA) "$(INTDIR)" + +"$(INTDIR)\squeakgrenade.sbr" : $(SOURCE) $(DEP_CPP_SQUEA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SQUEA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\squeakgrenade.obj" : $(SOURCE) $(DEP_CPP_SQUEA) "$(INTDIR)" + +"$(INTDIR)\squeakgrenade.sbr" : $(SOURCE) $(DEP_CPP_SQUEA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SQUEA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\squeakgrenade.obj" : $(SOURCE) $(DEP_CPP_SQUEA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SQUEA=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\squeakgrenade.obj" : $(SOURCE) $(DEP_CPP_SQUEA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\tempmonster.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_TEMPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\tempmonster.obj" : $(SOURCE) $(DEP_CPP_TEMPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_TEMPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\tempmonster.obj" : $(SOURCE) $(DEP_CPP_TEMPM) "$(INTDIR)" + +"$(INTDIR)\tempmonster.sbr" : $(SOURCE) $(DEP_CPP_TEMPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_TEMPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\tempmonster.obj" : $(SOURCE) $(DEP_CPP_TEMPM) "$(INTDIR)" + +"$(INTDIR)\tempmonster.sbr" : $(SOURCE) $(DEP_CPP_TEMPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_TEMPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\tempmonster.obj" : $(SOURCE) $(DEP_CPP_TEMPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_TEMPM=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\tempmonster.obj" : $(SOURCE) $(DEP_CPP_TEMPM) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\tripmine.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_TRIPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tripmine.obj" : $(SOURCE) $(DEP_CPP_TRIPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_TRIPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tripmine.obj" : $(SOURCE) $(DEP_CPP_TRIPM) "$(INTDIR)" + +"$(INTDIR)\tripmine.sbr" : $(SOURCE) $(DEP_CPP_TRIPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_TRIPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tripmine.obj" : $(SOURCE) $(DEP_CPP_TRIPM) "$(INTDIR)" + +"$(INTDIR)\tripmine.sbr" : $(SOURCE) $(DEP_CPP_TRIPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_TRIPM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tripmine.obj" : $(SOURCE) $(DEP_CPP_TRIPM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_TRIPM=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tripmine.obj" : $(SOURCE) $(DEP_CPP_TRIPM) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\hornetgun.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HORNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornetgun.obj" : $(SOURCE) $(DEP_CPP_HORNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HORNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornetgun.obj" : $(SOURCE) $(DEP_CPP_HORNE) "$(INTDIR)" + +"$(INTDIR)\hornetgun.sbr" : $(SOURCE) $(DEP_CPP_HORNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HORNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornetgun.obj" : $(SOURCE) $(DEP_CPP_HORNE) "$(INTDIR)" + +"$(INTDIR)\hornetgun.sbr" : $(SOURCE) $(DEP_CPP_HORNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HORNE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornetgun.obj" : $(SOURCE) $(DEP_CPP_HORNE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HORNE=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornetgun.obj" : $(SOURCE) $(DEP_CPP_HORNE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\WXDEBUG.CPP + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_WXDEB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\wxdebug.h"\ + + +"$(INTDIR)\WXDEBUG.OBJ" : $(SOURCE) $(DEP_CPP_WXDEB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_WXDEB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\wxdebug.h"\ + + +"$(INTDIR)\WXDEBUG.OBJ" : $(SOURCE) $(DEP_CPP_WXDEB) "$(INTDIR)" + +"$(INTDIR)\WXDEBUG.SBR" : $(SOURCE) $(DEP_CPP_WXDEB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_WXDEB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\wxdebug.h"\ + + +"$(INTDIR)\WXDEBUG.OBJ" : $(SOURCE) $(DEP_CPP_WXDEB) "$(INTDIR)" + +"$(INTDIR)\WXDEBUG.SBR" : $(SOURCE) $(DEP_CPP_WXDEB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_WXDEB=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\wxdebug.h"\ + + +"$(INTDIR)\WXDEBUG.OBJ" : $(SOURCE) $(DEP_CPP_WXDEB) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_WXDEB=\ + "..\engine\const.h"\ + ".\activity.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\wxdebug.h"\ + + +"$(INTDIR)\WXDEBUG.OBJ" : $(SOURCE) $(DEP_CPP_WXDEB) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\squadmonster.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SQUAD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\squadmonster.obj" : $(SOURCE) $(DEP_CPP_SQUAD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SQUAD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\squadmonster.obj" : $(SOURCE) $(DEP_CPP_SQUAD) "$(INTDIR)" + +"$(INTDIR)\squadmonster.sbr" : $(SOURCE) $(DEP_CPP_SQUAD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SQUAD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\squadmonster.obj" : $(SOURCE) $(DEP_CPP_SQUAD) "$(INTDIR)" + +"$(INTDIR)\squadmonster.sbr" : $(SOURCE) $(DEP_CPP_SQUAD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SQUAD=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\squadmonster.obj" : $(SOURCE) $(DEP_CPP_SQUAD) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SQUAD=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\plane.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + + +"$(INTDIR)\squadmonster.obj" : $(SOURCE) $(DEP_CPP_SQUAD) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\plane.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_PLANE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\cdll_dll.h"\ + ".\extdll.h"\ + ".\plane.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plane.obj" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_PLANE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\cdll_dll.h"\ + ".\extdll.h"\ + ".\plane.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plane.obj" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)" + +"$(INTDIR)\plane.sbr" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_PLANE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\cdll_dll.h"\ + ".\extdll.h"\ + ".\plane.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plane.obj" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)" + +"$(INTDIR)\plane.sbr" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_PLANE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\cdll_dll.h"\ + ".\extdll.h"\ + ".\plane.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plane.obj" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_PLANE=\ + "..\engine\const.h"\ + ".\extdll.h"\ + ".\plane.h"\ + ".\vector.h"\ + + +"$(INTDIR)\plane.obj" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\genericmonster.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GENER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\genericmonster.obj" : $(SOURCE) $(DEP_CPP_GENER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GENER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\genericmonster.obj" : $(SOURCE) $(DEP_CPP_GENER) "$(INTDIR)" + +"$(INTDIR)\genericmonster.sbr" : $(SOURCE) $(DEP_CPP_GENER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GENER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\genericmonster.obj" : $(SOURCE) $(DEP_CPP_GENER) "$(INTDIR)" + +"$(INTDIR)\genericmonster.sbr" : $(SOURCE) $(DEP_CPP_GENER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GENER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\genericmonster.obj" : $(SOURCE) $(DEP_CPP_GENER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GENER=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\genericmonster.obj" : $(SOURCE) $(DEP_CPP_GENER) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\tentacle.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_TENTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tentacle.obj" : $(SOURCE) $(DEP_CPP_TENTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_TENTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tentacle.obj" : $(SOURCE) $(DEP_CPP_TENTA) "$(INTDIR)" + +"$(INTDIR)\tentacle.sbr" : $(SOURCE) $(DEP_CPP_TENTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_TENTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tentacle.obj" : $(SOURCE) $(DEP_CPP_TENTA) "$(INTDIR)" + +"$(INTDIR)\tentacle.sbr" : $(SOURCE) $(DEP_CPP_TENTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_TENTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tentacle.obj" : $(SOURCE) $(DEP_CPP_TENTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_TENTA=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\tentacle.obj" : $(SOURCE) $(DEP_CPP_TENTA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\leech.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_LEECH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\leech.obj" : $(SOURCE) $(DEP_CPP_LEECH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_LEECH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\leech.obj" : $(SOURCE) $(DEP_CPP_LEECH) "$(INTDIR)" + +"$(INTDIR)\leech.sbr" : $(SOURCE) $(DEP_CPP_LEECH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_LEECH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\leech.obj" : $(SOURCE) $(DEP_CPP_LEECH) "$(INTDIR)" + +"$(INTDIR)\leech.sbr" : $(SOURCE) $(DEP_CPP_LEECH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_LEECH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\leech.obj" : $(SOURCE) $(DEP_CPP_LEECH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_LEECH=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\leech.obj" : $(SOURCE) $(DEP_CPP_LEECH) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\talkmonster.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_TALKM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\talkmonster.obj" : $(SOURCE) $(DEP_CPP_TALKM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_TALKM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\talkmonster.obj" : $(SOURCE) $(DEP_CPP_TALKM) "$(INTDIR)" + +"$(INTDIR)\talkmonster.sbr" : $(SOURCE) $(DEP_CPP_TALKM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_TALKM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\talkmonster.obj" : $(SOURCE) $(DEP_CPP_TALKM) "$(INTDIR)" + +"$(INTDIR)\talkmonster.sbr" : $(SOURCE) $(DEP_CPP_TALKM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_TALKM=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\talkmonster.obj" : $(SOURCE) $(DEP_CPP_TALKM) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_TALKM=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\defaultai.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\scripted.h"\ + ".\scriptevent.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\talkmonster.h"\ + ".\util.h"\ + + +"$(INTDIR)\talkmonster.obj" : $(SOURCE) $(DEP_CPP_TALKM) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\osprey.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_OSPRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\osprey.obj" : $(SOURCE) $(DEP_CPP_OSPRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_OSPRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\osprey.obj" : $(SOURCE) $(DEP_CPP_OSPRE) "$(INTDIR)" + +"$(INTDIR)\osprey.sbr" : $(SOURCE) $(DEP_CPP_OSPRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_OSPRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\osprey.obj" : $(SOURCE) $(DEP_CPP_OSPRE) "$(INTDIR)" + +"$(INTDIR)\osprey.sbr" : $(SOURCE) $(DEP_CPP_OSPRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_OSPRE=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\customentity.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\osprey.obj" : $(SOURCE) $(DEP_CPP_OSPRE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_OSPRE=\ + "..\engine\customentity.h"\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\osprey.obj" : $(SOURCE) $(DEP_CPP_OSPRE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\apache.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_APACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\apache.obj" : $(SOURCE) $(DEP_CPP_APACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_APACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\apache.obj" : $(SOURCE) $(DEP_CPP_APACH) "$(INTDIR)" + +"$(INTDIR)\apache.sbr" : $(SOURCE) $(DEP_CPP_APACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_APACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\apache.obj" : $(SOURCE) $(DEP_CPP_APACH) "$(INTDIR)" + +"$(INTDIR)\apache.sbr" : $(SOURCE) $(DEP_CPP_APACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_APACH=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\apache.obj" : $(SOURCE) $(DEP_CPP_APACH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_APACH=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\apache.obj" : $(SOURCE) $(DEP_CPP_APACH) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mortar.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_MORTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mortar.obj" : $(SOURCE) $(DEP_CPP_MORTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_MORTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mortar.obj" : $(SOURCE) $(DEP_CPP_MORTA) "$(INTDIR)" + +"$(INTDIR)\mortar.sbr" : $(SOURCE) $(DEP_CPP_MORTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_MORTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mortar.obj" : $(SOURCE) $(DEP_CPP_MORTA) "$(INTDIR)" + +"$(INTDIR)\mortar.sbr" : $(SOURCE) $(DEP_CPP_MORTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_MORTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mortar.obj" : $(SOURCE) $(DEP_CPP_MORTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_MORTA=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\decals.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\mortar.obj" : $(SOURCE) $(DEP_CPP_MORTA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\bloater.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_BLOAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bloater.obj" : $(SOURCE) $(DEP_CPP_BLOAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_BLOAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bloater.obj" : $(SOURCE) $(DEP_CPP_BLOAT) "$(INTDIR)" + +"$(INTDIR)\bloater.sbr" : $(SOURCE) $(DEP_CPP_BLOAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_BLOAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bloater.obj" : $(SOURCE) $(DEP_CPP_BLOAT) "$(INTDIR)" + +"$(INTDIR)\bloater.sbr" : $(SOURCE) $(DEP_CPP_BLOAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_BLOAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\bloater.obj" : $(SOURCE) $(DEP_CPP_BLOAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_BLOAT=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + + +"$(INTDIR)\bloater.obj" : $(SOURCE) $(DEP_CPP_BLOAT) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\airtank.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_AIRTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\airtank.obj" : $(SOURCE) $(DEP_CPP_AIRTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_AIRTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\airtank.obj" : $(SOURCE) $(DEP_CPP_AIRTA) "$(INTDIR)" + +"$(INTDIR)\airtank.sbr" : $(SOURCE) $(DEP_CPP_AIRTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_AIRTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\airtank.obj" : $(SOURCE) $(DEP_CPP_AIRTA) "$(INTDIR)" + +"$(INTDIR)\airtank.sbr" : $(SOURCE) $(DEP_CPP_AIRTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_AIRTA=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\airtank.obj" : $(SOURCE) $(DEP_CPP_AIRTA) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_AIRTA=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\airtank.obj" : $(SOURCE) $(DEP_CPP_AIRTA) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\healthkit.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HEALT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\healthkit.obj" : $(SOURCE) $(DEP_CPP_HEALT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HEALT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\healthkit.obj" : $(SOURCE) $(DEP_CPP_HEALT) "$(INTDIR)" + +"$(INTDIR)\healthkit.sbr" : $(SOURCE) $(DEP_CPP_HEALT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HEALT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\healthkit.obj" : $(SOURCE) $(DEP_CPP_HEALT) "$(INTDIR)" + +"$(INTDIR)\healthkit.sbr" : $(SOURCE) $(DEP_CPP_HEALT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HEALT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\healthkit.obj" : $(SOURCE) $(DEP_CPP_HEALT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HEALT=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\healthkit.obj" : $(SOURCE) $(DEP_CPP_HEALT) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\nihilanth.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_NIHIL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\nihilanth.obj" : $(SOURCE) $(DEP_CPP_NIHIL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_NIHIL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\nihilanth.obj" : $(SOURCE) $(DEP_CPP_NIHIL) "$(INTDIR)" + +"$(INTDIR)\nihilanth.sbr" : $(SOURCE) $(DEP_CPP_NIHIL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_NIHIL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\nihilanth.obj" : $(SOURCE) $(DEP_CPP_NIHIL) "$(INTDIR)" + +"$(INTDIR)\nihilanth.sbr" : $(SOURCE) $(DEP_CPP_NIHIL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_NIHIL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\nihilanth.obj" : $(SOURCE) $(DEP_CPP_NIHIL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_NIHIL=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\nodes.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\nihilanth.obj" : $(SOURCE) $(DEP_CPP_NIHIL) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\aflock.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_AFLOC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\aflock.obj" : $(SOURCE) $(DEP_CPP_AFLOC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_AFLOC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\aflock.obj" : $(SOURCE) $(DEP_CPP_AFLOC) "$(INTDIR)" + +"$(INTDIR)\aflock.sbr" : $(SOURCE) $(DEP_CPP_AFLOC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_AFLOC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\aflock.obj" : $(SOURCE) $(DEP_CPP_AFLOC) "$(INTDIR)" + +"$(INTDIR)\aflock.sbr" : $(SOURCE) $(DEP_CPP_AFLOC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_AFLOC=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\aflock.obj" : $(SOURCE) $(DEP_CPP_AFLOC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_AFLOC=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + + +"$(INTDIR)\aflock.obj" : $(SOURCE) $(DEP_CPP_AFLOC) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\skill.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SKILL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\skill.obj" : $(SOURCE) $(DEP_CPP_SKILL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SKILL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\skill.obj" : $(SOURCE) $(DEP_CPP_SKILL) "$(INTDIR)" + +"$(INTDIR)\skill.sbr" : $(SOURCE) $(DEP_CPP_SKILL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SKILL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\skill.obj" : $(SOURCE) $(DEP_CPP_SKILL) "$(INTDIR)" + +"$(INTDIR)\skill.sbr" : $(SOURCE) $(DEP_CPP_SKILL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SKILL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\skill.obj" : $(SOURCE) $(DEP_CPP_SKILL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SKILL=\ + "..\engine\const.h"\ + ".\activity.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\skill.obj" : $(SOURCE) $(DEP_CPP_SKILL) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\controller.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_CONTR=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\controller.obj" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_CONTR=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\controller.obj" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)" + +"$(INTDIR)\controller.sbr" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_CONTR=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\controller.obj" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)" + +"$(INTDIR)\controller.sbr" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_CONTR=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\controller.obj" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_CONTR=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\squadmonster.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\controller.obj" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\spectator.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SPECT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\spectator.obj" : $(SOURCE) $(DEP_CPP_SPECT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SPECT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\spectator.obj" : $(SOURCE) $(DEP_CPP_SPECT) "$(INTDIR)" + +"$(INTDIR)\spectator.sbr" : $(SOURCE) $(DEP_CPP_SPECT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SPECT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\spectator.obj" : $(SOURCE) $(DEP_CPP_SPECT) "$(INTDIR)" + +"$(INTDIR)\spectator.sbr" : $(SOURCE) $(DEP_CPP_SPECT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SPECT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\spectator.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\spectator.obj" : $(SOURCE) $(DEP_CPP_SPECT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SPECT=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\spectator.h"\ + ".\util.h"\ + + +"$(INTDIR)\spectator.obj" : $(SOURCE) $(DEP_CPP_SPECT) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\gman.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GMAN_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gman.obj" : $(SOURCE) $(DEP_CPP_GMAN_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GMAN_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gman.obj" : $(SOURCE) $(DEP_CPP_GMAN_) "$(INTDIR)" + +"$(INTDIR)\gman.sbr" : $(SOURCE) $(DEP_CPP_GMAN_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GMAN_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gman.obj" : $(SOURCE) $(DEP_CPP_GMAN_) "$(INTDIR)" + +"$(INTDIR)\gman.sbr" : $(SOURCE) $(DEP_CPP_GMAN_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GMAN_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gman.obj" : $(SOURCE) $(DEP_CPP_GMAN_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GMAN_=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gman.obj" : $(SOURCE) $(DEP_CPP_GMAN_) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\gamerules.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GAMER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gamerules.obj" : $(SOURCE) $(DEP_CPP_GAMER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GAMER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gamerules.obj" : $(SOURCE) $(DEP_CPP_GAMER) "$(INTDIR)" + +"$(INTDIR)\gamerules.sbr" : $(SOURCE) $(DEP_CPP_GAMER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GAMER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gamerules.obj" : $(SOURCE) $(DEP_CPP_GAMER) "$(INTDIR)" + +"$(INTDIR)\gamerules.sbr" : $(SOURCE) $(DEP_CPP_GAMER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GAMER=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gamerules.obj" : $(SOURCE) $(DEP_CPP_GAMER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GAMER=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\gamerules.obj" : $(SOURCE) $(DEP_CPP_GAMER) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\xen.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_XEN_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\xen.obj" : $(SOURCE) $(DEP_CPP_XEN_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_XEN_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\xen.obj" : $(SOURCE) $(DEP_CPP_XEN_C) "$(INTDIR)" + +"$(INTDIR)\xen.sbr" : $(SOURCE) $(DEP_CPP_XEN_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_XEN_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\xen.obj" : $(SOURCE) $(DEP_CPP_XEN_C) "$(INTDIR)" + +"$(INTDIR)\xen.sbr" : $(SOURCE) $(DEP_CPP_XEN_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_XEN_C=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\xen.obj" : $(SOURCE) $(DEP_CPP_XEN_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_XEN_C=\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + + +"$(INTDIR)\xen.obj" : $(SOURCE) $(DEP_CPP_XEN_C) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\func_tank.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_FUNC_T=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\func_tank.obj" : $(SOURCE) $(DEP_CPP_FUNC_T) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_FUNC_T=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\func_tank.obj" : $(SOURCE) $(DEP_CPP_FUNC_T) "$(INTDIR)" + +"$(INTDIR)\func_tank.sbr" : $(SOURCE) $(DEP_CPP_FUNC_T) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_FUNC_T=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\func_tank.obj" : $(SOURCE) $(DEP_CPP_FUNC_T) "$(INTDIR)" + +"$(INTDIR)\func_tank.sbr" : $(SOURCE) $(DEP_CPP_FUNC_T) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_FUNC_T=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\func_tank.obj" : $(SOURCE) $(DEP_CPP_FUNC_T) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_FUNC_T=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\effects.h"\ + ".\enginecallback.h"\ + ".\explode.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\func_tank.obj" : $(SOURCE) $(DEP_CPP_FUNC_T) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\hornet.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_HORNET=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornet.obj" : $(SOURCE) $(DEP_CPP_HORNET) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_HORNET=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornet.obj" : $(SOURCE) $(DEP_CPP_HORNET) "$(INTDIR)" + +"$(INTDIR)\hornet.sbr" : $(SOURCE) $(DEP_CPP_HORNET) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_HORNET=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornet.obj" : $(SOURCE) $(DEP_CPP_HORNET) "$(INTDIR)" + +"$(INTDIR)\hornet.sbr" : $(SOURCE) $(DEP_CPP_HORNET) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_HORNET=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornet.obj" : $(SOURCE) $(DEP_CPP_HORNET) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_HORNET=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\hornet.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\monsters.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\soundent.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\hornet.obj" : $(SOURCE) $(DEP_CPP_HORNET) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\teamplay_gamerules.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_TEAMP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\teamplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_TEAMP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_TEAMP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\teamplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_TEAMP) "$(INTDIR)" + +"$(INTDIR)\teamplay_gamerules.sbr" : $(SOURCE) $(DEP_CPP_TEAMP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_TEAMP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\teamplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_TEAMP) "$(INTDIR)" + +"$(INTDIR)\teamplay_gamerules.sbr" : $(SOURCE) $(DEP_CPP_TEAMP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_TEAMP=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\teamplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_TEAMP) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_TEAMP=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\teamplay_gamerules.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\teamplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_TEAMP) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\multiplay_gamerules.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_MULTI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\multiplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_MULTI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_MULTI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\multiplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_MULTI) "$(INTDIR)" + +"$(INTDIR)\multiplay_gamerules.sbr" : $(SOURCE) $(DEP_CPP_MULTI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_MULTI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\multiplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_MULTI) "$(INTDIR)" + +"$(INTDIR)\multiplay_gamerules.sbr" : $(SOURCE) $(DEP_CPP_MULTI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_MULTI=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\multiplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_MULTI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_MULTI=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\multiplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_MULTI) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\singleplay_gamerules.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_SINGL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\singleplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_SINGL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_SINGL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\singleplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_SINGL) "$(INTDIR)" + +"$(INTDIR)\singleplay_gamerules.sbr" : $(SOURCE) $(DEP_CPP_SINGL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_SINGL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\singleplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_SINGL) "$(INTDIR)" + +"$(INTDIR)\singleplay_gamerules.sbr" : $(SOURCE) $(DEP_CPP_SINGL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_SINGL=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\vector.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\singleplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_SINGL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_SINGL=\ + ".\activity.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\items.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\skill.h"\ + ".\util.h"\ + ".\weapons.h"\ + + +"$(INTDIR)\singleplay_gamerules.obj" : $(SOURCE) $(DEP_CPP_SINGL) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\game.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_GAME_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\game.obj" : $(SOURCE) $(DEP_CPP_GAME_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_GAME_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\game.obj" : $(SOURCE) $(DEP_CPP_GAME_) "$(INTDIR)" + +"$(INTDIR)\game.sbr" : $(SOURCE) $(DEP_CPP_GAME_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_GAME_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\game.obj" : $(SOURCE) $(DEP_CPP_GAME_) "$(INTDIR)" + +"$(INTDIR)\game.sbr" : $(SOURCE) $(DEP_CPP_GAME_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_GAME_=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\game.obj" : $(SOURCE) $(DEP_CPP_GAME_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_GAME_=\ + "..\common\cvardef.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\eiface.h"\ + ".\activity.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\game.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\game.obj" : $(SOURCE) $(DEP_CPP_GAME_) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\maprules.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_MAPRU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\maprules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\maprules.obj" : $(SOURCE) $(DEP_CPP_MAPRU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_MAPRU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\maprules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\maprules.obj" : $(SOURCE) $(DEP_CPP_MAPRU) "$(INTDIR)" + +"$(INTDIR)\maprules.sbr" : $(SOURCE) $(DEP_CPP_MAPRU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_MAPRU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\maprules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\maprules.obj" : $(SOURCE) $(DEP_CPP_MAPRU) "$(INTDIR)" + +"$(INTDIR)\maprules.sbr" : $(SOURCE) $(DEP_CPP_MAPRU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_MAPRU=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\maprules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\maprules.obj" : $(SOURCE) $(DEP_CPP_MAPRU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_MAPRU=\ + "..\common\cvardef.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\eiface.h"\ + ".\activity.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\gamerules.h"\ + ".\maprules.h"\ + ".\monsterevent.h"\ + ".\player.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\maprules.obj" : $(SOURCE) $(DEP_CPP_MAPRU) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\animating.cpp + +!IF "$(CFG)" == "hl - Win32 Release" + +DEP_CPP_ANIMAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\animating.obj" : $(SOURCE) $(DEP_CPP_ANIMAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + +DEP_CPP_ANIMAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\animating.obj" : $(SOURCE) $(DEP_CPP_ANIMAT) "$(INTDIR)" + +"$(INTDIR)\animating.sbr" : $(SOURCE) $(DEP_CPP_ANIMAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + +DEP_CPP_ANIMAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\animating.obj" : $(SOURCE) $(DEP_CPP_ANIMAT) "$(INTDIR)" + +"$(INTDIR)\animating.sbr" : $(SOURCE) $(DEP_CPP_ANIMAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +DEP_CPP_ANIMAT=\ + "..\common\const.h"\ + "..\common\cvardef.h"\ + "..\common\in_buttons.h"\ + "..\engine\../common/crc.h"\ + "..\engine\custom.h"\ + "..\engine\edict.h"\ + "..\engine\eiface.h"\ + "..\engine\progdefs.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\basemonster.h"\ + ".\cbase.h"\ + ".\cdll_dll.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\animating.obj" : $(SOURCE) $(DEP_CPP_ANIMAT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + +DEP_CPP_ANIMAT=\ + "..\engine\const.h"\ + ".\activity.h"\ + ".\animation.h"\ + ".\cbase.h"\ + ".\enginecallback.h"\ + ".\extdll.h"\ + ".\monsterevent.h"\ + ".\saverestore.h"\ + ".\schedule.h"\ + ".\util.h"\ + ".\vector.h"\ + + +"$(INTDIR)\animating.obj" : $(SOURCE) $(DEP_CPP_ANIMAT) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quiver\goldsrc\pm_shared\pm_shared.c +DEP_CPP_PM_SH=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\common\mathlib.h"\ + "..\common\usercmd.h"\ + "..\engine\pmtrace.h"\ + "..\pm_shared\pm_debug.h"\ + "..\pm_shared\pm_defs.h"\ + "..\pm_shared\pm_info.h"\ + "..\pm_shared\pm_movevars.h"\ + "..\pm_shared\pm_shared.h"\ + + +!IF "$(CFG)" == "hl - Win32 Release" + + +"$(INTDIR)\pm_shared.obj" : $(SOURCE) $(DEP_CPP_PM_SH) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + + +BuildCmds= \ + $(CPP) $(CPP_PROJ) $(SOURCE) \ + + +"$(INTDIR)\pm_shared.obj" : $(SOURCE) $(DEP_CPP_PM_SH) "$(INTDIR)" + $(BuildCmds) + +"$(INTDIR)\pm_shared.sbr" : $(SOURCE) $(DEP_CPP_PM_SH) "$(INTDIR)" + $(BuildCmds) + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + + +BuildCmds= \ + $(CPP) $(CPP_PROJ) $(SOURCE) \ + + +"$(INTDIR)\pm_shared.obj" : $(SOURCE) $(DEP_CPP_PM_SH) "$(INTDIR)" + $(BuildCmds) + +"$(INTDIR)\pm_shared.sbr" : $(SOURCE) $(DEP_CPP_PM_SH) "$(INTDIR)" + $(BuildCmds) + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + + +"$(INTDIR)\pm_shared.obj" : $(SOURCE) $(DEP_CPP_PM_SH) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + + +"$(INTDIR)\pm_shared.obj" : $(SOURCE) $(DEP_CPP_PM_SH) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quiver\goldsrc\pm_shared\pm_math.c +DEP_CPP_PM_MA=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\common\mathlib.h"\ + + +!IF "$(CFG)" == "hl - Win32 Release" + + +"$(INTDIR)\pm_math.obj" : $(SOURCE) $(DEP_CPP_PM_MA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + + +BuildCmds= \ + $(CPP) $(CPP_PROJ) $(SOURCE) \ + + +"$(INTDIR)\pm_math.obj" : $(SOURCE) $(DEP_CPP_PM_MA) "$(INTDIR)" + $(BuildCmds) + +"$(INTDIR)\pm_math.sbr" : $(SOURCE) $(DEP_CPP_PM_MA) "$(INTDIR)" + $(BuildCmds) + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + + +BuildCmds= \ + $(CPP) $(CPP_PROJ) $(SOURCE) \ + + +"$(INTDIR)\pm_math.obj" : $(SOURCE) $(DEP_CPP_PM_MA) "$(INTDIR)" + $(BuildCmds) + +"$(INTDIR)\pm_math.sbr" : $(SOURCE) $(DEP_CPP_PM_MA) "$(INTDIR)" + $(BuildCmds) + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + + +"$(INTDIR)\pm_math.obj" : $(SOURCE) $(DEP_CPP_PM_MA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + + +"$(INTDIR)\pm_math.obj" : $(SOURCE) $(DEP_CPP_PM_MA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quiver\goldsrc\pm_shared\pm_debug.c +DEP_CPP_PM_DE=\ + "..\common\const.h"\ + "..\common\in_buttons.h"\ + "..\common\mathlib.h"\ + "..\common\usercmd.h"\ + "..\engine\pmtrace.h"\ + "..\pm_shared\pm_debug.h"\ + "..\pm_shared\pm_defs.h"\ + "..\pm_shared\pm_info.h"\ + "..\pm_shared\pm_movevars.h"\ + "..\pm_shared\pm_shared.h"\ + + +!IF "$(CFG)" == "hl - Win32 Release" + + +"$(INTDIR)\pm_debug.obj" : $(SOURCE) $(DEP_CPP_PM_DE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "hl - Win32 Debug" + + +BuildCmds= \ + $(CPP) $(CPP_PROJ) $(SOURCE) \ + + +"$(INTDIR)\pm_debug.obj" : $(SOURCE) $(DEP_CPP_PM_DE) "$(INTDIR)" + $(BuildCmds) + +"$(INTDIR)\pm_debug.sbr" : $(SOURCE) $(DEP_CPP_PM_DE) "$(INTDIR)" + $(BuildCmds) + +!ELSEIF "$(CFG)" == "hl - Win32 Germany" + + +BuildCmds= \ + $(CPP) $(CPP_PROJ) $(SOURCE) \ + + +"$(INTDIR)\pm_debug.obj" : $(SOURCE) $(DEP_CPP_PM_DE) "$(INTDIR)" + $(BuildCmds) + +"$(INTDIR)\pm_debug.sbr" : $(SOURCE) $(DEP_CPP_PM_DE) "$(INTDIR)" + $(BuildCmds) + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + + +"$(INTDIR)\pm_debug.obj" : $(SOURCE) $(DEP_CPP_PM_DE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "hl - Win32 HLDEMO Release" + + +"$(INTDIR)\pm_debug.obj" : $(SOURCE) $(DEP_CPP_PM_DE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/dlls/hlgl.def b/dlls/hlgl.def new file mode 100644 index 0000000..883f3e5 --- /dev/null +++ b/dlls/hlgl.def @@ -0,0 +1,15 @@ +LIBRARY hlgl +EXPORTS + GiveFnptrsToDll @1 + GetEntityInterfaces @2 + SetChangeParms @3 + SetNewParms @4 + ClientKill @5 + PutClientInServer @6 + PlayerPreThink @7 + PlayerPostThink @8 + ClientConnect @9 + ClientDisconnect @10 + StartFrame @11 +SECTIONS + .data READ WRITE diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index 3165f0a..a0b03c2 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -100,13 +100,6 @@ void CHornet :: Spawn( void ) if ( !pSoundEnt ) pSoundEnt = edict(); - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM); break; - } - if ( !FNullEnt(pev->owner) && (pev->owner->v.flags & FL_CLIENT) ) { pev->dmg = gSkillData.plrDmgHornet; @@ -409,11 +402,11 @@ void CHornet::DieTouch ( CBaseEntity *pOther ) 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 fe7c9a1..2145c76 100644 --- a/dlls/hornet.h +++ b/dlls/hornet.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index 0a5800a..e6d1b2d 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -34,28 +34,13 @@ enum hgun_e { HGUN_SHOOT }; -class CHgun : public CBasePlayerWeapon +enum firemode_e { -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 4; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( void ); - BOOL IsUseable( void ); - void Holster( int skiplocal = 0 ); - void Reload( void ); - void WeaponIdle( void ); - float m_flNextAnimTime; - - float m_flRechargeTime; - - int m_iFirePhase;// don't save me. + FIREMODE_TRACK = 0, + FIREMODE_FAST }; + + LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun ); BOOL CHgun::IsUseable( void ) @@ -82,6 +67,8 @@ void CHgun::Precache( void ) PRECACHE_MODEL("models/w_hgun.mdl"); PRECACHE_MODEL("models/p_hgun.mdl"); + m_usHornetFire = PRECACHE_EVENT ( 1, "events/firehornet.sc" ); + UTIL_PrecacheOther("hornet"); } @@ -89,11 +76,14 @@ 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 ); @@ -129,7 +119,6 @@ BOOL CHgun::Deploy( ) void CHgun::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - // m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); SendWeaponAnim( HGUN_DOWN ); //!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either. @@ -149,30 +138,43 @@ void CHgun::PrimaryAttack() 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_flRechargeTime = gpGlobals->time + 0.5; + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - SendWeaponAnim( HGUN_SHOOT ); + 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 < gpGlobals->time) + if (m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) { - m_flNextPrimaryAttack = gpGlobals->time + 0.25; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; } - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -186,6 +188,8 @@ void CHgun::SecondaryAttack( void ) return; } + //Wouldn't be a bad idea to completely predict these, since they fly so fast... +#ifndef CLIENT_DLL CBaseEntity *pHornet; Vector vecSrc; @@ -233,20 +237,28 @@ void CHgun::SecondaryAttack( void ) 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; - m_flRechargeTime = gpGlobals->time + 0.5; - - SendWeaponAnim( HGUN_SHOOT ); - - // player "shoot" animation + // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + 0.1; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 ); + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; + m_flTimeWeaponIdle = gpGlobals->time + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -271,21 +283,21 @@ void CHgun::WeaponIdle( void ) return; int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.75) { iAnim = HGUN_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + 30.0 / 16 * (2); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); } else if (flRand <= 0.875) { iAnim = HGUN_FIDGETSWAY; - m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; } else { iAnim = HGUN_FIDGETSHAKE; - m_flTimeWeaponIdle = gpGlobals->time + 35.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 35.0 / 16.0; } SendWeaponAnim( iAnim ); } diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp new file mode 100644 index 0000000..ae5c9ec --- /dev/null +++ b/dlls/houndeye.cpp @@ -0,0 +1,1304 @@ +/*** +* +* 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. +* +* 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 0000000..e793c7f --- /dev/null +++ b/dlls/ichthyosaur.cpp @@ -0,0 +1,1108 @@ +/*** +* +* 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. +* +* 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 0000000..a42ece2 --- /dev/null +++ b/dlls/islave.cpp @@ -0,0 +1,866 @@ +/*** +* +* 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. +* +* 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 69b11ed..31220a7 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -217,6 +217,11 @@ class CItemBattery : public CItem } BOOL MyTouch( CBasePlayer *pPlayer ) { + if ( pPlayer->pev->deadflag != DEAD_NO ) + { + return FALSE; + } + if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && (pPlayer->pev->weapons & (1<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 ); + 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( DeadThink ); +} + + diff --git a/dlls/lights.cpp b/dlls/lights.cpp index 925acf8..ef195c2 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -196,4 +196,4 @@ void CEnvLight :: Spawn( void ) CVAR_SET_STRING( "sv_skyvec_z", szVector ); CLight::Spawn( ); -} \ No newline at end of file +} diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp index bc3b5ba..20f8b85 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/maprules.h b/dlls/maprules.h index 636ab2e..8b4867c 100644 --- a/dlls/maprules.h +++ b/dlls/maprules.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/monsterevent.h b/dlls/monsterevent.h index b8dbcab..34de446 100644 --- a/dlls/monsterevent.h +++ b/dlls/monsterevent.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp new file mode 100644 index 0000000..5bb1e69 --- /dev/null +++ b/dlls/monstermaker.cpp @@ -0,0 +1,292 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 + 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 ( 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 0000000..ddf592f --- /dev/null +++ b/dlls/monsters.cpp @@ -0,0 +1,3448 @@ +/*** +* +* 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. +* +* 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", 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 ) + { + 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; +} + +//========================================================= +// 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 d245b7b..258f5a9 100644 --- a/dlls/monsters.h +++ b/dlls/monsters.h @@ -1,15 +1,15 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. +* 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 @@ -24,6 +24,11 @@ */ +// 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 @@ -35,6 +40,35 @@ #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 ); @@ -59,7 +93,50 @@ BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTarget #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. @@ -85,4 +162,22 @@ public: }; +#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 0000000..775bcda --- /dev/null +++ b/dlls/monsterstate.cpp @@ -0,0 +1,234 @@ +/*** +* +* 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. +* +* 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 ffc4456..64dbeb1 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 6f3f622..5626bc7 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -36,26 +36,7 @@ enum mp5_e }; -class CMP5 : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 3; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - void PrimaryAttack( void ); - void SecondaryAttack( void ); - int SecondaryAmmoIndex( void ); - BOOL Deploy( void ); - void Reload( void ); - void WeaponIdle( void ); - float m_flNextAnimTime; - int m_iShell; -private: - unsigned short m_usMP5; -}; LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ); LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ); @@ -95,7 +76,6 @@ void CMP5::Precache( void ) PRECACHE_SOUND("items/clipinsert1.wav"); PRECACHE_SOUND("items/cliprelease1.wav"); -// PRECACHE_SOUND("items/guncock1.wav"); PRECACHE_SOUND ("weapons/hks1.wav");// H to the K PRECACHE_SOUND ("weapons/hks2.wav");// H to the K @@ -107,6 +87,7 @@ void CMP5::Precache( void ) 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) @@ -150,59 +131,77 @@ void CMP5::PrimaryAttack() if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = gpGlobals->time + 0.15; + m_flNextPrimaryAttack = 0.15; return; } if (m_iClip <= 0) { PlayEmptySound(); - m_flNextPrimaryAttack = gpGlobals->time + 0.15; + m_flNextPrimaryAttack = 0.15; return; } - PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usMP5 ); - 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 ); - - if ( g_pGameRules->IsDeathmatch() ) + 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 - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2 ); + 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 - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2 ); + 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 = m_flNextPrimaryAttack + 0.1; - if (m_flNextPrimaryAttack < gpGlobals->time) - m_flNextPrimaryAttack = gpGlobals->time + 0.1; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + 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 = gpGlobals->time + 0.15; + m_flNextPrimaryAttack = 0.15; return; } @@ -216,58 +215,54 @@ void CMP5::SecondaryAttack( void ) m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; - m_pPlayer->m_flStopExtraSoundTime = gpGlobals->time + 0.2; + m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--; - SendWeaponAnim( MP5_LAUNCH ); - // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - if ( RANDOM_LONG(0,1) ) - { - // play this sound through BODY channel so we can hear it if player didn't stop firing MP3 - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM); - } - else - { - // play this sound through BODY channel so we can hear it if player didn't stop firing MP3 - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/glauncher2.wav", 0.8, ATTN_NORM); - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + 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 = gpGlobals->time + 1; - m_flNextSecondaryAttack = gpGlobals->time + 1; - m_flTimeWeaponIdle = gpGlobals->time + 5;// idle pretty soon after shooting. + 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); - - m_pPlayer->pev->punchangle.x -= 10; } 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 > gpGlobals->time) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; int iAnim; @@ -285,7 +280,7 @@ void CMP5::WeaponIdle( void ) SendWeaponAnim( iAnim ); - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );// how long till we do this again. + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. } diff --git a/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index b01e53b..48e8f96 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 89368b1..6d19bee 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -21,28 +21,58 @@ #include "player.h" #include "weapons.h" #include "gamerules.h" + #include "skill.h" #include "game.h" #include "items.h" +#include "voice_gamemgr.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 @@ -83,6 +113,14 @@ CHalfLifeMultiplay :: CHalfLifeMultiplay() } } +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 ) @@ -140,10 +178,15 @@ void CHalfLifeMultiplay::RefreshSkillData( void ) #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; @@ -153,20 +196,31 @@ void CHalfLifeMultiplay :: Think ( void ) if ( g_fGameOver ) // someone else quit the game already { + // bounds check + int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); + if ( time < 10 ) + CVAR_SET_STRING( "mp_chattime", "10" ); + 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 - || ((m_flIntermissionEndTime + MAX_INTERMISSION_TIME) < gpGlobals->time) ) + || ( ( 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); + time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) { GoToIntermission(); @@ -342,6 +396,7 @@ BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerI //========================================================= BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) { + g_VoiceGameMgr.ClientConnected(pEntity); return TRUE; } @@ -361,7 +416,23 @@ void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) 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" ) ); - UTIL_LogPrintf( "\"%s<%i>\" has entered the game\n", STRING( pl->pev->netname ), GETPLAYERUSERID( pl->edict() ) ); + // team match? + if ( g_teamplay ) + { + UTIL_LogPrintf( "\"%s<%i><%u><%s>\" entered the game\n", + STRING( pl->pev->netname ), + GETPLAYERUSERID( pl->edict() ), + GETPLAYERWONID( pl->edict() ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pl->edict() ), "model" ) ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%u><%i>\" entered the game\n", + STRING( pl->pev->netname ), + GETPLAYERUSERID( pl->edict() ), + GETPLAYERWONID( pl->edict() ), + GETPLAYERUSERID( pl->edict() ) ); + } UpdateGameMode( pl ); @@ -371,6 +442,8 @@ void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) WRITE_BYTE( ENTINDEX(pl->edict()) ); WRITE_SHORT( 0 ); WRITE_SHORT( 0 ); + WRITE_SHORT( 0 ); + WRITE_SHORT( 0 ); MESSAGE_END(); SendMOTDToClient( pl->edict() ); @@ -387,6 +460,8 @@ void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) 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(); } } @@ -409,7 +484,24 @@ void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) if ( pPlayer ) { FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); - UTIL_LogPrintf( "\"%s<%i>\" disconnected\n", STRING( pPlayer->pev->netname ), GETPLAYERUSERID( pPlayer->edict() ) ); + + // team match? + if ( g_teamplay ) + { + UTIL_LogPrintf( "\"%s<%i><%u><%s>\" disconnected\n", + STRING( pPlayer->pev->netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERWONID( pPlayer->edict() ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ) ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%u><%i>\" disconnected\n", + STRING( pPlayer->pev->netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERWONID( pPlayer->edict() ), + GETPLAYERUSERID( pPlayer->edict() ) ); + } pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items } @@ -420,7 +512,7 @@ void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) //========================================================= float CHalfLifeMultiplay :: FlPlayerFallDamage( CBasePlayer *pPlayer ) { - int iFallDamage = (int)CVAR_GET_FLOAT("mp_falldamage"); + int iFallDamage = (int)falldamage.value; switch ( iFallDamage ) { @@ -500,7 +592,7 @@ float CHalfLifeMultiplay :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) BOOL CHalfLifeMultiplay :: AllowAutoTargetCrosshair( void ) { - return ( CVAR_GET_FLOAT( "mp_autocrosshair" ) != 0 ); + return ( aimcrosshair.value != 0 ); } //========================================================= @@ -551,6 +643,8 @@ void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKille 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 @@ -563,6 +657,8 @@ void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKille 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. @@ -639,22 +735,94 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, killer_weapon_name = tau; if ( pVictim->pev == pKiller ) - { // killed self - UTIL_LogPrintf( "\"%s<%i>\" killed self with %s\n", STRING( pVictim->pev->netname ), GETPLAYERUSERID( pVictim->edict() ), killer_weapon_name ); + { + // killed self + + // team match? + if ( g_teamplay ) + { + UTIL_LogPrintf( "\"%s<%i><%u><%s>\" committed suicide with \"%s\"\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERWONID( pVictim->edict() ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), + killer_weapon_name ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%u><%i>\" committed suicide with \"%s\"\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERWONID( pVictim->edict() ), + GETPLAYERUSERID( pVictim->edict() ), + killer_weapon_name ); + } } else if ( pKiller->flags & FL_CLIENT ) { - UTIL_LogPrintf( "\"%s<%i>\" killed \"%s<%i>\" with %s\n", STRING( pKiller->netname ), - GETPLAYERUSERID( ENT(pKiller) ), - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - killer_weapon_name ); + // team match? + if ( g_teamplay ) + { + UTIL_LogPrintf( "\"%s<%i><%u><%s>\" killed \"%s<%i><%u><%s>\" with \"%s\"\n", + STRING( pKiller->netname ), + GETPLAYERUSERID( ENT(pKiller) ), + GETPLAYERWONID( ENT(pKiller) ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( ENT(pKiller) ), "model" ), + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERWONID( pVictim->edict() ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), + killer_weapon_name ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%u><%i>\" killed \"%s<%i><%u><%i>\" with \"%s\"\n", + STRING( pKiller->netname ), + GETPLAYERUSERID( ENT(pKiller) ), + GETPLAYERWONID( ENT(pKiller) ), + GETPLAYERUSERID( ENT(pKiller) ), + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERWONID( pVictim->edict() ), + GETPLAYERUSERID( pVictim->edict() ), + killer_weapon_name ); + } } else - { // killed by the world - UTIL_LogPrintf( "\"%s<%i>\" killed by world with %s\n", STRING( pVictim->pev->netname ), GETPLAYERUSERID( pVictim->edict() ), killer_weapon_name ); + { + // killed by the world + + // team match? + if ( g_teamplay ) + { + UTIL_LogPrintf( "\"%s<%i><%u><%s>\" committed suicide with \"%s\" (world)\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERWONID( pVictim->edict() ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), + killer_weapon_name ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%u><%i>\" committed suicide with \"%s\" (world)\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERWONID( pVictim->edict() ), + GETPLAYERUSERID( pVictim->edict() ), + killer_weapon_name ); + } } + MESSAGE_BEGIN( MSG_SPEC, SVC_HLTV ); + WRITE_BYTE ( DRC_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 @@ -719,7 +887,7 @@ void CHalfLifeMultiplay :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerIte //========================================================= float CHalfLifeMultiplay :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) { - if ( CVAR_GET_FLOAT("mp_weaponstay") > 0 ) + if ( weaponstay.value > 0 ) { // make sure it's only certain weapons if ( !(pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) @@ -783,7 +951,7 @@ int CHalfLifeMultiplay :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) //========================================================= BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) { - if ( CVAR_GET_FLOAT("mp_weaponstay") > 0 ) + if ( weaponstay.value > 0 ) { if ( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) return CGameRules::CanHavePlayerItem( pPlayer, pItem ); @@ -953,14 +1121,14 @@ BOOL CHalfLifeMultiplay :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) BOOL CHalfLifeMultiplay :: FAllowFlashlight( void ) { - return CVAR_GET_FLOAT( "mp_flashlight" ) != 0; + return flashlight.value != 0; } //========================================================= //========================================================= BOOL CHalfLifeMultiplay :: FAllowMonsters( void ) { - return ( CVAR_GET_FLOAT( "mp_allowmonsters" ) != 0 ); + return ( allowmonsters.value != 0 ); } //========================================================= @@ -975,7 +1143,16 @@ void CHalfLifeMultiplay :: GoToIntermission( void ) MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); MESSAGE_END(); - m_flIntermissionEndTime = gpGlobals->time + INTERMISSION_TIME; + // bounds check + int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); + if ( time < 10 ) + CVAR_SET_STRING( "mp_chattime", "10" ); + 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; } @@ -1127,6 +1304,8 @@ int COM_TokenWaiting( char *buffer ) return 0; } + + /* ============== ReloadMapCycleFile @@ -1218,7 +1397,6 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); } - } FREE_FILE( aFileList ); @@ -1469,14 +1647,19 @@ void CHalfLifeMultiplay :: ChangeLevel( void ) } #define MAX_MOTD_CHUNK 60 -#define MAX_MOTD_LENGTH (MAX_MOTD_CHUNK * 4) +#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( "motd.txt", &length ); + 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 diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp new file mode 100644 index 0000000..fc4b3d2 --- /dev/null +++ b/dlls/nihilanth.cpp @@ -0,0 +1,1836 @@ +/*** +* +* 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. +* +* 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) + { + 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( 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) + { + 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( 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 ); + } + + 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 \ No newline at end of file diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp new file mode 100644 index 0000000..4690ac5 --- /dev/null +++ b/dlls/nodes.cpp @@ -0,0 +1,3640 @@ +/*** +* +* 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. +* +* 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 +#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 index 6bc7c89..724e7bf 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -1,54 +1,374 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. +* 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 //========================================================= -#ifndef NODES_H -#define NODES_H +//========================================================= +// DEFINE +//========================================================= +#define MAX_STACK_NODES 100 +#define NO_NODE -1 +#define MAX_NODE_HULLS 4 -#define bits_NODE_GROUP_REALM 1 +#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? - int m_cLinks;// total number of links + 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 ShowNodeConnections ( int iNode ); - int FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ); - int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ); + 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); }; -extern CGraph WorldGraph; +//========================================================= +// 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, -#endif // NODES_H \ No newline at end of file + 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 0000000..1ee91e9 --- /dev/null +++ b/dlls/osprey.cpp @@ -0,0 +1,805 @@ +/*** +* +* 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. +* +* 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) + { + 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 1d0ff3e..f9e56c3 100644 --- a/dlls/pathcorner.cpp +++ b/dlls/pathcorner.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/plane.cpp b/dlls/plane.cpp index 06bfa46..c96bf46 100644 --- a/dlls/plane.cpp +++ b/dlls/plane.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -13,7 +13,6 @@ * ****/ #include "extdll.h" -#include "util.h" #include "plane.h" //========================================================= diff --git a/dlls/plane.h b/dlls/plane.h index 918cc02..ea2aa33 100644 --- a/dlls/plane.h +++ b/dlls/plane.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 16a0c3d..d447790 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/player.cpp b/dlls/player.cpp index 6752b96..95057d9 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -30,9 +30,10 @@ #include "weapons.h" #include "soundent.h" #include "monsters.h" -#include "../engine/shake.h" +#include "shake.h" #include "decals.h" #include "gamerules.h" +#include "game.h" // #define DUCKFIX @@ -41,20 +42,18 @@ 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 ); -int MapTextureTypeStepType(char chTextureType); // the world node graph extern CGraph WorldGraph; -#define PLAYER_WALLJUMP_SPEED 300 // how fast we can spring off walls -#define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump - #define TRAIN_ACTIVE 0x80 #define TRAIN_NEW 0xc0 #define TRAIN_OFF 0x00 @@ -67,12 +66,6 @@ extern CGraph WorldGraph; #define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes #define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit) - -//#define PLAYER_MAX_SAFE_FALL_DIST 20// falling any farther than this many feet will inflict damage -//#define PLAYER_FATAL_FALL_DIST 60// 100% damage inflicted if player falls this many feet -//#define DAMAGE_PER_UNIT_FALLEN (float)( 100 ) / ( ( PLAYER_FATAL_FALL_DIST - PLAYER_MAX_SAFE_FALL_DIST ) * 12 ) -//#define MAX_SAFE_FALL_UNITS ( PLAYER_MAX_SAFE_FALL_DIST * 12 ) - // Global Savedata for player TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = { @@ -177,6 +170,7 @@ int gmsgTeamInfo = 0; int gmsgTeamScore = 0; int gmsgGameMode = 0; int gmsgMOTD = 0; +int gmsgServerName = 0; int gmsgAmmoPickup = 0; int gmsgWeapPickup = 0; int gmsgItemPickup = 0; @@ -187,6 +181,7 @@ int gmsgTextMsg = 0; int gmsgSetFOV = 0; int gmsgShowMenu = 0; int gmsgGeigerRange = 0; +int gmsgTeamNames = 0; void LinkUserMessages( void ) { @@ -213,11 +208,12 @@ void LinkUserMessages( void ) 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", 5 ); + 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 ); @@ -227,6 +223,7 @@ void LinkUserMessages( void ) 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 ); } LINK_ENTITY_TO_CLASS( player, CBasePlayer ); @@ -377,6 +374,7 @@ Vector CBasePlayer :: GetGunPosition( ) Vector origin; origin = pev->origin + pev->view_ofs; + return origin; } @@ -504,6 +502,14 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, m_rgbTimeBasedDamage[i] = 0; } + // tell director about it + MESSAGE_BEGIN( MSG_SPEC, SVC_HLTV ); + WRITE_BYTE ( DRC_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? @@ -843,13 +849,9 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) { CSound *pSound; - #ifdef PERSISTENCE_SAMPLE - // PERSISTENCE_TODO: - // Log other changes to the player's persistence info like this. - - // Update the persistence database. - m_PersistenceInfo.IncField_PlayerInfo_NumKills(); - #endif + // Holster weapon immediately, to allow it to cleanup + if ( m_pActiveItem ) + m_pActiveItem->Holster( ); g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); @@ -869,14 +871,14 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) } 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); + ClearBits( pev->flags, FL_ONGROUND ); if (pev->velocity.z < 10) pev->velocity.z += RANDOM_FLOAT(0,300); @@ -897,7 +899,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) MESSAGE_END(); // reset FOV - m_iFOV = m_iClientFOV = 0; + pev->fov = m_iFOV = m_iClientFOV = 0; MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); WRITE_BYTE(0); @@ -1096,6 +1098,25 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) 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" ) ); +} + /* =========== @@ -1181,17 +1202,6 @@ void CBasePlayer::WaterMove() { if (FBitSet(pev->flags, FL_INWATER)) { -#if 0 - // play leave water sound - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM); break; - } -#endif - ClearBits(pev->flags, FL_INWATER); } return; @@ -1224,33 +1234,16 @@ void CBasePlayer::WaterMove() if (!FBitSet(pev->flags, FL_INWATER)) { -#if 0 - // player enter water sound - if (pev->watertype == CONTENT_WATER) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM); break; - } - } -#endif - SetBits(pev->flags, FL_INWATER); pev->dmgtime = 0; } - - if (!FBitSet(pev->flags, FL_WATERJUMP)) - pev->velocity = pev->velocity - 0.8 * pev->waterlevel * gpGlobals->frametime * pev->velocity; } // TRUE if the player is attached to a ladder BOOL CBasePlayer::IsOnLadder( void ) { - return (pev->movetype == MOVETYPE_FLY); + return ( pev->movetype == MOVETYPE_FLY ); } void CBasePlayer::PlayerDeathThink(void) @@ -1280,11 +1273,16 @@ void CBasePlayer::PlayerDeathThink(void) { StudioFrameAdvance( ); - m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands + 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; @@ -1321,7 +1319,7 @@ void CBasePlayer::PlayerDeathThink(void) // wait for any button down, or mp_forcerespawn is set and the respawn time is up if (!fAnyButtonDown - && !( g_pGameRules->IsMultiplayer() && CVAR_GET_FLOAT("mp_forcerespawn") > 0 && (gpGlobals->time > (m_fDeadTime + 5))) ) + && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && (gpGlobals->time > (m_fDeadTime + 5))) ) return; pev->button = 0; @@ -1536,16 +1534,18 @@ void CBasePlayer::Jump() // 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 ( FBitSet(pev->flags, FL_DUCKING ) || FBitSet(m_afPhysicsFlags, PFLAG_DUCKING) ) + if ( m_fLongJump && + (pev->button & IN_DUCK) && + ( pev->flDuckTime > 0 ) && + pev->velocity.Length() > 50 ) { - if ( m_fLongJump && (pev->button & IN_DUCK) && gpGlobals->time - m_flDuckTime < 1 && pev->velocity.Length() > 50 ) - { - SetAnimation( PLAYER_SUPERJUMP ); - } + 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) ) @@ -1578,7 +1578,10 @@ void CBasePlayer::Duck( ) { if (pev->button & IN_DUCK) { - SetAnimation( PLAYER_WALK ); + if ( m_IdealActivity != ACT_LEAP ) + { + SetAnimation( PLAYER_WALK ); + } } } @@ -1614,6 +1617,8 @@ void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) 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(); } @@ -1636,355 +1641,6 @@ void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) } } -#if 0 -void CBasePlayer::CheckWeapon(void) -{ - // play a weapon idle anim if it's time! - if ( gpGlobals->time > m_flTimeWeaponIdle ) - { - WeaponIdle ( ); - } -} -#endif - - -// play a footstep if it's time - this will eventually be frame-based. not time based. - -#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 - -// Play correct step sound for material we're on or in - -void CBasePlayer :: PlayStepSound(int step, float fvol) -{ - static int iSkipStep = 0; - - if ( !g_pGameRules->PlayFootstepSounds( this, fvol ) ) - return; - - // irand - 0,1 for right foot, 2,3 for left foot - // used to alternate left and right foot - int irand = RANDOM_LONG(0,1) + (m_iStepLeft * 2); - - m_iStepLeft = !m_iStepLeft; - - switch (step) - { - default: - case STEP_CONCRETE: - switch (irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step4.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_METAL: - switch(irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_metal1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_metal3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_metal2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_metal4.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_DIRT: - switch(irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_dirt1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_dirt3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_dirt2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_dirt4.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_VENT: - switch(irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_duct1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_duct3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_duct2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_duct4.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_GRATE: - switch(irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_grate1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_grate3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_grate2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_grate4.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_TILE: - if (!RANDOM_LONG(0,4)) - irand = 4; - switch(irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_tile1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_tile3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_tile2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_tile4.wav", fvol, ATTN_NORM); break; - case 4: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_tile5.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_SLOSH: - switch(irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_slosh1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_slosh3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_slosh2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_slosh4.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_WADE: - if ( iSkipStep == 0 ) - { - iSkipStep++; - break; - } - - if ( iSkipStep++ == 3 ) - { - iSkipStep = 0; - } - - switch (irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_wade1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_wade2.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_wade3.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_wade4.wav", fvol, ATTN_NORM); break; - } - break; - case STEP_LADDER: - switch(irand) - { - // right foot - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_ladder1.wav", fvol, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_ladder3.wav", fvol, ATTN_NORM); break; - // left foot - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_ladder2.wav", fvol, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_ladder4.wav", fvol, ATTN_NORM); break; - } - break; - } -} - -// Simple mapping from texture type character to step type - -int 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; - } -} - -// Play left or right footstep based on material player is on or in - -void CBasePlayer :: UpdateStepSound( void ) -{ - int fWalking; - float fvol; - char szbuffer[64]; - const char *pTextureName; - Vector start, end; - float rgfl1[3]; - float rgfl2[3]; - Vector knee; - Vector feet; - Vector center; - float height; - float speed; - float velrun; - float velwalk; - float flduck; - int fLadder; - int step; - - if (gpGlobals->time <= m_flTimeStepSound) - return; - - if (pev->flags & FL_FROZEN) - return; - - speed = pev->velocity.Length(); - - // determine if we are on a ladder - fLadder = IsOnLadder(); - - // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!! - if (FBitSet(pev->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 = 0.1; - } - else - { - velwalk = 120; - velrun = 210; - flduck = 0.0; - } - - // ALERT (at_console, "vel: %f\n", vecVel.Length()); - - // if we're on a ladder or on the ground, and we're moving fast enough, - // play step sound. Also, if m_flTimeStepSound is zero, get the new - // sound right away - we just started moving in new level. - - if ((fLadder || FBitSet (pev->flags, FL_ONGROUND)) && pev->velocity != g_vecZero - && (speed >= velwalk || !m_flTimeStepSound)) - { - SetAnimation( PLAYER_WALK ); - - fWalking = speed < velrun; - - center = knee = feet = (pev->absmin + pev->absmax) * 0.5; - height = pev->absmax.z - pev->absmin.z; - - knee.z = pev->absmin.z + height * 0.2; - feet.z = pev->absmin.z; - - // find out what we're stepping in or on... - if (fLadder) - { - step = STEP_LADDER; - fvol = 0.35; - m_flTimeStepSound = gpGlobals->time + 0.35; - } - else if ( UTIL_PointContents ( knee ) == CONTENTS_WATER ) - { - step = STEP_WADE; - fvol = 0.65; - m_flTimeStepSound = gpGlobals->time + 0.6; - } - else if (UTIL_PointContents ( feet ) == CONTENTS_WATER ) - { - step = STEP_SLOSH; - fvol = fWalking ? 0.2 : 0.5; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - } - else - { - // find texture under player, if different from current texture, - // get material type - - start = end = center; // center point of player BB - start.z = end.z = pev->absmin.z; // copy zmin - start.z += 4.0; // extend start up - end.z -= 24.0; // extend end down - - start.CopyToArray(rgfl1); - end.CopyToArray(rgfl2); - - pTextureName = TRACE_TEXTURE( ENT( pev->groundentity), rgfl1, rgfl2 ); - if ( pTextureName ) - { - // strip leading '-0' or '{' or '!' - if (*pTextureName == '-') - pTextureName += 2; - if (*pTextureName == '{' || *pTextureName == '!') - pTextureName++; - - if (_strnicmp(pTextureName, m_szTextureName, CBTEXTURENAMEMAX-1)) - { - // current texture is different from texture player is on... - // set current texture - strcpy(szbuffer, pTextureName); - szbuffer[CBTEXTURENAMEMAX - 1] = 0; - strcpy(m_szTextureName, szbuffer); - - // ALERT ( at_aiconsole, "texture: %s\n", m_szTextureName ); - - // get texture type - m_chTextureType = TEXTURETYPE_Find(m_szTextureName); - } - } - - step = MapTextureTypeStepType(m_chTextureType); - - switch (m_chTextureType) - { - default: - case CHAR_TEX_CONCRETE: - fvol = fWalking ? 0.2 : 0.5; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - break; - - case CHAR_TEX_METAL: - fvol = fWalking ? 0.2 : 0.5; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - break; - - case CHAR_TEX_DIRT: - fvol = fWalking ? 0.25 : 0.55; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - break; - - case CHAR_TEX_VENT: - fvol = fWalking ? 0.4 : 0.7; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - break; - - case CHAR_TEX_GRATE: - fvol = fWalking ? 0.2 : 0.5; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - break; - - case CHAR_TEX_TILE: - fvol = fWalking ? 0.2 : 0.5; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - break; - - case CHAR_TEX_SLOSH: - fvol = fWalking ? 0.2 : 0.5; - m_flTimeStepSound = fWalking ? gpGlobals->time + 0.4 : gpGlobals->time + 0.3; - break; - } - } - - m_flTimeStepSound += flduck; // slower step time if ducking - - // play the sound - - // 35% volume if ducking - if ( pev->flags & FL_DUCKING ) - fvol *= 0.35; - } -} - #define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing #define MAX_CLIMB_SPEED 200 // fastest vertical climbing speed possible @@ -1995,10 +1651,6 @@ void CBasePlayer :: UpdateStepSound( void ) void CBasePlayer::PreThink(void) { int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame - - #ifdef PERSISTENCE_SAMPLE - m_PersistenceInfo.Update(); - #endif // Debounced button codes for pressed/released // UNDONE: Do we need auto-repeat? @@ -2108,10 +1760,6 @@ void CBasePlayer::PreThink(void) if ((pev->button & IN_DUCK) || FBitSet(pev->flags,FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) ) Duck(); - // play a footstep if it's time - this will eventually be frame-based. not time based. - - UpdateStepSound(); - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) { m_flFallVelocity = -pev->velocity.z; @@ -2370,6 +2018,7 @@ Things powered by the battery */ // if in range of radiation source, ping geiger counter + #define GEIGERDELAY 0.25 void CBasePlayer :: UpdateGeigerCounter( void ) @@ -2696,8 +2345,8 @@ void CBasePlayer :: UpdatePlayerSound ( void ) if (m_iWeaponFlash < 0) m_iWeaponFlash = 0; - UTIL_MakeVectors ( pev->angles ); - gpGlobals->v_forward.z = 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. @@ -2739,8 +2388,6 @@ void CBasePlayer::PostThink() if ( (FBitSet(pev->flags, FL_ONGROUND)) && (pev->health > 0) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) { - float fvol = 0.5; - // ALERT ( at_console, "%f\n", m_flFallVelocity ); if (pev->watertype == CONTENT_WATER) @@ -2767,24 +2414,6 @@ void CBasePlayer::PostThink() TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); pev->punchangle.x = 0; } - - fvol = 1.0; - } - else if ( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 ) - { - // EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_jumpland2.wav", 1, ATTN_NORM); - fvol = 0.85; - } - else if ( m_flFallVelocity < PLAYER_MIN_BOUNCE_SPEED ) - { - fvol = 0; - } - - if ( fvol > 0.0 ) - { - // get current texture under player right away - m_flTimeStepSound = 0; - UpdateStepSound(); } if ( IsAlive() ) @@ -2847,6 +2476,18 @@ pt_end: { 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; @@ -2857,6 +2498,24 @@ pt_end: 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 @@ -2984,7 +2643,6 @@ ReturnSpot: return pSpot->edict(); } - void CBasePlayer::Spawn( void ) { pev->classname = MAKE_STRING("player"); @@ -2994,7 +2652,8 @@ void CBasePlayer::Spawn( void ) pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_WALK; pev->max_health = pev->health; - pev->flags = FL_CLIENT; + 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; @@ -3011,7 +2670,7 @@ void CBasePlayer::Spawn( void ) g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - m_iFOV = 0;// init field of view. + 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. @@ -3073,12 +2732,6 @@ void CBasePlayer::Spawn( void ) m_lastx = m_lasty = 0; g_pGameRules->PlayerSpawn( this ); - - #ifdef PERSISTENCE_SAMPLE - // Start getting their persistence data. - // (Only does it the first time they spawn). - m_PersistenceInfo.StartGettingInfo(g_engfuncs.pfnGetPlayerWONId(pev->pContainingEntity)); - #endif } @@ -3175,7 +2828,8 @@ int CBasePlayer::Restore( CRestore &restore ) if ( FBitSet(pev->flags, FL_DUCKING) ) { // Use the crouch HACK - // FixPlayerCrouchStuck( edict() ); + //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 @@ -3183,6 +2837,17 @@ int CBasePlayer::Restore( CRestore &restore ) 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(); return status; @@ -3607,7 +3272,7 @@ void CBasePlayer::ImpulseCommands( ) if ( tr.flFraction != 1.0 ) {// line hit something, so paint a decal - m_flNextDecalTime = gpGlobals->time + CVAR_GET_FLOAT("decalfrequency"); + m_flNextDecalTime = gpGlobals->time + decalfrequency.value; CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL); pCan->Spawn( pev ); } @@ -3944,6 +3609,8 @@ int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) MESSAGE_END(); } + TabulateAmmo(); + return i; } @@ -3988,7 +3655,7 @@ void CBasePlayer::ItemPostFrame() if ( m_pTank != NULL ) return; - #if defined( CLIENT_WEAPONS ) +#if defined( CLIENT_WEAPONS ) if ( m_flNextAttack > 0 ) #else if ( gpGlobals->time < m_flNextAttack ) @@ -4422,7 +4089,7 @@ Vector CBasePlayer :: GetAutoaimVector( float flDelta ) // m_vecAutoAim = m_vecAutoAim * 0.99; // Don't send across network if sv_aim is 0 - if ( CVAR_GET_FLOAT( "sv_aim" ) != 0 ) + if ( g_psv_aim->value != 0 ) { if ( m_vecAutoAim.x != m_lastx || m_vecAutoAim.y != m_lasty ) @@ -4450,7 +4117,7 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD edict_t *bestent; TraceResult tr; - if ( CVAR_GET_FLOAT("sv_aim") == 0 ) + if ( g_psv_aim->value == 0 ) { m_fOnTarget = FALSE; return g_vecZero; @@ -4611,7 +4278,7 @@ int CBasePlayer :: GetCustomDecalFrames( void ) //========================================================= void CBasePlayer::DropPlayerItem ( char *pszItemName ) { - if ( !g_pGameRules->IsMultiplayer() || (CVAR_GET_FLOAT("mp_weaponstay") > 0) ) + if ( !g_pGameRules->IsMultiplayer() || (weaponstay.value > 0) ) { // no dropping in single player. return; diff --git a/dlls/player.h b/dlls/player.h index adee653..deb2bbb 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -16,9 +16,7 @@ #define PLAYER_H -#ifdef PERSISTENCE_SAMPLE - #include "persistencehelpers.h" -#endif +#include "pm_materials.h" #define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet @@ -174,12 +172,6 @@ public: char m_szTeamName[TEAM_NAME_LENGTH]; - - #ifdef PERSISTENCE_SAMPLE - PlayerPersistenceInfo m_PersistenceInfo; - #endif - - virtual void Spawn( void ); void Pain( void ); @@ -268,8 +260,6 @@ public: void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); void UpdateGeigerCounter( void ); void CheckTimeBasedDamage( void ); - void UpdateStepSound( void ); - void PlayStepSound(int step, float fvol); BOOL FBecomeProne ( void ); void BarnacleVictimBitten ( entvars_t *pevBarnacle ); @@ -288,6 +278,13 @@ public: 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? }; #define AUTOAIM_2DEGREES 0.0348994967025 diff --git a/dlls/playermonster.cpp b/dlls/playermonster.cpp new file mode 100644 index 0000000..ce1781a --- /dev/null +++ b/dlls/playermonster.cpp @@ -0,0 +1,115 @@ +//========================================================= +// 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 5cc0af3..df3d915 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -34,27 +34,6 @@ enum python_e { PYTHON_IDLE3 }; -class CPython : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 2; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - void Reload( void ); - void WeaponIdle( void ); - float m_flSoundDelay; - - BOOL m_fInZoom;// don't save this. - -private: - unsigned short m_usFirePython; -}; LINK_ENTITY_TO_CLASS( weapon_python, CPython ); LINK_ENTITY_TO_CLASS( weapon_357, CPython ); @@ -119,7 +98,11 @@ void CPython::Precache( void ) BOOL CPython::Deploy( ) { +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else if ( g_pGameRules->IsMultiplayer() ) +#endif { // enable laser sight geometry. pev->body = 1; @@ -143,29 +126,33 @@ void CPython::Holster( int skiplocal /* = 0 */ ) } m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = gpGlobals->time + 10 + RANDOM_FLOAT ( 0, 5 ); + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); SendWeaponAnim( PYTHON_HOLSTER ); } void CPython::SecondaryAttack( void ) { +#ifdef CLIENT_DLL + if ( !bIsMultiplayer() ) +#else if ( !g_pGameRules->IsMultiplayer() ) +#endif { return; } - if ( m_fInZoom ) + if ( m_pPlayer->pev->fov != 0 ) { m_fInZoom = FALSE; - m_pPlayer->m_iFOV = 0; // 0 means reset to default fov + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov } - else + else if ( m_pPlayer->pev->fov != 40 ) { m_fInZoom = TRUE; - m_pPlayer->m_iFOV = 40; + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40; } - m_flNextSecondaryAttack = gpGlobals->time + 0.5; + m_flNextSecondaryAttack = 0.5; } void CPython::PrimaryAttack() @@ -174,7 +161,7 @@ void CPython::PrimaryAttack() if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = gpGlobals->time + 0.15; + m_flNextPrimaryAttack = 0.15; return; } @@ -185,51 +172,63 @@ void CPython::PrimaryAttack() else { EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_flNextPrimaryAttack = gpGlobals->time + 0.15; + m_flNextPrimaryAttack = 0.15; } return; } - PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usFirePython ); - 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 ); - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); Vector vecSrc = m_pPlayer->GetGunPosition( ); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0 ); + + 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 = gpGlobals->time + 0.75; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - + m_flNextPrimaryAttack = 0.75; + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } void CPython::Reload( void ) { - if ( m_fInZoom ) + if ( m_pPlayer->ammo_357 <= 0 ) + return; + + if ( m_pPlayer->pev->fov != 0 ) { m_fInZoom = FALSE; - m_pPlayer->m_iFOV = 0; // 0 means reset to default fov + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov } if (DefaultReload( 6, PYTHON_RELOAD, 2.0 )) { - m_flSoundDelay = gpGlobals->time + 1.5; + m_flSoundDelay = 1.5; } } @@ -241,36 +240,36 @@ void CPython::WeaponIdle( void ) m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); - if (m_flSoundDelay != 0 && m_flSoundDelay <= gpGlobals->time) + 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 > gpGlobals->time) + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); if (flRand <= 0.5) { iAnim = PYTHON_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + (70.0/30.0); + m_flTimeWeaponIdle = (70.0/30.0); } else if (flRand <= 0.7) { iAnim = PYTHON_IDLE2; - m_flTimeWeaponIdle = gpGlobals->time + (60.0/30.0); + m_flTimeWeaponIdle = (60.0/30.0); } else if (flRand <= 0.9) { iAnim = PYTHON_IDLE3; - m_flTimeWeaponIdle = gpGlobals->time + (88.0/30.0); + m_flTimeWeaponIdle = (88.0/30.0); } else { iAnim = PYTHON_FIDGET; - m_flTimeWeaponIdle = gpGlobals->time + (170.0/30.0); + m_flTimeWeaponIdle = (170.0/30.0); } SendWeaponAnim( iAnim ); } diff --git a/dlls/rat.cpp b/dlls/rat.cpp new file mode 100644 index 0000000..5882745 --- /dev/null +++ b/dlls/rat.cpp @@ -0,0 +1,98 @@ +/*** +* +* 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. +* +* 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 0000000..780bbc3 --- /dev/null +++ b/dlls/roach.cpp @@ -0,0 +1,460 @@ +/*** +* +* 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. +* +* 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 index 815df82..9e9ee33 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -24,6 +24,8 @@ #include "gamerules.h" + + enum rpg_e { RPG_IDLE = 0, RPG_FIDGET, @@ -37,61 +39,11 @@ enum rpg_e { RPG_FIDGET_UL, // unloaded fidget }; - -class CLaserSpot : public CBaseEntity -{ - void Spawn( void ); - void Precache( void ); - - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - -public: - void Suspend( float flSuspendTime ); - void EXPORT Revive( void ); - - static CLaserSpot *CreateSpot( void ); -}; -LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); - - -class CRpg : public CBasePlayerWeapon -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - void Reload( void ); - int iItemSlot( void ) { return 4; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - - BOOL Deploy( void ); - BOOL CanHolster( void ); - void Holster( int skiplocal = 0 ); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - void WeaponIdle( void ); - - void UpdateSpot( void ); - BOOL ShouldWeaponIdle( void ) { return TRUE; }; - - CLaserSpot *m_pSpot; - int m_fSpotActive; - int m_cActiveRockets;// how many missiles in flight from this launcher right now? - -}; LINK_ENTITY_TO_CLASS( weapon_rpg, CRpg ); -TYPEDESCRIPTION CRpg::m_SaveData[] = -{ - DEFINE_FIELD( CRpg, m_fSpotActive, FIELD_INTEGER ), - DEFINE_FIELD( CRpg, m_cActiveRockets, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CRpg, CBasePlayerWeapon ); +#ifndef CLIENT_DLL + +LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); //========================================================= //========================================================= @@ -147,36 +99,8 @@ void CLaserSpot::Precache( void ) PRECACHE_MODEL("sprites/laserdot.spr"); }; - - - - -class CRpgRocket : public CGrenade -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - void Spawn( void ); - void Precache( void ); - void EXPORT FollowThink( void ); - void EXPORT IgniteThink( void ); - void EXPORT RocketTouch( CBaseEntity *pOther ); - static CRpgRocket *CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ); - - int m_iTrail; - float m_flIgniteTime; - CRpg *m_pLauncher;// pointer back to the launcher that fired me. -}; LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); -TYPEDESCRIPTION CRpgRocket::m_SaveData[] = -{ - DEFINE_FIELD( CRpgRocket, m_flIgniteTime, FIELD_TIME ), - DEFINE_FIELD( CRpgRocket, m_pLauncher, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ); - //========================================================= //========================================================= CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ) @@ -273,20 +197,6 @@ void CRpgRocket :: IgniteThink( void ) MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - - -/* - WRITE_BYTE( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( MSG_BROADCAST, TE_BEAMFOLLOW); - WRITE_SHORT(entindex()); // entity - WRITE_SHORT(MSG_BROADCAST, m_iTrail ); // model - WRITE_BYTE( MSG_BROADCAST, 40 ); // life - WRITE_BYTE( MSG_BROADCAST, 5 ); // width - WRITE_BYTE( MSG_BROADCAST, 224 ); // r, g, b - WRITE_BYTE( MSG_BROADCAST, 224 ); // r, g, b - WRITE_BYTE( MSG_BROADCAST, 255 ); // r, g, b - WRITE_BYTE( MSG_BROADCAST, 255 ); // brightness -*/ m_flIgniteTime = gpGlobals->time; // set to follow laser spot @@ -368,11 +278,7 @@ void CRpgRocket :: FollowThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - - - - - +#endif @@ -386,6 +292,9 @@ void CRpg::Reload( void ) 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 @@ -396,7 +305,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 = gpGlobals->time + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; if ( m_cActiveRockets && m_fSpotActive ) { @@ -405,21 +314,20 @@ void CRpg::Reload( void ) return; } - if (m_pSpot && m_fSpotActive) +#ifndef CLIENT_DLL + if ( m_pSpot && m_fSpotActive ) { m_pSpot->Suspend( 2.1 ); - m_flNextSecondaryAttack = gpGlobals->time + 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) - { - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - } + + if ( iResult ) + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } void CRpg::Spawn( ) @@ -430,7 +338,11 @@ void CRpg::Spawn( ) 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; @@ -457,6 +369,8 @@ void CRpg::Precache( void ) PRECACHE_SOUND("weapons/rocketfire1.wav"); PRECACHE_SOUND("weapons/glauncher.wav"); // alternative fire sound + + m_usRpg = PRECACHE_EVENT ( 1, "events/rpg.sc" ); } @@ -516,26 +430,29 @@ void CRpg::Holster( int skiplocal /* = 0 */ ) m_fInReload = FALSE;// cancel any reload in progress. m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - // m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + 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) + if ( m_iClip ) { m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - SendWeaponAnim( RPG_FIRE2 ); - +#ifndef CLIENT_DLL // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); @@ -546,20 +463,24 @@ void CRpg::PrimaryAttack() 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) - - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM ); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM ); + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); m_iClip--; - //m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_flNextPrimaryAttack = gpGlobals->time + 1.5; - m_flTimeWeaponIdle = gpGlobals->time + 1.5; - m_pPlayer->pev->punchangle.x -= 5; + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } else { @@ -573,13 +494,15 @@ 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 = gpGlobals->time + 0.2; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2; } @@ -589,13 +512,13 @@ void CRpg::WeaponIdle( void ) ResetEmptySound( ); - if (m_flTimeWeaponIdle > gpGlobals->time) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.75 || m_fSpotActive) { if ( m_iClip == 0 ) @@ -603,7 +526,7 @@ void CRpg::WeaponIdle( void ) else iAnim = RPG_IDLE; - m_flTimeWeaponIdle = gpGlobals->time + 90.0 / 15.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 15.0; } else { @@ -612,14 +535,14 @@ void CRpg::WeaponIdle( void ) else iAnim = RPG_FIDGET; - m_flTimeWeaponIdle = gpGlobals->time + 3.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0; } SendWeaponAnim( iAnim ); } else { - m_flTimeWeaponIdle = gpGlobals->time + 1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1; } } @@ -627,6 +550,8 @@ void CRpg::WeaponIdle( void ) void CRpg::UpdateSpot( void ) { + +#ifndef CLIENT_DLL if (m_fSpotActive) { if (!m_pSpot) @@ -641,17 +566,10 @@ void CRpg::UpdateSpot( void ) TraceResult tr; UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr ); - // ALERT( "%f %f\n", gpGlobals->v_forward.y, vecAiming.y ); - - /* - float a = gpGlobals->v_forward.y * vecAiming.y + gpGlobals->v_forward.x * vecAiming.x; - m_pPlayer->pev->punchangle.y = acos( a ) * (180 / M_PI); - - ALERT( at_console, "%f\n", a ); - */ - UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos ); } +#endif + } @@ -672,7 +590,11 @@ class CRpgAmmo : public CBasePlayerAmmo { int iGive; - if ( g_pGameRules->IsMultiplayer() ) +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { // hand out more ammo per rocket in multiplayer. iGive = AMMO_RPGCLIP_GIVE * 2; diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index ab34ca7..afd15ae 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -167,37 +167,9 @@ void CSatchelCharge :: BounceSound( void ) } } -class CSatchel : public CBasePlayerWeapon -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 5; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - void PrimaryAttack( void ); - void SecondaryAttack( void ); - int AddDuplicate( CBasePlayerItem *pOriginal ); - BOOL CanDeploy( void ); - BOOL Deploy( void ); - BOOL IsUseable( void ); - - void Holster( int skiplocal = 0 ); - void WeaponIdle( void ); - void Throw( void ); - int m_chargeReady; -}; LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ); -TYPEDESCRIPTION CSatchel::m_SaveData[] = -{ - DEFINE_FIELD( CSatchel, m_chargeReady, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ); //========================================================= // CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal @@ -206,7 +178,11 @@ int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) { CSatchel *pSatchel; +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else if ( g_pGameRules->IsMultiplayer() ) +#endif { pSatchel = (CSatchel *)pOriginal; @@ -229,7 +205,7 @@ int CSatchel::AddToPlayer( CBasePlayer *pPlayer ) pPlayer->pev->weapons |= (1<pev->viewmodel = MAKE_STRING("models/v_satchel_radio.mdl"); - m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel_radio.mdl"); - SendWeaponAnim( SATCHEL_RADIO_DRAW ); - // use hivehand animations - strcpy( m_pPlayer->m_szAnimExtention, "hive" ); - } - else - { - m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel.mdl"); - m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel.mdl"); - SendWeaponAnim( SATCHEL_DRAW ); - // use tripmine animations - strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - } m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + 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; } @@ -342,7 +309,7 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - if (m_chargeReady) + if ( m_chargeReady ) { SendWeaponAnim( SATCHEL_RADIO_HOLSTER ); } @@ -391,19 +358,10 @@ void CSatchel::PrimaryAttack() } } - if (m_chargeReady == 1) - { - // play buzzer sound - } - else - { - // play click sound - } - m_chargeReady = 2; - m_flNextPrimaryAttack = gpGlobals->time + 0.5; - m_flNextSecondaryAttack = gpGlobals->time + 0.5; - m_flTimeWeaponIdle = gpGlobals->time + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; break; } @@ -418,7 +376,7 @@ void CSatchel::PrimaryAttack() void CSatchel::SecondaryAttack( void ) { - if (m_chargeReady != 2) + if ( m_chargeReady != 2 ) { Throw( ); } @@ -427,18 +385,23 @@ void CSatchel::SecondaryAttack( void ) 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() ); 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 @@ -448,15 +411,15 @@ void CSatchel::Throw( void ) m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_flNextPrimaryAttack = gpGlobals->time + 1.0; - m_flNextSecondaryAttack = gpGlobals->time + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; } } void CSatchel::WeaponIdle( void ) { - if (m_flTimeWeaponIdle > gpGlobals->time) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; switch( m_chargeReady ) @@ -479,19 +442,24 @@ void CSatchel::WeaponIdle( void ) 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 = gpGlobals->time + 0.5; - m_flNextSecondaryAttack = gpGlobals->time + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; m_chargeReady = 0; break; } - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );// how long till we do this again. + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. } //========================================================= diff --git a/dlls/saverestore.h b/dlls/saverestore.h index 4b5b1ef..7ddac8f 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -83,7 +83,6 @@ 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 ); diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp new file mode 100644 index 0000000..2b6058e --- /dev/null +++ b/dlls/schedule.cpp @@ -0,0 +1,1514 @@ +/*** +* +* 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. +* +* 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 45e7ffc..4cc3da4 100644 --- a/dlls/schedule.h +++ b/dlls/schedule.h @@ -1,31 +1,290 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. +* 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 0000000..9805095 --- /dev/null +++ b/dlls/scientist.cpp @@ -0,0 +1,1428 @@ +/*** +* +* 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. +* +* 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 ) +{ + 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 (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 0000000..1b8ad0a --- /dev/null +++ b/dlls/scripted.cpp @@ -0,0 +1,1260 @@ +/*** +* +* 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. +* +* 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 ) ) + { + 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( 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 0000000..d83614a --- /dev/null +++ b/dlls/scripted.h @@ -0,0 +1,107 @@ +/*** +* +* 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. +* +* 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 b3f5314..d660e4b 100644 --- a/dlls/scriptevent.h +++ b/dlls/scriptevent.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 429b281..44dd897 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -39,47 +39,8 @@ enum shotgun_e { SHOTGUN_IDLE_DEEP }; -class CShotgun : public CBasePlayerWeapon -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int iItemSlot( ) { return 3; } - int GetItemInfo(ItemInfo *p); - int AddToPlayer( CBasePlayer *pPlayer ); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( ); - void Reload( void ); - void WeaponIdle( void ); - int m_fInReload; - float m_flNextReload; - int m_iShell; - float m_flPumpTime; -private: - unsigned short m_usDoubleFire; - unsigned short m_usSingleFire; -}; LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ); - -TYPEDESCRIPTION CShotgun::m_SaveData[] = -{ - DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), - DEFINE_FIELD( CShotgun, m_fInReload, 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 ); - - - void CShotgun::Spawn( ) { Precache( ); @@ -155,14 +116,13 @@ 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 = gpGlobals->time + 0.15; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } @@ -174,30 +134,43 @@ void CShotgun::PrimaryAttack() return; } - PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usSingleFire ); - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; m_iClip--; - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + 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 ); - if ( g_pGameRules->IsDeathmatch() ) + Vector vecDir; + +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { - // altered deathmatch spread - m_pPlayer->FireBullets( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); + 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. - m_pPlayer->FireBullets( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); + 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); @@ -205,13 +178,13 @@ void CShotgun::PrimaryAttack() if (m_iClip != 0) m_flPumpTime = gpGlobals->time + 0.5; - m_flNextPrimaryAttack = gpGlobals->time + 0.75; - m_flNextSecondaryAttack = gpGlobals->time + 0.75; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; if (m_iClip != 0) - m_flTimeWeaponIdle = gpGlobals->time + 5.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; else - m_flTimeWeaponIdle = 0.75; - m_fInReload = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; + m_fInSpecialReload = 0; } @@ -221,7 +194,7 @@ void CShotgun::SecondaryAttack( void ) if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = gpGlobals->time + 0.15; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } @@ -232,30 +205,45 @@ void CShotgun::SecondaryAttack( void ) return; } - PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usDoubleFire ); - 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; - if ( g_pGameRules->IsDeathmatch() ) +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { // tuned for deathmatch - m_pPlayer->FireBullets( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); + 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 - m_pPlayer->FireBullets( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); + 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 @@ -264,14 +252,15 @@ void CShotgun::SecondaryAttack( void ) if (m_iClip != 0) m_flPumpTime = gpGlobals->time + 0.95; - m_flNextPrimaryAttack = gpGlobals->time + 1.5; - m_flNextSecondaryAttack = gpGlobals->time + 1.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; if (m_iClip != 0) - m_flTimeWeaponIdle = gpGlobals->time + 6.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; else m_flTimeWeaponIdle = 1.5; - m_fInReload = 0; + m_fInSpecialReload = 0; + } @@ -280,30 +269,27 @@ void CShotgun::Reload( void ) if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP) return; - if (m_flNextReload > gpGlobals->time) - return; - // don't reload until recoil is done - if (m_flNextPrimaryAttack > gpGlobals->time) + if (m_flNextPrimaryAttack > UTIL_WeaponTimeBase()) return; // check to see if we're ready to reload - if (m_fInReload == 0) + if (m_fInSpecialReload == 0) { SendWeaponAnim( SHOTGUN_START_RELOAD ); - m_fInReload = 1; + m_fInSpecialReload = 1; m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; - m_flTimeWeaponIdle = gpGlobals->time + 0.6; - m_flNextPrimaryAttack = gpGlobals->time + 1.0; - m_flNextSecondaryAttack = gpGlobals->time + 1.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; return; } - else if (m_fInReload == 1) + else if (m_fInSpecialReload == 1) { - if (m_flTimeWeaponIdle > gpGlobals->time) + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) return; // was waiting for gun to move to side - m_fInReload = 2; + 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)); @@ -312,15 +298,15 @@ void CShotgun::Reload( void ) SendWeaponAnim( SHOTGUN_RELOAD ); - m_flNextReload = gpGlobals->time + 0.5; - m_flTimeWeaponIdle = gpGlobals->time + 0.5; + 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_fInReload = 1; + m_fInSpecialReload = 1; } } @@ -331,20 +317,20 @@ void CShotgun::WeaponIdle( void ) 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)); m_flPumpTime = 0; } - if (m_flTimeWeaponIdle < gpGlobals->time) + if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { - if (m_iClip == 0 && m_fInReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { Reload( ); } - else if (m_fInReload != 0) + else if (m_fInSpecialReload != 0) { if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { @@ -357,28 +343,28 @@ void CShotgun::WeaponIdle( void ) // 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_fInReload = 0; - m_flTimeWeaponIdle = gpGlobals->time + 1.5; + m_fInSpecialReload = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } } else { int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.8) { iAnim = SHOTGUN_IDLE_DEEP; - m_flTimeWeaponIdle = gpGlobals->time + (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) { iAnim = SHOTGUN_IDLE; - m_flTimeWeaponIdle = gpGlobals->time + (20.0/9.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); } else { iAnim = SHOTGUN_IDLE4; - m_flTimeWeaponIdle = gpGlobals->time + (20.0/9.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); } SendWeaponAnim( iAnim ); } diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index 9adccdc..160757a 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/skill.cpp b/dlls/skill.cpp index 71c7b1d..6718db5 100644 --- a/dlls/skill.cpp +++ b/dlls/skill.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/skill.h b/dlls/skill.h index 63ec8f7..3b0cf9e 100644 --- a/dlls/skill.h +++ b/dlls/skill.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 40c8475..7784d38 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -1064,7 +1064,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres strcpy(szfound, "!"); strcat(szfound, szgroupname); - itoa(ipick, sznum, 10); + sprintf(sznum, "%d", ipick); strcat(szfound, sznum); if (ipick >= count) @@ -1126,7 +1126,7 @@ int USENTENCEG_Pick(int isentenceg, char *szfound) { strcpy(szfound, "!"); strcat(szfound, szgroupname); - itoa(ipick, sznum, 10); + sprintf(sznum, "%d", ipick); strcat(szfound, sznum); return ipick; } @@ -1250,7 +1250,7 @@ void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick) strcpy(buffer, "!"); strcat(buffer, rgsentenceg[isentenceg].szgroupname); - itoa(ipick, sznum, 10); + sprintf(sznum, "%d", ipick); strcat(buffer, sznum); STOP_SOUND(entity, CHAN_VOICE, buffer); @@ -1400,7 +1400,7 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum) if (sentencenum) { strcpy(sentencenum, "!"); - itoa(i, sznum, 10); + sprintf(sznum, "%d", i); strcat(sentencenum, sznum); } return i; @@ -1612,7 +1612,7 @@ char TEXTURETYPE_Find(char *name) for (int i = 0; i < gcTextures; i++) { - if (!_strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) + if (!strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) return (grgchTextureType[i]); } diff --git a/dlls/soundent.cpp b/dlls/soundent.cpp index bd4fa81..ff16d49 100644 --- a/dlls/soundent.cpp +++ b/dlls/soundent.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/soundent.h b/dlls/soundent.h index 5e03b6a..9753aa3 100644 --- a/dlls/soundent.h +++ b/dlls/soundent.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/spectator.cpp b/dlls/spectator.cpp index a794d3d..28002eb 100644 --- a/dlls/spectator.cpp +++ b/dlls/spectator.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/spectator.h b/dlls/spectator.h index aa2e73e..f4c4ef3 100644 --- a/dlls/spectator.h +++ b/dlls/spectator.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/squad.h b/dlls/squad.h new file mode 100644 index 0000000..abf3194 --- /dev/null +++ b/dlls/squad.h @@ -0,0 +1,13 @@ +//========================================================= +// 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 0000000..35d52ca --- /dev/null +++ b/dlls/squadmonster.cpp @@ -0,0 +1,623 @@ +/*** +* +* 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. +* +* 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 0000000..b151734 --- /dev/null +++ b/dlls/squadmonster.h @@ -0,0 +1,120 @@ +/*** +* +* 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. +* +* 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 c035a24..4af57de 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -40,6 +40,8 @@ enum squeak_e { SQUEAK_THROW }; +#ifndef CLIENT_DLL + class CSqueakGrenade : public CGrenade { void Spawn( void ); @@ -405,23 +407,8 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. } +#endif - -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; -}; LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ); @@ -449,6 +436,8 @@ void CSqueak::Precache( void ) PRECACHE_SOUND("squeek/sqk_hunt2.wav"); PRECACHE_SOUND("squeek/sqk_hunt3.wav"); UTIL_PrecacheOther("monster_snark"); + + m_usSnarkFire = PRECACHE_EVENT ( 1, "events/snarkfire.sc" ); } @@ -489,9 +478,9 @@ BOOL CSqueak::Deploy( ) void CSqueak::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + 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<m_rgAmmo[m_iPrimaryAmmoType]) + if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) { UTIL_MakeVectors( m_pPlayer->pev->v_angle ); TraceResult tr; @@ -523,16 +512,24 @@ 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 ); - if (tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25) - { - SendWeaponAnim( SQUEAK_THROW ); + 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 ); @@ -548,8 +545,8 @@ void CSqueak::PrimaryAttack() m_fJustThrown = 1; - m_flNextPrimaryAttack = gpGlobals->time + 0.3; - m_flTimeWeaponIdle = gpGlobals->time + 1.0; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; } } } @@ -563,7 +560,7 @@ void CSqueak::SecondaryAttack( void ) void CSqueak::WeaponIdle( void ) { - if (m_flTimeWeaponIdle > gpGlobals->time) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; if (m_fJustThrown) @@ -577,26 +574,26 @@ void CSqueak::WeaponIdle( void ) } SendWeaponAnim( SQUEAK_UP ); - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); return; } int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.75) { iAnim = SQUEAK_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + 30.0 / 16 * (2); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); } else if (flRand <= 0.875) { iAnim = SQUEAK_FIDGETFIT; - m_flTimeWeaponIdle = gpGlobals->time + 70.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0; } else { iAnim = SQUEAK_FIDGETNIP; - m_flTimeWeaponIdle = gpGlobals->time + 80.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0; } SendWeaponAnim( iAnim ); } diff --git a/dlls/stats.cpp b/dlls/stats.cpp new file mode 100644 index 0000000..54ea283 --- /dev/null +++ b/dlls/stats.cpp @@ -0,0 +1,149 @@ +#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 a068c95..87c024a 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp new file mode 100644 index 0000000..bfd9b91 --- /dev/null +++ b/dlls/talkmonster.cpp @@ -0,0 +1,1472 @@ +/*** +* +* 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. +* +* 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 ); + 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 index cf4b324..1558459 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -1,26 +1,183 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. +* 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: - static float g_talkWaitTime; + 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 8eae4a4..2b5c28c 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -68,6 +68,9 @@ CHalfLifeTeamplay :: CHalfLifeTeamplay() extern cvar_t timeleft, fragsleft; +#include "voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + void CHalfLifeTeamplay :: Think ( void ) { ///// Check game rules ///// @@ -77,6 +80,8 @@ void CHalfLifeTeamplay :: Think ( void ) int frags_remaining = 0; int time_remaining = 0; + g_VoiceGameMgr.Update(gpGlobals->frametime); + if ( g_fGameOver ) // someone else quit the game already { CHalfLifeMultiplay::Think(); @@ -140,6 +145,9 @@ void CHalfLifeTeamplay :: Think ( void ) //========================================================= BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { + if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) + return TRUE; + if ( FStrEq( pcmd, "menuselect" ) ) { if ( CMD_ARGC() < 2 ) @@ -158,7 +166,8 @@ BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd extern int gmsgGameMode; extern int gmsgSayText; extern int gmsgTeamInfo; - +extern int gmsgTeamNames; +extern int gmsgScoreInfo; void CHalfLifeTeamplay :: UpdateGameMode( CBasePlayer *pPlayer ) { @@ -201,9 +210,20 @@ const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) //========================================================= 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" ); @@ -224,7 +244,7 @@ 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 ( int i = 1; i <= gpGlobals->maxClients; i++ ) + for ( i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); if ( plr && IsValidTeam( plr->TeamID() ) ) @@ -276,6 +296,14 @@ void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTea 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(); } @@ -318,7 +346,12 @@ void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infob sprintf( text, "* %s has changed to team \'%s\'\n", STRING(pPlayer->pev->netname), mdls ); UTIL_SayTextAll( text, pPlayer ); - UTIL_LogPrintf( "\"%s<%i>\" changed to team %s\n", STRING( pPlayer->pev->netname ), GETPLAYERUSERID( pPlayer->edict() ), mdls ); + UTIL_LogPrintf( "\"%s<%i><%u><%s>\" joined team \"%s\"\n", + STRING(pPlayer->pev->netname), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERWONID( pPlayer->edict() ), + pPlayer->m_szTeamName, + mdls ); ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); // recound stuff @@ -381,7 +414,7 @@ BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) { // my teammate hit me. - if ( (CVAR_GET_FLOAT("mp_friendlyfire") == 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; diff --git a/dlls/teamplay_gamerules.h b/dlls/teamplay_gamerules.h index 05632e4..54bf402 100644 --- a/dlls/teamplay_gamerules.h +++ b/dlls/teamplay_gamerules.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/tempmonster.cpp b/dlls/tempmonster.cpp new file mode 100644 index 0000000..8dfeef8 --- /dev/null +++ b/dlls/tempmonster.cpp @@ -0,0 +1,117 @@ +/*** +* +* 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. +* +* 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 0000000..92f3064 --- /dev/null +++ b/dlls/tentacle.cpp @@ -0,0 +1,1044 @@ +/*** +* +* 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. +* +* 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 index d7ee1a3..15aa38c 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 9af5b68..43d0335 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 4134976..ba912b9 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -39,6 +39,7 @@ enum tripmine_e { }; +#ifndef CLIENT_DLL class CTripmineGrenade : public CGrenade { @@ -349,29 +350,10 @@ void CTripmineGrenade::DelayDeathThink( void ) Explode( &tr, DMG_BLAST ); } +#endif -class CTripmine : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 5; } - int GetItemInfo(ItemInfo *p); - void SetObjectCollisionBox( void ) - { - //!!!BUGBUG - fix the model! - pev->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 ); -}; LINK_ENTITY_TO_CLASS( weapon_tripmine, CTripmine ); - void CTripmine::Spawn( ) { Precache( ); @@ -387,7 +369,11 @@ void CTripmine::Spawn( ) 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) ); } @@ -398,6 +384,8 @@ 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) @@ -419,7 +407,7 @@ int CTripmine::GetItemInfo(ItemInfo *p) BOOL CTripmine::Deploy( ) { - pev->body = 0; + //pev->body = 0; return DefaultDeploy( "models/v_tripmine.mdl", "models/p_tripmine.mdl", TRIPMINE_DRAW, "trip" ); } @@ -453,29 +441,30 @@ void CTripmine::PrimaryAttack( void ) 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) { - // ALERT( at_console, "hit %f\n", tr.flFraction ); - 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 ); CBaseEntity *pEnt = CBaseEntity::Create( "monster_tripmine", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, m_pPlayer->edict() ); - CTripmineGrenade *pMine = (CTripmineGrenade *)pEnt; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) - { - SendWeaponAnim( TRIPMINE_DRAW ); - } - else + + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) { // no more mines! RetireWeapon(); @@ -491,17 +480,17 @@ void CTripmine::PrimaryAttack( void ) { } - - m_flNextPrimaryAttack = gpGlobals->time + 0.3; - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + + 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 > gpGlobals->time) + 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 ); } @@ -512,25 +501,24 @@ void CTripmine::WeaponIdle( void ) } int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.25) { iAnim = TRIPMINE_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + 90.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; } else if (flRand <= 0.75) { iAnim = TRIPMINE_IDLE2; - m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 30.0; } else { iAnim = TRIPMINE_FIDGET; - m_flTimeWeaponIdle = gpGlobals->time + 100.0 / 30.0; + 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 0000000..0210049 --- /dev/null +++ b/dlls/turret.cpp @@ -0,0 +1,1305 @@ +/*** +* +* 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. +* +* 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; + 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(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 ); + 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(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.cpp b/dlls/util.cpp index 2a79212..2732567 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -25,19 +25,12 @@ #include "cbase.h" #include "saverestore.h" #include -#include "../engine/shake.h" +#include "shake.h" #include "decals.h" #include "player.h" #include "weapons.h" #include "gamerules.h" -/* -===================== -UTIL_WeaponTimeBase - -Time basis for weapons ( zero based of predicting client weapons ) -===================== -*/ float UTIL_WeaponTimeBase( void ) { #if defined( CLIENT_WEAPONS ) @@ -89,7 +82,6 @@ UTIL_SharedRandomLong */ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) { - unsigned int range; U_Srand( (int)seed + low + high ); @@ -1774,7 +1766,8 @@ 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 */ @@ -1789,7 +1782,7 @@ extern "C" { } return num; - } +} } #endif @@ -2547,3 +2540,4 @@ int CRestore::BufferCheckZString( const char *string ) } return 0; } + diff --git a/dlls/util.h b/dlls/util.h index ee07d0a..fbc6e97 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -47,8 +47,7 @@ inline edict_t *FIND_ENTITY_BY_TARGET(edict_t *entStart, const char *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_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) \ @@ -79,16 +78,19 @@ typedef int BOOL; #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 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" EXPORT void mapClassName( entvars_t *pev ); \ + 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 // @@ -420,6 +422,13 @@ extern DLL_GLOBAL int g_Language; #define SVC_CDTRACK 32 #define SVC_WEAPONANIM 35 #define SVC_ROOMTYPE 37 +#define SVC_HLTV 50 + +// prxoy director stuff +#define DRC_EVENT 3 // informs the dircetor about ann important game event + +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_DRAMATIC (1<<5) // triggers #define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger @@ -475,20 +484,6 @@ void TEXTURETYPE_Init(); char TEXTURETYPE_Find(char *name); float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); -#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' - // 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. @@ -521,7 +516,6 @@ void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname); #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 ); diff --git a/dlls/vector.h b/dlls/vector.h index 3a10197..282e3b9 100644 --- a/dlls/vector.h +++ b/dlls/vector.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index a6aa07d..0ae777b 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -645,6 +645,8 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_iClip += j; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; + m_pPlayer->TabulateAmmo(); + m_fInReload = FALSE; } @@ -655,6 +657,7 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fFireOnEmpty = TRUE; } + m_pPlayer->TabulateAmmo(); SecondaryAttack(); m_pPlayer->pev->button &= ~IN_ATTACK2; } @@ -665,6 +668,7 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fFireOnEmpty = TRUE; } + m_pPlayer->TabulateAmmo(); PrimaryAttack(); } else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) @@ -827,7 +831,7 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { bSend = TRUE; } - + if ( bSend ) { MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pPlayer->pev ); @@ -848,8 +852,13 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) } -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal ) +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 ) @@ -972,6 +981,7 @@ BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, 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 ); @@ -1491,6 +1501,73 @@ void CWeaponBox::SetObjectCollisionBox( void ) 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 ae30d1b..756244d 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. @@ -15,6 +15,7 @@ #ifndef WEAPONS_H #define WEAPONS_H +#include "effects.h" class CBasePlayer; extern int gmsgWeapPickup; @@ -312,7 +313,7 @@ public: virtual BOOL PlayEmptySound( void ); virtual void ResetEmptySound( void ); - virtual void SendWeaponAnim( int iAnim, int skiplocal = 0 ); // skiplocal is 1 if client is predicting weapon animations + virtual void SendWeaponAnim( int iAnim, int skiplocal = 1, int body = 0 ); // skiplocal is 1 if client is predicting weapon animations virtual BOOL CanDeploy( void ); virtual BOOL IsUseable( void ); @@ -330,7 +331,7 @@ public: virtual BOOL ShouldWeaponIdle( void ) {return FALSE; }; virtual void Holster( int skiplocal = 0 ); virtual BOOL UseDecrement( void ) { return FALSE; }; - + int PrimaryAmmoIndex(); int SecondaryAmmoIndex(); @@ -338,6 +339,8 @@ public: virtual CBasePlayerItem *GetWeaponPtr( void ) { return (CBasePlayerItem *)this; }; + float m_flPumpTime; + int m_fInSpecialReload; // Are we in the middle of a reload for the shotguns float m_flNextPrimaryAttack; // soonest time ItemPostFrame will call PrimaryAttack float m_flNextSecondaryAttack; // soonest time ItemPostFrame will call SecondaryAttack float m_flTimeWeaponIdle; // soonest time ItemPostFrame will call WeaponIdle @@ -349,6 +352,7 @@ 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. + }; @@ -453,6 +457,11 @@ public: int m_cAmmoTypes;// how many ammo types packed into this box (if packed by a level designer) }; +#ifdef CLIENT_DLL +bool bIsMultiplayer ( void ); +void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ); +#endif + class CGlock : public CBasePlayerWeapon { public: @@ -485,4 +494,522 @@ private: unsigned short m_usFireGlock2; }; + +class CCrowbar : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 1; } + void EXPORT SwingAgain( void ); + void EXPORT Smack( void ); + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + int Swing( int fFirst ); + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + int m_iSwing; + TraceResult m_trHit; + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } +private: + unsigned short m_usCrowbar; +}; + +class CPython : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 2; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + void Reload( void ); + void WeaponIdle( void ); + float m_flSoundDelay; + + BOOL m_fInZoom;// don't save this. + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usFirePython; +}; + +class CMP5 : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 3; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + int SecondaryAmmoIndex( void ); + BOOL Deploy( void ); + void Reload( void ); + void WeaponIdle( void ); + float m_flNextAnimTime; + int m_iShell; + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usMP5; + unsigned short m_usMP52; +}; + +class CCrossbow : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( ) { return 3; } + int GetItemInfo(ItemInfo *p); + + void FireBolt( void ); + void FireSniperBolt( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + int AddToPlayer( CBasePlayer *pPlayer ); + BOOL Deploy( ); + void Holster( int skiplocal = 0 ); + void Reload( void ); + void WeaponIdle( void ); + + int m_fInZoom; // don't save this + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usCrossbow; + unsigned short m_usCrossbow2; +}; + +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; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + BOOL Deploy( ); + void Reload( void ); + void WeaponIdle( void ); + int m_fInReload; + float m_flNextReload; + int m_iShell; + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usDoubleFire; + unsigned short m_usSingleFire; +}; + +class CLaserSpot : public CBaseEntity +{ + void Spawn( void ); + void Precache( void ); + + int ObjectCaps( void ) { return FCAP_DONT_SAVE; } + +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 ); + int iItemSlot( void ) { return 4; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + BOOL Deploy( void ); + BOOL CanHolster( void ); + void Holster( int skiplocal = 0 ); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + + void UpdateSpot( void ); + BOOL ShouldWeaponIdle( void ) { return TRUE; }; + + CLaserSpot *m_pSpot; + int m_fSpotActive; + int m_cActiveRockets;// how many missiles in flight from this launcher right now? + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usRpg; + +}; + +class CRpgRocket : public CGrenade +{ +public: + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + void Spawn( void ); + void Precache( void ); + void EXPORT FollowThink( void ); + void EXPORT IgniteThink( void ); + void EXPORT RocketTouch( CBaseEntity *pOther ); + static CRpgRocket *CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ); + + int m_iTrail; + float m_flIgniteTime; + CRpg *m_pLauncher;// pointer back to the launcher that fired me. +}; + +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; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + + void StartFire( void ); + void Fire( Vector vecOrigSrc, Vector vecDirShooting, float flDamage ); + float GetFullChargeTime( void ); + int m_iBalls; + int m_iGlow; + int m_iBeam; + int m_iSoundState; // don't save this + + // was this weapon just fired primary or secondary? + // we need to know so we can pick the right set of effects. + BOOL m_fPrimaryFire; + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usGaussFire; + unsigned short m_usGaussSpin; +}; + +class CEgon : 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; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + + void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ); + + void CreateEffect ( void ); + void DestroyEffect ( void ); + + void EndAttack( void ); + void Attack( void ); + void PrimaryAttack( void ); + void WeaponIdle( void ); + + float m_flAmmoUseTime;// since we use < 1 point of ammo per update, we subtract ammo on a timer. + + float GetPulseInterval( void ); + float GetDischargeInterval( void ); + + void Fire( const Vector &vecOrigSrc, const Vector &vecDir ); + + BOOL HasAmmo( void ); + + void UseAmmo( int count ); + + enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; + + CBeam *m_pBeam; + CBeam *m_pNoise; + CSprite *m_pSprite; + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + + unsigned short m_usEgonStop; + +private: + float m_shootTime; + EGON_FIREMODE m_fireMode; + float m_shakeTime; + BOOL m_deployed; + + unsigned short m_usEgonFire; +}; + +class CHgun : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 4; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + BOOL Deploy( void ); + BOOL IsUseable( void ); + void Holster( int skiplocal = 0 ); + void Reload( void ); + void WeaponIdle( void ); + float m_flNextAnimTime; + + float m_flRechargeTime; + + int m_iFirePhase;// don't save me. + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } +private: + unsigned short m_usHornetFire; +}; + + + +class CHandGrenade : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 5; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + BOOL Deploy( void ); + BOOL CanHolster( void ); + void Holster( int skiplocal = 0 ); + void WeaponIdle( void ); + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } +}; + +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; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + int AddDuplicate( CBasePlayerItem *pOriginal ); + 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 ) + return TRUE; +#else + return FALSE; +#endif + } +}; + + +class CTripmine : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 5; } + int GetItemInfo(ItemInfo *p); + void SetObjectCollisionBox( void ) + { + //!!!BUGBUG - fix the model! + pev->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 d91670e..4f5f9ed 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/wpn_shared/hl_wpn_glock.cpp b/dlls/wpn_shared/hl_wpn_glock.cpp index e1de76f..13b68eb 100644 --- a/dlls/wpn_shared/hl_wpn_glock.cpp +++ b/dlls/wpn_shared/hl_wpn_glock.cpp @@ -120,13 +120,6 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; -#if defined ( OLD_WEAPONS ) - if (m_iClip != 0) - SendWeaponAnim( GLOCK_SHOOT ); - else - SendWeaponAnim( GLOCK_SHOOT_EMPTY ); -#endif - int flags; #if defined( CLIENT_WEAPONS ) @@ -135,46 +128,20 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) flags = 0; #endif - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); -#if defined ( OLD_WEAPONS ) - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecShellVelocity = m_pPlayer->pev->velocity - + gpGlobals->v_right * RANDOM_FLOAT(50,70) - + gpGlobals->v_up * RANDOM_FLOAT(100,150) - + gpGlobals->v_forward * 25; - EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); -#endif - // silenced if (pev->body == 1) { m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; -#if defined ( OLD_WEAPONS ) - switch(RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); - break; - } -#endif } else { // non-silenced m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; -#if defined ( OLD_WEAPONS ) - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); -#endif } Vector vecSrc = m_pPlayer->GetGunPosition( ); @@ -189,7 +156,10 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) vecAiming = gpGlobals->v_forward; } - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); + 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; @@ -198,21 +168,20 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - -#if defined ( OLD_WEAPONS ) - m_pPlayer->pev->punchangle.x -= 2; -#endif } 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( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); + iResult = DefaultReload( 17, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); if (iResult) { diff --git a/dlls/wxdebug.h b/dlls/wxdebug.h new file mode 100644 index 0000000..321b1bc --- /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 index c1d1a9a..055a18c 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* 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. diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp new file mode 100644 index 0000000..127cb26 --- /dev/null +++ b/dlls/zombie.cpp @@ -0,0 +1,346 @@ +/*** +* +* 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. +* +* 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 similarity index 100% rename from engine/Anorms.h rename to engine/anorms.h diff --git a/engine/cdll_int.h b/engine/cdll_int.h index 8801448..f0fa76b 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -22,6 +22,12 @@ #ifndef CDLL_INT_H #define CDLL_INT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "const.h" + // this file is included by both the engine and the client-dll, // so make sure engine declarations aren't done twice @@ -205,12 +211,41 @@ typedef struct cl_enginefuncs_s 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 ); } cl_enginefunc_t; #ifndef IN_BUTTONS_H @@ -261,5 +296,12 @@ extern void ClientDLL_VGui_ConsolePrint(const char* text); extern int ClientDLL_Key_Event( int down, int keynum, const char *pszCurrentBinding ); extern void ClientDLL_TempEntUpdate( double ft, double ct, double grav, struct tempent_s **ppFreeTE, struct tempent_s **ppActiveTE, int ( *addTEntity )( struct cl_entity_s *pEntity ), void ( *playTESound )( struct tempent_s *pTemp, float damp ) ); extern struct cl_entity_s *ClientDLL_GetUserEntity( int index ); +extern void ClientDLL_VoiceStatus(int entindex, qboolean bTalking); +extern void ClientDLL_DirectorEvent(unsigned char command, unsigned int firstObject, unsigned int secondObject, unsigned int flags); + + +#ifdef __cplusplus +} +#endif #endif // CDLL_INT_H diff --git a/engine/custom.h b/engine/custom.h index 0ec8713..ab21eac 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -99,4 +99,4 @@ qboolean COM_CreateCustomization( struct customization_s *pListHead, struct reso struct customization_s **pCustomization, int *nLumps ); int COM_SizeofResourceList ( struct resource_s *pList, struct resourceinfo_s *ri ); -#endif // CUSTOM_H \ No newline at end of file +#endif // CUSTOM_H diff --git a/engine/eiface.h b/engine/eiface.h index d0989e6..3c822b7 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -253,6 +253,11 @@ typedef struct enginefuncs_s 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); } enginefuncs_t; // ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138 diff --git a/engine/keydefs.h b/engine/keydefs.h index 8558f5b..d4b54df 100644 --- a/engine/keydefs.h +++ b/engine/keydefs.h @@ -58,6 +58,7 @@ #define K_KP_SLASH 172 #define K_KP_MINUS 173 #define K_KP_PLUS 174 +#define K_CAPSLOCK 175 // @@ -118,4 +119,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/Progs.h b/engine/progs.h similarity index 100% rename from engine/Progs.h rename to engine/progs.h diff --git a/engine/studio.h b/engine/studio.h index 69c7c84..53479c3 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -359,4 +359,4 @@ typedef struct #define RAD_TO_STUDIO (32768.0/M_PI) #define STUDIO_TO_RAD (M_PI/32768.0) -#endif \ No newline at end of file +#endif diff --git a/game_shared/bitvec.h b/game_shared/bitvec.h new file mode 100644 index 0000000..a7f2b15 --- /dev/null +++ b/game_shared/bitvec.h @@ -0,0 +1,179 @@ +//========= Copyright © 1996-2001, 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 0000000..109964f --- /dev/null +++ b/game_shared/vgui_checkbutton2.cpp @@ -0,0 +1,197 @@ +//========= Copyright © 1996-2001, 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 0000000..ca0b12f --- /dev/null +++ b/game_shared/vgui_checkbutton2.h @@ -0,0 +1,101 @@ +//========= Copyright © 1996-2001, 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 0000000..7d9ceca --- /dev/null +++ b/game_shared/vgui_defaultinputsignal.h @@ -0,0 +1,39 @@ +//========= Copyright © 1996-2001, 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 0000000..2fc8cba --- /dev/null +++ b/game_shared/vgui_grid.cpp @@ -0,0 +1,398 @@ +//========= Copyright © 1996-2001, 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 0000000..cfd9376 --- /dev/null +++ b/game_shared/vgui_grid.h @@ -0,0 +1,122 @@ +//========= Copyright © 1996-2001, 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 0000000..c84ea10 --- /dev/null +++ b/game_shared/vgui_helpers.cpp @@ -0,0 +1,45 @@ +//========= Copyright © 1996-2001, 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 0000000..e79a06d --- /dev/null +++ b/game_shared/vgui_helpers.h @@ -0,0 +1,31 @@ +//========= Copyright © 1996-2001, 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 0000000..760a7f5 --- /dev/null +++ b/game_shared/vgui_listbox.cpp @@ -0,0 +1,201 @@ + +#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 0000000..f24a947 --- /dev/null +++ b/game_shared/vgui_listbox.h @@ -0,0 +1,115 @@ +//========= Copyright © 1996-2001, 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 0000000..fd90571 --- /dev/null +++ b/game_shared/vgui_loadtga.cpp @@ -0,0 +1,93 @@ +//========= Copyright © 1996-2001, 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 0000000..ba85bb6 --- /dev/null +++ b/game_shared/vgui_scrollbar2.h @@ -0,0 +1,62 @@ +//========= Copyright © 1996-2001, 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 0000000..c8af14b --- /dev/null +++ b/game_shared/vgui_slider2.cpp @@ -0,0 +1,436 @@ +//========= Copyright © 1996-2001, 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 0000000..4f1d3f8 --- /dev/null +++ b/game_shared/vgui_slider2.h @@ -0,0 +1,67 @@ +//========= Copyright © 1996-2001, 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 0000000..af29510 --- /dev/null +++ b/game_shared/voice_banmgr.cpp @@ -0,0 +1,197 @@ +//========= Copyright © 1996-2001, 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 0000000..3db37b9 --- /dev/null +++ b/game_shared/voice_banmgr.h @@ -0,0 +1,57 @@ +//========= Copyright © 1996-2001, 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 0000000..abd49ef --- /dev/null +++ b/game_shared/voice_common.h @@ -0,0 +1,24 @@ +//========= Copyright © 1996-2001, 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 0000000..18726f4 --- /dev/null +++ b/game_shared/voice_gamemgr.cpp @@ -0,0 +1,246 @@ +//========= Copyright © 1996-2001, 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"}; + + + +// ------------------------------------------------------------------------ // +// 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 ); + + CVAR_REGISTER( &voice_serverdebug ); + 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); +} + + +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; + + 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() && 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 0000000..21e8f51 --- /dev/null +++ b/game_shared/voice_gamemgr.h @@ -0,0 +1,75 @@ +//========= Copyright © 1996-2001, 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); + + +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 0000000..3e98d82 --- /dev/null +++ b/game_shared/voice_status.cpp @@ -0,0 +1,861 @@ +//========= Copyright © 1996-2001, 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. +#include "../cl_dll/hud.h" + +#include "../cl_dll/cl_util.h" +#include +#include +#include +#include "../cl_dll/parsemsg.h" +#include "../cl_dll/hud_servers.h" +#include "../cl_dll/demo.h" +#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; +} + + +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(gEngfuncs.pfnGetGameDirectory()) + { + if(m_bBanMgrInitialized) + { + m_BanMgr.SaveState(gEngfuncs.pfnGetGameDirectory()); + } + } +} + + +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->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->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); + return 1; +} + + +int CVoiceStatus::VidInit() +{ + FreeBitmaps(); + + + if( m_pLocalBitmap = vgui_LoadTGA("gfx/vgui/icntlk_pl.tga") ) + { + m_pLocalBitmap->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + } + + if( m_pAckBitmap = vgui_LoadTGA("gfx/vgui/icntlk_sv.tga") ) + { + m_pAckBitmap->setColor(Color(255,255,255,1)); // 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_pLabel->setVisible( m_Labels[i].m_clientindex != -1 ); + } + else + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pLabel->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], 100 ); + 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_pLabel->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]; + if(!gEngfuncs.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 bSquelch = !IsPlayerAudible(iClient+1); + bool bBanned = m_BanMgr.GetPlayerBan(playerID); + bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; + + // Get the appropriate image to display on the panel. + if (bSquelch) + { + pPanel->setImage(NULL); + } + else 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_pIcon ) + pLabel->m_pIcon->setVisible( false ); + + if( pLabel->m_pBackground ) + pLabel->m_pBackground->setVisible( false ); + + if( pLabel->m_pLabel ) + pLabel->m_pLabel->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->setVisible( true ); + + pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); + } + else + { + pLabel->m_pIcon->setVisible( false ); + } + + 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 (m_AudiblePlayers[iPlayer-1]) + { + 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, !m_BanMgr.GetPlayerBan(playerID)); + UpdateServerState(false); + } +} diff --git a/game_shared/voice_status.h b/game_shared/voice_status.h new file mode 100644 index 0000000..31f97c5 --- /dev/null +++ b/game_shared/voice_status.h @@ -0,0 +1,225 @@ +//========= Copyright © 1996-2001, 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); + +private: + + 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); + + +private: + + 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. + +private: + + bool m_bBanMgrInitialized; + + // Labels telling who is speaking. + CVoiceLabel m_Labels[MAX_VOICE_SPEAKERS]; +}; + + +// 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 0000000..2812b76 --- /dev/null +++ b/game_shared/voice_vgui_tweakdlg.cpp @@ -0,0 +1,289 @@ +//========= Copyright © 1996-2001, 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 0000000..94e5590 --- /dev/null +++ b/game_shared/voice_vgui_tweakdlg.h @@ -0,0 +1,25 @@ +//========= Copyright © 1996-2001, 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 d503680..c78e3bc 100644 --- a/pm_shared/pm_debug.c +++ b/pm_shared/pm_debug.c @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "mathlib.h" #include "const.h" #include "usercmd.h" @@ -300,4 +301,4 @@ void PM_ViewEntity( void ) } } -#endif \ No newline at end of file +#endif diff --git a/pm_shared/pm_debug.h b/pm_shared/pm_debug.h index d9818a4..84c5088 100644 --- a/pm_shared/pm_debug.h +++ b/pm_shared/pm_debug.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -21,4 +21,4 @@ void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert); void PM_ShowClipBox( void ); -#endif // PMOVEDBG_H \ No newline at end of file +#endif // PMOVEDBG_H diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index dbd2d5c..7bf0112 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -84,6 +84,7 @@ typedef struct physent_s } physent_t; typedef struct playermove_s playermove_t; + struct playermove_s { int player_index; // So we don't try to run the PM_CheckStuck nudging too quickly. diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h index fd380d1..dcfce83 100644 --- a/pm_shared/pm_info.h +++ b/pm_shared/pm_info.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -19,4 +19,4 @@ #define MAX_PHYSINFO_STRING 256 -#endif // PM_INFOH \ No newline at end of file +#endif // PM_INFOH diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h index 8974238..e402f0a 100644 --- a/pm_shared/pm_materials.h +++ b/pm_shared/pm_materials.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -30,4 +30,4 @@ #define CHAR_TEX_GLASS 'Y' #define CHAR_TEX_FLESH 'F' -#endif // !PM_MATERIALSH \ No newline at end of file +#endif // !PM_MATERIALSH diff --git a/pm_shared/pm_math.c b/pm_shared/pm_math.c index 51c59f9..e9ae9df 100644 --- a/pm_shared/pm_math.c +++ b/pm_shared/pm_math.c @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -167,6 +167,82 @@ void AngleIMatrix (const vec3_t angles, float matrix[3][4] ) 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( vec3_t v1, 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) { @@ -335,4 +411,4 @@ void VectorAngles( const vec3_t forward, vec3_t angles ) angles[0] = pitch; angles[1] = yaw; angles[2] = 0; -} \ No newline at end of file +} diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 56d971b..872a23e 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -29,14 +29,21 @@ #ifdef CLIENT_DLL // Spectator Mode + #include "..\common\hltv.h" float vecNewViewAngles[3]; float vecNewViewOrigin[3]; int iHasNewViewAngles; int iHasNewViewOrigin; int iIsSpectator; + unsigned int uiDirectorFlags; + + int iJumpSpectator; + float vJumpOrigin[3]; + float vJumpAngles[3]; #endif static int pm_shared_initialized = 0; +void InterpolateAngles( float *start, float *end, float *output, float frac ); #pragma warning( disable : 4305 ) @@ -1777,6 +1784,7 @@ void GetChaseOrigin( vec3_t targetangles, int iTargetIndex, vec3_t offset, vec3_ #endif } + /* =============== PM_SpectatorMove @@ -1792,8 +1800,12 @@ void PM_SpectatorMove (void) float fmove, smove; vec3_t wishdir; float wishspeed; + static vec3_t lastAngle; #ifdef CLIENT_DLL + vec3_t tempVec; + pmtrace_t tr; + if ( pmove->runfuncs ) { // Set spectator flag @@ -1801,31 +1813,62 @@ void PM_SpectatorMove (void) } #endif - // Are we locked onto a target? - if ( pmove->iuser2 ) + // Are we not roaming and locked onto a target? + if ( (pmove->iuser1 != OBS_ROAMING) && pmove->iuser2 ) { vec3_t vecViewAngle; vec3_t vecNewOrg; vec3_t vecOffset; - int i; + + int target1,target2 = 0; // Find the client this player's targeting - for (i = 0; i < pmove->numphysent; i++) + for (target1 = 0; target1 < pmove->numphysent; target1++) { - if ( pmove->physents[i].info == pmove->iuser2 ) + if ( pmove->physents[target1].info == pmove->iuser2 ) break; } - if (i == pmove->numphysent) - return; + if (target1 == pmove->numphysent) + { +#ifdef CLIENT_DLL + if ( pmove->runfuncs ) + { + // Force the client to keep last know view + VectorCopy( vecNewViewOrigin, pmove->origin ); + VectorCopy( vecNewViewAngles, pmove->angles ); + VectorCopy( vec3_origin, pmove->velocity ); + iHasNewViewAngles = true; + iHasNewViewOrigin = true; + } +#endif + return; // if we don't find the observers primary target, stop whole function + } VectorCopy( vec3_origin, vecOffset ); - // Calculate a camera position based upon the target's origin and angles - if (pmove->iuser1 == 1) + + if ( (pmove->iuser1 == OBS_DIRECTED) && pmove->iuser3 ) { - // Locked onto the target - VectorCopy( pmove->physents[i].angles, vecViewAngle ); + // find cameras seconds target + // Find the client this player's targeting + for (target2 = 0; target2 < pmove->numphysent; target2++) + { + if ( pmove->physents[target2].info == pmove->iuser3 ) + break; + } + + if (target2 == pmove->numphysent) + { + target2 = -1; // if we didn't found the second target + } + } + + // Calculate a camera position based upon the target's origin and angles + if ( (pmove->iuser1 == OBS_CHASE_LOCKED) ) + { + // use the targets directon as viewangles + VectorCopy( pmove->physents[target1].angles, vecViewAngle ); vecViewAngle[0] = 0; #ifdef CLIENT_DLL @@ -1834,6 +1877,67 @@ void PM_SpectatorMove (void) // Force the client to start smoothing both the spectator's origin and angles iIsSpectator |= (SPEC_SMOOTH_ANGLES | SPEC_SMOOTH_ORIGIN); } +#endif + } + else if ( pmove->iuser1 == OBS_DIRECTED ) + { + // use angles between primary and second target as viewangle + // tracking also seconds target +#ifdef CLIENT_DLL + if ( target2 > 0 ) + { + VectorSubtract( pmove->physents[target2].origin, pmove->physents[target1].origin, vecViewAngle ); + VectorAngles(vecViewAngle, vecViewAngle ); + vecViewAngle[0] = -vecViewAngle[0]; + + if ( uiDirectorFlags & DRC_FLAG_DRAMATIC ) + vecViewAngle[0]-=12.5f; + else + vecViewAngle[0]+=12.5f; + + if ( uiDirectorFlags & DRC_FLAG_SIDE ) + vecViewAngle[1]+=22.5f; + else + vecViewAngle[1]-=22.5f; + + GetChaseOrigin( vecViewAngle, target1, vecOffset, &tempVec); + + tr = *(pmove->PM_TraceLine( (float *)&tempVec, (float *)&pmove->physents[target2].origin, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); + + // if second target isn't viewable from this side, choose the other side + if ( tr.fraction != 1.0 ) + { + if ( uiDirectorFlags & DRC_FLAG_SIDE ) + vecViewAngle[1]-=2.0f * 22.5f; + else + vecViewAngle[1]+=2.0f * 22.5f; + } + } + else + { + + if ( target2 == -1 ) + { + // we had a second target but it disappeard, keep last known view angles + VectorCopy( vecNewViewAngles, vecViewAngle ); + + } + else + { // we have no second target, choose view direction based on + // entity/player direction + VectorCopy( pmove->physents[target1].angles, vecViewAngle ); + vecViewAngle[1] *= -0.5f; + } + } + + + if ( pmove->runfuncs ) + { + // Force the client to start smoothing both the spectator's origin and angles + iIsSpectator |= (SPEC_SMOOTH_ANGLES | SPEC_SMOOTH_ORIGIN); + InterpolateAngles( lastAngle, vecViewAngle, vecViewAngle, 0.1f ); + VectorCopy( vecViewAngle, lastAngle ); + } #endif } else @@ -1842,7 +1946,7 @@ void PM_SpectatorMove (void) VectorCopy( pmove->angles, vecViewAngle ); } - GetChaseOrigin( vecViewAngle, i, vecOffset, &vecNewOrg); + GetChaseOrigin( vecViewAngle, target1, vecOffset, &vecNewOrg); VectorCopy( vecNewOrg, pmove->origin ); VectorCopy( vecViewAngle, pmove->angles ); VectorCopy( vec3_origin, pmove->velocity ); @@ -1862,6 +1966,19 @@ void PM_SpectatorMove (void) { // Move around in normal spectator method // friction + + #ifdef CLIENT_DLL + // in free roam mode, spectator can jump within level + if ( iJumpSpectator ) + { + VectorCopy( vJumpOrigin, pmove->origin ); + VectorCopy( vJumpAngles, pmove->angles ); + VectorCopy( vec3_origin, pmove->velocity ); + iJumpSpectator = 0; + return; + } + #endif + speed = Length (pmove->velocity); if (speed < 1) { @@ -1913,6 +2030,7 @@ void PM_SpectatorMove (void) addspeed = wishspeed - currentspeed; if (addspeed <= 0) return; + accelspeed = pmove->movevars->accelerate*pmove->frametime*wishspeed; if (accelspeed > addspeed) accelspeed = addspeed; @@ -1922,6 +2040,7 @@ void PM_SpectatorMove (void) // move VectorMA (pmove->origin, pmove->frametime, pmove->velocity, pmove->origin); + } } @@ -2454,6 +2573,40 @@ void PM_NoClip() } +// 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 @@ -2545,6 +2698,8 @@ void PM_Jump (void) // 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 ); diff --git a/pm_shared/pm_shared.h b/pm_shared/pm_shared.h index eede8b5..d3ef95d 100644 --- a/pm_shared/pm_shared.h +++ b/pm_shared/pm_shared.h @@ -29,4 +29,11 @@ char PM_FindTextureType( char *name ); #define SPEC_SMOOTH_ANGLES (1<<1) #define SPEC_SMOOTH_ORIGIN (1<<2) +// 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_DIRECTED 4 + #endif \ No newline at end of file diff --git a/utils/bspinfo/mssccprj.scc b/utils/bspinfo/mssccprj.scc deleted file mode 100644 index 28c912c..0000000 --- a/utils/bspinfo/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[bspinfo.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/bspinfo", CFZBAAAA diff --git a/utils/common/cmdlib.c b/utils/common/cmdlib.c index 356dfe0..842e37d 100644 --- a/utils/common/cmdlib.c +++ b/utils/common/cmdlib.c @@ -39,6 +39,24 @@ qboolean archive; char archivedir[1024]; +void COM_FixSlashes( char *pname ) +{ +#if 0 + while ( *pname ) { + if ( *pname == '/' ) + *pname = '\\'; + pname++; + } +#else + while ( *pname ) { + if ( *pname == '\\' ) + *pname = '/'; + pname++; + } +#endif +} + + /* ================= Error diff --git a/utils/common/cmdlib.h b/utils/common/cmdlib.h index 93d0216..5af4065 100644 --- a/utils/common/cmdlib.h +++ b/utils/common/cmdlib.h @@ -49,6 +49,7 @@ typedef unsigned char byte; extern int myargc; extern char **myargv; +void COM_FixSlashes( char *pname ); char *strupr (char *in); char *strlower (char *in); int Q_strncasecmp (char *s1, char *s2, int n); diff --git a/utils/makels/makels.mak b/utils/makels/makels.mak new file mode 100644 index 0000000..d0f4a57 --- /dev/null +++ b/utils/makels/makels.mak @@ -0,0 +1,212 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=makels - Win32 Debug +!MESSAGE No configuration specified. Defaulting to makels - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "makels - Win32 Release" && "$(CFG)" != "makels - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "makels.mak" CFG="makels - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "makels - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "makels - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "makels - Win32 Debug" +RSC=rc.exe +CPP=cl.exe + +!IF "$(CFG)" == "makels - 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 "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\makels.exe" + +CLEAN : + -@erase "$(INTDIR)\makels.obj" + -@erase "$(OUTDIR)\makels.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /Fp"$(INTDIR)/makels.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/makels.bsc" +BSC32_SBRS= \ + +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:console /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:console /machine:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\ + /subsystem:console /incremental:no /pdb:"$(OUTDIR)/makels.pdb" /machine:I386\ + /out:"$(OUTDIR)/makels.exe" +LINK32_OBJS= \ + "$(INTDIR)\makels.obj" + +"$(OUTDIR)\makels.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "makels - 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 "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\makels.exe" "$(OUTDIR)\makels.bsc" + +CLEAN : + -@erase "$(INTDIR)\makels.obj" + -@erase "$(INTDIR)\makels.sbr" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\makels.bsc" + -@erase "$(OUTDIR)\makels.exe" + -@erase "$(OUTDIR)\makels.ilk" + -@erase "$(OUTDIR)\makels.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /YX /c +CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR"$(INTDIR)/" /Fp"$(INTDIR)/makels.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/"\ + /c +CPP_OBJS=.\Debug/ +CPP_SBRS=.\Debug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/makels.bsc" +BSC32_SBRS= \ + "$(INTDIR)\makels.sbr" + +"$(OUTDIR)\makels.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +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:console /debug /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:console /debug /machine:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\ + /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/makels.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/makels.exe" +LINK32_OBJS= \ + "$(INTDIR)\makels.obj" + +"$(OUTDIR)\makels.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "makels - Win32 Release" +# Name "makels - Win32 Debug" + +!IF "$(CFG)" == "makels - Win32 Release" + +!ELSEIF "$(CFG)" == "makels - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\makels.cpp + +!IF "$(CFG)" == "makels - Win32 Release" + + +"$(INTDIR)\makels.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "makels - Win32 Debug" + + +"$(INTDIR)\makels.obj" : $(SOURCE) "$(INTDIR)" + +"$(INTDIR)\makels.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/utils/makels/mssccprj.scc b/utils/makels/mssccprj.scc deleted file mode 100644 index db5158e..0000000 --- a/utils/makels/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[makels.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/makels", LGZBAAAA diff --git a/utils/makevfont/StdAfx.cpp b/utils/makevfont/StdAfx.cpp deleted file mode 100644 index afb75a8..0000000 --- a/utils/makevfont/StdAfx.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// makevfont.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/utils/makevfont/StdAfx.h b/utils/makevfont/StdAfx.h deleted file mode 100644 index 0027f8c..0000000 --- a/utils/makevfont/StdAfx.h +++ /dev/null @@ -1,23 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__BAA53BFF_1A0D_11D4_8B54_009027BA6863__INCLUDED_) -#define AFX_STDAFX_H__BAA53BFF_1A0D_11D4_8B54_009027BA6863__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - - -#include -#include - - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__BAA53BFF_1A0D_11D4_8B54_009027BA6863__INCLUDED_) diff --git a/utils/makevfont/fileimage.cpp b/utils/makevfont/fileimage.cpp deleted file mode 100644 index bb1265f..0000000 --- a/utils/makevfont/fileimage.cpp +++ /dev/null @@ -1,198 +0,0 @@ - -#include -#include "fileimage.h" - - -// TGA header. -#pragma pack(1) - class TGAFileHeader - { - public: - unsigned char m_IDLength; - unsigned char m_ColorMapType; - unsigned char m_ImageType; - unsigned short m_CMapStart; - unsigned short m_CMapLength; - unsigned char m_CMapDepth; - unsigned short m_XOffset; - unsigned short m_YOffset; - unsigned short m_Width; - unsigned short m_Height; - unsigned char m_PixelDepth; - unsigned char m_ImageDescriptor; - }; -#pragma pack() - - - -// ---------------------------------------------------------------------------------------- // -// FileImageStream_Memory. -// ---------------------------------------------------------------------------------------- // -FileImageStream_Memory::FileImageStream_Memory(void *pData, int dataLen) -{ - m_pData = (unsigned char*)pData; - m_DataLen = dataLen; - m_CurPos = 0; - m_bError = false; -} - -void FileImageStream_Memory::Read(void *pData, int len) -{ - unsigned char *pOut; - int i; - - pOut = (unsigned char*)pData; - for(i=0; i < len; i++) - { - if(m_CurPos < m_DataLen) - { - pOut[i] = m_pData[m_CurPos]; - ++m_CurPos; - } - else - { - pOut[i] = 0; - m_bError = true; - } - } -} - -bool FileImageStream_Memory::ErrorStatus() -{ - bool ret=m_bError; - m_bError=false; - return ret; -} - - - -// ---------------------------------------------------------------------------------------- // -// Encode/decode functions. -// ---------------------------------------------------------------------------------------- // -static void WriteRun(unsigned char *pColor, FILE *fp, int runLength) -{ - unsigned char runCount; - - runCount = runLength - 1; - runCount |= (1 << 7); - fwrite(&runCount, 1, 1, fp); - fwrite(pColor, 1, 4, fp); -} - - -// Load in a 32-bit TGA file. -bool Load32BitTGA( - FileImageStream *fp, - FileImage *pImage) -{ - TGAFileHeader hdr; - char dummyChar; - int i, x, y; - long color; - int runLength, curOut; - unsigned char *pLine; - unsigned char packetHeader; - - - pImage->Term(); - - // Read and verify the header. - fp->Read(&hdr, sizeof(hdr)); - if(hdr.m_PixelDepth != 32 || hdr.m_ImageType != 10) - return false; - - // Skip the ID area.. - for(i=0; i < hdr.m_IDLength; i++) - fp->Read(&dummyChar, 1); - - pImage->m_Width = hdr.m_Width; - pImage->m_Height = hdr.m_Height; - pImage->m_pData = new unsigned char[hdr.m_Width * hdr.m_Height * 4]; - if(!pImage->m_pData) - return false; - - // Read in the data.. - for(y=pImage->m_Height-1; y >= 0; y--) - { - pLine = &pImage->m_pData[y*pImage->m_Width*4]; - - curOut = 0; - while(curOut < pImage->m_Width) - { - fp->Read(&packetHeader, 1); - - runLength = (int)(packetHeader & ~(1 << 7)) + 1; - if(curOut + runLength > pImage->m_Width) - return false; - - if(packetHeader & (1 << 7)) - { - fp->Read(&color, 4); - for(x=0; x < runLength; x++) - { - *((long*)pLine) = color; - pLine += 4; - } - } - else - { - for(x=0; x < runLength; x++) - { - fp->Read(&color, 4); - *((long*)pLine) = color; - pLine += 4; - } - } - - curOut += runLength; - } - } - - return true; -} - - -// Write a 32-bit TGA file. -void Save32BitTGA( - FILE *fp, - FileImage *pImage) -{ - TGAFileHeader hdr; - int y, runStart, x; - unsigned char *pLine; - - - memset(&hdr, 0, sizeof(hdr)); - hdr.m_PixelDepth = 32; - hdr.m_ImageType = 10; // Run-length encoded RGB. - hdr.m_Width = pImage->m_Width; - hdr.m_Height = pImage->m_Height; - - fwrite(&hdr, 1, sizeof(hdr), fp); - - // Lines are written bottom-up. - for(y=pImage->m_Height-1; y >= 0; y--) - { - pLine = &pImage->m_pData[y*pImage->m_Width*4]; - - runStart = 0; - for(x=0; x < pImage->m_Width; x++) - { - if((x - runStart) >= 128 || - *((long*)&pLine[runStart*4]) != *((long*)&pLine[x*4])) - { - // Encode this run. - WriteRun(&pLine[runStart*4], fp, x - runStart); - runStart = x; - } - } - - // Encode the last run. - if(x - runStart > 0) - { - WriteRun(&pLine[runStart*4], fp, x - runStart); - } - } -} - - diff --git a/utils/makevfont/fileimage.h b/utils/makevfont/fileimage.h deleted file mode 100644 index 8bd6800..0000000 --- a/utils/makevfont/fileimage.h +++ /dev/null @@ -1,85 +0,0 @@ - -#ifndef __FILEIMAGE_H__ -#define __FILEIMAGE_H__ - - - #include - - - class FileImageStream - { - public: - virtual void Read(void *pOut, int len)=0; - - // Returns true if there were any Read errors. - // Clears error status. - virtual bool ErrorStatus()=0; - }; - - - // Use to read out of a memory buffer.. - class FileImageStream_Memory : public FileImageStream - { - public: - FileImageStream_Memory(void *pData, int dataLen); - - virtual void Read(void *pOut, int len); - virtual bool ErrorStatus(); - - - private: - unsigned char *m_pData; - int m_DataLen; - int m_CurPos; - bool m_bError; - }; - - - - // Generic image representation.. - class FileImage - { - public: - FileImage() - { - Clear(); - } - - ~FileImage() - { - Term(); - } - - void Term() - { - if(m_pData) - delete [] m_pData; - - Clear(); - } - - // Clear the structure without deallocating. - void Clear() - { - m_Width = m_Height = 0; - m_pData = NULL; - } - - int m_Width, m_Height; - unsigned char *m_pData; - }; - - - // Functions to load/save FileImages. - bool Load32BitTGA( - FileImageStream *fp, - FileImage *pImage); - - void Save32BitTGA( - FILE *fp, - FileImage *pImage); - - -#endif - - diff --git a/utils/makevfont/fontfiles.pl b/utils/makevfont/fontfiles.pl deleted file mode 100644 index 3763a38..0000000 --- a/utils/makevfont/fontfiles.pl +++ /dev/null @@ -1,99 +0,0 @@ - -##################################################################################### -# FontFiles.pl -# Parses the VGUI scheme text files and generates font bitmaps. -# Font bitmaps go in valve\gfx\vgui\fonts or tfc\gfx\vgui\fonts. -##################################################################################### - -##################################################################################### -# NOTE TO MOD AUTHORS -# Point gameDir at the game's root directory. -##################################################################################### - - -$gameDir = "..\\..\\.."; - -# Other paths -$searchDir = "$gameDir\\tfc"; -$makevfontCmd = "release\\makevfont.exe"; -$outDir = "$gameDir\\valve\\gfx\\vgui\\fonts"; - - -# Open stuff and make sure it all exists. -open (TESTFILE1, $makevfontCmd) or die "File $makevfontCmd doesn't exist, please edit the script to point to the right location.\n"; -opendir(DIR, $searchDir) or die "Directory $searchDir doesn't exist, please edit the script to point to the right location.\n"; -opendir(TESTDIR1, $outDir) or die "Directory $outDir doesn't exist, please edit the script to point to the right location.\n"; - - -while($_ = readdir(DIR)) -{ - if($_ =~ /_textscheme.txt/) - { - # Get the filename. - $filename = $_; - - # Extract the prefix. - s{ - (.*)_textscheme\.txt - }{$1}x; - $prefix = $_; - - # Parse it. - $schemeName = ""; - $fontName = ""; - $fontSize = ""; - - open(FILE, "$searchDir\\$filename") or die "Cannot open $filename for read!"; - while() - { - if($_ =~ /SchemeName.*=.*/) - { - # Get SchemeName. - s{ - SchemeName.*=.*\"(.*)\" - }{$1}x; - s{(.*)\n}{$1}x; # For some reason, it captures the carriage return here.. - $schemeName = $_; - } - else - { - if($_ =~ /FontName.*=.*/) - { - # Get FontName. - s{ - FontName.*=.*\"(.*)\" - }{$1}x; - s{(.*)\n}{$1}x; # For some reason, it captures the carriage return here.. - $fontName = $_; - } - else - { - if($_ =~ /FontSize.*=.*/) - { - # Get FontSize. - s{ - FontSize.*=[ ]*(.*) - }{$1}x; - s{(.*)\n}{$1}x; # For some reason, it captures the carriage return here.. - $fontSize = $_; - } - } - } - - if($schemeName =~ /.+/ && $fontName =~ /.+/ && $fontSize =~ /.+/) - { - # Ok, found a scheme.. generate a file for it. - $cmd = "$makevfontCmd -font \"$fontName\" -pointsize $fontSize \"$outDir\\$prefix\_$schemeName.tga\"\n"; - print "$cmd"; - system("$cmd"); - print "\n"; - - $schemeName = ""; - $fontName = ""; - $fontSize = ""; - } - } - } -} - - diff --git a/utils/makevfont/makevfont.cpp b/utils/makevfont/makevfont.cpp deleted file mode 100644 index 82ce2a4..0000000 --- a/utils/makevfont/makevfont.cpp +++ /dev/null @@ -1,378 +0,0 @@ -// makevfont.cpp : Defines the entry point for the console application. -// - -#include "stdafx.h" -#include "fileimage.h" -#include "vfontdata.h" - - - - -bool CreateVFont( - char *pOutFile, - char *pFontName, - int pointSize, - bool bItalic, - bool bBold, - bool bUnderline) -{ - HFONT hFont, hOldFont; - int i; - char theChar; - SIZE charSize; - int bitmapCharWidth, bitmapCharHeight; - HDC hDC, hMemDC; - bool bRet; - RECT rc, rcChar; - HBITMAP hBitmap, hOldBitmap; - BITMAPINFOHEADER *pbmheader; - BITMAPINFO tempbmi; - BITMAPINFO *pbmi; - unsigned char *bits; - int nScans; - FileImage fileImage; - FILE *fp; - - - hFont = hOldFont = NULL; - hDC = hMemDC = NULL; - hBitmap = hOldBitmap = NULL; - pbmi = NULL; - bRet = true; - - - // Make the font. - hFont = CreateFont( - pointSize, - 0, - 0, - 0, - bBold ? FW_HEAVY : FW_MEDIUM, - bItalic, - bUnderline, - 0, - ANSI_CHARSET, - OUT_TT_PRECIS, - CLIP_DEFAULT_PRECIS, - PROOF_QUALITY, - VARIABLE_PITCH | FF_DONTCARE, - pFontName); - - if(!hFont) - { - printf("CreateFont failed!\n"); - goto HANDLE_ERROR; - } - - hDC = GetDC(NULL); - hMemDC = CreateCompatibleDC(hDC); - if(!hMemDC) - { - printf("CreateCompatibleDC failed!\n"); - goto HANDLE_ERROR; - } - hOldFont = (HFONT)SelectObject(hMemDC, hFont); - - // Figure out the biggest character. - bitmapCharWidth = bitmapCharHeight = 0; - for(i=0; i < NUM_VFONT_CHARS; i++) - { - theChar = (char)i; - if(!GetTextExtentPoint32(hMemDC, &theChar, 1, &charSize)) - { - printf("GetTextExtentPoint32 failed!\n"); - goto HANDLE_ERROR; - } - - if(charSize.cx > bitmapCharWidth) - bitmapCharWidth = charSize.cx; - - if(charSize.cy > bitmapCharHeight) - bitmapCharHeight = charSize.cy; - } - - // We get 1 pixel of padding because, for some reason, Windows likes to clip off the left pixel - // on some letters like W. - bitmapCharWidth++; - - // Setup our bitmap. - hBitmap = CreateBitmap(bitmapCharWidth * NUM_VFONT_CHARS, bitmapCharHeight, 1, 1, NULL); - if(!hBitmap) - { - printf("CreateBitmap failed!\n"); - goto HANDLE_ERROR; - } - hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); - - SetTextColor( hMemDC, 0x00ffffff ); - SetBkMode( hMemDC, TRANSPARENT ); - - // Fill the background. - rc.left = rc.top = 0; - rc.right = bitmapCharWidth * NUM_VFONT_CHARS; - rc.bottom = bitmapCharHeight; - FillRect( hMemDC, &rc, (HBRUSH)GetStockObject( BLACK_BRUSH ) ); - - // Draw characters in. - for(i=0; i < NUM_VFONT_CHARS; i++) - { - // Draw the letter in the first slot for a letter. - rcChar.left = 0; - rcChar.top = 0; - rcChar.right = bitmapCharWidth; - rcChar.bottom = bitmapCharHeight; - FillRect( hMemDC, &rcChar, (HBRUSH)GetStockObject( BLACK_BRUSH ) ); - - if(i != '\t') - { - rcChar.left = 1; // 1-pixel border for letters like W... - theChar = (char)i; - DrawText(hMemDC, &theChar, 1, &rcChar, DT_NOPREFIX | DT_LEFT); - - // Blit into the correct spot (by drawing/blitting, it sort of automatically clips the letter into - // its box (Windows seems to want to draw some of them out of their bounding box). - rcChar.left = i * bitmapCharWidth; - rcChar.top = 0; - rcChar.right = (i+1) * bitmapCharWidth; - rcChar.bottom = bitmapCharHeight; - - if(!BitBlt(hMemDC, - i * bitmapCharWidth, - 0, - bitmapCharWidth, - bitmapCharHeight, - hMemDC, - 0, - 0, - SRCCOPY)) - { - printf("BitBlt failed!\n"); - goto HANDLE_ERROR; - } - } - } - - // Get the bits out. - memset(&tempbmi, 0, sizeof(BITMAPINFO)); - pbmheader = ( BITMAPINFOHEADER * )&tempbmi; - - pbmheader->biSize = sizeof( BITMAPINFOHEADER ); - pbmheader->biWidth = bitmapCharWidth * NUM_VFONT_CHARS; - pbmheader->biHeight = -bitmapCharHeight; - pbmheader->biPlanes = 1; - pbmheader->biBitCount = 32; - pbmheader->biCompression = BI_RGB; - - // Figure out how many bytes to allocate and setup a buffer. - nScans = GetDIBits(hMemDC, hBitmap, 0, bitmapCharHeight, NULL, &tempbmi, DIB_RGB_COLORS); - pbmi = ( BITMAPINFO * )malloc( sizeof ( BITMAPINFOHEADER ) + 2 * sizeof( RGBQUAD ) + pbmheader->biSizeImage ); - memcpy( pbmi, &tempbmi, sizeof( BITMAPINFO ) ); - bits = ( unsigned char * )pbmi + sizeof( BITMAPINFOHEADER ) + 2 * sizeof( RGBQUAD ); - - // Read the bits in. - nScans = GetDIBits(hMemDC, hBitmap, 0, bitmapCharHeight, bits, pbmi, DIB_RGB_COLORS); - if(nScans == 0) - { - printf("GetDIBits failed!\n"); - goto HANDLE_ERROR; - } - - - // Save as a PCX/TGA file. - fp = fopen(pOutFile, "wb"); - if(!fp) - { - printf("fopen(%s, \"wb\") failed!\n", pOutFile); - goto HANDLE_ERROR; - } - - fileImage.m_Width = bitmapCharWidth * NUM_VFONT_CHARS; - fileImage.m_Height = bitmapCharHeight; - fileImage.m_pData = (unsigned char*)bits; - Save32BitTGA(fp, &fileImage); - fileImage.Clear(); - - fclose(fp); - - goto CLEANUP; - - -HANDLE_ERROR:; - bRet = false; - - -CLEANUP:; - if(hMemDC) - { - if(hOldBitmap) - SelectObject(hMemDC, hOldBitmap); - - if(hOldFont) - SelectObject(hMemDC, hOldFont); - - DeleteDC(hMemDC); - } - - if(hBitmap) - { - DeleteObject(hBitmap); - } - - if(hFont) - { - DeleteObject(hFont); - } - - if(pbmi) - { - free(pbmi); - } - - return true; -} - - -/* -// Writes out a test string to "testout.tga" using the font it just generated for debugging purposes. -void DoTest(char *pFilename) -{ - // TEST. - FILE *fp; - VFontData fontData; - char *pStr = "Blah blah blah. This is a string of text I am printing out. \"Here is something in quotes, blah blah blah.\""; - int len, curXOffset, iChar, width, x, y; - HWND hWnd; - HDC hDC; - FileImage outImage; - - - - fp=fopen(pFilename, "rb"); - LoadVFontDataFrom32BitTGA(fp, &fontData); - - int spacing=1; - - len = strlen(pStr); - outImage.m_Width = fontData.m_BitmapCharWidth * len + len*spacing; - outImage.m_Height = fontData.m_BitmapCharHeight; - outImage.m_pData = new unsigned char[outImage.m_Width * outImage.m_Height * 4]; - memset(outImage.m_pData, 0, outImage.m_Width*outImage.m_Height); - - hWnd = GetDesktopWindow(); - hDC = GetDC(hWnd); - - curXOffset = 0; - for(iChar=0; iChar < len; iChar++) - { - width = fontData.m_CharWidths[(unsigned char)pStr[iChar]]+1; - for(y=0; y < fontData.m_BitmapCharHeight; y++) - { - for(x=0; x < width; x++) - { - if(fontData.m_pBitmap[y*fontData.GetLineWidth()+x+(unsigned char)pStr[iChar]*fontData.m_BitmapCharWidth]) - { - *((unsigned long*)&outImage.m_pData[(y*outImage.m_Width+curXOffset+x)*4]) = 0xFFFFFFFF; - } - else - { - *((long*)&outImage.m_pData[(y*outImage.m_Width+curXOffset+x)*4]) = 0; - } - } - - for(x=0; x < spacing; x++) - { - *((long*)&outImage.m_pData[(y*outImage.m_Width+curXOffset+width+x)*4]) = 0; - } - } - - curXOffset += width + spacing; - } - - ReleaseDC(hWnd, hDC); - - fclose(fp); - - - fp = fopen("testout.tga", "wb"); - Save32BitTGA(fp, &outImage); - fclose(fp); -} -*/ - - -int main(int argc, char* argv[]) -{ - char fontName[256]; - int pointSize; - bool bItalic, bBold, bUnderline; - int i; - - - // Setup defaults. - strcpy(fontName, "Arial"); - pointSize = 7; - bItalic = bBold = bUnderline = false; - - - printf("makevfont.exe Version 1.0 by Valve (%s)\n", __DATE__ ); - printf ("----- Creating Font ----\n"); - - - // Read parameters in. - for (i=1 ; i= argc ) - { - printf( "MakeVFont: Insufficient point sizes specified\n" ); - return -1; - } - pointSize = atoi( argv[i+1] ); - i += 1; - } - else if (!strcmp(argv[i],"-italic")) - { - bItalic = true; - printf ( "italic set\n"); - } - else if (!strcmp(argv[i],"-bold")) - { - bBold = true; - printf ( "bold set\n"); - } - else if (!strcmp(argv[i],"-underline")) - { - bUnderline = true; - printf ( "underline set\n"); - } - else if ( argv[i][0] == '-' ) - { - printf("Unknown option \"%s\"", argv[i]); - return -1; - } - else - break; - } - - if ( i != argc - 1 ) - { - printf("usage: makevfont [-font \"fontname\"] [-italic] [-underline] [-bold] [-pointsize size] outfile"); - return -1; - } - - CreateVFont( - argv[argc-1], - fontName, - pointSize, - bItalic, - bBold, - bUnderline); - - return 0; -} diff --git a/utils/makevfont/makevfont.dsp b/utils/makevfont/makevfont.dsp deleted file mode 100644 index d023e7b..0000000 --- a/utils/makevfont/makevfont.dsp +++ /dev/null @@ -1,123 +0,0 @@ -# Microsoft Developer Studio Project File - Name="makevfont" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=makevfont - Win32 Debug -!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 "makevfont.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 "makevfont.mak" CFG="makevfont - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "makevfont - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "makevfont - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "makevfont - 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 "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c -# 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 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:console /machine:I386 -# ADD 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 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:console /machine:I386 - -!ELSEIF "$(CFG)" == "makevfont - 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 "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# 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 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:console /debug /machine:I386 /pdbtype:sept -# ADD 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 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:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "makevfont - Win32 Release" -# Name "makevfont - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\fileimage.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=.\makevfont.cpp -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"stdafx.h" -# End Source File -# Begin Source File - -SOURCE=.\vfontdata.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# Begin Source File - -SOURCE=.\ReadMe.txt -# End Source File -# End Target -# End Project diff --git a/utils/makevfont/vfontdata.cpp b/utils/makevfont/vfontdata.cpp deleted file mode 100644 index 6f75e77..0000000 --- a/utils/makevfont/vfontdata.cpp +++ /dev/null @@ -1,77 +0,0 @@ - -#include "vfontdata.h" -#include "fileimage.h" - - - -VFontData::VFontData() -{ - m_BitmapCharWidth = m_BitmapCharHeight = 0; - m_pBitmap = NULL; -} - -VFontData::~VFontData() -{ - if(m_pBitmap) - delete [] m_pBitmap; -} - - - -bool LoadVFontDataFrom32BitTGA(FileImageStream *fp, VFontData *pData) -{ - FileImage fileImage; - unsigned char *pInLine, *pOutLine; - int i, x, y; - int rightX; - - - if(!Load32BitTGA(fp, &fileImage)) - return false; - - pData->m_pBitmap = new unsigned char[fileImage.m_Width * fileImage.m_Height]; - if(!pData->m_pBitmap) - return false; - - pData->m_BitmapCharWidth = fileImage.m_Width / NUM_VFONT_CHARS; - pData->m_BitmapCharHeight = fileImage.m_Height; - - // Convert the data and figure out the extents of each letter. - for(i=0; i < NUM_VFONT_CHARS; i++) - { - pInLine = &fileImage.m_pData[i * pData->m_BitmapCharWidth * 4]; - pOutLine = &pData->m_pBitmap[i * pData->m_BitmapCharWidth]; - - rightX = 0; - for(y=0; y < pData->m_BitmapCharHeight; y++) - { - for(x=0; x < pData->m_BitmapCharWidth; x++) - { - if(*((long*)&pInLine[x*4])) - { - pOutLine[x] = 1; - if(x > rightX) - rightX = x; - } - else - { - pOutLine[x] = 0; - } - } - - pInLine += pData->m_BitmapCharWidth * NUM_VFONT_CHARS * 4; - pOutLine += pData->m_BitmapCharWidth * NUM_VFONT_CHARS; - } - - // Wouldn't normally detect any spacing for the space character.. - if(i == ' ') - pData->m_CharWidths[i] = pData->m_BitmapCharWidth / 4; - else - pData->m_CharWidths[i] = rightX; - } - - return true; -} - - - diff --git a/utils/makevfont/vfontdata.h b/utils/makevfont/vfontdata.h deleted file mode 100644 index a552094..0000000 --- a/utils/makevfont/vfontdata.h +++ /dev/null @@ -1,44 +0,0 @@ - -#ifndef __VFONTDATA_H__ -#define __VFONTDATA_H__ - - - #include - #include "fileimage.h" - - - #define NUM_VFONT_CHARS 256 - - - class VFontData - { - public: - VFontData(); - ~VFontData(); - - // Line width in pixels. - int GetLineWidth() {return m_BitmapCharWidth * NUM_VFONT_CHARS;} - - - public: - - int m_CharWidths[NUM_VFONT_CHARS]; - - // The letters are placed in the bitmap at constant spacing. - // m_CharWidths is used while drawing. - int m_BitmapCharWidth; - int m_BitmapCharHeight; - - // Each pixel is a byte - 1 or 0. - unsigned char *m_pBitmap; - }; - - - // Setup a VFontData from a TGA file. - bool LoadVFontDataFrom32BitTGA(FileImageStream *fp, VFontData *pData); - - -#endif - - - diff --git a/utils/mkmovie/mssccprj.scc b/utils/mkmovie/mssccprj.scc deleted file mode 100644 index 70bf234..0000000 --- a/utils/mkmovie/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[mkmovie.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/mkmovie", XGZBAAAA diff --git a/utils/qbsp2/mssccprj.scc b/utils/qbsp2/mssccprj.scc deleted file mode 100644 index 3d005bf..0000000 --- a/utils/qbsp2/mssccprj.scc +++ /dev/null @@ -1,9 +0,0 @@ -SCC = This is a Source Code Control file - -[qbsp2.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/qbsp2", FHZBAAAA - -[writebsp.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/qbsp2", FHZBAAAA diff --git a/utils/qcsg/mssccprj.scc b/utils/qcsg/mssccprj.scc deleted file mode 100644 index 0a0734b..0000000 --- a/utils/qcsg/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[qcsg.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/qcsg", WHZBAAAA diff --git a/utils/qlumpy/mssccprj.scc b/utils/qlumpy/mssccprj.scc deleted file mode 100644 index be6f84c..0000000 --- a/utils/qlumpy/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[qlumpy.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/qlumpy", HIZBAAAA diff --git a/utils/qrad/mssccprj.scc b/utils/qrad/mssccprj.scc deleted file mode 100644 index c9a109f..0000000 --- a/utils/qrad/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[qrad.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/qrad", OIZBAAAA diff --git a/utils/readme.txt b/utils/readme.txt deleted file mode 100644 index 5e2cb9a..0000000 --- a/utils/readme.txt +++ /dev/null @@ -1,24 +0,0 @@ -last updated: January 4th, 1999 - -This ZIP file contains the source code to many of the tools Valve used to build the game Half-Life. Most are derived from Quake 1 tools released by id Software (c). - -BSPINFO: minor changes from the Quake1 original. - -QCSG: added ability for textures to stay in WAD's, other minor changes from the Quake1 original. - -QBSP2: minor changes from the Quake1 original. - -VIS: minor changes from the Quake1 original. - -QRAD: added 1/R*R light falloff, colored lighting, sun/sky illumination, automatic smoothing, and fixed minor bugs. - -QLUMPY: added support for paletted sprites. - -MAKELS: reads a directory tree and automatically builds a script for qlumpy. - -SMDLEXP: exports our intermediate model format (SMD) from 3DStudio Max 2.x and Character Studio 2.x (tm). You'll need to get 3DStudio Max SDK as well as the Character Studio SDK in order to compile the program. See http://www.ktx.com for more information. Their SDK comes included with 3DStudio Max, so if you have MAX than you'll have everything you need. If you don't have 3DStudio Max, then it doesn't really matter since without it this program is useless other than as a example of how to export to our intermediate format. - -STUDIOMDL: highly modified version of the Quake1 modelgen. Added support for skeletons, events, multiple textures, tristrips, and other features. - -MDLVIEWER: an OpenGL MDL viewer. This program really doesn't do much, but it's included as an example of how to process the MDL files and how to do all the math required to have them draw correctly. You can get the necessary GLUT include files and library files at http://www.opengl.org/Downloads/Downloads.html . From the ZIP file, extract glut.h into your equivalent \msdev6\vc98\Include\Gl directory, and the libs into \msdev6\vc98\Lib directory. - diff --git a/utils/smdlexp/mssccprj.scc b/utils/smdlexp/mssccprj.scc deleted file mode 100644 index e2547f5..0000000 --- a/utils/smdlexp/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[smdlexp.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/smdlexp", YIZBAAAA diff --git a/utils/sprgen/mssccprj.scc b/utils/sprgen/mssccprj.scc deleted file mode 100644 index de63216..0000000 --- a/utils/sprgen/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[sprgen.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/sprgen", HJZBAAAA diff --git a/utils/studiomdl/mssccprj.scc b/utils/studiomdl/mssccprj.scc deleted file mode 100644 index 9fbe338..0000000 --- a/utils/studiomdl/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[studiomdl.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/studiomdl", NJZBAAAA diff --git a/utils/studiomdl/studiomdl.c b/utils/studiomdl/studiomdl.c index 0d4d833..c8bc0cd 100644 --- a/utils/studiomdl/studiomdl.c +++ b/utils/studiomdl/studiomdl.c @@ -2592,7 +2592,7 @@ int lookupActivity( char *szActivity ) int Cmd_Sequence( ) { int depth = 0; - char smdfilename[4][1024]; + char smdfilename[MAXSTUDIOGROUPS][1024]; int i; int numblends = 0; int start = 0; diff --git a/utils/vgui/include/VGUI_ImagePanel.h b/utils/vgui/include/VGUI_ImagePanel.h index b33c3d6..e5a3689 100644 --- a/utils/vgui/include/VGUI_ImagePanel.h +++ b/utils/vgui/include/VGUI_ImagePanel.h @@ -13,6 +13,11 @@ class Image; class VGUIAPI ImagePanel : public Panel { public: + inline ImagePanel() + { + _image=null; + } + ImagePanel(Image* image); public: virtual void setImage(Image* image); diff --git a/utils/vgui/include/VGUI_InputSignal.h b/utils/vgui/include/VGUI_InputSignal.h index e421d0b..7bf4dc4 100644 --- a/utils/vgui/include/VGUI_InputSignal.h +++ b/utils/vgui/include/VGUI_InputSignal.h @@ -26,7 +26,6 @@ public: virtual void keyTyped(KeyCode code,Panel* panel)=0; virtual void keyReleased(KeyCode code,Panel* panel)=0; virtual void keyFocusTicked(Panel* panel)=0; - //virtual void hotKeyTyped(const HotKey* hotKey,Panel* panel)=0; }; } diff --git a/utils/vgui/include/VGUI_Label.h b/utils/vgui/include/VGUI_Label.h index 2617bd4..72bc80b 100644 --- a/utils/vgui/include/VGUI_Label.h +++ b/utils/vgui/include/VGUI_Label.h @@ -34,6 +34,11 @@ public: Label(const char* text,int x,int y,int wide,int tall); Label(const char* text,int x,int y); Label(const char* text); + + inline Label() : Panel(0,0,10,10) + { + init(1,"",true); + } private: void init(int textBufferLen,const char* text,bool textFitted); public: diff --git a/utils/vgui/include/VGUI_LineBorder.h b/utils/vgui/include/VGUI_LineBorder.h index c72a354..f8fd8f7 100644 --- a/utils/vgui/include/VGUI_LineBorder.h +++ b/utils/vgui/include/VGUI_LineBorder.h @@ -20,6 +20,8 @@ public: LineBorder(int thickness); LineBorder(Color color); LineBorder(int thickness,Color color); + + inline void setLineColor(int r, int g, int b, int a) {_color = Color(r,g,b,a);} private: virtual void init(int thickness,Color color); protected: diff --git a/utils/vgui/lib/win32_vc6/vgui.lib b/utils/vgui/lib/win32_vc6/vgui.lib index ddb2c91207b900d9b88b7a9c0eae2b28f3c45438..66f7e909a7f18fec6b0f7ca5b4bb8e070b5f0735 100644 GIT binary patch delta 67293 zcmeFacXU-n^v64A%Ati2Is`}pgx*3&YUmw8N2G)*y@`kjTu?+ngg`KZNEZ>2E&?Lb zL_|bNL`0IP}fM6w!O7L!T>55z%;$xSU|H%Y`#S1)nq6nZ`3hU7F+&9?29@aI-;P z*~SPJ;hTjYvzT4CoI#z9V}_7yOcCdq!7jHN1Ay|S6IqW}SmoRO2D=YtNW6K)phk3L zgxwo*#DEqC^)?g+cHid?zWybd4dlPa4R)79%%Lk@yE6ICJtiAIaVQLP6Eond=)Df5 z;7elWeI|QVGKeQP7$L_tV6yowhp>1iiBGaH*%j@HN`sk?e#p4AOjbk(MBkzgX*rX` z2UVGD10{gCRXvdvcm@A3hvU} z^DKk<^B6Pid&Cs6qme-lSi%T#VqYTd@!ForYZwsN9A*b9V=seT0Ji{D`;5a1!~xN^ zkHO9|oe}D&4+9}&`)ppK1q_vG>j}skV8%w#KrWO z8MrXfAaB>f1nXdO)eS21YDUN}pr8*wRD<;nYdT_v;Pt)+JLgbFsDFAm96HJr@pFtp z4nx`kaSB;ssDoDwcKwjS7PlCo0^u$o7hW)^I**v)n+43L@I$qOpMjlqg+cvwjTwFq zLePL+bqsRQR7Qx)g&i)YXd8fa@PK$~MRF*vkx%3oVcna>j=dgATQ$!~OBCvC9 z@X-&ZPCx-7KGaD6|56}kOyBZHkG7b8@5WCoC5p-=(U)OPq5 z{SaL)8SFgq2-0|_PQ${)pS~*i0e&55kZ-!9zc*DK!6@MsN+aO;t;irxm5Idp4 zNG%|)MmStq%LI^jV+?k>;fzpOPXONuCYPZg0M)p(!#bFacq74J=f-LV)XB9Df54Z- zFMAB~t#aZ z@xu;=4}m&`0f;~DIP7hK+T8-PgCB_iWC1ZTfys9G9f;e(2D@emBh<&O4R%8;$v}?k z%4DPA25~zEvfvIgs1NF4{r{jIgpkvXZaD;G1#RL)Ic7YW|DZfCXevdT(sLziZpYX9DahQyOi77~3g4P=1ePjtS9_i_$ zALH-~keLwG#D^!C44m!I{tS~qJj!B_?;#lfi!;b(2vQ(!qND=(4(j?1#1fDVM>$l1 z*@?JYO!g~oP%UC``-L=o7>@lPeuxJsm%y%%I~XA6!v91i_=t!bjeCOS2Jsjv2Gp#o z2011kHyDEr;>l3lc!0+b4f5?3SWQamJVG*u_O^5+v!=Xf);I#>p z8&4U;i!CT*Tj2leX_+Ff-gmfigDD`NbvCHYScHJwh~I(QJklUpJw~Xoat8SV)sXlO z@j|RPZcxo(Enqh~Wsp9|w7ljJu?P8&A2Jr2^@a(FP}Bip+7c$az_)}|&SAXGWKA`l6-)u0M@WP}~`zC($J%m#Ajbc33;4Y9KgeXhp--&)NiuWqnAZ)Ju~ z8<}k=ir1n{JuT_*WGPcbA-Dy|RZ9)3GU5T);V}+@&zTKWEyxjt;5s0GK`|nJW)8pj zINkue$2k1_92dae$qv5;GD+-B>#zrniJ!+i{0egdHLblvEEXLg$0K8+E;;axnA}Dj zOms3xQJN8I+5z|Y5GM%Mt3w^G zjbnXhdGIh z+#uKNW`_6i+GeOjnyF|rm8txQdg8U34yCd%1?1!D4iB#}2~+~*e**j#k;S1bHW5U- z^$rnp@%~&yax;T^cQtA{cqfO!#zB&yB5FEN)pi){w&fV1?CK70oni{urMW@H?uMIo zGrNNiv+DpFBU*t>f5c&8HoVgBpe;;Cq=Tu63{4E`D|AA9dBtG~tOMl3J`VE=FbPz- zybfjOFa_+E;Rd<(4Ay`AQ1k8^~S~%lL7S!q8P}_l^iY#rQ@(8*g*Bj(! zWYlI~XPi`xa9|ghO|&UsP#NGB;KM#$`N8&FZG3&1Wj-Jqs7V1&$d!r+rRVSXZ4SBIQ1Es-0Y0y`T1CaSG9 z$W>t|xnSL3gZi`{Gt5Wy1G`BhgPigZdp;;l6kp~rGl1x!Xz>E6xMZgOcZ+LF#R}AL@_fWZ(fHyunLhE89;p8gvrjW z9rD>s=JU~yF^MGLH375PV~`)i6`i3a5i&ZF`*;QS;~hT3D^Lr@8RWDGte6;p2!(}! zT@kw~po(H?2Qn<$p!#1x{ih$@ODBTJ><)T9ap+xuDWV4kAo`tf=)0LIqEBmwHzzYi zbc;(Q3tmC=3Wv{*Fh$Hjg(Tvd8SFRqGavnsmp40HSc;+oE+JBhqgfJx>5hWG@jG!W z#^F3bPNFa3Y=Fa=iA)lI%yKw96*UF?gQ8^!hyVWxXR3d+!vX{muv;!OsJWQ6 zp)Fq9GP`r6K@CG)C&CdYz%GNj4phw+2AR;65$YyZNy9X}0v3|UJiLOuzR~zWAkBz- zeI4%hXUcF1uQ+fBL;4V*F%Dq?_#Ly{5N}W=QKEs|iWCOw+(d_8(I+tk*NK1eZ(xU{ zHz?omN=y-zYC4pLAAwyX#Gpz9GDCqKxSQR$EKCt+pyZip@c&u_4^XEQ4Dy>EjIiJA>d!g9ba?4Z(LV20H^Y?hU5j}J#S1XQeJDyaL**kz7d6L#A~g{gKz?(_psMd-gx%h^ z7C+W9wGcG`*iEsH16d5UpNLt4)vAs|QMk!~85hM&w;@x2-2=f2R1GLegl%!yT9_%K zEMf)N^{@^Am8OA%y^Sd!e%N)fks#{TacGK}0vUtc?G7^$#UdRZqv!y&ypO{&CN&?&Gx zpx^+d;|+E*Y`cIg9$`=mpTLq&m@HAip=V7diIP|c42ZLm$b=lI2RYKh|0UoTqIx}p z%JDufypPii_?{R!&0zo{pXd+E5F>*PO4dQag5{#S8e~Z<&%_Uy1Thl>_uS%8eFMe- zr3N~z_ASANVhOYJ4o@TjuL)Q@jvG`F_?0Ny*Wohagt%lol$eI{3C2 zs4GA%UGDHDlq9|iH`rZaNy3*okl8>z2{zbukf#J|?@*!_Zk>BERlc~vZqSht>ct_4 z48xfMcCm8~#m_Jss250I;&F^aOcSPvng<-lPDeSOj{Ki>4EOyN93q-ANtC`|P+M0c zg29ia4R%AA7|3r?h=AQ}wL#A6%Ve*O4rMxH=HP1-C7|d-N+8Q327ns3(qa4~oPa&T z{oniR9ef9n4q$4O!xRJ=@gZhFd=zbv+fLxP4g9#rVaGTofx3~+Aa|z4Ap?S|{91(v|IT4iRgW#tGhePRcP7L;CaoB~~ z5x+x*`0XVz_&3=9l5F@ll)QwQ6IGC+KK!s-l{Tn3m^qN;N++@$uLz(e6Ad=pWOyA4 z12y%y!7kndK1YzwLBIhy8xh`TwL|$Z+-!s~y9jEE0euvqF;^OVcI)DdP@(9MsEVp& zfZ3{oR(%~}b|HXvF}rzDgRFqr8&D@IfQrnZs=%GVE{bYrK%5i>tr65f&8%mz^J6i} zzW|^A?ub@6R2+>?L1m<)0l`gWG?l!3ERk1KsWp+Ev63F#)9oF5z-OddhCc)&u z?l{Mw9>MIuE`WZBN+%5JHrz(=6%M$^P((3U6UgTS4a)ZjfdK4+$aA9dP=mSy(-T8s zGUBZU4x>;&h`~=B{@aI@5B`q(7q4$f5j4@ z5hD8q{0HnRwn5!NFcGag8{|{uFY#oNgO0{wGTcN|Yhh41Cow~=5PT>Rf^3-Xuqyx= z0@j2(d_Iv$VmW>OzdQyTM?@r$Pl6mCpePalJu#@ok`Yp$LhY~OQ1t+lhGuvL)%F?G zVkkkBajVm^rxQ;l2LPW%;XK&CC zc><;!oRG|(ev%$Zw(pVe8|Y&y&@YA9{To(HvQfl++A!6<%L^TZzdMd|UAdD;xg zBM;QwCs?JmZ-~g~|85a|Xc1I>_7M;CzhoMy*s#4Rt|T_vHkqeOy^+p1RHV3+*s8`9 zp4P2&=I){Zsiv}Y=-a#ZK(8@zF^@j6zzT4W6Fa?Ju)Z@?Wr&UWCA|(?XnE$EbXA9a z#M8g3T~MkQsEO2TCwb?U)T0@%%mT|ZwWO=2agGK`PZk{K$%m?XW2mfH}d{=l-tnaT3u`_;1s|RNiLErBF>+i<;=gT}>Y{?G-^!3X; zyWX6ehe0S%ue!o>k@Tj^`K|65^z4#W79%z7Di6}>XYjK6%t(=4=bgdB^oml})XZ=7 z9?`7d;NEqI3>-2%lKvGNvn^Nb_-*L}Q@ovfQ-#vjH{W?5@T~Y+;sc)lNyY;H6fEGF zV3B_dwr`GP^J+*oyQXBhKt!Zu9UDkCy{=@ZYD@OKj${jJNfuI1vMYE$3;sO<@3p|S zt&pu=U$XVMwg<1fo(WcToMhKpNVfN;U^fOR*1DU`cKN#6Y<~rtb?k1luojAS?Wx%0 zUW!%fp;(iCiskC7*vj6DUFm~=M=O?aS+VePHai!r*!WB~n{-LB$Z*9r7gTK970G5r zC|0hn&En1~mMugvc3!d7kS|@{X6wQJZzbE`$7WaF#F!%#^R4e~vlatvmhiS>&->b} zWPh6-|5vg@U2N7B+`}IKNkeE}7&Dsz?V~ZW-D)mbd>E|o z3FNv;Hn@^xY2zSQQL>_aCF5x&tNMXt_u9ZRw**@O*gwL@rXLq<+f@i!HX9M3*pc}d zAX2gEUn|z5jbgJh+w9n%iapw=Sfd?^Eg2x$z7vAA2ivYemfNgXM#c6oknBut#U`y# ztWR6C&w_SG6}$hNV%2xz{ehBQ_(!nepeEW4M!OpUKE`pfL{VU1(G*K+zTeS6cQ7j^l&5oQ>EbfS6r}o0HBP7dlNwAoU zf*rk$*`~2s)hvqDTq;@XhOopM#R5AimL-?X9{!`)sKYoo+oRZmVUj&MC)hv`d`q%0 z8*vbXm|7y)@cM|K)r#fqs94Dy=yWLHlnMo7zsX z6eGZI81s3CXIw;(!w(1hDvtntYFb#(oLkLvRQh#VjFfz@%7-cRT!fK zEaA&;vt@rPcIN;z|4Fe1aK-U6g0%+s5Nr|+$7F)v&@ciGk0RI(AlNP;*n-fm8QOJ3 zyVVG`h^vCFy@I&83xB7x*@>*M+%m~ZH%3;i!(`q-HsrS1+LMZP`a`ijzrg>U-$Fw) zS_^-0G`t2^v`529Un062VMb`!0}Z>PVF5JU4Oi4e!+5x&3L<+g1`R=UKf!=K5Z$XW z;4TcE;i-KV8wqtS-lMNk&N zBud$A&JoE1{*tWtImxEQOE&qCWHsNFY+z$d_O4H`kr2+CU9zQA#c2q|6*&ho{$M4YZW?0Ra15u5Nw|N*$mCt6g(9tz?Bp(abbqut9gvFwn zWOp#|L@3a)lVm-zp!7o7a~&nyjlrrs5G?Ki2D=X>-bU18Jqg6`{Rd&-he)~4V6mSh ztMD#z{sz*$fz6`o+idGh_hOu!>;@ zcQBh-lMw?`FbFDV$oq(m@pv7F%z;Zze2CRD5M{VMtOdodp|3dfIS>)0 z-%(gkI#z*8z+%<6g=BSt@j4a3 z)BX*~8ex6Dlm~vaz*3kpKW6w`unQX%Yx^DY8wCG=VzLQQy#*cN{YCiw4t_th0ZTPF zwNbJy2*|Y8k!Dv>Pp&|bXNdI8c*V7mc&*1ID;I`7UcgF-f#bdvC=Sih7@EaFnQMsP zJrR;MiAAyLjUWk?Y{@hPSr;_4Q02xW%A;U~bdoK@ayqcB^HfL2!iv2gg!Q0=&8F{^ zY#Xe#8uHaSu6MTC#!e_)pyX42*M!>KANZ4F}&Bm zwPbVfdq5hbD(e38^NR6{2*x$Yg7?u!8!WN7b_lMk`5IQoQt0n7Ecy_ZOu+9EHVY|> zT~Irl&Bec)!Sbu$MHJ_F2R?6sl&EO49o4Xwx3yVy8!mYZ1C+MeZp?0J2kZ$NqsFI~ zEZamxFJ3Rf^cUcUCK;f>S14XzVh6PZd5!@K%tJPn!$MXTf!)$(XVzkagNaN=+dl2! zVzil#+R@hc3HExIu^e82pD$uX`x7Yyf{sDpFPQBda{VM`Z~`^pG^_!F{=jm57;$qP z%78;qtVepd;W?~P0fS=Z<*LKyD6@q#N;a;f&FaiXJ@^n+vpp<}_rj2-kAmR;-6*G{ z@Q*VcP{pRBl)y8Y^2h?4l9XgV*8V zt54w$v~AP`Suq7=yAv{|IIK4llj;HaBFKyxNV$65v5P?m`_SLHa|cY%UP>-~tg8@{55_%H-gf22%z#nyu-J+XQ0jjGlIGwp|sNM97BJ_w#SQ8>CG zlEI2-tm&U&^Ev~2fHZ`f?}Wn>28sOTk>-=k0xWceG_^%&kekHzN{20e)kI*SxO zgZM!l`KBI5;Qa%?fM_W399k|z#KzA>kpPh>9@Vip?F&aX!2B(0VlR+@PHtj_12{@z z^T6o5Sm{9DdkD0yONY||r zrCT9oo1&1RMw~-sT!y@_lN&py0PHg|+H4?7b3FDHX~!b}vy4HfXRtd#jwYPOiuMfx z3%5t3`r7Q$2-NI8h<4l|O&_V)+9riT*|63=#K1jVZ_o`99**(~T4)p_1nwTZHwHn> z!EVIMh{AYOzy9T+=dyqq4aL33xDDF&FG{wI@pC2jYMYwk5N9C!{^IT6TU!j zZpZEk9d3PyGTt2T6~{7N8zzTh>C50fC^vN_tOR8vFXN;Wf77R2(?-G#17L~%k_F@6br57-qfz}JpW_F#MN!#; zJ~p7uz*3ks>c{ZBxT^-o6R>3~g3LgwkG_n1jZ26(1b45}D9^qcC=O+?%UO#0jRhq9 zD`?sk(T}^{;3tUOI?hK;y-L`uczNvgv3EQ40>Ol`d#)H3mf}cB{2ucdn~)epIMQ?a zSX9zk*zfh0tXTwV3kF&ZE0_KeN@IuJ=v({_3-pDIZ(}d4$53D|(rMBnL}po3xN*qO z@kqV*(IG4pH5I0tfErY3(yUu(N4+MLb>V{6l?zgdjM=Q)?#f~ zi@54D7uMT{{lh^7H%LG{r9Xtig!d-xLj4c?9T$E>l_K_|L+}VDs!#@||Z=G;sk>~8H}=w6fKAL4bVOd z+6UqKYE;sgcaZzIo`8PX3oKGlG#>3cqiEGcp<46=ufqm2m-k*fDTZ9x0h=7s^ z-d+P>nY3_Q0v0U1Hoy+6e;&k45GGU*`M(j{?0uCG^#Z;DBU^&B*zJJ5+mVV}u*t;Y z@dTaouMzd#P<{h(f^iia6V&{wSFqi>2>)NgiiXv0*?B}fR=P!J5lcr9Z1I@D3GA%U z&$KbPlSc6h#2ONT80uUsI|2p!y(`Gi_VCrI9yVK)j(vKYHx@^&Biedo74)67PFUNm zAFX)nkhR2GWSzIJSeLEl?2dKUx^3OFo?1B><40tFDSKM+H}N0%F8-DE z4?o3E`uGWcnvb#0@=4Z2YpHdKU*VVeMShh(=8vqWJb_Cggc4~*I+0!kicBKA$j@_$ zD7HY%7YoHw@rC$Od?Qwhbz-ex;#<*>Z4nRoA#qro5xu{54tjDDNt}$-eRr{+1je-@&U@IRl%$xDnyesd? zKNkb|>#P|6h=0mESsVC4tDm)n@8n-wRkeD9Bs0C1QnGBe-bH z9`V!Spm@Ol6KQ2LBy&j_#{cGTW|e<(pKQ<0S;wsnSj8;Ft&S8tJo{CP%NOFg_}0oS zn#B5S>vr+@`SYI7Au~&5xcCq@+Yf~{M6cM)sqcmY5u)zE4PUa zRx4SX*WwL%9o~RP@|wIpugmN4M!bzrwvg>*2l=|}DBH=+a;l|ylx!(m%Xh40yt23< zM_OOY* zHTkx+h?f;tllH!v5j29OdWCS}WyRy+tcYSJwzaAtS%kAre5*8pMZLUBw@=3@goQi^{wPFTsb1O!9#Yk~zg(xl&#gT|`znL$nq{_$nSJ-Vis$ zUb#<}Wq*knK7%h4VX~oYBv+Tv9G@qK%1Lsq{7_$okZ&sw7X?L8 zR!9VkJfa{A5&2nOQGn$Wg;{=4gcT5lSeOWBp`xnDE%wVi?7ZwJ)>*y8H}VVFUM!c3 zWTcp9y)M3%i=_`=wiqW?Tea8(@h)E>m&gy~ch)GrTih0(h-u;-aa)cQ#pQ2SRk_!y zA@}*LYI3Iat5se0wB8o8te>q&IosN8)t0f=9;=r8#i}WL$}ZN&R%0H;=kSC40)N7b zi1nhV941H0@2v|~8Qz3X;OqG|ev4-iMa6QlO577&WN-PAEG%k@8Y0e`V0GuQ{0zU% zvxsWqH}ODJkvrutGWRJNEvNAd;<=Sm=8_-t^CGvL%Fl_@I{S00P^k<&J?C8TG~D8f zr{mdp7T$q(7GDPm-{Ad08 z3#(A}KKw^HT)ZW|6K7>LUXsPjl01)&#U)>W%qZtu9mQdOh_@6`qJhKRF6}$$w?I>?I4yP+5wv;|KU~Ydr5S>WK6FEk2Tu;6p`mR*6++ zRoEIUguTaeh-ETPE|9C`MERkN7TrZR@sYUBS92{oi?4j5v-OL(DfWo#;%9M9{3?Hw z`D8hKv~ofm6PvA5R(`q3Dl5BM53D@=1O7F?!#@@K#Yyq6C@+W0v2rxuA!hRG;&;BE zca{U>K>04dbJJ9g<@eM2H6F^gia*4E@}Zn2r^=6IcUc2pVynu=h-z#sK7oH<)Mg)unr!^1*Lm~*TVnrz zy2SckF0p@F^;tKomo>_I-C6uo3vbmH+=%{{LI~|8M30 zzm@<0!^;2K|I3wMh}eVma_DIpdB#m=((|5y=20L$IyVo{{d40fpRfW}Ivp0wRqTMj za&8)%o42y`*kB&0p9DkX`!q6}4#~sQZMq%I+ZRvq>=7PFi_l?9tTcLXeV!)8Wjuj4 z*!?Cw#I|W)eLgAD{jPb6srDpZ<9~Rp>dXSG(*N>+Rnq0ruk7c#`wBhRmiz?U$EjYb z={(_vht(RVdfnE~C-a8x$FHN_pn3eN%r$Q7gQctt8?W&buep0qdJ+r|{6)Nc@-NkA`I4RsG*^qhlyx2~j9vX} zq1c6c&2xh(A2swmgjhUDZqwRuv8qw3+TgjgvSx&Q3#|-pLnS@m_VQ`FO8@g?a4)Y` zjvFjmzN(`j-Ey#a?7o`xh@yGoP%l~p<1DI{hMo*;ovK_$eQJ?aot`xGjFQ}sc?ePe zzR;@viYE)5#|}5m87kJ)PU&UyOx&i1>&5fzNe{s3yC+00-Fq+YsN)(JtF~#>Uh#>= zUxeuwzlox{%svr8zjWUxE+jRXnLnrQ^_vJ%rh#6yUxey8zu|1lX=NIe-7gw>8qC=* zg3Jhd<$kd$Q8aJ*$eu$64K3ZT7n)A^T{K8)qH7<3TBqNUS)E4De;3s}7fU$r4?W=b zzSAfJsaAmDOb#bLx6*SwTp2G=QI3kt-d>Dgeh3OjFozx(F9P(M>mp0C;LJ}{2_qN| zL7XAQ?rfAx--s6({W=^r5?f9hSyw$IY9zNeChm6a1mY&Wsm{jUo=a-_L(Y zmPkjPRmPxcb**?&Dt1vTNfXJF+&c4`q#@%)%jEZyd)*Q5?)C0*;Y=k0y=GuCE`S%( z3y)&Tch0zN;~70bw>0&mX9$irV+%-{7pH%rG1Wzbz#N4SWNKJ0H= zGh`*mWYfN5qU0;POPbf{WA1q+*&*(4_uFKK0CFw9k->5zqIBp#yrkdohw1*s1XI9q z(I$DG`IjWd#cODsTW3BlB2ux0(=zNI(Kxv!P1<>Xk>`DiiA4DmuaNh=4~M*zKPg%z z_fIin(u5*56h@tyiI?%4Rgy(?#3_H1n6_k+{Ajy96EE&JujJ^de%jr3@iOIPN(Hnn zsB51VB~lCNbvK1$^^y<^C#x?$$qVX;>nIF&F1dsMaIQrE6ozCWNXAb1JD-l=5`vyA zp@cUfQV@cL^}4enn{IiNr=w1jla%V^(061u$Hptqipt40JNrRm525IxsOcegO+BTn zoO5-cNg=28)N`Vit93}?`*G*RYsqidKL64|L(hx4$?qo{|Jr%C0h7BQdcobjr|y*| zhi2w^b<}+rEIN&JRnoIB_0XLzx)mXlJ9_WCDC#FG(tT8-$BJOqW%a>}BA*_A8qcYF zi(9LrFQ>ijl6xLh+)S{PMf38g$B}!A>AsiU7E5lr<+7(KO1beEmGX*uI~wVHPg9h? zWQ#1n;@Sk|irT?V4NB!;cf^SOSVx z!yLOG3)Tyti16etNf~2?LJ+~%=OB_#hdp(h!4vZ}D3aIx9;_D?l?9W#@kDz~M<&&1 zCzTv;Uc2G;CQZTEv^eyL)VFVlyn6f@u5_)dFzk+;?np_Fh%-0ceIy&U^DVbwJsDP4 zcfTca=$p4hfn@b5sFTWcJx8M9Ijs2a-4?;gVw7l(^80V69-`InxE1nDs-doZN92oL zbsUE+z% zmI%9y_e>Q{E_fR2d7`mH9*7RfPDn0HD<8On-J?)zz3zbs)$HoO%=c>O-t>YQ2J~xo>NDc zk*)|Mvzfdkv*AmiOz*tR^QX2)NRF)_OS(2$T8Yj2TR9pu7En!q`j2P_>-*LpE(#ZVD9eFl&qa20(LfqZQyLwd`w_|BH zWd;bt0Hf(*PP!{~Y3f;=-qRV=$vk>>TKA&vnadcGsFJLor}d=ae7#K znOASif#^NmT)9FsscsleX&Lj8Y@OtesM48>rEqaPjglwsI!^C$WNJOibZ`nl@FiT zdsit>s?OHUvw2+RUT{9uKW1}Jf)p@?p4Kt^K?D|e3pYn2pSd?Io{4I`D!bdGRKJbC zXoo*XFV2BP8&XiZHu#=O^BGC_m47onHOE)fnQk@MD&S`Va)YrFt!JOZ1d&6m&{yrt zjUe3|&vOLBb(x}WuhaG`NoGD|B0^zLWRTy@gpr}*xWJJKp(V$)r}a#0p}w0N^=*DA z7C-M@xF?$yk(fK1+^$)yy9c{n<0%$P=wh(`d^A2$cpmI7Jst;qp%3SQ1Mb8?%o|3Y z-jE0jHR`BLx9i@Dr+*XhH5=kJkSMzXJR=U3#;vmaTxW22qzookCi%d7D_Rf*+^ zf}#4)d~R3KP-dYktTTrqIj3E4JIQlXwL&ird1Vp%hA#TAKAxyvsh@=+ec?Y>;8LWR z(57fwMG}$8Wsb~lLWBYre+wb@Y^4AFgXffTjS&gfYwzOopV0j7X?nIAYY}aCK1+S8 zLH0-r%XN+*4rLN=G5n7+C~J&~DQnh~i4T8f&ZsBgDdrIyml5oW-St@C5*{s(U!tycy zoU?~YF(0?=_ay6D07(xs5t{54Ok`+r%WRNcA?lgz4~|SO9lZ`WbQ?2yGSKaotuFD=Uin*6NPbt|&60U&vthhhX#R7WKca|b0(`nx`_eTw+sWC5w-fl#G^l?+u{e46x zHZe!>^fSd=?ajCa!-h5hN2l(42v2nGNt6uJGj8H8z&p0*{Pq`k<8ZuHh@xKUsPFM( zQc1V(l0MWh>Xw5VdtWy3h2!uiT`6~_QbwEjqt6|F)!jcoA(Q08d3Bv&Up-HVNNLlZ~LmLWXG}=)7PNoQb$Pt*HTR_jcet?8(JjBAj%(J!d zM8rW|D#ER?XPrC*A9gDeuET25>9OaSIcW=RbfPWvVH$4TLwqEYn)u5PNsM@Ph{r=b zc1DTvuav%>Ht|!F+K~Q3mnkRPCtE$`=PF0^&T=v;S;BlQ+EBfy zf-L40GXs#=N&S0e*&_L(QK4EDnbmYu2NI_eI~umWh+juZ>YCX{LiRLbHo7RU^2+IV z!$)Ao^|c^L=vcL7XF@8Bcg_Sm|LHnw?Zz??LeNjKF=1vxm#+PV_VL$mR>^Yvej3~MFa}hr+ zJU2gA^m{e@>x;27P2(!;e76`r`0-kfK3p<>qYt32K@SRmVMl{wyIjcRC+ewX*Y&fS z?y+b-#uDU#8+vRl>H1LH)AFW%QOn)Zvq;_2zDV~%N8Oq!P`9^Xg68Lo`Kje`7XFYG zi#=W1-&yogndyc;D!U6ygq6StkEs+JPl3Cq->c*HnP+?UFM1hV!U?kfy~5o$9)6K} zfx{e)3uulH92e*b7WPTwD_Qeo(TC*KdtAsJ$;B^ z0-ZkVeT3e0tLMB_YKBQ#_KcHh*?X+525u*N7ThN^->7)}_kx>v_n(r-56>vBOQ!Az8qOGtb`{SPja5tGh&dJ4dkpnL-)-bJlxIk0Nv!0l z59txKEE#*}2b0$RbMSn4%k{7(GWod?O*e_93woLerPwe7@ zChYx3@{}Q^Z#H#@G)>x!M29CfM*4J}DD3Ank}*~!nKY0=iO}mxTiH^J&!n7X19sj`b-&{Y`b_$Clw0kT_QJWkUR#Ez zZZD*WaRsGF=0sNvyM@0ZcB_qhz4k<57Ib)Hu$5{UQhhZYQtio_*kR^So@(v!RN8D1 z)|mzV;+xmTDJPU2;~y&jiU4p=C`aP>2S;1kbxd9Nggis%q@ib~9GYfrJWJNW(ONrq z27A&Vw?5d;od%w=AFP|UcVDD#lZ>9{rH%5#=+R|)>NVFLi+M5q!DXGjtt)*!nU{}d zG+m}hJ<`jhCmkq+Kq$8MU9*DwCsLBt&HO3tLiNs$?%jyzZY)gKdfk07W%K;{$Nxp5 zfUefb-G^sF1xeR6b^S{Tg_}uI3b$~iOwdXH<(#@Plb~u-NdNGL+lkmdI_+!VVqqAz z_I|6P{|y@4WyYW=C<2+W@vn$|_v39vAy{iF*4!9d*!s;b?wdHz0Yx$WV;9c>#mfiw zjGyRyyEr*>n=NwdmR;T5B%OpC?MSi&6^*E1t^V{sCp7U!XNe`zS*=>NW7jpysw29& z&%L|fNW2xU39(XSZ!4yv&e_8~gm3@ zpx(_*Rs+4Wm&_Xb?5(o8i$^)njaEfnrkDFhYi6&+^{oZ^u0+ahf4{z82cDa;%7}x| zO8D!b-+K({k*NZisFX4jHYaW}n_#ThATyy7ucL?ba$C})Y*n54O}Dair)DfkcWTv0 z*~L?;`6+uA_xnaB3^LV8CgOBXzW}29eG_AJzh482w5rTaFs9Q7`+Cku+-Isa(V5Oa zmCnigxmEV;>uMzmp@2@ovDTdP?qh$?VN#^d)ZcZOL=S`Y=`XVd(amNa=vCWN2<&c^ zbxohU(03n{7z`nhsiSZAm*tWp#dDBR7ahc&-I7Z;^SN&YJss532M4%2@Mu_H*BI#1 zF!|A26O5Ff4fMK!?hjv*GB`=1p)NScEkUE3DU$k)UQThy5S-5i4RAjYQfB7|fl{Z!#X6x76Pcb$8?0{zU1;!(^y#fFH?jrF&4L1>J+T zB8eu+7d@X;wbn(3yFU)`OtTG5v+KQJy=o9NEc2Ep(%qk_wbdEkay!jq$##0|TW&LZ zPW{{KyKi|;g;Ny&4rHfRfhhjlK1g9FPbzgJ$)SNFOg|sta*KKX$b=Am!1g+XOqR?{ zhfV0vw_Ro<|E+#oW;2${3)xQkx3^_PlI33d*SL`U`vwhoI1tZjwixLi&|}2TBy>Fx z4r6d)xG&Z)AVf~yU}Mo z7s)@yTy!GbBhg&3wa4Vp+eW&q8%)^3fYf@W(486yHlgx4)+}O_9vlLL3pMJJ^7_giVz#1hm3WFn5Nap7%B{N9jN~q z>rPJ3wrP-VIxf|1lW9)HcCg+#&K(k-#2=!|`&@m$bV62IO(?d9ViuGqQQZgY!=q)< zq%81$nm$Zt9`7E*6Z*r+67LPN@Sx~;x4AsA`Ii1~ygN2MwPS=HFu{G%Qy1UXrzg1M zgj{7NPpkAu-TZxj#mq$t`FHg8_x-y~im*|n^^13L$K;I!kJj(%#UHqPAlsTA=$Ww5 z)WeJ{c*3;wME`jkA=2SJ68a_!>VkK<^+doJ{dl6wOUWy$>4uyA#G4 zJU&kU^P#&h&+Ubex*1ji_mm?hxmETQ*zt)%IrN1|()CEPXA3ofglev`a_Vj$`K6p= zA@a`qB=lo(e6VupBhPT|4^}=Pp|x34WLr}4OESVll01+V$%`86Zv;<3eW)``ar-T) zucWM*qq7by+KblAE~=8a>(1KqO_AyP<4@f86LdphmJ7Nen1LQ@b??RG1iE2clyIC*Q z=ypXG*K=}^8ajogJO>!D`fLpSwV_Qaw|;iZ{Yk1vY&MCxKa$1GwYi%rqldv}vC&Pk z=x&>#-He&;-4cw1?RE%@Rd$AD5<}=DugOZ*GGw`{3=SFrG6PK;fK$`}! zr{AsQ=ba>L8d0+597nWto8o%gCvJ1XNPfM3=7`>2f?hqAHyW2&n5c0}^g7oOjh<5> zZmvp>j+yy$>1uNm<=%kY=Z;*|5PYORSGgYAP6{}qCOp%W_m+rWHKiVR6oc#$LC zVpUPSb-t(Pm!c*Z>gv;<$-J>aU*Ys4SY*=UyLe>D3)2>;EJn7C_RYm7(NXxzO4_$0 zWgw)O-4{j&9bJQ0(2J_s$)3>0a+z)<>f0RCTk6Qp*r}?eW;KuOmpcFFvWIJ(ZDTAEPut;W=OP^{E!QXK$=1m&ab)aVtb&VQ>jCp+ zv*e4^(o}V7xq|Y2VK>X)i?!W~eWNEVa4Y6H4_HYTac-Fp-#|^J0C+w!Sf$r3bWeg- zK2t~O`4s&59ETx z=wV;DeUx&|`%b_3!nNj6(r5ZoItx-4^so`rimc7s>HD`_2N*BK%s?czNtgIi4o~(s zdB9ADK789ulL-vNm+ri$g*0PhKbrCPmYh|std3dcu4}YR7zsMn-2zp%AIGOVaF**~ zLC<$3f1sfjgo%>+%msI9(vvGjANuCuRuVcCCQADmmqs%)qS1cT!Ml1^6s)9> zH+H0u|C#K#uz)D0KT^u&5zoT9N0(UTwj+IzYR01vQh&jCYd*&RrUy~(zu!rktf{8e zb?r5%rZo%VBgv@D5Pp8zy-P64dA#22sJ6Ge4B9M~eUV zQ`Z@)kl$9-a|V1EYJ@Ja%IVV!{nOUO0Uc$vbh1i`m*L5_hdYu zrybK*H@H8Fp@qcEl$O-L(Lq83UP9yl4&Zi*`vbY-`sR1;4pN%oA3bQJ+YFv_!4vxW zM)$d3%H}8auubmfp4xOu-`?b&zh@mht%q%PuY+{2Y34?sL7hRVY4r@>lJ`uFbW3vd zS%}O`DCH;Od9LsrL~bYGYvG<=JU0yI5stBgo);t;|DxuJhzt6~7I#D>dD|#N-o6Nb z9RAWOPGRBS6`92dQpvsq!B)$yVt(=CvCd^ZcB|Vuo(1KKwtjRMLQiyFMeo+vDWcP3 z-fNI~@fH5|OYkOl1k;3#mh|Yxb;#^&%nPJu8P7s_g9=gUVpu4>8w`qMQ?2MT!J8x$ zT}%{7ty+2ZQMWLzZyBER^=21YFbfqCvfynhBE5!0b$?5rZ3Goli28l&^$v}GwwN#} z`#<{TE<)zncDQDz+b}d0V;GvsJt(-Z37$lOjQ`Wz9>IShc=uI;^p{XPC!_cEf4g3p zEDyBxGj2Vn|0K&N?~IZ{Fsa}?bi`uv;%Fr`?NSW-pVOd2!_*sicE68E*8RYYJ7FJV zu2-7k(V^8pyA9_F+b4R$9z2dbJ~w1b>~R;ply&7P$-4F{o{kdqi#_i6Puct#NfglY ze{nzEon)`1lzk3O7Bs_7+xuZK#hQs+inSMrow#6pLN|Y}`w4i;r}Pw$RIV7;&-Z$6 zP|<_ANV@j>zV|F{gfwSt{$y zM_`umho$SU`lReBGxZcs)=#VV7qK$?cjx}gEm@pV7oJ8Gdo}c|3RyW8-R(tm^!Vq>_18I)0?FhLNoVJ%y@TsxK}toO>ZO@=gwFgI zW_>CO-||XD&T~JMQ_uVpvU79cGo-42x^?x4KCa`|#}P zgY}G~?hTOVVjjAfQ)euPv%~F2-SrHC?hHi-7yG^GVVnj&xR?q3)~ew~?lM=TJ!3ZjH0VRQjg-EaNeHYB`KNcBdSkGQ*voYiCJ$ zk!$w9n4lSdbpOpDx$Ja+Xo^to%aYI4f>ZHsaJFU6D6qR7pPgymZdPQ4IymN)kF)O>zJdY;BFY^3zqHrO{nGkgPYpF4m(haN>p z)^#vN9T~0a>FsAEzD8dGMoOiVl<8W`8Fj`f_o2P#l&ZL1d>RG|=~LKGdvxXm6CHS! zASstdDMun|0EURjJdE9GQn?5a;B#;mvvE@BV^?F$#S-!pyb~ zW?SCr?TyO#i|+N!vxBdsw_kKG97&5`QuyoeLSH(f{jEuOM?3Pt!N!}RI2G*FCP6X>g?;)@AaQ$vhckxV`pov?$ zr>w7kx#_+sfP@npw6HY5c(LV=q0k7yBE(%d1HO^w&%$?_n%;Ef?j5J!k=LC9*`w%2h7xIJJ1w@+dJV&YuLyY zEtEPY=;>sm85weDbx~Z8e(H` zOc@3J)^4+Ere+RWl#G(Jt8Yb04yyrgcf9XblD0I)@^r7*TCch9t`KymYcA3!25oei z2ks*UPl&XI9tU2>5%s|b?yRDP+UQCPbvwuecf$WKeQ1Q|1jz0C_ImL{_he}fMgy8d z2VLwxcX)YDPdcLa&~cW(OHGi{`KVEY4*g!|GOi0R@8^0?rR=1)KXTi_qs1F~=VR=m zGaW^J=>OPlOOIG*5_5gQ$#YBCMQ?wCXWUw5RY7`n9`}NtRM^a{sjzh=S@+lZ+$QO! zTRwG<;@J;G>%&hytFOCdcik<)-O>{XJ@nZGw*fp)JN4AvpLzBL-bbNuF>7o{i%fdE zcV^uA=eWMz9X+#`Au<2nime{EXv>)xaP8QNgjd-_8#y z*PhRlIDPfm7oJ#hZvpzz#T=jdRPtk6&Ql4rSQu5R>oo#nl%5lox+eIL7;Cl>t)pv6 zXuW6yFAy6uR;D8F*@+J{W5;fv8Jvow2>?>U7>iEd2N`jFu#R}8CLa00j(q5SmG>3e zm@z!x86D!NG<0luDk^!DAL{g8>w(Jgirziq!yNI`Qn~&_g(pgfJ44r6Um%sCQ(6OO zXmFekt(U4blG5E+kJ5dFBk!|S)#T;Pb5{Dc9+C#$%algB{!WAE@s*Jzky@abqC!4; z2fL3k|4(IC9$sa2ynB<}TTucD$|7456%<*6B1(iLt_4JbED8t&5d{I+s)7q)ajVMa zRYpYww6-b&p)M#Y1hFny4Y4k*tt@J5)heNOQ>*;mcfRCi=DQ#I{Qk@H*vl@9}}TVz#^oja%RTO}{o z>f4Ry7hth*Vn&I4nrqeV!jIdexS1VAdI{O>@FdSTprB&IxhrD-`9RP3IR6V?0Tqa$c$IWwdck{TM60{$X zSty@3w-lV4x)WtsaZ^&BvNAPXPIVGwlAFHi!008sFFAg95xDQG!f>=~1FgHIx@Fw7 zd2q6H$uqR1_T2Kp&NZ1y(CO=;(OpWFG_d##3<5>!W2>z$~8vGw@0aHW3>;ZID&R#ZBK1I!+apTiQlYIWPsMz)>A6 zCwJ<>k2ii&QLMaLDt>|L$?Q#6%rm&MQt#+|a<`Q~X^dxD+a^hLN?3Od#1F~g*&-gJ7F)M=~H3tTBuLr2rcXVY%vdQ19 zwU14I7ohgcMWfhxamhP5-lc(_n}9b0WVfNMW!dn|T-G9oi?&HIDZaNCijqUrS$%lsDRoD~ivixHU@4h}7^!4(fy!So0v*;PxVUSD zn&5}|z2o*C*UIr$igYj5C>!Nb+@L-5`9<+|$*Ku$!S|=KeimN3qdGYxb5NrE(y4XD z!57K?BAiRt%tJ|jdI7tW@tr_|-4~+H4zXF-1`^oB?a#+e4{*7DY@5}Pj z?INd_QkTLs+n?xCmh3}Vv22`OU(Ub&nVVdN^zC-iho*N1wQ94VQk3*e3^y?J2_f_z&To z$6N&;zof(t+eKU-0n@k(RP)nPH+MF#^|6d8wMQk_TJkTlr_}l-=llOkedUhMEReZp zSn@7e@CouTHXd-H%ikd1nwY4tqthrEX!=4%z3Dp zl=qLD_rC=L>aH?}%c_C#0-67__@LB?=oY{DS)E%P53T(pptX2QM!zT--9_eC0k&)` z7Ss3r?br>^ia{7f&di=s)Ckl08V=6?BDFl}_h3escO>NfIvD+$L2>)F8atwI z0%GN(d&>3arx9ZjwGtZ&V&4YDYR`|Gk2o>nR+q$x8((ApiF{v<0(8{GhM&E-`x2By z4UU`gt@P#dJ(ka7*TG_aRlG*3OpPg1-liTT)8*sg@*|u%nJSWJm!D(?$mX)96t5+H zWeHD^iez;{49FFips?T96A+^ld$PJNB6$kHF!uUYA9nqhVK8|MKM&qUtrhK#eKM$7z^I(Fu#5&^J< z92{nSqBEtRO4AXD)o#B5XBYo8#~tVnBg`aV%+gsq62C9IFy2HCPQdq=JP{XN9WKQe z+VED@#b;0|@nA@NL}pgWJ4m?qJtUYDU{bfXfpeDMK!Hha=nC<0uR*S>8P_w3^&Op}7nhV-E^0G1USx=8wc1 z$z^|n&T~2>Oqms;I{;D`+THpedxlaqn?DztCdubwX0th%pwYHdc*AS(U7-z z@@$#;G7euQ6JTE5C)un>>KDqFzi17C|$@NTp{FnJ46JmQtYJgZ{Zu`Cam(uL>}teg; z2p6+=p%&&%LAo4_!V~BM(XLW(g$+dAA)*_}RA#3iBCI`i$Cx%;jY>y9CUQ|VGk4Jg znDsXyK^!5DOLP`W_EhT<9hIJ-a{a_ZP_Z=zC&|I7c2I7OoD3@M_Tf15z%)DMbW!Ti z`JSd12fk-2s{2C^YU=B26v=D#Q;5u+mU&7#vU5jXdU1>F4N&oviF41HKH;j_!zNFd z@}m!tQaK`3A#+5hLhOoFv6DjY4N{&&-x|?RoL0xIY}UltvmK+U^`B)uDl$N@w`P67 zZRX9mHS(ybno5;ShZH8TNsTEK_ zt#SqQtK&ax?u`G(Fx{#ymLW4kOd7mR3B1kJExn}mEN3USpte+I&axXNd}G6z{tP)V zD}G7pcoDopcJHyzB%)>bOSR}^?EITLT=ydREd8B+?>2;Wd8@Of>(8xUW=Ph7+T+9J zbEv&()32I6F~U%SZzM;E;k^2}Fp}yu@ai5&HtMFx=4UvK$Ibg_wl33kF#!MUpOPWU zhEhU=BPw?@IRHYuuo^e55F!i=YzBd^+AIU#fhmp`PMQe2buSS44d>7+I~SgwCrhuk z;i=m)2SJX(kHb~^mu)VtLV?yb)?D0CWw7MVvB8RqcFJIjOTX8!DqIigVyhvNJ=exo zINyh^xi5g6`&uHU9`R(T%E{(3UvN-A^Wa)L5 zI!B?tj_&tDP~UYMu9iG?>RTNzugxyPOv;*BC|LCew^SgeCdjL?kvPZLv<4NcWEe({ zBAI8Oh~X0|=}*{G+EZG*z8x(KD&nZxnrAa1ZW{4rIU*L%vz00iF-8%|;(r}|2%f>} zVcupep*ACfjaOx1AU7`H)IBG5q_1jCS3$Wfm~ZL0l>d1Cv$^a(7H3tjOP3wGBw$xw zh=R2UT{$zH5MYm9X!CULw*S%qv3lVl6*)0Lv|DsYMP3#lIxj}g!3c@cXYX>!z0qAq z*&Nv<$-ODwO6D!jI5LWwQ`ux<&Bc4V#;=g&H(8Clyz3MiUG5oJgb`vpHQ|$Vx5V4a zm3?trvgKyG4>6`uQ()XbjWB!3!O{=+ocl^ye2cwjgKKQq>84}7&0B-Bf|2O%>6 z{4$;%gxFiQnZVr80uMbS#^&x#X93uFDeg@@SEs4j)KpDjw5B*Ex{z6P`g0-+itxM> zd`(8)#eP?TWln#@ei5=czE_i4Yz~rn5y;fGq7IAO$~B-n_!c(gNPmaV`BW*nX6KM@ z`&GECjG_xQDw0coE|JUTpwc!9Y43Bd1@rTl;XW5YGjP6TS8D7IaUH4cnS;!US2pA8 zY=#7k(ys@oShlW<;S=vm>}^;o_ELjm>~(|GERDC6vboSuL=Mhf3(Og&cOxwVBPO_)g13Ln@}w zR6$IkEviGF5#pst25pLD_UOhG&2HDB8py{!ni_TOiEfh2yW*D_`O-3NH)E9F-pNec z4@5Akd79cSQhK*t$j-iR1*w@yod3sdMlh7#u1S-Mou%mmXy!Eidc5EBk4(4(RQbGo zzYQVB_)*P&v~!dGfQS6s^#?6v*E8{+;R8l}e>L~tLw1NLh$xOk9u9DYa^=I;+&K`% zFz@;+U=G|1EBD{bb1MBcRk}M(rS1gri0t{b9kaUxdXy?XxCoa(zSD&Z)E<*B9+G&X$yJAp zXDUIx;C&>*%huzH%ip>)NvE^QoBmA_TaN?BpI4%8V$FIh31RB-J4x)xc&p^%vZhkK z5gUVlQ0F4aCuG5fcnfKNe;PGsN>38jQkratn`i89*MEwLL+$!c>(7%{j%Xvbl@Q4H zRdRGT2b?x+j2Ag~7ASz(wPyli58R(mV&N>VORGK`K)X%t7=pTa*%GiEyD4to_%mQu zos;Er0i7kYBUm<|p07h)8i5LRA$uW!mMuK)hXmUipsF^u{vp)10QKdgVU&h(?(uMy zLZyx19;M&Lc;k>|xG`@J$lfs~ay0Jg$cq8l#;ZX#Vt!quy@SiR>=%e5{W5m3$V*rZ zWvkI>W3Ov!lRDw4m3NbaTjOonsq#c)DfI~uojV@kUzVEZaL%g_f5K0p)1AO8{6Xvb zILJiU%w;L(0a8v{w}z6>fTZLIMTFX&VxCT}ekkUvCFY>bqAOtKm46 z^aWD*s*;x4DqHHnt7WxTUM;^HD55U<3G;P(-Fve36)o~d3V^gpf!Pk+1;p-vV*Y)Q;KMX!ab@ciFiX9M z(Dt%q3wtM|W8H4Gm)K)u@0^TgQCKI!K4Q%spZn*BfqXfaM9SxU#YX|OwgNp3enh;F zW&CS)Q+BfdC7`qG5$#hDo!A%ibmRFqh243pwkj~Q z78s80@%$+^gW9pNQ=_Ux$ytMLHhKPxTT97U+|~OcO;=<5xr}?m)~&d9b$Kc9(s!4QpHus#Mw#3U|A7G>ei71ZKSt^+DXoblmD*STNkns*b`g3VL{M{^ z{=Ybcs->}xK5>m&&tRAZ5bfW*SfT7rg2=5464})0$pLVmPK0UI)s=$Tza??L(d^zLn1JxS2y?nEsN5VgHkj?w>A2 z_Z?a9{=A3OzH5V67j}OyFT8um6Wl=z@4R)mH3@Y@#VJnBGJq_eJ@MzsF8u>5x!5g>^7*PuyB+i8;5`l%U-Eu&M6dV?k~Q$&ucB?e>DT8n9ssB$pJrU5)cH zYIqy1*k{Yg-SMlL4BBUp#oX*vSiZ$Ll2kspFSA(QTW_=7PL88w+J{yS=X;uyLXSo8 zdCTyWra`}?plV~|=N3@g%#9hR5EI@BQ?sh;nwig*vi4(?X}0}1(f}1kD``d8s0NPd zgpLjfy-7*ZWAmZsCE^q>|u}LhLl(a0b`!kkEuiAyI7yu1HJR<$I61w ztWVd4wNc0BYq`mPwPEq%rUXJg}^ z6M(M%4a!o{WZIl7oVGi0(92ds+YuyP`shTdIS@ZGxhAb;nL~9}lvI5g@7!R&E^*X_ zh~~*PX)Vj#2G*6R7HrIcufo@&+_I_r9E4lN-4vUwxGJ*S7%f>92X5fV~448gZD1`3`ZaZ2Fh=$EpjLMmjB^ zG5FuM=+4R9CqV4^cbd#@krf3nblGSVnn-2psZ4|?sCW^em`0MHO_kZo00zP^R;zm>7yVUIl`~R$S zbJr5*$e{0RNSg}HbhR)vL#wUtLUk2E)sZF!x=Hs0-mD_okSqT?3(h)18rNc^zYNJr z;DYjOq#b-~E_W^;Kv?V4bE8m5k)9gED5kLqDXjjn(T`Fc6i~Gfj5sSmQ$-FBHq;#dyW~!vzBo4GkIgT>`<&p5!;LBEz&G38ZKq zye0(b0#A_MTshL4Un(=3BuqhRdJsL4h~|>tG;waj+&UVU1&A%%@Eplck9v8xjb1K& za}uT_lFQRflIom+y5an0}-j5iG|x@<=xD}Q@NWW#3HQ0U44-8&?ZJ2g(%2y-J& zjlQ{ZYM<1|pEfds$f}Jfk@wA?-Ih2LEC+uW>nb~&+e4YlTF;V#770^zm%b6rmbEPs zrje4{$9^t(Ev8{Y46%adbhtzt1{I2U3S>_AnIKYF|H`&ub& zZCA82jqBuv)^_A66I9Eh30^OyZ4#!z34h+6bzwA~8z3Z;J?Blna^jiOr%s<$!oQNs zwzdjM#PCF=W=uX0Qg7dZ(`AHj^2v;(6JGjMO#}-!=4drF-+mvi;bE zeOy+5p{uz_MxRUS%u^Oj$!xP?b4-(w;lzhqpG(QT@n)>g2t#t|k7Y#e8y=XPNftTZ zwH%|)84*yk7@IV{Q>JyazKi)2U46`-B;|{a)>7See3wi)K4EIWc|oCi?1*39t@1sc z*)A&1cgPh)u9<|iV$_MiZrOt2G<}ty`iM9>0H|VfZ@))IcCuq~PtfiqzXhA|1npoa zYgR6-xeu)7znXDe6f2j1SSd9pCi)rEvrhDWvRZx(AC0<YO*T0G1_vR&s`&9E4!`ZA&8RP zcj^hU<#l_Ub#dx1WqS97Nnw0c%s*%xhX;FPYE*L_89!+g17O$Ha&KB+0u1# z^hws$yNkQWsm1Bf=0$yfA!R?h+~{i7bNWl3<0o~}*M>9L4RY_v)?nSElZ_;^{5f2F zgN!jX_vEJ%`r6+PH;TT00KL1)!^mJ03FY++j`<-%x=i`RUgU-{W@a9S!bRzWT+JFP%lD^ieoX6d+xZ}7%Hg48NW^Cj-QM+*Oewbdg_i*yPf zhr5Ybq1;n+N_aI^17xz|KfR>QIo6_eX}GNLTQc(;ds^j2sv2fQ{CkO=n=qYH`8ZHn z9E*RxO<@jf$0y(;-oCii{tiYqV*uQRFQ(Ak5uah`yzsrjyVxv>{@p)x@5+J$g|Oh@ zJy_l{~s z;&k~Z$sTBR=?wDEXlCRL@=d({+H*}^@0w%4<^w8p`3`)t=kBN7Ri8cC?k1>m2MVe~ zVO0I2_mtFoAobQBVX2)3?BzJJ4PlJXGr6dPm z!rpz41EqomHE{+DpUD0)8*J+AGqAG3SIsDg#UWAvwTa7e8;IY1S^vAj5>yJIn@_gv9hR{Djc9Lfg!?(d zFJ8t7qdM^r&JsXXD-V~okpBC3P>tcG*I~NrrUP=r2peC!wTRu_c`}WpYQMS{qy_y^mshynESlXb-l0mc3tN>=bmn*6ieGs zY)-M9wd&TXQ>$K$8gnCx`D)auTRR;8^$TV!XbKbiYBKRXI53#Wck(h>EzKb&g-Js% z96|Nb4s{nZNz^*(P&1NAqE=If*mF!0wFfxVtHLA^+uh)kHMijcP-9*O3`bBW!J+nD zTnOq08^n#vjF2OSG8rFj5NS6Up?b|Q*sYV9Lkx}}yuL%*z03xxak4{~bRSb)(wXX3 z(V_EkriiC6JM`Gb6w$q{!&B3kB0AzT;>T+SyVN{Js9cjB9*km&I6Bs$P#RN)9ys=3 z@F3EvA57x?~26aRg!E2DvJP5q4*ckm%Cgpa$M! zgxv{pMEC6mHE1y-?5;x{eBBl?8_4tH40fx=%+T@xvw<8^o5}i(9g4x+#3Z!1Xm&xvE1Bh#d408B%CgZ9*6bxmO@O5XhBd#YZZel+AA*Z#)FKB@1In*E?L@`3X zGLgv^Py&dv12Z^^BRE*m;fF0u0C^H-1?uWWgZ!ruGt4QTcI(rF4`db>}P~Hl-uFpB8(JnI+hhdJ{x!ujY-I=uT3 zBLvMbFd`j;BzCuU*g6>f0pD5#8jyW@7{t;0%wa5!W0^dS5dn2$m_a^5N5niR2vkj2 zh**d~CR!Xd*es3_YR@Q#|Eyw)SijpK`we1*PoxfGhSQgr0P@$a26cBlGpIRC0r}nn zgKA(i!xE$|(Jswk=ZIv4+P~K!8Ga@GA%)sGG zAQwzFs5-Zp;r+`@5v|u7Y$+L`zP;q|)exqLP4GLA&!Xx9aXj4Nr}<0(nfir6-73J; zEgybZwGDFq3Pz~f_>5Q-?9dX50h^aLsJ&H~;Y;|HNE&321Hu_0QmQ-ryp{)vH4U=wK}Lv^ z?Hx{#KjGK2!3K33$`b+>0a8aARNZ;Zuy{ICL>mkU*m9MRelWFfyu*&%Oc9%w800`? z01#(T)ri#F2Kg%m>LsTB3U;tdG6m!!6e^$^piN>a+9BFcHP|`!AV~Kx^?gr=UA`z3 z9PoJ`gM7XxBgA23gJBSk7|Aa%BT(178)Q0)4>1>+0TgCT!-9J#G@$tmhexm;@pW5= zZG)L2)~zu}U*9;GG!B7M#o;)D2FNo=L!fS96oj?UAm44z2vvKB!=fz+QqXFc!RDAZ zfZDs)VS9DN3`n|fkOOujNOvO>@)~^N*fd7S)ba*(6A?`?Xb9wdZcw#GF~fU9m?Bz+ z8f~5BL#o1oAW{pwshE|8LxNVDKT3iTwWXCO03C@p>CnOulT z1gLrk9X^2Rh_;Ijwz|j&_1y}Go$w{`**1fGZW$xQFX)gsi4K80yTYJupF&mufq??4 z_Zw6_lx-jV_yGPP+F~@oRviuMyF%y??0|oX&teSnxlnW%igMl0;S@Rq^4t!Cx^o31 z1Pbi|xeyiss{R0nC5V2aU2Wt)e%LmA2-JRbK&gZ!p0GklBeB96ih zM=}4)ud6uhLU|-!oD4;h4B|ooW;nkDjV@s_2ZECrcZtb1%M9YeWXRx}Pq!J=TL%~+ zU%bI&L$pogOm=v^JB}?J+9KF}_#rN&J6s&Y1duyc8`P_NU`mwNp##y#dV{!#r8e=~ zD1!>>$P6Qpp2Vn?4zGkTMZAon1!NM^4XC%^QXnq{8+`KP#mw+2v;->0B7>YgmJw<| z4}%?q7y)wVaV8sK5emc=6fGc!!R&t|8DtZr84*;|;q`q?B9ja%lu2S7^1lu0O`GyQ zjN*#JB}6k&XQvtDc|pGZ+c&Q~uh2Md=+{_?f!pin{%yK|Bj&iW@Z(?jXj<|+sRn{Q> zs1GY3XotZ%mvvUw3S0uzM7R{l;V^rXO$KpwA#*5=_21RfnDMST z{C$^6;{GUu`W+V=VD{fZ69g9!*QYpKn~oa|0;3_WV|oTEUv-1Li!=pxje`a`{2r5W zYaMdKRk^2P{Wl&Tv|D5lH%8#*as*R2NywYY1~sPuGvr4+0C5ws0@RA*4$E6GWkBjJ z2OsBl_z-2CScRA(R&;jwcplD!4}B;SAA)7OGiZooLnc3oG>BX0P;hYm_i0P_RYxVpiv*_IJ<(&^=!v&0xuUuxb1p*O>KhGOf z=snbb{7?@^8|)&N7$G;IW1uD`8N_V_9)YQouu=C7Ey^;RXuiOpe#1bBiwhhIBNl*M ziZ+3&*wtW%OlE|-e*^XZ{tc$8L68U?XOP=q8sc-9lh}$$g!sIq!aV@bW+~EtD9jLJ_9eg!0^`bzH^6g;qi711(lZw&7ufgy&5O=#9)YxQPl+5JI zsA^B310e1mb@;0#6F{y(ybzy2S)e{bhPlVU$4JOLn+llL?^yg2{6jsbN<;KoU>zWTvw;skW(_i^$nDIbE{=7XT_2lD zKz@io0%{ua9>_5V(9s%$NWX?ot}(e2)&lA^xC_Xik2@UO%Or8Uslzwhum}Nr5qyMi zA9B)w2KIp;TRZ%K1`J(s1czZ-1I&CFe2wdfT~LJhzPiKy%}fHjR%3&Fz!{+~BSwgF z1070ZkichGSjGtP2+@}F~W{tX;2Ap1(2^H=*MCIN48$=Ad$~NeS%2_$Tf%ypso&bxN@8+U^kv)kPqiG zLPhm4*!ib22OCGwFw&vH8fFtk?;6x=d*Gry%nru3Ua*gTj4{adLz$r*f{}P@Fq2P@ za43V4OT39(o;s1q9-|E^ZXqM2n&DtyX3{VQM?xCZ+n5i4%mKFo6(8c@8wWoCnJe5O z2xcaNS7ZQF27_D}EwJ0duSA8?2Dx+~N-OvfX$#b(+753c%7I-A*#qQwtQXp$eh?+0 zB=JU9?EiH`fDpwCIZS5QSe)jNJ1>(!jYDPtnMYW0E+&&tWe{KztkR@E!hbh`|y32sz^5wG0r@2f>lG8I;8l?5XasI|}~C4|$-e z!}ohoM35fOFo)>~B49TtWKdIa&VVX6wFQ)2Z&3YDF+<@YnD2)$yEw`>P|?>6@(NrB zR7wUXCNc%&jUDj+4fygVf(EEO#WPrlBS`J(aJm;$h7=re|DPKZ5s?cE2}3%L=;UMg zAE;8%2D$zoQu-dY@W(iOei_?5pdZc?XMFhO%w=W=Jv68R$C;sgDpN!l{0QudnC*Zn zvEHE|W-wrv4|gaR!fXS!^UEPtQqeAP5+f!0Og6~(M=?SjhC+nz$T+5eoeyRPs`qq* zU3>&ghzP#ZD}xjqG5Uth91h`Pq6iuWb}6_BsGxHWSRW|jZ^#qJ`Z$a#i~B?H(rSZG z4MlVk2cRX8E9M#0_t&sRhCupYmBH?OfEl`6WHwOGO*Pn^kW$1`oek=Fm=)OFuqGh7 z#~9R>A=uIfPb3)RtcRF&A7cJ5zsw--!8F8`@dounIv&Lk1ssOfg`(g^j0)IKz$HMH zgz`j%REJo|19=OX1Js#e4&`tj*tM%0ROuwlfW9R7HPj&f#?Azgqi5k*+aQ}G)qskh zXOM*$GZaMKAPT`nz;3bGAbrT7PPrWl_hXVMgi=csh6{lzgX{rzrQFQ+;fI>M-5?Wc zWWpMh)L@4q$xIqr;D|hflTEVhyve#hJm>~`G^>Q`6*$j@*dsPa7wcKu+ikf6-1-3FC5mKhq= zW{McH&tO+ZdJ<8OL0m-TWO7MO^fLx0a+3=A5iaH zG00Mbn4#NbO!uHP<_X}Fr4eXA*(eA=mP&Pqp2j3l^h^iH7g{^#aJSx(@4bV@kY%j=QBhMBjt|qwhf=$zd5>0qmRuGq{H1HQZv4GpM4R z8H&N*#E*y*;>bORl2uR(s^Ezz20~OD;t+{>0jN2!6fqYuMe9Y#0&p&62pkAL|e~2U>%OiUzfM86p^b5^k`o!^A*-G{a!mEy)NuWi6fq z-*<>uhHJs%+y*scEF)wY!~pQAVLQ+<7>@EtjFb+;TjO^yrm4d#2uR{({7#HULqI0w zbl5PFNn&GZgG#Y6-y>T#!VN%`?U=zS98Y1nc9+2Y|8F=6>?X*4qQDA+oPoS2zO3Sq z3@Z>j*E?)pjD0?k3>o5!O%9)xN09E+DBFaZf|LYuDgwO6EeG6wNnjU5 zVIzD6QCx^d#WPrl<3el}!CXY;J`PbZ8_^U|PmG7+z^=Q%Aj@}W4hL}r6`C1TrOvpu z@67B%J2F7kD+C%BGWgVl+KjOC%*h}GM^Fz@4CGrUaR+qGp~4O{3Zmd+qS6Y3dZ7m+ z?6Sxh!*m>{L($0&Z#Kh<7YbEI8X9KdIE&dGk}&^wK#A=b<1yq%j20IR; z1af6+2Jqp^7^Y&z8SG{@Bh-1A9oTs>S|YNwLH&Z92lCI>29>uYGZgoslj7*?I?@BE z^N0mt=R=+ok*NlC3h7DoN9iS=z34C)J|_C21LD{120L$AC;%ehBA|Ye4*im_@C47c zckm6yD2Tq$o+!T9Ag?25fn8>_L7hS;MAL@``3Edvh{F-Qy^_gi;3lH#JcG(vo;mEm zaR;6$L_2I+i|swId@$-ie#n{o92Om85~zE)5Xj3(4i}N<#3h&zs2O(+a(X0_y~aCK zMXV52<~T&>MQP8=)J)U~A{=c3yJ}v83SW!g*TVnMmQcN5A|UVGGN?xGsJKwvs)sW1V2Q)SqD(yW6~+Ag zg+Z=`Nr_b$B~UYw>%{!q2D?p1MyUJf0LT+34XQU32Qme}6F=>C__;myfWZFh4#!$x zF9;l(;&2ph8$v(!pb`H+}8Hba34P`!57Q%tTX}T1Vj}dj!KY8O(p$oLG5Rc* ze*G3i=!gTT*qA>ky&DLc#txrGqzRgyzX2#oWze~ny?h~x$ z_ks;RAXwgaBulF%SxSs#y})R^DYLk)WJhaB7FkoWrZ}F9m25z5$*R`}$i3MtkD^f@6}^$5k5 zMcZuJ4~lKhtJtlBctTy;W{W|1n9V{~NmjqJ&ANB7*}Z{^`NBKdYVaSrUy-bK3&{qa73?Uecu@G*mLCM`b5gR4R~0Mtk7PyX zNH#52v4nROXOYy?NMyie-zujUa>*_Ae$=K zrPG3S{Z+E@cNLqX6kG6~#NGs4y#%iFwNorI2mHSuK2BEb@MgvK41&o|2(~RnurX

4ZYfsV zQf$S1{JXYd!HX2z-cqsB+-6nwVz6Jr|AUeg3m*Xgp|iC=3wG`de2osWAGhh-|lG7D>9v|6z!SZ47f#ZG+< z%fd1>VVQ${v1fZyustW>|KPKdwZ08=30OiScRku>3!X(z;-}WNYFjTY+mTo<|@TK)e*Q zS>10WTl+22^(b8VHG*@OWRuZe651;?p@ zG?XkkCxYg6$y(r8vaMw4kQsAPu+=*x+XKZ14wY;@(gkmd4LHSpZ z=P#pdCrK8EHiIu=9{CvUqK`$s9MEz$TrdEp3bNU8G!)$kC$GRA!=U9K@MjarY6jsE z1{7F~&O;Tl0Lqq!vRBYqze@d*>JtLtsf(-2(hjR5}ZPs`ul&FMjr$OnSa1#btWuo%2 zP)r`1Fv5jb1uG4%Ay@DIjWoFrEBubpfR$)$%5_XMm~7I)ZT!1>KGcZ2h;GEpJ+!eF z6VTM$IF5%|+etP8Q|{EEtVr?LGF)zNRbawdRHmd87Jm_ zj7Y`ryO$}}5JY~0IUYfF|2R_TC&f~aVV<}u*|n95EnAI9#&PJMn9V{E?Kfa0d{+7c zSfMdSU(;qM5uDLY;g&Lz&3aR^drx6d1u)r7gd00b*3)-eu-2mxxe!|LP_WCGB9kyh zo=2niLKPeRP_auzY!E6>3dwT95}TVNHgIkPayhk< zVw*}~F25|<^xsg5FQM@gHk(lrE1P(m<-~E$VoWSUP^6w$Y*sx)IaXHvs=!rEY<3E< zGI1cJN2MbZ5;5)0g;KLHtD(a|voIA$ zDpnWFs}J*k2tQ&Z2XO5gTz3uEMDIk6cnxm)S+c#yutq$NLiP>PcQ4$x53vAR|0vn< zAK)f1$9EVb1xa6{5mct?-(%GKG5^;>eSd%pFQd4WL#L%NiV8MMMd`!>osB4JvziH5 z2fT_(*wT5txmKX9*AQShmTir6lQ4S+m><^J0@(zdNeK<4~M(!T;-n5S78u7|hRwkz*xX8Y3Nu zNZ#}z0&)^ufD5<4BK48mC6U{gOTv6_U^LyZ04G-@*2UINlUN=7q z(goz~42*U<(h~W*0OvO0^ZF48!eTIU0nGEyV0F_8wWPCRi@KtYbi+K*1*N?w){#%c zdfleI0Z8WUO$Xv{{c7l;WS@Qv}bZy$G6bar_P?73@Rs zTsw#*HCTHDRs+@dz|Xr8YzI)X5kCw{+<=mW;I=(eQSHEbw0o*Q79OY(w~O2CS~LcD z1^J(j31Q+1loeAr0@XhhGn3G5R@D zvLB9TP#I|g8-P?Tk5Puf{}nOGlt9@n2w#`S%||)hUx3SKd*VqHsXnOxquxhD$oX+c zpmjc*P4A7u0S$ZI!L1i))=;rAs0)*eU_`j{ITwVQeowJxf1`Ax9GAruyZR-Vb0``; zfYe0oxQ4agDwN>^xYN0aJDsV|;XH11IzNR%t#io)NSp|F^i_ULhmcxisk($+O+bjv`8H&+v`&+PCsBE=y zjBbv_EFzs1l59pn#0`#{QL^_S=5lvJ5Ee!t`|x23{?VcgW+SYEwj%~=Cm>28&@~jR z77+Ia7LWKW7?GP?1hQZY;$<5mdSI|($6$%%d{C@_&8DDcY`%X~1$qN`!z2m~+|78n0Q4FQqWU>Q)p4lIl7ZCpPE*RF+P zJ?6vZ^Wgs}vthzd6)TSh*Plb4L#yftnrT&RmH@@pAdsd&v4c>o1zeE^PCZpe_*upC%z!#((HS~L{Np;*fou!0^8H}sb5VJ|3%f1kSzUmR$I zMPeA{;&r$fMI{}L+`~ml`0OGI$iSRP7clNB3Qkc3Pch8-KOzGVuvHKftHUK5QVq2s z5(|$xm^tSn7BF|LZ-r&pKXB_s1TJpLTcW~t$5g%_uHK6k(e6LsGT%e2%L?1m^mDE`vBH(Gd@CPt825hQ*eXY9p`X9 z_hQJ;KszYMJ8*sKa8$#QC^R@W9Rqj1g5%3rbB@M9l92xsH=rzTgl|v>R^!;QEbi67 z-3u_`Z-@g-ohuMnYf$;Bdutt_g@13tdZ9dmYyDRM=VP`5{ChKwmyaSi zE8@ljb4b%EsDx$VDlldiZc00%%s01vm_D(N!|3-w;NDc+Q1*by%c1dt2pmwn5$=#c z#}MRuWhfT~&70!Z99CL@(RVM8H6UnK0XM6aP{;~lo&bd~nbn?vNi7cw4=8~3z{$5z z8!%bzfNbd~%sZ9f{~j;EM`clXz+^Ps4COeqG9n!$b+B0!G_8+g&MLUksDe)8Fb%K7 zD8aZGtPPssuJ}AU&TF&Qk*ILLz}$brHF=?EakPCMmcaS$`EVW1N1sATMk&7dEN)bN zgAvVrabJ!cEsF*=V=|FwAPFV4Jp^KK-p2XGXlNN48eImKLIV$>XzCxR4PfQl7}YZ< zHdWz@oKOTr??9Su!j!ulK|K>Owg~4?HIptQJ}x3qFJYC9IPpbJN5$)fB{D9agAwLM zo$9w0#@7-w|0id5a4SWm#*gC|I@+17PkB_&G@u}7nYo(RKPx2G|XZ{QSgI~3-@@xDq zzr+9H_xS_#+y#Rp=E_)x46xA;fmNw!v8;=9Gy;;7gu zE{Y5MlDI1V5SPVY;-SDp1Q{+X%A7Jx7UY%Xe%?`5?Ie53Z~1d_kbGW_lHFJr_LDVQ zzAS&R#>v;EPi~c4{b~Qfs@FZ0)l?w0^NV zuq#$EHq0u(OYnI9B=5p|@R_0?e;V6Mi=wEGP#V+$BVwd=h|1R!}wyc6IEerD>_|paDcYLJm&VIHIS*zsd z@=tL~yt|&4Eu3oI7B|HW@tGw=6M4*9C*R;>-~EkO@U53miAr)P&&yvDUx+l3%B%A0 z{2#Ga_TevzxA+F z-?eJXy0Q%aRJM>wVzc#xtj%lkhP)1Mz-#duygskX>+wdsxr~!7Whs?+(oRqV9De<$M!%K@4Ig6JR$7KvVCi}2)Y$&_O4l-SU z^U_aq(LipLlldU7txa;B_)$E^ljKVIp?qD`#xADK+w+-nsm#smiTdJ}HAQ?TrptZu zJ9$U+7JbC;*30~W_+E??JLN8U#!9o6@-?Ec+^*l|h>9!Xx>#hbmY>Ku*0W-jc!F1E zU(1_T1JO{tBWtot)@spL=HlOq+tvU+(&{L_k=0lO7qH7nb}@av3CM$R+X@ z(LpFVNi-7!`3gQwv=gb~3%Om!vhT#3dw}l{>M6DmE}$N82&Ne#MAgcytr5-mWuPDgM3Q9CX0#~QB5qcCRyG2H2xz$ z%cZC)z7oHQDEXQEk31|p%SrsW_|poK!7_md{UmTFhHb|qdS_lB+2f_M(zmbc>%tiP>)tbHOvM#`-`MeGqjiyw6Ue2CU3#TeaA@m9W}Vu+X^YOwL5 zg{Z~)iC(;i=*^!NQdVVcrI3|qqnCH!l6T~Scj9&A7ORe^D}I&T#C!5>Iae;1jYSjD zNOTo%idJH?NV3*io2(OJgIFM^%2~3Q%quJNDBe&e%jfx7>zuWWe=3T~LNY{t!TEo5 z5u2AQ{0!e92a4y!$KppB!>h18GJ@yPop8#RE*^;wtk&WizK6$)rXo%ZlP^gv-;%Rs zPf?BUtmEC0#nO{coReU!eWxc|CiJD?Cf04hy2Z$(Eo7G`; z*#@gL8^Lpmg>sslBbUiB@>SVcbP=7zYvMHjkiRY3i}yq?pYA@mcpL$ zQF&LK;$dvP_(uFLFUg5=yqqAr$VP0WsLzIp25h*9W1~epdqp&6qx7dac)S12rT_2E zr9qG9()~I%m>2ZzwU%2at@i8>t0)_4y=dj<#d#cW!8`M(_&cI6@4-s(ar|xmw6&V= zww|}v^3V8YzS^2#y=i@9{mQRdH~2lC&Xp*_JF!IZzE~#yH@}&?>||R{!6u{{Meguk(L3s|%6X zqI@{eHNdnPp!0~_4(QSGktmvpP*-bY{e!X-q$2C=43uSag|kD z&zZ+_>cbydWwu_M$NSXZI_3x7x$M^8Z}Jn?*3>`wAN8o4$i%diLV85Bcu5~#ZIw;T z_g#*}kQ7_L{)tsi5BtQ*vGwI@Vp2=epr+}3-o9WR_L`Wgi+^NACx$f4p^J|bdq{^E z9rC)!ow)3~dXN8+leEhCc*4n`#MFH)NHyn^t#K2?hIsv2eyg%h+9`7BMFp(#^sjtd zr|%Srg)`qA(y?F2V!H89BCnjVyIj4k9e)xtEq*CXpE)ji(6Qdn;(Vs`+=wE&VTuSb zvbtjmZfhLTiuzHC$VtBhoe(WO@*_@&5JheOs5_;IFun4Gn3-`^N!{V3bJf!)MT^X< z^v!v)axS_glF@&XT&ur2B})56&R!Ko_3YkuK}VIAzla9@lXQL1o%}t-U(C3)HZBdq-?o@k zfLEq#bL)<0+~cG^j7g{u1X-G>kQmb0Sfqr%Ijf?|7;y14(aQh1zxzdLf!&){srx*7 zX_}~-UFW2wW5?BJMF)Sg5eFZC9(~UJ`OQ1Bs6LZl70gXeY>2i)m}H6ZgKA`By|bS{ z*!RB5h=jObMK^yB{sA5M)jgp2!H;`xd*1VTrltpQ59)7+G&KXQ1!W5BBj-hx01x@c zm~tWTN@whSF1kOD?`Bsv!>f-Li(+`%y1--qZG0OpKOWz(-$WO`UNkfMNxhe#zD_fQdDTH^(fAU)^0JDp8~r%T9;pij9j>iKouSmW{7THX*(_&@g) ziz=k(SJC>f8=|;h#G^n}DA2KJ_6qn*MBg_-*|kJ9&`HIR z+oDZ2Et#02mTKz!cSH&O=r2(q!0`TY=f2|}w?A$Y?zrP-()5hNQ4Y=4(IfAQl6pir znOir>EnPE(e~?4(x(7*FX{rR}cRebCoqn#6-Pkg%VWepc^&RQb0d^l5{MZPof4Kvn z6m^W#^PYPE{zN%^&n@pCaNED#^3=YuV`b>jM1OT31HN8Xmd(c8PIry(yJOVf-M0Jg z?mTvEsy93kp}NBZ;cC{Op=%zvJ>xGfr60PBOJ+_QZ7C<4JI(HV=$?5!aoPeA*1tsd zahmA?XIOLoaSzLHt>ARGwQx~})f3XilYSeac4d5?p6)JNo&TSW4T|#o@79&B49twVcV|dfUU@9t{@uBlT|c_^RLIKcA}oVKmN? zuKJ0o+v&U!I`4=Yv+=LuiM|IV^aAO=oJy35)JhQRM3I{OAe`db)kUU$I-R=}^mwET z#+PneB@*KfWt;P4_{@sh)e$aDYc*HV^DhPlOX*tm_?>e}N|$poJ#8AMTzd))?<&P3 zv&&3>Vx=kRno+14857Wo>}gs6bQ+FV{Nt{o<}8)&;y|`Gl9W`s`3}O);XnX&6_!BC%kv$l&+bDEM?Lt z8V&c=9dgRTx?`GEP+#kyg7mN;=~{7n;;SFF>SU;XRGJ&_xxDXB=PJQ&J^X>UEZ7}* zelwTMC5~~@ zb4%BB9ALR&dEBj2>>1zE%IpR5?ecO~QJr)XU-|H+3=Jf+uny5@^U64XI+Bv+Caau2 zomYnIN49j`EO{;+syl?pl8G_f11;`q<4``dvHdFUBD^;=p7Jvcw%8b+rTmZ`jVhJ& zt`J!^K$VSEl{1Qp81D$ZGrw%;9|gsyxwL}*GQTXPI~I^-{AWo&V*ql*D7~S8tnWYR zy7bcmvbb(gP?mR{#SNipI8sLx#Mz;xWWEKp+)+tkZyGO)#$VC-3dy?u%c+Q%%ggIr zg(SYYv(ZxedO7K;AtYk1rt8Ze2mTX2W9AaZhtfs4*$155mL3QOd z-62#q_DguQ97iWhkeggZJu}!cYt!ra!=s1(wK8Q!Hoi)xlWSSU^;fCx>5nqo$WUfa zaAeBskM4Ntr@Qn_r0$C8sKYUl-&?|8TVYrgKSA{bosbpwQk#Mkr1yfvuO}<(#=SXhE3ms*;o^rYXvkx6sta zGTcm%fgO9w(=_U{F`PKOlso@DY5TS#Qz5`RWHMt{GTC&pYebw?LSJue1=fko5HsQw zrtf5kN9eeEGRT`)nbMg-JwwNbxq~{Z#7vSXp&K#*(6)r9|WFaGDn9+xQhwRJ?2W<-84ENh_5s&D)mrb|Siw1h>v zE$><9BpNe~v;r489v9AsdpeG?O6l6U-P1b-t%(N;+IJn9;yR(E%o}hg;i>ft^w~1* zX~I*bG@UG|x2K9c-aRo-6AN{Ra*+C$C48n+-y<tYghRelOeKu4CT@4BR#w_I>rnYxY+be(5pzyH9>pg=VN`O3e9q} zoeGhSx&2AB+L2A4W!Y3Cyz9K8+A}SFLb9%D(NnM2==iE`jXY8GDV;2;t0h`_^_i;w zI{3AEV>AZ8_)eCUHr;NU0HE9LbtKlzUot$FS+8TOx%Kc^W&@opmg&}j(w?>6CF!u3 zz);JK!;N&Z1T`l0wip@aSIAQnHo^6273pimo|`C7ZTZZR3Dv%bS&Eq_E;nnu!sE*3 ztSWy_62%j9XGv?al1WFJxVBK5?AnN%jBNI>Jd#^8Bt!Mo8tzq-N3CtTZ%vfgM>X8r z37+uy4@m?BY{ts%Yz@rw*DG-ofB}<~r_e#Y-fPIE&{|b=;Zdxg*^5 zST3Uw2L((USv|a4hapjQGTs^VhMb8^nufk6374_SipJQL^zyn`CNJG#1?ogQz~=fo zxc(cRzrJkiZ=4>Nn3MFlWG|hppp)ynBcAfp^bn)-)R&cMvJEsHS;shvtb@O;fE%hu z&W*XN=#ZvHhzk988AASqbxCHOH1_Mc4c+C*NO;y7-)pN;;9A4;#=m_`~v?x>y+_pgooh(_{M z4Q#|b>hZ;A+!e*4kz@M(c-hsj$&p4G1*HW}{zR79SgBEVBc^>XqYCYN9oM^>%J%+N zvi9>cNfgq3pK#|^rkF7?sgr`l=@-rGX4j*U?$9hl`DTzlp;m^L+9Q+_?Tsr2r96El;CnX2peNHxkb(|Xmq1p!^@6t zdRI+e?!UG72iiOMYqsrW)_qfa=w|K;*==^y2x>69-pxp;_p502=B2<$@YLUH)K-UT zkpaqOKAAI})3T;Y>lkj+7|#C77%1#AW9m*upCfZyh4jv+ zWt2aAJ-g60n_C*N@iGlqLPReK7Ucud$rD>Dqn(X-k6b4|gWDnR!vqR`lfo4I zwuS#AN?p7el#ORR0hWWhj>z@z0cM({)l^P28P*U>WA9?YW2zv%w3pjdp7&&e(ZKR1 zR#bL6dHkPCFYWF2zh}{$TZi=tm|C2t#hG<34~CRj?TKvT%wwdyP-w@_zKbCSZdu%11@ZBNgYp*q*IfmfP*Bd;HgQNjWty&7hUwxe^1^z_KzFtFY+x2Ai*?E?Op7jyc><_}p7fksZBGD| z)Yc&PfIW6Br6&w>+tG8YRT_gy{tR#Uc{9KhQ(-jVdOX|2BS90T-x_#)RxYE#`Ti-9wlItk-9A+yp@Vbq zXfx+M_x+RSmA{Jm`it%xFweU*84bi_=rpntmRuvG z)V>0uNPuFVo0nMq{RsEXi>Jrx)MNkAjRG3*$kZ@0&t)T1RM%;v3Yz=+_PWzZSy0az zC0#GMdGx5I!(Mjl;kk*bO?_-w6RS_Z?6$D6--{=e^ZHe548IN%VOAsFG#iDDjp<&q zuKr=P?CH00=G~qNM!MUpN8RP0-XNfr%sm4m7!JYu5Y(p&!NT5$L7968CPV2tMFS|- zr!oE#V6LH9edkMYzX#yifNZEcy^2lDIgPQQ^umA)*h8%}T+ z2TvapBd*) zdXEk*bf?$dI(Y2-q~7_udy@;pbo!=eLoKQA*`cDij(Nj9M9(N%k20cxr0minD0g1>dkol# zguW~S1CB^=8_+c8*;MPSzfEv^&|~5*)XXfr1{4?rcxq-8qV3AABs3`)4~q{@a`)wl zrfwwExG18@8*-iHKfFmhzNb_(Pmda+QQSJ@i{|xRUGf zo1}$lhliZ~G&*V0q;H)Tqx!$}oQ|E~exJb;H9d9zDQ;hT4EzkKI*MYfqGMe3FWO~)SzpY_Vn6^ggO<2TfGMI2=yhQkt7u05BD?P zemehK?)0Nu1rw%p+uL8i{g(Tl+>^KibgpTxD<2QG;A8tfi|)z3ZTk<T;GM557<*HJe4Z>YzBoS4>KskM6hg|j*B zWuAbl;~DW#Jz<919A?B+6pY8HD7>Vv&v0#?KX!^aPeDIS_nqmscBajY1ler3{$XZ7 zAN~S5LN}T9ucqIL zH61@M%jNV$HZxwvk)HimAYQyV?8g29rth z%Tky4>ufv$DjQC$XmJ2HLHo=VtUxy-vGtM#;IEAvTpXI-HVi z{nwsHr*G+{3tjcndvcmC@}B1;JwWn2ws~96e$V~bCUdoHGM84%({XoXxkOw`vm7P;MSHsR>oFJ^^Y50W!1nRxbWtZv`Jc1^uziBGo?rn~l#o2iey zF9-Nz!zkoS&3IVT91^qi@Wt*0KHdKt!_lL)*`!eWAyyfEZ9m>&U4O^@^^4fS8T%$3 zAvs4+`all!cjVbOnX4m~xVI5JC+E@0!a6lvgy@iK?qPfODH3(;GQ4OJvs6~~_hJTo zW>m(2pM)OsNvvpMzuA@a^`=mH_G!bNdkog|84qha=tIl!#%bK*Se0g~@OmW9ixNet^j~CS^4C6dL=$X)MGSo|upjs%N!Scwx|MVYik`oL2kIz|IZ+RJni9+B2A? zj@U91OB?DQi7|27Dp|nX7kANzKEmBz+6+-k&q{L3c}Be4X>LR_e3NX$;4Cp%LQsf(f@%>)f|f)R^%sHMUxB z_*8cG2e?P!PtendiGd1Z)Q&Q=0kFmq3Dwuvdg?1Z_onZanU3hWz^D49b?)Z^o;&ch z`sO(Ir`7O;ue`JPqodVPJpdzI@cJ{$B%{CODv7&GgoQI6_mlFpyx-Y}sj z`{rakPHxoiC&}*q%V~qlR9f2L+63h`mcW;tp#0y$$gFvm$&5Iykgpni41PG>B!()&|s7P1NGeHSd)ab;`#OA z_f^0bZmu<=tFnhH#eSJ-~Z^a&)v7a^iGTE zgWhTR0u3x}#j6E4)HAhwN#?j2CCccS-?98o_{JTVEUo)6Nda%*kOzF34%+_-}3PbmYqEM?XNZM|<28h?yQ}o6?MxwkeY#owu@8 zQ=i%9Hda=_T`+vY_cgN{Zf2P?A=w43?$*2hBM19Kl5)XxNq2l-qs!Re@Nnq2LdtdX zNwcbvp$86oAagbi6L*tjs(`O5*Q=TIc-0gV`oi)z>n+WHFf z>w};0ws|;OZr{M|Hxq93HDn`CZ^L|R`S(}XkCNeI?-b_QX+5C7Pj(j$&ua`npu6}_ zU^?$>%2XDNBk0-1LAZU={qht{E?;HtHW@kEZ90UuuD8QWT3$gWSd(Joi0<^YyH0xEj6I6$d$-3cwBA1GL50zS9)SG_nb>t!Mf4Gvl`x|tM-$mG z$SrS=qMc2aP=m(Q)ZkC#Ld&u$1oY}Dp2zhM-?)mW_SBl6b(_8J2=QE*qL1u#Ur8x% zVvF8aIH5ay>$V1sz?`HJoYY6Ybx&BHJFs6!>!esbX3l1Oo**~{L!@=UyDZrVdfxOq zt)KbM{idI%9Hvr#`6Uw8>zm9#F=|twoY8&vyQfl5X-I=I6Fc&#Y`jN?F-{@FoTct| zRTt!D*EHa<&pCbid$)Z^U!w)x8T_jIA8;?}DNfBv`sT!WefoggCuCU@VDte00#uCa zgl|lZ+w1N+bD)_SaS?)jk6D2kLB==ZpcjdL!#EPZ_@+ug!h0h6655F^h3CfE%;26y z%J2G_LvG7@W{=Bg<$fn#$!jnQMWYO*`X6M}jq5DR&%oUAv~>kF;icqC3y!!A;7OXR z)YOrhq5@S^yI(7D$INZ0KeG#BCht#flX)WYjz0U7jMQ)a z%T z`L_nrEuD74{oPR-u<4va`4P^Zl;Jug!pf1=&z{vYHpNcLhy}mMTKA4$WDN#C7uFN!?3#KD;oAy7T19v)%k*Vk^j z*T0??bCJC3Epks|x#?tCom5w3+mKP7c9)FF>24{H(|fLq_|8K3Id{fUgqnNtYI@@t zSupY7&fLd3?QYX+xp(u=99==auu+ zm!f2WdkqCm9|2PX$r;;I9V!Nse)aUflzgZ7nwmwolEtab)4y7kv$pBEt0;js^Y_GS zOt@$BE*qQ%P3P2LNeJFNXI0Uk^mpH)c#K<0Z@eOlCEjTMU-$h=J5mqZ1xislG>)Qr z8b(qj5|dj6O3|y`Mv7kT4kxLSi5=c46|mE2(%kb7dxR0yUpB^{MZ>OSkWMVdq&D>=*vHGMwbQLqh^&l-BJdc!+bZhd1aHf(Mz&C<5VkoEO1f4f%#p2TmUd*63Im&v-X z+fZM<@7~wVlrWa1UE)SG%#BB^W&u9%tn3>@@sJnsrxmZ4gt|K;-P`u8=gQ%%x-;3BA)COG&SgXD2uwLW%LWs_9?;37lI@$kT3dQyrV`ULF`HQoS=F zLC>Y0fZ{v)^M<-lCF~(Sa<6V_JJ_^D+riCryGQQFMV@`X=3FLLyZF^p#hYO7}o<@#!bXARp< z=ab6)En4??tlR6^Qn}tv^W2tn&_PPM{>BMS$3{8Y$^w<$bE?5-n%6khE(h3_txdX5L_{W;y^^2k0#vMz&r%+^DP1*@>cmJ9y~74%YcIn?}5$Zj{dvSBc@Hiu@lg$<+M? zN13JV#J?)dUQ`bcRb~C_ zF3;N+BlV%sY=gwKLP0VLt(~S`sK~ow+}Oqwb+71uiYnKmLeCOpjGkT0o%iN)&l>hsoxiy1=^wqP&W@!z zo1{=@Q;NH_@MPL+x>^Z$rcu>1S|6KgPHzspPQCQ%gm+9v zlyvvvxg8&mhSFZd?ReJN*>pzJ?gU3BOdkwZ75qcW>V=6AtTvR#Wix|PrzVMLY2efS zOS>m&n9pB^67-qU?t<%Ct4^XZE$@uA>eSWl1+B+Bll4DgZtr-^`iAy}yUm()6jLw? z-()LJw~BDv*0aobQ!kD1i~z4_o8i&h*Hd+=NagzDJDw}w(z7GoS9&J1X*y4te_aE- zO=FMfirdunW!(Oxif?>H>%Zw(B8AtD3HUpwo(Em;=$U1e>$~D~(p*npB%gu7kLYAo z*KNvq29GLh#z)WbX5x>wDc5s6@~w$F^6f0rGOQb3@W4tXaK7<$H5;n7`@4F;iq|uR z&e7E>xTjFhZp&P~p@Lfty3&k;_7dk|9LtB}OPC!zi*8fU=-Ijvr2UITN3ghldpQ0E z-HqY+)q9C&9X6jv*Q7gqkWKyYEVJK5L*aX^e_Ljo{%P5{0CF8i@Wy)PBX`mAgoV~; zqTFHO$>4=(AZY|L*joz7RHhU1*n5!aw7^-{1r}3JPm6TlD(;>#?PZ)#_Ih9cQboCT z?>*1&7VExM-7cXekBJPr*ZzQPm;My~Cc0Ns&$?)d?j7x(7$~vLZ31m{Ekz5srLgwk zMW|&pRD{14k&}!VEtZ!#V(a$c#l%M=@uy$VAO2`jg!>lF^K5B3X|}Wn{>XK+Ki%K5 z^4!v{fDL0u;g)tEOzbsGn^bv#5h_W!Hw$^)yaj(+nV@1ZS{ zphXBvmb!x&0)p&GWN~3hBDeq{1SwJk1O#`GL|i{veZr^+0dYYrgop?T2#6MtH9%EB zHnpu)S)%RNRt))mGdJAK+RSKE6xR2{ZU*d-;dn7P&U_3*S<~)vERxP{!x8|~$H8r|K=XW} zgoizF2+3D_(zz5|2yqGeQV^Or4y`Xe8={lOr4-jjZ?`dW?^014t>|4|vEn!ZeCdIzgM(Pgz`Q;*G}6)V=Pu+jtTGM8wyqq%pR@e zp$_F?kKS*ucNuf_L?Wx`q7HhiMR#!2C+|bU6D)g?s~v3C zL~K*xfH0J4OP@J09ii4>GJ_`bJ%$l{j`3Y(yB3(rqPR{T)6QpD)|M^Dhdkl(0Vo2s zt74SFIuP3RAe2FX;2Mp%9*?{Ap?BO3UB|kCuF8z4w~gji%}2B@Q+wM+S#PA$ETk>t zZ>mH6v$R4msE-+?@(M;_eIg_%|A5-qeO;Ji`S*Mz` z|0bOrlWMZdZ>}nGz6-P2>Hg`Q6OrBGWZ*6bU(y+Eu?^mvAZXIoE2B^Ou}{t+vKBZn`Gz54zdyap5_1@>=jXc zd(9h)FDW-$2O(?~WCXrMI|ycr4opix58ML!?ZR> zTNl$7@Caq(YTf1Pco~9q{80=sbpk5k_T}m!T%gR9fnQPDZF+Z%$MZF)?3w_N$KIHj zknkI7)>|`bX7LwF?-OYdD}f%}-&?PTLH(6cDhp}U{NE_9f20xZ>=U`pXgef9bp83a z3~L-aJ~ff1UlK(srJgQ1H3j&87bu;69KOtmJ2h8w7}ADSb$jiO<@wGbd!*0RG%uu~ zhT``Q#fckz6mfVRHG4ai^ogY44RW-D<&D*5&%3JB<{%7t%pum}#!x$2e^*4kn>AON z#~oNxz#zM3^2Q}*|EP&?sFpm0nJ&s+`aB%{z~>tlQ#$}Gv5%4*Ti18Ciykg_{Czepu!y3rCr!!X+Mq8(w_`<4tnw-li)i`8Iqms$`GXtj;L=N z3BhTDtLE7QkYB;O?9>H?AJayLuk*|k1fAvM40)UbY(Z7aQMS-#my8X5s8P=MW+cRmnzvBqPg}jUS_6dRI4GI`#8Udyj+ZBsMrnNW*iLn zbjU>c09`_9_vwjp!dLc%6TZL2XeG~v+Iy%lMhYGnQx{Xp7&exspNzDidG|+ZdtM9} zt9dCM7^O{~BQv^GqaF4(nq;8n^|CFgrJsR!d}1b}p_rEr^3&nH~qd z4X{Q(Y(r-tvqoma8Zw>2u}Coi1Uko2FrlF!6`i8lyT?`2p!{fXZeT; zlHW3=GV;T5VL7krjG1%zJFu4bJkFsV*IW`_Mh6}=M?iOry_`oG^#HKEKk`Alfo4q7;gvB3Z7BIkZ3^VTo4B$q6+aod`&>SJJ4V!VK2qvARcBgZ z$=Y$sq&=@)!DHc!pjo@xMtEm!(}5O0qxBIx7P9qR71$9PWXI+#?@9KJ*@?#-^=4e) znC1c|16#7;4cztMX_N}KjYiF6YDeEiTFqZ&CVX?1Sr!#Pub0)><{K$_vNl=9?sWzW zc`>wcheN7#n6a>3sNocCVR5*e?dI#It~7s&&a#>Sxf>-<)d4c|CF{wK@=X|e?)502 zvu{yN+WBT+;$MU(7x19OjC2dlnWjfF6S$S?OxF`IYNR`cm@yY>B)}y%#<&N?&oIVV z_l@aEGiK=AhFPOtROdz1+BAMa2d8F_vK>V7OmyNxZKC%rq`~G?VPm=q!9>cr4kE7* z4Z!Tanw!wu7^X_K%xrs8otbd_*3S$H4R5ewl9+uMt7@(cGq=->nR?mG&fMW}+NlWL zs!(>QB+zh*-bTEDql?0qcqU|4<}L@;l=R9NL|+GSavZk}@vpPlwSErvz$|pY2`Gs) zlk6|pS%k$3AZr#Y?+mmCT}z>hJ+7_Ug8>c)g-;;UAHadptofAsirxdWegkR#D|)Bd zq>1uilUBe#CQ(5SNIrqRiL80y5!=;UBm({-gpVAw?)MP;vP2gx`h zqv`MhSm(PE@f0QC#jnZ4j$y1S?PIT4c9#n&?g!(sLEooQ@#{J_X-x81uzcv1kk=-g zFn%0Odn0mhwL@WY{14EWx6nSbaCWH0Sv>@k>3h)mL;SONifo+^(-`9+hN(6Q;K@j5m{!=iaf%IMB27cXJcGZ5*X)K@L9IE^=UL``!T9h0xf>>?MTz= z6)=eL4&r=0VJ0x_{5@eFXW0LvC(J|#zw^PCo<2M>PgBrUDA02?hmj@8#gY^`R0BK2 z2#C`%PdK3ScZr$Az{J?nVI6F<5hM0bGDt;WMjD>t9~)EVWhihsM`xI)g`@L!hIvL{ zvH!L+%(D*F^L2)Kj#A&%6A+12InkYqA`N3H%UTDtgONm0Hf6tq1pI&B3TCpy*F1kK z7!yoQVf|G)1uOR_(?&z|7w0x*LpgGvN{yFmKbIXz`H>57rqTT6+6Ck>#1rL!Z8|*r z@*kS{M{xen&gu+W{Jth`0{9mweT5F-UEV~QF>f(eW`~b8rN6Dv%FOseFH*;qUKWJ_ zvpAENA!}OjGO!vKB)=$}RfWXItyk%4K{I25;%vA8*XIF?YThTlM14Qd8B+h$Ugq)Y zOh>}RKR0)UU%?7zAM*}pc4#&oTdk+hre6Nfrv6p%dujpNoCG*1#+1(iaNaza@&Ioh zyjMpba{Ze7wc5derEnhSPg13VCGr5+f4mM#^M19MdnG~&yWXpOmSiDKczGe#V%Ku~eiy8#Y zz`W5|<_tApCY;=}%vJ{NNO2#b3_gEhF#CQNWw}Fm*OrL-OtEpC-^Y1bx)6?Yz+h8y>Xhe&8#X>V z1DAGr=Y(z)D0@cLSF+4#_uW;i-w(ro?9fwwk@`+CGb+N{jk31FPeH-W)!Zo0JFLR3 zW8AtuI&PMIT+<-xG&Q^fgKnzgtg2C-mz=7fTDJ{X=V#m_B^xFl+2W9cQ>4BNZ_)>! zQtAP`0m=AG>t%!3>LAt`gpuTJjF4i9TGaD%kD5ZTuRo8rov~aoArHB|2gL8D?+`qf zO(apmkE(Alv96IV$e`phl+6_kuN6De2in!3T#5qiN*k)6gt7@QMZt2CTaF2rQ9VKjvOW{EnY`U*UPW?qX#wUFh&$OgpEj z_N=+MAPacvE{yWC8o}R8MSm82dJvYG6j&!p{S0$izXV^I{}F9n{jcY%VDkZ^`|d^e z-vFGF`_#`PDRg9M=<=Xp-6^?CzMoPLYXfSm>jBx1*yv}`-^4T=6*}hj`%7r{ydiOI zf{N7KQN=aljXub((b3{?`yjZf;5URQ9#brx>^R8!Gz-5q!Znk+U^@`3oad z8rS^&uax~4?Nzh&6R(e= zNd?8f^Loy|p}wbU1#2G}m1|(W1F;#)&fhred*0&A*TPo^jcQu||G=YWwZ=!YO|J}| zf^f!HB*&Oq_F!bC0xE`0WN;j@N@;mhPv1hbrzdFb-}RpQ{o<39^_?$nGM;leZ8ZoJ z_5R2+N-4kA!-T>7Bs2Oot{MH^8fDsiXa5fdCB2Oc-hjL`#|BcT!K!N$kFAv^$7qviUTDOGAb81{2Zo&6Oq2vqp}8)QTb~86pz~c4Lri@wOl_~bLj|@ z>HNaTqnlAEVW;S5WmJsIh~@9L~T)Y%|g7df!5a^L2J zYM}mPER~ML4agY=)qb*Bkrm-?D`8;i=$q&PJmDWY9OIx(xZ^x+jT$v(twcc}3Lh_| z(e?C9IS>(I9KuJKSngXW@CsU9{gyO}X$)A2SB&)*YmLOL$*9a)%^Edg8GBlLAVz6j z05WAO5mWRUWL87Z@Iq!PeIaHDkk=1zH(o~NjsG=BCTzvcuAPD_OQQ5ymVQGe|JG$W zE-6_KCRK|^9GO8Hhom}jk0hetcP2wJ7dFIpQIKlEZM`bFPJnPk@`6j$M~OP<#(zood-NSgkV z997TEu+r6GeqBZ=*Nk^xc7XLgiV08a(PfYL4n`21IIlzc>&6mp^|p2L%LjTpg`=u!lIJX|$_EqOoWjvdV<#R6 zZ02Mn5zU+crNcF%>aDIJb{XYHqH2fD_M?vzk2LqCM%4Te>gY1Q*R|Zn4Mjtzn$dc( z+C#k!olL3(4V`L6&(>N24V`L68+sZ#8Gg{viKm0k1c3~htj;wK??)!21o3XTLU$)7 zi`E42Z~XH#SoC;eEE*I9VpRl|9*!o)mb{xBM3QGEF+)dM97d5m+7qB{px=ErrwOf| zc<2+oaFY)S%H5VzW^UQr(9VRYdip5{^K!Z^NS)pgy4FLAoi1UB zovwBimk7z{rxi6X)&m+;dj~Zz=OXl|M|F2zA6OgPL(r^22gaj9 zh2OAvlQV49!we;&26Z!KHPGkBpBcMF=-@dRSjia7GN6shv4ZU!vnr(vDXx%dRAd3&g2RWO4p!Ag}C=Kw< z%mdIIDocv02cSkvU+00Eb1F?N>ka33K&rS>k8XY}prWhvk4A(B@sBAq`aOhnR(cGLyD9M+z@~2rMdNK|l`N*QZ9^fM z>$k$T^>3=JmaM5MRQ>~%Hq|@I{*WAIjyZ=RN=*Jajm9_Ae41Rty%=c26{sNt#+SX< zeNTr|ZZmE7*?X3OxQ1>72HO51zTNbb4u_0`J(9Ao(^`P{M*h!!&3)kF$UxM>{`)%3 zsjQ3f3Pw?OniewSP>-g8&9(R8U)C`gXWn)!Yk`il3sXk9oh2+4aXth0wP z79^JpLSiVup)m=saWtldR?H??e*jdncR=laaJA0T_-F8-1H`N2_O%16=XBM_LsZ#P zJ94b5gmKOcJ&Zj|-QAuxPttqljws59Yd0RD#8&$3nO%L9=Csng>bDb*@k(ZHfSu^r z+9%3f;UsI$NrUl>?7z*IfHGW9!2C;h;*HT+(pfS+ruI01DVxzv(Hb(xi-K~MVOhCO zV7v|Y7d#6QXkT!|HUmKm!x z3f9*OI%_>ybheYvVbRx>;cC&35kidlA0|{V7N)FjCoK@hXLz25chYiY{D8?ArTOmA z<(^SE?3YnEojZj`d50VIfRzg=qm~Yic}WDxDafgeEc+OFcAF?O8haWI%+!nO?y5|k z>yD;_sr9>2KI+*wo!FfL%*oxsiCs{vj`LoiV_Evlndl=%V{X)YD7>(i6khnr%!?Rj z^qx>l4=+X%W}-EQreYEgvnZ~MPCOV7lW1BOEx$6pv0g9n2JQ7lW@d+9ra4{p4!g6E zjp13mf{lqSJ=((aF+6uT0kVdg%{!R&D$Iu!JCo6R73!{hZ6?r^`4keS z=%ugH?PfvWVo>%L+zs1pbZv^5B#u26(y1Og;b(l2x3PhnciQImwS?kwk%-#) zDT1VTa{02KX+3Ny`CDxlQ|GMguQ%FiCXn z$w>UHR=S5X<3!N7Dam_0#lo%VqYiWJ`CuFt#8G%$vbLN?_0|fXGOKA_6mwPJQM(axtgb( ze+?dR2Bgl7h^?WDJG6-LmJ3&W;l37J&E1Czvj8gYpzeYAkjn4Wi{K)J9<#L$^bYMq ztCIl##qo*s71VlOlYO{?x~i|1HsgeBpb34o6JjLxBdX|Y^oG85+Q>_kyaTsRi~DKv z9D>O@@~z*;4C=Q7oi+jT8gLWBd;(@O$2iYmydjKvB=;vu%!{giHD)(9(Ud&B8F3YlvbeU%guXa0^C7#Cx)Is1C7%+73d8z$@X2; zc#w{^cxWNOyH^H-c3t`nL7L4ko4YYu^GAK3-!ksP9xA!pu&ZAm?xm)KwX_+>_0PO* zBg(>!smEXl(&^W9XC%{d?=$dGbPzY!0BR!zOD!jjE%oO#?f3emnb)LWfWX>=cum@5 zh$es;S7)U6QPB|XNt*o3eySXzqj?kF9-tZb=mqyD1HPohq5AKlzc}`gePJ*4AUK?N z2wtk~AY%6J5HPzAg>LXX@ZmEjXMsx;4)dbkx+mN$s7-+A6Z3572z4J8EvSwx{Hz~k zL<3sd4PRk6vNwEbP!kZ>gvxX{$omScE;$_P=wVfW=6dF9iXU$B2KqAO8%iI6RNT_x SQB}JE8r9|r9hyc&v;GgAa24(V diff --git a/utils/visx2/mssccprj.scc b/utils/visx2/mssccprj.scc deleted file mode 100644 index 3ddd63e..0000000 --- a/utils/visx2/mssccprj.scc +++ /dev/null @@ -1,5 +0,0 @@ -SCC = This is a Source Code Control file - -[vis.mak] -SCC_Aux_Path = "\\Jeeves\VSSCODE\" -SCC_Project_Name = "$/Sdk/Standard/utils/visx2", ZNZBAAAA