From a9a5a22d06998e40e8a4fec8cc5c4233a3ace125 Mon Sep 17 00:00:00 2001 From: g-cont Date: Fri, 9 Jul 2010 00:00:00 +0400 Subject: [PATCH] 09 Jul 2010 --- backup.lst | 3 +- bshift/animation.cpp | 112 +- bshift/bshift.dsp | 2 +- bshift/cbase.h | 2 +- bshift/player.cpp | 11 + change.log | 14 + client/client.dsp | 16 +- client/global/dll_int.cpp | 14 +- client/global/enginecallback.h | 1 + client/global/studio.cpp | 4 +- client/global/utils.cpp | 164 +- client/global/utils.h | 15 +- client/global/view.cpp | 149 +- client/hud/hud.cpp | 103 +- client/hud/hud.h | 51 +- client/hud/hud_ammo.cpp | 63 +- client/hud/hud_ammo.h | 2 +- client/hud/hud_health.cpp | 10 +- client/hud/hud_health.h | 21 +- client/hud/hud_message.cpp | 26 +- client/hud/hud_msg.cpp | 70 +- client/hud/hud_train.cpp | 4 +- client/hud/hud_warhead.cpp | 157 - client/hud/hud_zoom.cpp | 75 - common/basetypes.h | 1 - common/clgame_api.h | 4 +- common/const.h | 3 + common/{studio_ref.h => studio.h} | 38 +- common/studio_event.h | 4 +- debug.bat | 8 - engine/client/cl_effects.c | 2 + engine/client/cl_game.c | 144 +- engine/client/cl_scrn.c | 79 +- engine/client/client.h | 12 +- engine/common.h | 2 +- engine/common/con_utils.c | 3 +- engine/server/sv_game.c | 11 +- engine/uimenu/ui_local.h | 4 +- launch/imagelib/imagelib.h | 27 - launch/imagelib/img_wad.c | 25 +- launch/memlib.c | 4 +- launch/soundlib/snd_ogg.c | 42 +- physic/cm_studio.c | 82 +- public/mathlib.h | 299 +- public/qfiles_ref.h | 29 +- public/render_api.h | 3 +- release.bat | 8 - server/cbase.h | 38 - server/ents/basebeams.h | 115 - server/ents/basebrush.cpp | 861 ---- server/ents/basebrush.h | 210 - server/ents/baseentity.cpp | 921 ---- server/ents/baseentity.h | 335 -- server/ents/basefunc.cpp | 2360 ---------- server/ents/basefx.cpp | 2913 ------------ server/ents/baseinfo.cpp | 449 -- server/ents/baseinfo.h | 108 - server/ents/baseitem.cpp | 635 --- server/ents/baseitem.h | 69 - server/ents/baselogic.cpp | 1381 ------ server/ents/baselogic.h | 53 - server/ents/basemover.cpp | 1396 ------ server/ents/basemover.cpp.old | 1855 -------- server/ents/basemover.h | 158 - server/ents/baseother.cpp | 286 -- server/ents/basephys.cpp | 34 - server/ents/baserockets.cpp | 982 ---- server/ents/baserockets.h | 111 - server/ents/basesprite.h | 150 - server/ents/basetank.cpp | 1154 ----- server/ents/basetank.h | 143 - server/ents/basetrain.cpp | 1074 ----- server/ents/basetrigger.cpp | 938 ---- server/ents/baseweapon.cpp | 2084 --------- server/ents/baseweapon.h | 371 -- server/ents/baseworld.cpp | 68 - server/ents/baseworld.h | 20 - server/game/game.cpp | 56 - server/game/game.h | 26 - server/game/gamerules.cpp | 160 - server/game/gamerules.h | 307 -- server/game/lights.cpp | 281 -- server/game/maprules.cpp | 961 ---- server/game/multiplay_gamerules.cpp | 1441 ------ server/game/singleplay_gamerules.cpp | 261 -- server/game/sound.cpp | 1952 -------- server/game/spectator.h | 27 - server/game/teamplay_gamerules.cpp | 614 --- server/game/teamplay_gamerules.h | 56 - server/global/client.cpp | 2134 --------- server/global/client.h | 115 - server/global/decals.cpp | 51 - server/global/decals.h | 63 - server/global/defaults.h | 441 -- server/global/dll_int.cpp | 510 --- server/global/enginecallback.h | 164 - server/global/extdll.h | 57 - server/global/globals.cpp | 84 - server/global/globals.h | 107 - server/global/hierarchy.h | 29 - server/global/parent.cpp | 324 -- server/global/plane.h | 176 - server/global/saverestore.cpp | 1250 ------ server/global/saverestore.h | 167 - server/global/sfx.cpp | 150 - server/global/sfx.h | 27 - server/global/soundent.h | 99 - server/global/spectator.cpp | 147 - server/global/utils.cpp | 3112 ------------- server/global/utils.h | 847 ---- server/monsters/activity.h | 132 - server/monsters/activitymap.h | 121 - server/monsters/ai_sound.cpp | 379 -- server/monsters/animating.cpp | 342 -- server/monsters/animation.cpp | 556 --- server/monsters/animation.h | 52 - server/monsters/apache.cpp | 942 ---- server/monsters/barnacle.cpp | 435 -- server/monsters/barney.cpp | 926 ---- server/monsters/baseanimating.h | 50 - server/monsters/basemonster.cpp | 6234 -------------------------- server/monsters/basemonster.h | 352 -- server/monsters/combat.cpp | 261 -- server/monsters/damage.h | 21 - server/monsters/defaultai.cpp | 1260 ------ server/monsters/defaultai.h | 98 - server/monsters/flyingmonster.cpp | 281 -- server/monsters/flyingmonster.h | 53 - server/monsters/generic.cpp | 395 -- server/monsters/gman.cpp | 243 - server/monsters/hassassin.cpp | 1068 ----- server/monsters/headcrab.cpp | 562 --- server/monsters/hgrunt.cpp | 2615 ----------- server/monsters/leech.cpp | 744 --- server/monsters/monsterevent.h | 29 - server/monsters/monstermaker.cpp | 363 -- server/monsters/monsters.h | 152 - server/monsters/nodes.cpp | 3654 --------------- server/monsters/nodes.h | 374 -- server/monsters/osprey.cpp | 823 ---- server/monsters/player.cpp | 4777 -------------------- server/monsters/player.h | 363 -- server/monsters/rat.cpp | 104 - server/monsters/roach.cpp | 466 -- server/monsters/schedule.h | 292 -- server/monsters/scientist.cpp | 1458 ------ server/monsters/scripted.cpp | 1246 ----- server/monsters/scripted.h | 128 - server/monsters/scriptevent.h | 29 - server/monsters/squad.h | 20 - server/monsters/squadmonster.cpp | 642 --- server/monsters/squadmonster.h | 121 - server/monsters/talkmonster.cpp | 1557 ------- server/monsters/talkmonster.h | 186 - server/monsters/turret.cpp | 1343 ------ server/monsters/zombie.cpp | 381 -- server/server.def | 5 - server/server.dsp | 576 --- server/weapon_generic.cpp | 67 - snd_al/s_export.c | 54 - snd_al/s_load.c | 397 -- snd_al/s_main.c | 1018 ----- snd_al/s_openal.c | 402 -- snd_al/s_openal.h | 313 -- snd_al/s_stream.c | 326 -- snd_al/snd_al.dsp | 149 - snd_al/sound.h | 183 - snd_dx/s_stream.c | 4 +- spirit/animation.cpp | 122 +- spirit/cbase.h | 10 +- spirit/combat.cpp | 6 +- spirit/weapons.cpp | 6 +- todo.log | 27 - vid_gl/r_decals.c | 3 +- vid_gl/r_image.c | 16 +- vid_gl/r_local.h | 1 + vid_gl/r_main.c | 3 + vid_gl/r_math.c | 49 +- vid_gl/r_math.h | 1 + vid_gl/r_model.h | 9 +- vid_gl/r_register.c | 4 +- vid_gl/r_shader.c | 92 +- vid_gl/r_shader.h | 9 +- vid_gl/r_sprite.c | 185 +- vid_gl/r_studio.c | 186 +- xash.dsw | 24 - xtools/mdllib.h | 2 +- xtools/spritegen.c | 6 +- xtools/studio.c | 105 +- xtools/utils.c | 2 +- 190 files changed, 1251 insertions(+), 79132 deletions(-) create mode 100644 change.log delete mode 100644 client/hud/hud_warhead.cpp delete mode 100644 client/hud/hud_zoom.cpp rename common/{studio_ref.h => studio.h} (91%) delete mode 100644 server/cbase.h delete mode 100644 server/ents/basebeams.h delete mode 100644 server/ents/basebrush.cpp delete mode 100644 server/ents/basebrush.h delete mode 100644 server/ents/baseentity.cpp delete mode 100644 server/ents/baseentity.h delete mode 100644 server/ents/basefunc.cpp delete mode 100644 server/ents/basefx.cpp delete mode 100644 server/ents/baseinfo.cpp delete mode 100644 server/ents/baseinfo.h delete mode 100644 server/ents/baseitem.cpp delete mode 100644 server/ents/baseitem.h delete mode 100644 server/ents/baselogic.cpp delete mode 100644 server/ents/baselogic.h delete mode 100644 server/ents/basemover.cpp delete mode 100644 server/ents/basemover.cpp.old delete mode 100644 server/ents/basemover.h delete mode 100644 server/ents/baseother.cpp delete mode 100644 server/ents/basephys.cpp delete mode 100644 server/ents/baserockets.cpp delete mode 100644 server/ents/baserockets.h delete mode 100644 server/ents/basesprite.h delete mode 100644 server/ents/basetank.cpp delete mode 100644 server/ents/basetank.h delete mode 100644 server/ents/basetrain.cpp delete mode 100644 server/ents/basetrigger.cpp delete mode 100644 server/ents/baseweapon.cpp delete mode 100644 server/ents/baseweapon.h delete mode 100644 server/ents/baseworld.cpp delete mode 100644 server/ents/baseworld.h delete mode 100644 server/game/game.cpp delete mode 100644 server/game/game.h delete mode 100644 server/game/gamerules.cpp delete mode 100644 server/game/gamerules.h delete mode 100644 server/game/lights.cpp delete mode 100644 server/game/maprules.cpp delete mode 100644 server/game/multiplay_gamerules.cpp delete mode 100644 server/game/singleplay_gamerules.cpp delete mode 100644 server/game/sound.cpp delete mode 100644 server/game/spectator.h delete mode 100644 server/game/teamplay_gamerules.cpp delete mode 100644 server/game/teamplay_gamerules.h delete mode 100644 server/global/client.cpp delete mode 100644 server/global/client.h delete mode 100644 server/global/decals.cpp delete mode 100644 server/global/decals.h delete mode 100644 server/global/defaults.h delete mode 100644 server/global/dll_int.cpp delete mode 100644 server/global/enginecallback.h delete mode 100644 server/global/extdll.h delete mode 100644 server/global/globals.cpp delete mode 100644 server/global/globals.h delete mode 100644 server/global/hierarchy.h delete mode 100644 server/global/parent.cpp delete mode 100644 server/global/plane.h delete mode 100644 server/global/saverestore.cpp delete mode 100644 server/global/saverestore.h delete mode 100644 server/global/sfx.cpp delete mode 100644 server/global/sfx.h delete mode 100644 server/global/soundent.h delete mode 100644 server/global/spectator.cpp delete mode 100644 server/global/utils.cpp delete mode 100644 server/global/utils.h delete mode 100644 server/monsters/activity.h delete mode 100644 server/monsters/activitymap.h delete mode 100644 server/monsters/ai_sound.cpp delete mode 100644 server/monsters/animating.cpp delete mode 100644 server/monsters/animation.cpp delete mode 100644 server/monsters/animation.h delete mode 100644 server/monsters/apache.cpp delete mode 100644 server/monsters/barnacle.cpp delete mode 100644 server/monsters/barney.cpp delete mode 100644 server/monsters/baseanimating.h delete mode 100644 server/monsters/basemonster.cpp delete mode 100644 server/monsters/basemonster.h delete mode 100644 server/monsters/combat.cpp delete mode 100644 server/monsters/damage.h delete mode 100644 server/monsters/defaultai.cpp delete mode 100644 server/monsters/defaultai.h delete mode 100644 server/monsters/flyingmonster.cpp delete mode 100644 server/monsters/flyingmonster.h delete mode 100644 server/monsters/generic.cpp delete mode 100644 server/monsters/gman.cpp delete mode 100644 server/monsters/hassassin.cpp delete mode 100644 server/monsters/headcrab.cpp delete mode 100644 server/monsters/hgrunt.cpp delete mode 100644 server/monsters/leech.cpp delete mode 100644 server/monsters/monsterevent.h delete mode 100644 server/monsters/monstermaker.cpp delete mode 100644 server/monsters/monsters.h delete mode 100644 server/monsters/nodes.cpp delete mode 100644 server/monsters/nodes.h delete mode 100644 server/monsters/osprey.cpp delete mode 100644 server/monsters/player.cpp delete mode 100644 server/monsters/player.h delete mode 100644 server/monsters/rat.cpp delete mode 100644 server/monsters/roach.cpp delete mode 100644 server/monsters/schedule.h delete mode 100644 server/monsters/scientist.cpp delete mode 100644 server/monsters/scripted.cpp delete mode 100644 server/monsters/scripted.h delete mode 100644 server/monsters/scriptevent.h delete mode 100644 server/monsters/squad.h delete mode 100644 server/monsters/squadmonster.cpp delete mode 100644 server/monsters/squadmonster.h delete mode 100644 server/monsters/talkmonster.cpp delete mode 100644 server/monsters/talkmonster.h delete mode 100644 server/monsters/turret.cpp delete mode 100644 server/monsters/zombie.cpp delete mode 100644 server/server.def delete mode 100644 server/server.dsp delete mode 100644 server/weapon_generic.cpp delete mode 100644 snd_al/s_export.c delete mode 100644 snd_al/s_load.c delete mode 100644 snd_al/s_main.c delete mode 100644 snd_al/s_openal.c delete mode 100644 snd_al/s_openal.h delete mode 100644 snd_al/s_stream.c delete mode 100644 snd_al/snd_al.dsp delete mode 100644 snd_al/sound.h delete mode 100644 todo.log diff --git a/backup.lst b/backup.lst index 8016f27d..7bf2b041 100644 --- a/backup.lst +++ b/backup.lst @@ -10,7 +10,7 @@ backup.lst backup.bat release.bat launchers.bat -todo.log +change.log baserc\ bshift\ @@ -42,7 +42,6 @@ server\game\ server\global\ server\monsters\ spirit\ -snd_al\ snd_dx\ vid_gl\ xtools\ diff --git a/bshift/animation.cpp b/bshift/animation.cpp index af059ea9..27efbed7 100644 --- a/bshift/animation.cpp +++ b/bshift/animation.cpp @@ -18,7 +18,7 @@ #include "extdll.h" #include "const.h" -#include "studio_ref.h" +#include "studio.h" #include "util.h" #include "activitymap.h" @@ -33,15 +33,15 @@ int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); mins[0] = pseqdesc[ sequence ].bbmin[0]; mins[1] = pseqdesc[ sequence ].bbmin[1]; @@ -57,15 +57,15 @@ int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ) int LookupActivity( void *pmodel, entvars_t *pev, int activity ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); int weighttotal = 0; int seq = ACTIVITY_NOT_AVAILABLE; @@ -85,15 +85,15 @@ int LookupActivity( void *pmodel, entvars_t *pev, int activity ) int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr ) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); int weight = 0; int seq = ACTIVITY_NOT_AVAILABLE; @@ -114,9 +114,9 @@ int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) void GetEyePosition ( void *pmodel, Vector &vecEyePosition ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr ) { @@ -129,15 +129,15 @@ void GetEyePosition ( void *pmodel, Vector &vecEyePosition ) int LookupSequence( void *pmodel, const char *label ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); for (int i = 0; i < pstudiohdr->numseq; i++) { @@ -162,17 +162,17 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) int index = LookupSequence( pmodel, pSequenceName ); if ( index >= 0 ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr || index >= pstudiohdr->numseq ) return; - dstudioseqdesc_t *pseqdesc; - dstudioevent_t *pevent; + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; - pevent = (dstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; + pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); for (int i = 0; i < pseqdesc->numevents; i++) { @@ -199,13 +199,13 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; if (pev->sequence >= pstudiohdr->numseq) { @@ -214,7 +214,7 @@ void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float * return; } - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; if (pseqdesc->numframes > 1) { @@ -232,14 +232,14 @@ void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float * int GetSequenceFlags( void *pmodel, entvars_t *pev ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) return 0; - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; return pseqdesc->flags; } @@ -247,19 +247,19 @@ int GetSequenceFlags( void *pmodel, entvars_t *pev ) int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) return 0; int events = 0; - dstudioseqdesc_t *pseqdesc; - dstudioevent_t *pevent; + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - pevent = (dstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); if (pseqdesc->numevents == 0 || index > pseqdesc->numevents ) return 0; @@ -294,13 +294,13 @@ int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEve float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return flValue; - dstudiobonecontroller_t *pbonecontroller = (dstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); + mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); // find first controller that matches the index for (int i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) @@ -348,15 +348,15 @@ float SetController( void *pmodel, entvars_t *pev, int iController, float flValu float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return flValue; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; if (pseqdesc->blendtype[iBlender] == 0) return flValue; @@ -392,14 +392,14 @@ float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return iGoalAnim; - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); // bail if we're going to or from a node 0 if (pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0) @@ -459,16 +459,16 @@ int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return; if (iGroup > pstudiohdr->numbodyparts) return; - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; if (iValue >= pbodypart->nummodels) return; @@ -481,16 +481,16 @@ void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; if (iGroup > pstudiohdr->numbodyparts) return 0; - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; if (pbodypart->nummodels <= 1) return 0; diff --git a/bshift/bshift.dsp b/bshift/bshift.dsp index 2f2fe9f3..baaa8e99 100644 --- a/bshift/bshift.dsp +++ b/bshift/bshift.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /GB /MD /W3 /GX /O2 /I "..\bshift" /I "..\common" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\bshift" /I "..\common" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /FD /c # SUBTRACT CPP /Fr /YX # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 diff --git a/bshift/cbase.h b/bshift/cbase.h index 689d058b..1fe562d7 100644 --- a/bshift/cbase.h +++ b/bshift/cbase.h @@ -46,7 +46,7 @@ CBaseEntity #include "saverestore.h" #include "schedule.h" -#include "studio_ref.h" +#include "studio.h" #ifndef MONSTEREVENT_H #include "monsterevent.h" diff --git a/bshift/player.cpp b/bshift/player.cpp index 3669e93f..f345ae32 100644 --- a/bshift/player.cpp +++ b/bshift/player.cpp @@ -3133,6 +3133,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; diff --git a/change.log b/change.log new file mode 100644 index 00000000..56f00e78 --- /dev/null +++ b/change.log @@ -0,0 +1,14 @@ +build ???? +SoundLib: ogg loop points (LOOP_START comment) +Client: recalc fov y for more matched with original HL + + +build 1249 + +ImageLib: added support for 4-bits and monochrome uncompressed BMPs. +ImageLib: fix data align for NPOT textures in menu (e.g. slider.bmp). +StdLib: skip empty symbols in numerical string for atoi and atof. +Render: implement LoadSprite for custom client sprites (e.g. hud) +Sound: fixed bug with background music looping +Fonts: implement Half-Life creditfonts +Client: move client.dll to valve folder \ No newline at end of file diff --git a/client/client.dsp b/client/client.dsp index 69be150b..22426573 100644 --- a/client/client.dsp +++ b/client/client.dsp @@ -61,8 +61,8 @@ TargetDir=\Xash3D\src_main\temp\client\!release InputPath=\Xash3D\src_main\temp\client\!release\client.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\client.dll "D:\Xash3D\bin\client.dll" +"D:\Xash3D\valve\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\client.dll "D:\Xash3D\valve\bin\client.dll" # End Custom Build @@ -101,8 +101,8 @@ TargetDir=\Xash3D\src_main\temp\client\!debug InputPath=\Xash3D\src_main\temp\client\!debug\client.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\client.dll "D:\Xash3D\bin\client.dll" +"D:\Xash3D\valve\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\client.dll "D:\Xash3D\valve\bin\client.dll" # End Custom Build @@ -213,14 +213,6 @@ SOURCE=.\hud\hud_train.cpp # End Source File # Begin Source File -SOURCE=.\hud\hud_warhead.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_zoom.cpp -# End Source File -# Begin Source File - SOURCE=.\global\input.cpp # End Source File # Begin Source File diff --git a/client/global/dll_int.cpp b/client/global/dll_int.cpp index 328d70e7..d3e2da0c 100644 --- a/client/global/dll_int.cpp +++ b/client/global/dll_int.cpp @@ -6,7 +6,7 @@ #include "extdll.h" #include "utils.h" #include "ref_params.h" -#include "studio_ref.h" +#include "studio.h" #include "hud.h" #include "aurora.h" #include "r_particle.h" @@ -165,18 +165,15 @@ int HUD_Redraw( float flTime, int state ) { switch( state ) { - case CL_LOADING: - DrawProgressBar(); - break; case CL_ACTIVE: - gHUD.Redraw( flTime ); - break; case CL_PAUSED: gHUD.Redraw( flTime ); - DrawPause(); + break; + case CL_LOADING: + // called while map is loading break; case CL_CHANGELEVEL: - DrawImageBar( 100, "m_loading" ); + // called once when changelevel in-action break; } return 1; @@ -342,6 +339,7 @@ void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const enti // g-cont. moved here because we may needs apply null scale to skyportal if( ent->v.scale == 0.0f && ent->v.skin >= 0 ) ent->v.scale = 1.0f; + if( ent->v.scale >= 100.0f ) ent->v.scale = 1.0f; // original HL issues ent->v.pContainingEntity = ent; } diff --git a/client/global/enginecallback.h b/client/global/enginecallback.h index 02e03da7..806b5172 100644 --- a/client/global/enginecallback.h +++ b/client/global/enginecallback.h @@ -12,6 +12,7 @@ #define FREE( x ) (*g_engfuncs.pfnMemFree)( x, __FILE__, __LINE__ ) // screen handlers +#define SPR_GetList (*g_engfuncs.pfnSPR_GetList) #define SPR_Frames (*g_engfuncs.pfnSPR_Frames) #define SPR_Width (*g_engfuncs.pfnSPR_Width) #define SPR_Height (*g_engfuncs.pfnSPR_Height) diff --git a/client/global/studio.cpp b/client/global/studio.cpp index 45cff789..f59c3ed3 100644 --- a/client/global/studio.cpp +++ b/client/global/studio.cpp @@ -33,7 +33,7 @@ void EV_DrawBeam ( void ) //====================== // Eject Shell //====================== -void EV_EjectShell( const dstudioevent_t *event, edict_t *entity ) +void EV_EjectShell( const mstudioevent_t *event, edict_t *entity ) { vec3_t view_ofs, ShellOrigin, ShellVelocity, forward, right, up; vec3_t origin = entity->v.origin; @@ -67,7 +67,7 @@ void EV_EjectShell( const dstudioevent_t *event, edict_t *entity ) EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); } -void HUD_StudioEvent( const dstudioevent_t *event, edict_t *entity ) +void HUD_StudioEvent( const mstudioevent_t *event, edict_t *entity ) { float pitch; Vector pos; diff --git a/client/global/utils.cpp b/client/global/utils.cpp index fccd8908..49de45aa 100644 --- a/client/global/utils.cpp +++ b/client/global/utils.cpp @@ -213,131 +213,6 @@ void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumb g_engfuncs.pfnTraceModel( vecStart, vecEnd, pentModel, ptr ); } -/* -============================================================================== - - HUD-SPRITES PARSING - -============================================================================== -*/ -/* -==================== -ParseHudSprite - -==================== -*/ -void ParseHudSprite( const char **pfile, char *psz, client_sprite_t *result ) -{ - int x = 0, y = 0, width = 0, height = 0; - client_sprite_t p; - int section = 0; - char *token; - - memset( &p, 0, sizeof( client_sprite_t )); - - while(( token = COM_ParseToken( pfile )) != NULL ) - { - if( !stricmp( token, psz )) - { - token = COM_ParseToken( pfile ); - if( !stricmp( token, "{" )) section = 1; - } - if( section ) // parse section - { - if( !stricmp( token, "}" )) break; // end section - - if( !stricmp( token, "file" )) - { - token = COM_ParseToken( pfile ); - strncpy( p.szSprite, token, 64 ); - - // fill structure at default - p.hSprite = SPR_Load( p.szSprite ); - width = SPR_Width( p.hSprite, 0 ); - height = SPR_Height( p.hSprite, 0 ); - x = y = 0; - } - else if ( !stricmp( token, "name" )) - { - token = COM_ParseToken( pfile ); - strncpy( p.szName, token, 64 ); - } - else if ( !stricmp( token, "x" )) - { - token = COM_ParseToken( pfile ); - x = atoi( token ); - } - else if ( !stricmp( token, "y" )) - { - token = COM_ParseToken( pfile ); - y = atoi( token ); - } - else if ( !stricmp( token, "width" )) - { - token = COM_ParseToken( pfile ); - width = atoi( token ); - } - else if ( !stricmp( token, "height" )) - { - token = COM_ParseToken( pfile ); - height = atoi( token ); - } - } - } - - if( !section ) return; // data not found - - // calculate sprite position - p.rc.left = x; - p.rc.right = x + width; - p.rc.top = y; - p.rc.bottom = y + height; - - memcpy( result, &p, sizeof( client_sprite_t )); -} - -client_sprite_t *SPR_GetList( const char *psz, int *piCount ) -{ - char *pfile = (char *)LOAD_FILE( psz, NULL ); - int iSprCount = 0; - - if( !pfile ) - { - *piCount = iSprCount; - return NULL; - } - - char *token; - const char *plist = pfile; - int depth = 0; - - while(( token = COM_ParseToken( &plist )) != NULL ) // calculate count of sprites - { - if( !stricmp( token, "{" )) depth++; - else if( !stricmp( token, "}" )) depth--; - else if( depth == 0 && !strcmp( token, "hudsprite" )) - iSprCount++; - } - - client_sprite_t *phud; - plist = pfile; - - phud = new client_sprite_t[iSprCount]; - - if( depth != 0 ) ALERT( at_console, "%s EOF without closing brace\n", psz ); - - for( int i = 0; i < iSprCount; i++ ) //parse structures - { - ParseHudSprite( &plist, "hudsprite", &phud[i] ); - } - - if( !iSprCount ) ALERT( at_console, "SPR_GetList: %s doesn't have sprites\n", psz ); - FREE_FILE( pfile ); - - *piCount = iSprCount; - return phud; -} - /* ============================================================================== @@ -345,16 +220,6 @@ client_sprite_t *SPR_GetList( const char *psz, int *piCount ) ============================================================================== */ -void Draw_VidInit( void ) -{ -} - -void DrawPause( void ) -{ - // pause image - DrawImageBar( 100, "m_pause" ); // HACKHACK -} - void DrawImageBar( float percent, const char *szSpriteName ) { int m_loading = gHUD.GetSpriteIndex( szSpriteName ); @@ -383,18 +248,6 @@ void DrawImageBar( float percent, const char *szSpriteName, int x, int y ) SPR_DrawAdditive( 0, x, y, &rcBar ); // progress bar } -// -// 27/12/08 moved here from cl_view.c -// -void DrawProgressBar( void ) -{ - if( !gHUD.m_iDrawPlaque ) return; - DrawImageBar( CVAR_GET_FLOAT( "scr_loading" ), "m_loading" ); - - if( !CVAR_GET_FLOAT( "scr_download" )) return; - DrawImageBar( CVAR_GET_FLOAT( "scr_download" ), "m_download", (ScreenWidth - 128)>>1, ScreenHeight - 60 ); -} - void AngleMatrix( const vec3_t angles, float (*matrix)[4] ) { float angle; @@ -592,7 +445,7 @@ void RotatePointAroundVector( Vector &dst, const Vector &dir, const Vector &poin float angle, c, s, d; Vector vr, vu, vf; - angle = degrees * (M_PI / 180.f); + angle = DEG2RAD( degrees ); s = sin( angle ); c = cos( angle ); @@ -755,6 +608,21 @@ const char *UTIL_FileExtension( const char *in ) return dot + 1; } +HSPRITE LoadSprite( const char *pszName ) +{ + int i; + char sz[256]; + + if ( ActualWidth < 640 ) + i = 320; + else + i = 640; + + sprintf( sz, pszName, i ); + + return SPR_Load( sz ); +} + /* ==================== VGui_ConsolePrint diff --git a/client/global/utils.h b/client/global/utils.h index 6dcde540..1bd8b0ba 100644 --- a/client/global/utils.h +++ b/client/global/utils.h @@ -44,7 +44,7 @@ extern void HUD_Shutdown( void ); extern void HUD_RenderCallback( int fTrans ); extern void HUD_CreateEntities( void ); extern int HUD_AddVisibleEntity( edict_t *pEnt, int ed_type ); -extern void HUD_StudioEvent( const dstudioevent_t *event, edict_t *entity ); +extern void HUD_StudioEvent( const mstudioevent_t *event, edict_t *entity ); extern void HUD_StudioFxTransform( edict_t *ent, float transform[4][4] ); extern int HUD_StudioDoInterp( edict_t *e ); extern void HUD_ParseTempEntity( void ); @@ -198,19 +198,18 @@ extern float UTIL_Probe( const Vector &origin, Vector *vecDirection, float stren extern void UTIL_GetForceDirection( const Vector &origin, float magnitude, Vector *resultDirection, float *resultForce ); extern void RotatePointAroundVector( Vector &dst, const Vector &dir, const Vector &point, float degrees ); -// drawing stuff -extern client_sprite_t *SPR_GetList( const char *name, int *count ); -extern void ParseHudSprite( const char **pfile, char *psz, client_sprite_t *result ); -extern void DrawPause( void ); +// client fade extern void SetScreenFade( Vector fadeColor, float alpha, float duration, float holdTime, int fadeFlags ); extern void ClearAllFades( void ); extern void ClearPermanentFades( void ); extern void DrawScreenFade( void ); + +// drawing progress bar (image must be grayscale) extern void DrawImageBar( float percent, const char *szSpriteName ); extern void DrawImageBar( float percent, const char *szSpriteName, int x, int y ); -extern void DrawGenericBar( float percent, int w, int h ); -extern void DrawGenericBar( float percent, int x, int y, int w, int h ); -extern void Draw_VidInit( void ); + +// sprite loading +extern HSPRITE LoadSprite( const char *pszName ); // mathlib extern void AngleMatrix( const vec3_t angles, float (*matrix)[4] ); diff --git a/client/global/view.cpp b/client/global/view.cpp index 6f32b012..b3134772 100644 --- a/client/global/view.cpp +++ b/client/global/view.cpp @@ -8,7 +8,7 @@ #include "ref_params.h" #include "triangle_api.h" #include "pm_movevars.h" -#include "studio_ref.h" +#include "studio.h" #include "usercmd.h" #include "hud.h" @@ -65,27 +65,6 @@ cvar_t *v_iroll_level; cvar_t *v_ipitch_level; cvar_t *v_dark; -//============================================================================== -// PASS MANAGER GLOBALS -//============================================================================== -// render manager global variables -bool g_FirstFrame = false; -bool g_bFinalPass = false; -bool g_bEndCalc = false; -int m_RenderRefCount = 0; // refcounter (use for debug) - -// passes info -bool g_bSkyShouldpass = false; -bool g_bSkyPass = false; - -// base origin and angles -Vector g_vecBaseOrigin; // base origin - transformed always -Vector g_vecBaseAngles; // base angles - transformed always -Vector g_vecCurrentOrigin; // current origin -Vector g_vecCurrentAngles; // current angles - - - //============================================================================== // VIEW RENDERING //============================================================================== @@ -240,18 +219,16 @@ void V_DriftPitch( ref_params_t *pparams ) //========================== float V_CalcFov( float fov_x, float width, float height ) { - float fov_y, x, rad = 360.0f * M_PI; - // check to avoid division by zero - if( fov_x == 0 ) HOST_ERROR( "V_CalcFov: null fov!\n" ); + if( fov_x < 1 || fov_x > 179 ) + { + ALERT( at_error, "V_CalcFov: invalid fov %g!\n", fov_x ); + fov_x = 90; + } - // make sure that fov in-range - fov_x = bound( 1, fov_x, 179 ); - x = width / tan( fov_x / rad ); - fov_y = atan2( height, x ); - fov_y = (fov_y * rad); - - return fov_y; + float x = width / tan( DEG2RAD( fov_x ) * 0.5f ); + float half_fov_y = atan( height / x ); + return RAD2DEG( half_fov_y ) * 2; } //========================== @@ -369,6 +346,8 @@ void V_PreRender( ref_params_t *pparams ) pparams->fov_x = gHUD.m_flFOV; // this is a final fov value pparams->fov_y = V_CalcFov( pparams->fov_x, pparams->viewport[2], pparams->viewport[3] ); + + memset( pparams->blend, 0, sizeof( pparams->blend )); } //========================== @@ -456,9 +435,9 @@ void V_CalcViewRoll( ref_params_t *pparams ) } //========================== -// V_SetViewportRefdef +// V_SetViewport //========================== -void V_SetViewportRefdef( ref_params_t *pparams ) +void V_SetViewport( ref_params_t *pparams ) { pparams->viewport[0] = 0; pparams->viewport[1] = 0; @@ -467,20 +446,9 @@ void V_SetViewportRefdef( ref_params_t *pparams ) } //========================== -// V_KillViewportRefdef +// V_ResetViewport //========================== -void V_KillViewportRefdef( ref_params_t *pparams ) -{ - pparams->viewport[0] = 0; - pparams->viewport[1] = 0; - pparams->viewport[2] = 1; - pparams->viewport[3] = 1; -} - -//========================== -// V_ResetViewportRefdef -//========================== -void V_ResetViewportRefdef( ref_params_t *pparams ) +void V_ResetViewport( ref_params_t *pparams ) { pparams->viewport[0] = 0; pparams->viewport[1] = 0; @@ -562,25 +530,6 @@ void V_GetChasePos( ref_params_t *pparams, edict_t *ent, float *cl_angles, Vecto V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); } -//========================== -// V_CalcNextView -//========================== -void V_CalcNextView( ref_params_t *pparams ) -{ - if( g_FirstFrame ) // first time not actually - { - g_FirstFrame = false; - - // first time in this function - V_PreRender( pparams ); - - g_bSkyShouldpass = (gHUD.m_iSkyMode ? true : false); - m_RenderRefCount = 0; // reset debug counter - g_bSkyPass = false; - g_bFinalPass = false; - } -} - //========================== // V_CalcCameraRefdef //========================== @@ -594,7 +543,7 @@ void V_CalcCameraRefdef( ref_params_t *pparams ) edict_t *viewentity = GetEntityByIndex( gHUD.viewEntityIndex ); if( viewentity ) { - dstudiohdr_t *viewmonster = (dstudiohdr_t *)GetModelPtr( viewentity ); + studiohdr_t *viewmonster = (studiohdr_t *)GetModelPtr( viewentity ); float m_fLerp = GetLerpFrac(); if( viewentity->v.movetype == MOVETYPE_STEP ) @@ -624,7 +573,7 @@ void V_CalcCameraRefdef( ref_params_t *pparams ) edict_t *viewentity = GetEntityByIndex( pparams->viewentity ); if( viewentity ) { - dstudiohdr_t *viewmonster = (dstudiohdr_t *)GetModelPtr( viewentity ); + studiohdr_t *viewmonster = (studiohdr_t *)GetModelPtr( viewentity ); float m_fLerp = GetLerpFrac(); if( viewentity->v.movetype == MOVETYPE_STEP ) @@ -781,16 +730,6 @@ void V_ApplyShake( Vector& origin, Vector& angles, float factor ) angles.z += gHUD.m_Shake.appliedAngle * factor; } -//========================== -// V_CalcFinalPass -//========================== -void V_CalcFinalPass( ref_params_t *pparams ) -{ - g_FirstFrame = true; // enable calc next passes - V_ResetViewportRefdef( pparams ); // reset view port as default - m_RenderRefCount++; // increase counter -} - //========================== // V_CalcThirdPersonRefdef //========================== @@ -982,7 +921,7 @@ void V_CalcFirstPersonRefdef( ref_params_t *pparams ) edict_t *view = GetViewModel(); int i; - if( g_bFinalPass ) V_DriftPitch( pparams ); + V_DriftPitch( pparams ); bob = V_CalcBob( pparams ); // refresh the position @@ -1102,57 +1041,15 @@ void V_CalcScreenBlend( ref_params_t *pparams ) #endif } -//========================== -// V_CalcMainRefdef -//========================== -void V_CalcMainRefdef( ref_params_t *pparams ) +void V_CalcRefdef( ref_params_t *pparams ) { - memset( pparams->blend, 0, sizeof( pparams->blend )); - - if( g_FirstFrame ) g_bFinalPass = true; + V_PreRender( pparams ); + V_CalcGlobalFog( pparams ); + V_ResetViewport( pparams ); V_CalcFirstPersonRefdef( pparams ); V_CalcThirdPersonRefdef( pparams ); V_CalcIntermisionRefdef( pparams ); V_CalcCameraRefdef( pparams ); V_CalcScreenBlend( pparams ); - - g_vecBaseOrigin = pparams->vieworg; - g_vecBaseAngles = pparams->viewangles; -} - -//========================== -// V_CalcSkyRefdef -//========================== -bool V_CalcSkyRefdef( ref_params_t *pparams ) -{ - if( g_bSkyShouldpass ) - { - g_bSkyShouldpass = false; - V_CalcMainRefdef( pparams ); // refresh position - pparams->vieworg = gHUD.m_vecSkyPos; - V_ResetViewportRefdef( pparams ); - pparams->nextView = 1; - g_bSkyPass = true; - m_RenderRefCount++; - return true; - } - if( g_bSkyPass ) - { - pparams->nextView = 0; - g_bSkyPass = false; - return false; - } - return false; -} - -void V_CalcRefdef( ref_params_t *pparams ) -{ - V_CalcNextView( pparams ); - - if( V_CalcSkyRefdef( pparams )) - return; - - V_CalcGlobalFog( pparams ); - V_CalcFinalPass ( pparams ); - V_CalcMainRefdef( pparams ); + } \ No newline at end of file diff --git a/client/hud/hud.cpp b/client/hud/hud.cpp index 0d24356b..ed4cccbf 100644 --- a/client/hud/hud.cpp +++ b/client/hud/hud.cpp @@ -7,10 +7,18 @@ #include "hud.h" #include "triangle_api.h" +#define MAX_LOGO_FRAMES 56 + +int grgLogoFrame[MAX_LOGO_FRAMES] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, + 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 +}; + void CHud :: Init( void ) { InitMessages(); - m_Zoom.Init(); // must be first m_Ammo.Init(); m_Health.Init(); m_SayText.Init(); @@ -18,7 +26,6 @@ void CHud :: Init( void ) m_Train.Init(); m_Battery.Init(); m_Flash.Init(); - m_Redeemer.Init(); m_Message.Init(); m_Scoreboard.Init(); m_StatusBar.Init(); @@ -71,11 +78,11 @@ void CHud :: VidInit( void ) // Load Sprites // --------- + m_hsprLogo = 0; m_hsprCursor = 0; m_hHudError = 0; spot = NULL; // clear intermission spot - Draw_VidInit (); ClearAllFades (); if( CVAR_GET_FLOAT( "hud_scale" )) @@ -85,25 +92,47 @@ void CHud :: VidInit( void ) // setup screen info GetScreenInfo( &m_scrinfo ); + if( ActualWidth < 640 ) + m_iRes = 320; + else m_iRes = 640; + // Only load this once if ( !m_pSpriteList ) { // we need to load the hud.txt, and all sprites within - m_pSpriteList = SPR_GetList( "scripts/hud.txt", &m_iSpriteCount ); + m_pSpriteList = SPR_GetList( "sprites/hud.txt", &m_iSpriteCountAllRes ); if( m_pSpriteList ) { + // count the number of sprites of the appropriate res + m_iSpriteCount = 0; + client_sprite_t *p = m_pSpriteList; + for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + m_iSpriteCount++; + p++; + } + // allocated memory for sprite handle arrays m_rghSprites = new HSPRITE[m_iSpriteCount]; m_rgrcRects = new wrect_t[m_iSpriteCount]; m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; - client_sprite_t *p = m_pSpriteList; - for ( int j = 0; j < m_iSpriteCount; j++ ) + p = m_pSpriteList; + int index = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) { - m_rghSprites[j] = SPR_Load( p->szSprite ); - m_rgrcRects[j] = p->rc; - strncpy( &m_rgszSpriteNames[j * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf(sz, "sprites/%s.spr", p->szSprite); + m_rghSprites[index] = SPR_Load(sz); + m_rgrcRects[index] = p->rc; + strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + + index++; + } p++; } } @@ -116,12 +145,20 @@ void CHud :: VidInit( void ) } else { - // engine may be release unused shaders after reloading map or change level - // loading them again here + // we have already have loaded the sprite reference from hud.txt, but + // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) client_sprite_t *p = m_pSpriteList; - for( int j = 0; j < m_iSpriteCount; j++ ) + int index = 0; + for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) { - m_rghSprites[j] = SPR_Load( p->szSprite ); + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf( sz, "sprites/%s.spr", p->szSprite ); + m_rghSprites[index] = SPR_Load(sz); + index++; + } + p++; } } @@ -141,8 +178,6 @@ void CHud :: VidInit( void ) m_Train.VidInit(); m_Battery.VidInit(); m_Flash.VidInit(); - m_Redeemer.VidInit(); - m_Zoom.VidInit(); m_MOTD.VidInit(); m_Message.VidInit(); m_Scoreboard.VidInit(); @@ -224,20 +259,10 @@ int CHud :: Redraw( float flTime ) DrawScreenFade(); // take a screenshot if the client's got the cvar set - if( CVAR_GET_FLOAT( "hud_takesshots" )) + if( m_flShotTime && m_flShotTime < flTime ) { - if( m_flTime > m_flShotTime ) - { - CLIENT_COMMAND( "screenshot\n" ); - m_flShotTime = m_flTime + 0.04f; - } - } - - // redeemer hud stuff - if( m_Redeemer.m_iHudMode > 0 ) - { - m_Redeemer.Draw( flTime ); - return 1; + CLIENT_COMMAND( "screenshot\n" ); + m_flShotTime = 0; } // custom view active, and flag "draw hud" isn't set @@ -265,6 +290,28 @@ int CHud :: Redraw( float flTime ) pList = pList->pNext; } } + + // are we in demo mode? do we need to draw the logo in the top corner? + if (m_iLogo) + { + int x, y, i; + + if (m_hsprLogo == 0) + m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); + + SPR_Set(m_hsprLogo, 250, 250, 250 ); + + x = SPR_Width(m_hsprLogo, 0); + x = ScreenWidth - x; + y = SPR_Height(m_hsprLogo, 0)/2; + + // Draw the logo at 20 fps + int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; + i = grgLogoFrame[iFrame] - 1; + + SPR_DrawAdditive(i, x, y, NULL); + } + return 1; } diff --git a/client/hud/hud.h b/client/hud/hud.h index 7150fbfc..fc705113 100644 --- a/client/hud/hud.h +++ b/client/hud/hud.h @@ -426,36 +426,6 @@ private: int m_iWidth; // width of the battery innards }; -class CHudRedeemer: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_WarHUD( const char *pszName, int iSize, void *pbuf ); - int m_iHudMode; - int m_iOldHudMode; - -private: - HSPRITE m_hSprite; - HSPRITE m_hCrosshair; - HSPRITE m_hStatic; - HSPRITE m_hCamera; - HSPRITE m_hCamRec; -}; - -class CHudZoom: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_ZoomHUD( const char *pszName, int iSize, void *pbuf ); - int m_iHudMode; -private: - HSPRITE m_hCrosshair; - HSPRITE m_hLines; -}; // //----------------------------------------------------- // @@ -519,7 +489,8 @@ private: message_parms_t m_parms; float m_gameTitleTime; client_textmessage_t *m_pGameTitle; - int HUD_Logo; // display logo + int m_HUD_title_life; + int m_HUD_title_half; }; // @@ -561,16 +532,15 @@ private: // //----------------------------------------------------- // - -#define SKY_OFF 0 -#define SKY_ON 1 - class CHud { private: HUDLIST *m_pHudList; + HSPRITE m_hsprLogo; + int m_iLogo; client_sprite_t *m_pSpriteList; int m_iSpriteCount; + int m_iSpriteCountAllRes; float m_flMouseSensitivity; int m_iConcussionEffect; int m_iNoClip; @@ -586,8 +556,6 @@ public: float m_flFOV; int m_Teamplay; int m_iRes; - Vector m_vecSkyPos; - int m_iSkyMode; int m_iCameraMode; int m_iLastCameraMode; int m_iFontHeight; @@ -618,8 +586,6 @@ public: CHudBattery m_Battery; CHudTrain m_Train; CHudFlashlight m_Flash; - CHudRedeemer m_Redeemer; - CHudZoom m_Zoom; CHudMessage m_Message; CHudScoreboard m_Scoreboard; CHudStatusBar m_StatusBar; @@ -644,6 +610,7 @@ public: // user messages int _cdecl MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_RoomType( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_ScreenFade( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ); @@ -656,18 +623,14 @@ public: int _cdecl MsgFunc_RainData( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_HUDColor( const char *pszName, int iSize, void *pbuf); int _cdecl MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_SetSky( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_CamData( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_SetBody( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_WeaponAnim( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_AddScreen( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_AddMirror( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_AddPortal( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_Particle( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_TempEntity( const char *pszName, int iSize, void *pbuf ); - // user commansds + // user commands void _cdecl UserCmd_ChangeLevel( void ); // Screen information diff --git a/client/hud/hud_ammo.cpp b/client/hud/hud_ammo.cpp index 5f99ea2e..f44dfdcd 100644 --- a/client/hud/hud_ammo.cpp +++ b/client/hud/hud_ammo.cpp @@ -25,7 +25,7 @@ WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise WEAPON *gpLastSel; // Last weapon menu selection -client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iCount ); +client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iRes, int iCount ); WeaponsResource gWR; int g_weaponselect = 0; @@ -60,10 +60,17 @@ int WeaponsResource :: HasAmmo( WEAPON *p ) void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) { - if( !pWeapon ) return; + int i, iRes; - int i; - char sz[256]; + if (ActualWidth < 640) + iRes = 320; + else + iRes = 640; + + char sz[128]; + + if ( !pWeapon ) + return; memset( &pWeapon->rcActive, 0, sizeof( wrect_t )); memset( &pWeapon->rcInactive, 0, sizeof( wrect_t )); @@ -74,33 +81,36 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->hAmmo = 0; pWeapon->hAmmo2 = 0; - sprintf( sz, "scripts/items/%s.txt", pWeapon->szName ); + sprintf( sz, "sprites/%s.txt", pWeapon->szName ); client_sprite_t *pList = SPR_GetList( sz, &i ); if( !pList ) return; client_sprite_t *p; - p = GetSpriteList( pList, "crosshair", i ); + p = GetSpriteList( pList, "crosshair", iRes, i ); if( p ) { - pWeapon->hCrosshair = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hCrosshair = SPR_Load(sz); pWeapon->rcCrosshair = p->rc; } else pWeapon->hCrosshair = 0; - p = GetSpriteList( pList, "autoaim", i ); + p = GetSpriteList( pList, "autoaim", iRes, i ); if( p ) { - pWeapon->hAutoaim = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAutoaim = SPR_Load(sz); pWeapon->rcAutoaim = p->rc; } else pWeapon->hAutoaim = 0; - p = GetSpriteList( pList, "zoom", i ); + p = GetSpriteList( pList, "zoom", iRes, i ); if( p ) { - pWeapon->hZoomedCrosshair = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedCrosshair = SPR_Load(sz); pWeapon->rcZoomedCrosshair = p->rc; } else @@ -109,10 +119,11 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair; } - p = GetSpriteList( pList, "zoom_autoaim", i ); + p = GetSpriteList( pList, "zoom_autoaim", iRes, i ); if( p ) { - pWeapon->hZoomedAutoaim = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedAutoaim = SPR_Load(sz); pWeapon->rcZoomedAutoaim = p->rc; } else @@ -121,10 +132,11 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair; } - p = GetSpriteList( pList, "weapon", i ); + p = GetSpriteList( pList, "weapon", iRes, i ); if( p ) { - pWeapon->hInactive = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hInactive = SPR_Load(sz); pWeapon->rcInactive = p->rc; gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); } @@ -135,10 +147,11 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); } - p = GetSpriteList( pList, "weapon_s", i ); + p = GetSpriteList( pList, "weapon_s", iRes, i ); if( p ) { - pWeapon->hActive = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hActive = SPR_Load(sz); pWeapon->rcActive = p->rc; } else @@ -147,24 +160,28 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->rcActive = gHUD.GetSpriteRect( gHUD.m_HUD_error ); } - p = GetSpriteList( pList, "ammo", i ); + p = GetSpriteList( pList, "ammo", iRes, i ); if( p ) { - pWeapon->hAmmo = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo = SPR_Load(sz); pWeapon->rcAmmo = p->rc; gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); } else pWeapon->hAmmo = 0; - p = GetSpriteList( pList, "ammo2", i ); + p = GetSpriteList( pList, "ammo2", iRes, i ); if( p ) { - pWeapon->hAmmo2 = SPR_Load( p->szSprite ); + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo2 = SPR_Load(sz); pWeapon->rcAmmo2 = p->rc; gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); } else pWeapon->hAmmo2 = 0; + // in original Half-Life this was a leak + FREE( pList ); } // Returns the first weapon for a given slot. @@ -1264,7 +1281,7 @@ sprite name 'psz' in the given sprite list 'pList' iCount is the number of items in the pList ================================= */ -client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iCount ) +client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iRes, int iCount ) { if( !pList ) return NULL; @@ -1273,7 +1290,7 @@ client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iCo while( i-- ) { - if( !strcmp( psz, p->szName )) + if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) return p; p++; } diff --git a/client/hud/hud_ammo.h b/client/hud/hud_ammo.h index 29cd7d4d..98a43a2b 100644 --- a/client/hud/hud_ammo.h +++ b/client/hud/hud_ammo.h @@ -17,7 +17,7 @@ #define __AMMO_H__ #define MAX_WEAPON_NAME 128 -#define MAX_WEAPON_SLOTS 6 // hud item selection slots +#define MAX_WEAPON_SLOTS 5 // hud item selection slots #define WEAPON_FLAGS_SELECTONEMPTY 1 #define WEAPON_IS_ONTARGET 0x40 diff --git a/client/hud/hud_health.cpp b/client/hud/hud_health.cpp index 869c10eb..9f0743ff 100644 --- a/client/hud/hud_health.cpp +++ b/client/hud/hud_health.cpp @@ -25,7 +25,8 @@ DECLARE_MESSAGE( m_Health, Health ) DECLARE_MESSAGE( m_Health, Damage ) -#define PAIN_NAME "sprites/pain.spr" +#define PAIN_NAME "sprites/%d_pain.spr" +#define DAMAGE_NAME "sprites/%d_dmg.spr" int giDmgHeight, giDmgWidth; @@ -39,7 +40,10 @@ int giDmgFlags[NUM_DMG_TYPES] = DMG_NERVEGAS, DMG_RADIATION, DMG_SHOCK, - DMG_NUCLEAR + DMG_CALTROP, + DMG_TRANQ, + DMG_CONCUSS, + DMG_HALLUC }; int CHudHealth :: Init( void ) @@ -160,7 +164,7 @@ int CHudHealth :: Draw( float flTime ) return 1; if( !m_hSprite ) - m_hSprite = SPR_Load( PAIN_NAME ); + m_hSprite = LoadSprite( PAIN_NAME ); // has health changed? Flash the health # if( m_fFade ) diff --git a/client/hud/hud_health.h b/client/hud/hud_health.h index cd90829a..dcdc8d13 100644 --- a/client/hud/hud_health.h +++ b/client/hud/hud_health.h @@ -64,8 +64,27 @@ #define DMG_SLOWBURN (1 << 21) // in an oven #define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer #define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) -#define DMG_NUCLEAR (1 << 24) // Players hit by this begin to burn +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + +// TF Healing Additions for TakeHealth +#define DMG_IGNORE_MAXHEALTH DMG_IGNITE +// TF Redefines since we never use the originals +#define DMG_NAIL DMG_SLASH +#define DMG_NOT_SELF DMG_FREEZE + + +#define DMG_TRANQ DMG_MORTAR +#define DMG_CONCUSS DMG_SONIC typedef struct { diff --git a/client/hud/hud_message.cpp b/client/hud/hud_message.cpp index 31fcd3af..f478e6b2 100644 --- a/client/hud/hud_message.cpp +++ b/client/hud/hud_message.cpp @@ -43,7 +43,8 @@ int CHudMessage :: Init( void ) int CHudMessage :: VidInit( void ) { - HUD_Logo = gHUD.GetSpriteIndex( "logo" ); + m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" ); + m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); return 1; } @@ -305,31 +306,34 @@ int CHudMessage :: Draw( float fTime ) drawn = 0; - if( m_gameTitleTime > 0 ) + if ( m_gameTitleTime > 0 ) { float localTime = gHUD.m_flTime - m_gameTitleTime; float brightness; // Maybe timer isn't set yet - if( m_gameTitleTime > gHUD.m_flTime ) + if ( m_gameTitleTime > gHUD.m_flTime ) m_gameTitleTime = gHUD.m_flTime; - if( localTime > ( m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout )) - { + if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) ) m_gameTitleTime = 0; - } else { brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime ); - int fullWidth = gHUD.GetSpriteRect(HUD_Logo).right - gHUD.GetSpriteRect(HUD_Logo).left; - int fullHeight = gHUD.GetSpriteRect(HUD_Logo).bottom - gHUD.GetSpriteRect(HUD_Logo).top; + int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left; + int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left; + int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top; int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth ); - int y = YPosition( m_pGameTitle->y, fullHeight); + int y = YPosition( m_pGameTitle->y, fullHeight ); - SPR_Set( gHUD.GetSprite( HUD_Logo ), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( HUD_Logo )); + + SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) ); + + SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) ); drawn = 1; } diff --git a/client/hud/hud_msg.cpp b/client/hud/hud_msg.cpp index 909c824d..23d8876b 100644 --- a/client/hud/hud_msg.cpp +++ b/client/hud/hud_msg.cpp @@ -24,10 +24,10 @@ extern ref_params_t *gpViewParams; // CHud message handlers +DECLARE_HUDMESSAGE( Logo ); DECLARE_HUDMESSAGE( HUDColor ); DECLARE_HUDMESSAGE( SetFog ); DECLARE_HUDMESSAGE( RoomType ); -DECLARE_HUDMESSAGE( SetSky ); DECLARE_HUDMESSAGE( RainData ); DECLARE_HUDMESSAGE( SetBody ); DECLARE_HUDMESSAGE( SetSkin ); @@ -40,9 +40,6 @@ DECLARE_HUDMESSAGE( Particle ); DECLARE_HUDMESSAGE( Concuss ); DECLARE_HUDMESSAGE( GameMode ); DECLARE_HUDMESSAGE( CamData ); -DECLARE_HUDMESSAGE( AddMirror ); -DECLARE_HUDMESSAGE( AddScreen ); -DECLARE_HUDMESSAGE( AddPortal ); DECLARE_HUDMESSAGE( TempEntity ); DECLARE_HUDMESSAGE( ServerName ); DECLARE_HUDMESSAGE( ScreenShake ); @@ -51,6 +48,7 @@ DECLARE_HUDCOMMAND( ChangeLevel ); int CHud :: InitMessages( void ) { + HOOK_MESSAGE( Logo ); HOOK_MESSAGE( ResetHUD ); HOOK_MESSAGE( GameMode ); HOOK_MESSAGE( ServerName ); @@ -63,15 +61,11 @@ int CHud :: InitMessages( void ) HOOK_MESSAGE( Particle ); HOOK_MESSAGE( TempEntity ); HOOK_MESSAGE( SetFog ); - HOOK_MESSAGE( SetSky ); HOOK_MESSAGE( CamData ); HOOK_MESSAGE( RainData ); HOOK_MESSAGE( WeaponAnim ); HOOK_MESSAGE( SetBody ); HOOK_MESSAGE( SetSkin ); - HOOK_MESSAGE( AddMirror); - HOOK_MESSAGE( AddScreen ); - HOOK_MESSAGE( AddPortal ); HOOK_MESSAGE( ScreenFade ); HOOK_MESSAGE( ScreenShake ); @@ -116,6 +110,18 @@ void CHud :: UserCmd_ChangeLevel( void ) m_Shake.duration = 0; } +int CHud :: MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pszName, iSize, pbuf ); + + // update Train data + m_iLogo = READ_BYTE(); + + END_READ(); + + return 1; +} + int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) { // clear all hud data @@ -172,7 +178,6 @@ int CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) { m_flStartDist = 0; m_flEndDist = 0; - m_iSkyMode = SKY_OFF; m_iIntermission = 0; // prepare all hud data @@ -223,20 +228,6 @@ int CHud :: MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf ) return 1; } -int CHud :: MsgFunc_SetSky( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - m_iSkyMode = READ_BYTE(); - m_vecSkyPos[0] = READ_COORD(); - m_vecSkyPos[1] = READ_COORD(); - m_vecSkyPos[2] = READ_COORD(); - - END_READ(); - - return 1; -} - int CHud :: MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pszName, iSize, pbuf ); @@ -365,39 +356,6 @@ int CHud :: MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf ) return 1; } -int CHud :: MsgFunc_AddScreen( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - // AddScreenBrushEntity( READ_BYTE() ); - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_AddMirror( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - // AddMirrorBrushEntity( READ_BYTE() ); - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_AddPortal( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - // AddPortalBrushEntity( READ_BYTE() ); - - END_READ(); - - return 1; -} - int CHud :: MsgFunc_Particle( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pszName, iSize, pbuf ); diff --git a/client/hud/hud_train.cpp b/client/hud/hud_train.cpp index a1bde7ae..9cc3c348 100644 --- a/client/hud/hud_train.cpp +++ b/client/hud/hud_train.cpp @@ -43,8 +43,8 @@ int CHudTrain::VidInit( void ) int CHudTrain::Draw(float fTime) { - if( !m_hSprite ) - m_hSprite = SPR_Load( "sprites/train.spr" ); + if ( !m_hSprite ) + m_hSprite = LoadSprite("sprites/%d_train.spr"); if( m_iPos ) { diff --git a/client/hud/hud_warhead.cpp b/client/hud/hud_warhead.cpp deleted file mode 100644 index 39399c4a..00000000 --- a/client/hud/hud_warhead.cpp +++ /dev/null @@ -1,157 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// warhead.cpp - hud for weapon_redeemer -// -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -#define GUIDE_S SPR_Width( m_hCrosshair, 0 ) -#define READOUT_S 192 -DECLARE_MESSAGE( m_Redeemer, WarHUD ) - -int CHudRedeemer::Init( void ) -{ - m_iHudMode = 0; - - HOOK_MESSAGE( WarHUD ); - m_iFlags |= HUD_ACTIVE; - gHUD.AddHudElem( this ); - - return 1; -} - -int CHudRedeemer :: VidInit( void ) -{ - m_hCrosshair = SPR_Load( "sprites/guidedx.spr" ); - m_hSprite = SPR_Load( "sprites/readout.spr" ); - m_hCamRec = SPR_Load( "sprites/cam_rec.spr" ); - m_hStatic = SPR_Load( "sprites/static.spr" ); - m_hCamera = SPR_Load( "sprites/camera.spr" ); - - m_iHudMode = m_iOldHudMode = 0; - return 1; -} - -int CHudRedeemer :: MsgFunc_WarHUD( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - m_iHudMode = READ_BYTE(); - m_iOldHudMode = -1; // force to update - ClearPermanentFades (); - END_READ(); - - return 1; -} - -int CHudRedeemer :: Draw( float flTime ) -{ - int x, y, w, h; - wrect_t rc; - int frame; - - // setup screen rectangle - rc.left = rc.top = 0; - rc.right = ScreenWidth; - rc.bottom = ScreenHeight; - - if( m_iHudMode == 1 ) // draw warhead screen (controllable rocket) - { - y = (ScreenWidth - GUIDE_S) / 2; - x = (ScreenHeight - GUIDE_S) / 2; - - SPR_Set( m_hCrosshair, 255, 128, 128 ); - SPR_DrawAdditive( 0, y, x, NULL); - - int yOffset = ScreenHeight; - yOffset -= ((int)(flTime * 650) % READOUT_S) - READOUT_S; - SPR_Set( m_hSprite, 255, 128, 128 ); - while( yOffset > -READOUT_S ) - { - SPR_DrawAdditive( 0, 0, yOffset, READOUT_S>>1, READOUT_S ); - yOffset -= READOUT_S; - } - - if( m_iOldHudMode != m_iHudMode ) - { - // enable red fade - SetScreenFade( Vector( 255, 0, 0 ), 64, 0, 0, FFADE_STAYOUT ); - } - } - else if( m_iHudMode == 2 ) // draw warhead screen with alpha noise (underwater) - { - // play at 15fps - frame = (int)(flTime * 15) % SPR_Frames( m_hStatic ); - - y = x = 0; - w = SPR_Width( m_hStatic, 0 ); - h = SPR_Height( m_hStatic, 0 ); - - for( y = -(RANDOM_LONG( 0, h )); y < ScreenHeight; y += h ) - { - for( x = -(RANDOM_LONG( 0, w )); x < ScreenWidth; x += w ) - { - SPR_Set( m_hStatic, 255, 255, 255, 100 ); - SPR_DrawAdditive( frame, x, y, NULL ); - } - } - - y = (ScreenWidth - GUIDE_S) / 2; - x = (ScreenHeight - GUIDE_S) / 2; - - SPR_Set( m_hCrosshair, 255, 128, 128 ); - SPR_DrawAdditive( 0, y, x, NULL ); - - int yOffset = ScreenHeight; - yOffset -= ((int)(flTime * 650) % READOUT_S) - READOUT_S; - SPR_Set( m_hSprite, 255, 128, 128 ); - while( yOffset > -READOUT_S ) - { - SPR_DrawAdditive( 0, 0, yOffset, READOUT_S>>1, READOUT_S ); - yOffset -= READOUT_S; - } - - if( m_iOldHudMode != m_iHudMode ) - { - // enable red fade - SetScreenFade( Vector( 255, 0, 0 ), 64, 0, 0, FFADE_STAYOUT ); - } - } - else if( m_iHudMode == 3 ) // draw static noise (self destroyed) - { - // play at 15fps - frame = (int)(flTime * 15) % SPR_Frames( m_hStatic ); - - SPR_Set( m_hStatic, 255, 255, 255 ); - SPR_Draw( frame, 0, 0, ScreenWidth, ScreenHeight ); - } - else if( m_iHudMode == 4 ) - { - // HACKHACK draw videocamera screen - // g-cont. i'm lazy same as BUzer, i won't to create new class :) - - // play at 1.5 fps - frame = (int)(flTime * 1.5f) % SPR_Frames( m_hCamRec ); - - // draw interlaces - SPR_Set( m_hCamera, 16, 96, 16, 64 ); // give this value from breaklight.bsp (xash03) - SPR_DrawAdditive( 0, 0, 0, ScreenWidth, ScreenHeight ); - - // draw recorder icon - SPR_Set( m_hCamRec, 255, 0, 0, 255 ); // give this value from breaklight.bsp (xash03) - - float scale = 2.5f; // REC[*] sprite scale - - // calculating pos for different resolutions - w = SPR_Width( m_hCamRec, 0 ) * scale; - h = SPR_Height( m_hCamRec, 0 ) * scale; - x = ScreenWidth - (w * 1.5f); - y = w * 0.4f; - SPR_DrawAdditive( frame, x, y, w, h ); - } - m_iOldHudMode = m_iHudMode; - - return 1; -} \ No newline at end of file diff --git a/client/hud/hud_zoom.cpp b/client/hud/hud_zoom.cpp deleted file mode 100644 index 9ed50bde..00000000 --- a/client/hud/hud_zoom.cpp +++ /dev/null @@ -1,75 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// warhead.cpp - hud for sniper rifle -//======================================================================= - -#include "extdll.h" -#include "triangle_api.h" -#include "utils.h" -#include "hud.h" - -void DrawQuad(float xmin, float ymin, float xmax, float ymax) -{ - //top left - g_engfuncs.pTriAPI->TexCoord2f(0,0); - g_engfuncs.pTriAPI->Vertex3f(xmin, ymin, 0); - //bottom left - g_engfuncs.pTriAPI->TexCoord2f(0,1); - g_engfuncs.pTriAPI->Vertex3f(xmin, ymax, 0); - //bottom right - g_engfuncs.pTriAPI->TexCoord2f(1,1); - g_engfuncs.pTriAPI->Vertex3f(xmax, ymax, 0); - //top right - g_engfuncs.pTriAPI->TexCoord2f(1,0); - g_engfuncs.pTriAPI->Vertex3f(xmax, ymin, 0); -} - -DECLARE_MESSAGE( m_Zoom, ZoomHUD ) - -int CHudZoom :: Init( void ) -{ - m_iHudMode = 0; - HOOK_MESSAGE( ZoomHUD ); - - m_iFlags |= HUD_ACTIVE; - - gHUD.AddHudElem( this ); - return 1; -} - -int CHudZoom::VidInit( void ) -{ - m_hLines = SPR_Load( "sprites/snlines.spr" ); - m_hCrosshair = SPR_Load( "sprites/snzoom.spr" ); - m_iHudMode = 0; - return 1; -} - -int CHudZoom :: MsgFunc_ZoomHUD( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - m_iHudMode = READ_BYTE(); - END_READ(); - - return 1; -} - -int CHudZoom :: Draw( float flTime ) -{ - if( !m_hLines || !m_hCrosshair ) return 0; - if( !m_iHudMode ) return 0; // draw scope - - float left = (float)(ScreenWidth - ScreenHeight) / 2; - float right = left + ScreenHeight; - - // draw crosshair - SPR_Set( m_hCrosshair, 255, 255, 255 ); - SPR_DrawTransColor( 0, left, 0, ScreenHeight, ScreenHeight ); - - // draw side-lines - SPR_Set( m_hLines, 255, 255, 255 ); - SPR_Draw( 0, 0, 0, left, ScreenHeight ); - SPR_Draw( 0, right, 0, left, ScreenHeight ); - - return 1; -} diff --git a/common/basetypes.h b/common/basetypes.h index 00371618..7c9d7931 100644 --- a/common/basetypes.h +++ b/common/basetypes.h @@ -29,7 +29,6 @@ typedef unsigned long CRC32_t; typedef float vec_t; #define DLLEXPORT __declspec( dllexport ) -#define NUMVERTEXNORMALS 162 // quake avertex normals #ifndef NULL #define NULL ((void *)0) diff --git a/common/clgame_api.h b/common/clgame_api.h index 27357936..a35260d5 100644 --- a/common/clgame_api.h +++ b/common/clgame_api.h @@ -15,7 +15,7 @@ typedef struct usercmd_s usercmd_t; typedef struct particle_s particle_t; typedef struct skyportal_s skyportal_t; typedef struct ref_params_s ref_params_t; -typedef struct dstudioevent_s dstudioevent_t; +typedef struct mstudioevent_s mstudioevent_t; typedef void (*ENTCALLBACK)( TEMPENTITY *ent ); typedef void (*HITCALLBACK)( TEMPENTITY *ent, TraceResult *ptr ); typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf ); // user message handle @@ -245,7 +245,7 @@ typedef struct void (*pfnDrawTriangles)( int fTrans ); void (*pfnCreateEntities)( void ); int (*pfnAddVisibleEntity)( edict_t *pEnt, int ed_type ); - void (*pfnStudioEvent)( const dstudioevent_t *event, edict_t *entity ); + void (*pfnStudioEvent)( const mstudioevent_t *event, edict_t *entity ); void (*pfnStudioFxTransform)( edict_t *pEdict, float transform[4][4] ); void (*pfnCalcRefdef)( ref_params_t *parms ); void (*pfnPM_Move)( playermove_t *ppmove, int server ); diff --git a/common/const.h b/common/const.h index f2e6ca82..cda42221 100644 --- a/common/const.h +++ b/common/const.h @@ -12,6 +12,9 @@ #define LM_STYLES 4 // MAXLIGHTMAPS +#define RAD2DEG( x ) ((float)(x) * (float)(180.f / M_PI)) +#define DEG2RAD( x ) ((float)(x) * (float)(M_PI / 180.f)) + // worldcraft predefined angles #define ANGLE_UP -1 #define ANGLE_DOWN -2 diff --git a/common/studio_ref.h b/common/studio.h similarity index 91% rename from common/studio_ref.h rename to common/studio.h index ab838533..ed3c11cb 100644 --- a/common/studio_ref.h +++ b/common/studio.h @@ -1,9 +1,9 @@ //======================================================================= // Copyright XashXT Group 2008 © -// studio_ref.h - studio model reference +// studio.h - studio model reference //======================================================================= -#ifndef STUDIO_REF_H -#define STUDIO_REF_H +#ifndef STUDIO_H +#define STUDIO_H /* ============================================================================== @@ -140,7 +140,7 @@ typedef struct int numtransitions; // animation node to animation node transition graph int transitionindex; -} dstudiohdr_t; +} studiohdr_t; // header for demand loaded sequence group data typedef struct @@ -150,7 +150,7 @@ typedef struct char name[64]; int length; -} dstudioseqhdr_t; +} mstudioseqhdr_t; // bones typedef struct @@ -161,7 +161,7 @@ typedef struct int bonecontroller[6]; // bone controller index, -1 == none float value[6]; // default DoF values float scale[6]; // scale for delta DoF values -} dstudiobone_t; +} mstudiobone_t; // bone controllers typedef struct @@ -172,7 +172,7 @@ typedef struct float end; int rest; // byte index value at rest int index; // 0-3 user set controller, 4 mouth -} dstudiobonecontroller_t; +} mstudiobonecontroller_t; // intersection boxes typedef struct @@ -181,7 +181,7 @@ typedef struct int group; // intersection group vec3_t bbmin; // bounding box vec3_t bbmax; -} dstudiobbox_t; +} mstudiobbox_t; // demand loaded sequence groups typedef struct @@ -190,7 +190,7 @@ typedef struct char name[64]; // file name void *cache; // cache index pointer (only in memory) int data; // hack for group 0 -} dstudioseqgroup_t; +} mstudioseqgroup_t; // sequence descriptions typedef struct @@ -236,7 +236,7 @@ typedef struct int nodeflags; // transition rules int nextseq; // auto advancing sequences -} dstudioseqdesc_t; +} mstudioseqdesc_t; // events #include "studio_event.h" @@ -247,7 +247,7 @@ typedef struct vec3_t org; // pivot point int start; int end; -} dstudiopivot_t; +} mstudiopivot_t; // attachment typedef struct @@ -257,12 +257,12 @@ typedef struct int bone; vec3_t org; // attachment point vec3_t vectors[3]; -} dstudioattachment_t; +} mstudioattachment_t; typedef struct { unsigned short offset[6]; -} dstudioanim_t; +} mstudioanim_t; // animation frames typedef union @@ -273,7 +273,7 @@ typedef union byte total; } num; short value; -} dstudioanimvalue_t; +} mstudioanimvalue_t; // body part index @@ -283,7 +283,7 @@ typedef struct int nummodels; int base; int modelindex; // index into models array -} dstudiobodyparts_t; +} mstudiobodyparts_t; // skin info typedef struct @@ -298,7 +298,7 @@ typedef struct int index; // disk: offset at start of buffer shader_t shader; // ref: shader number }; -} dstudiotexture_t; +} mstudiotexture_t; // skin families // short index[skinfamilies][skinref] // skingroup info @@ -323,7 +323,7 @@ typedef struct int numgroups; // deformation groups int groupindex; -} dstudiomodel_t; +} mstudiomodel_t; // meshes typedef struct @@ -333,11 +333,11 @@ typedef struct int skinref; int numnorms; // per mesh normals int normindex; // normal vec3_t -} dstudiomesh_t; +} mstudiomesh_t; typedef struct { void *data; } cache_user_t; -#endif//STUDIO_REF_H \ No newline at end of file +#endif//STUDIO_H \ No newline at end of file diff --git a/common/studio_event.h b/common/studio_event.h index 8a5acef8..91742adf 100644 --- a/common/studio_event.h +++ b/common/studio_event.h @@ -5,12 +5,12 @@ #ifndef STUDIO_EVENT_H #define STUDIO_EVENT_H -typedef struct dstudioevent_s +typedef struct mstudioevent_s { int frame; int event; int type; char options[64]; -} dstudioevent_t; +} mstudioevent_t; #endif//STUDIO_EVENT_H \ No newline at end of file diff --git a/debug.bat b/debug.bat index 3f32c59e..978381f4 100644 --- a/debug.bat +++ b/debug.bat @@ -29,15 +29,9 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% vid_gl/vid_gl.dsp %CONFIG%"vid_gl - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% server/server.dsp %CONFIG%"server - Win32 Debug" %build_target% -if errorlevel 1 set BUILD_ERROR=1 - %MSDEV% spirit/spirit.dsp %CONFIG%"spirit - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% snd_al/snd_al.dsp %CONFIG%"snd_al - Win32 Debug" %build_target% -if errorlevel 1 set BUILD_ERROR=1 - %MSDEV% snd_dx/snd_dx.dsp %CONFIG%"snd_dx - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 @@ -69,11 +63,9 @@ if exist client\client.plg del /f /q client\client.plg if exist engine\engine.plg del /f /q engine\engine.plg if exist launch\launch.plg del /f /q launch\launch.plg if exist physic\physic.plg del /f /q physic\physic.plg -if exist server\server.plg del /f /q server\server.plg if exist spirit\spirit.plg del /f /q spirit\spirit.plg if exist vid_gl\vid_gl.plg del /f /q vid_gl\vid_gl.plg if exist viewer\viewer.plg del /f /q viewer\viewer.plg -if exist snd_al\snd_al.plg del /f /q snd_al\snd_al.plg if exist snd_dx\snd_dx.plg del /f /q snd_dx\snd_dx.plg if exist xtools\xtools.plg del /f /q xtools\xtools.plg diff --git a/engine/client/cl_effects.c b/engine/client/cl_effects.c index b5829e65..528741d6 100644 --- a/engine/client/cl_effects.c +++ b/engine/client/cl_effects.c @@ -317,6 +317,8 @@ struct particle_s rgba_t pColor[4]; }; +#define NUMVERTEXNORMALS 162 // quake avertex normals + float cl_avertexnormals[NUMVERTEXNORMALS][3] = { #include "anorms.h" diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 71446692..8cc33174 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -110,7 +110,7 @@ StudioEvent Event callback for studio models ==================== */ -void CL_StudioEvent( dstudioevent_t *event, edict_t *pEdict ) +void CL_StudioEvent( mstudioevent_t *event, edict_t *pEdict ) { clgame.dllFuncs.pfnStudioEvent( event, pEdict ); } @@ -545,6 +545,61 @@ void CL_DrawCrosshair( void ) SPR_DrawGeneric( 0, x - 0.5f * width, y - 0.5f * height, -1, -1, &clgame.ds.rcCrosshair ); } +/* +============= +CL_DrawLoading + +draw loading progress bar +============= +*/ +void CL_DrawLoading( float percent ) +{ + int x, y, width, height, right; + float xscale, yscale, step, s2; + rgba_t color; + + re->GetParms( &width, &height, NULL, 0, cls.loadingBar ); + x = ( SCREEN_WIDTH - width )>>1; + y = ( SCREEN_HEIGHT - height )>>1; + + xscale = scr_width->integer / 640.0f; + yscale = scr_height->integer / 480.0f; + + x *= xscale; + y *= yscale; + width *= xscale; + height *= yscale; + + MakeRGBA( color, 128, 128, 128, 255 ); + re->SetColor( color ); + re->DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); + + step = (float)width / 100.0f; + right = (int)ceil( percent * step ); + s2 = (float)right / width; + width = right; + + MakeRGBA( color, 208, 152, 0, 255 ); + re->SetColor( color ); + re->DrawStretchPic( x, y, width, height, 0, 0, s2, 1, cls.loadingBar ); + re->SetColor( NULL ); +} + +/* +============= +CL_DrawPause + +draw pause sign +============= +*/ +void CL_DrawPause( void ) +{ + int w, h; + + re->GetParms( &w, &h, NULL, 0, cls.pauseIcon ); + SCR_DrawPic((SCREEN_WIDTH - w)>>1, ( SCREEN_HEIGHT - h )>>1, w, h, cls.pauseIcon ); +} + void CL_DrawHUD( int state ) { if( state == CL_ACTIVE && !cl.video_prepped ) @@ -555,10 +610,21 @@ void CL_DrawHUD( int state ) clgame.dllFuncs.pfnRedraw( cl.time, state ); - if( state == CL_ACTIVE || state == CL_PAUSED ) + switch( state ) { + case CL_PAUSED: + CL_DrawPause(); + // intentionally fallthrough + case CL_ACTIVE: CL_DrawCrosshair (); CL_DrawCenterPrint (); + break; + case CL_LOADING: + CL_DrawLoading( scr_loading->value ); + break; + case CL_CHANGELEVEL: + CL_DrawLoading( 100.0f ); + break; } } @@ -809,11 +875,10 @@ static HSPRITE pfnSPR_Load( const char *szPicName ) if( !re ) return 0; // render not initialized if( !szPicName || !*szPicName ) { - MsgDev( D_ERROR, "CL_SpriteLoad: invalid spritename\n" ); - return -1; + MsgDev( D_ERROR, "CL_LoadSprite: bad name!\n" ); + return 0; } - - return re->RegisterShader( szPicName, SHADER_NOMIP ); // replace with SHADER_GENERIC ? + return re->RegisterShader( szPicName, SHADER_SPRITE ); } /* @@ -983,24 +1048,27 @@ for parsing half-life scripts - hud.txt etc static client_sprite_t *pfnSPR_GetList( char *psz, int *piCount ) { client_sprite_t *pList; + int numSprites = 0; int index, iTemp; - int numSprites; script_t *script; token_t token; if( piCount ) *piCount = 0; + if( !clgame.itemspath[0] ) + FS_ExtractFilePath( psz, clgame.itemspath ); + script = Com_OpenScript( psz, NULL, 0 ); if( !script ) return NULL; - Com_ReadUlong( script, false, &numSprites ); + Com_ReadUlong( script, SC_ALLOW_NEWLINES, &numSprites ); // name, res, pic, x, y, w, h pList = Mem_Alloc( clgame.mempool, sizeof( *pList ) * numSprites ); for( index = 0; index < numSprites; index++ ) { - if( !Com_ReadToken( script, SC_ALLOW_NEWLINES, &token )) + if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token )) break; com.strncpy( pList[index].szName, token.string, sizeof( pList[index].szName )); @@ -1010,7 +1078,7 @@ static client_sprite_t *pfnSPR_GetList( char *psz, int *piCount ) pList[index].iRes = iTemp; // read spritename - Com_ReadToken( script, false, &token ); + Com_ReadToken( script, SC_PARSE_GENERIC, &token ); com.strncpy( pList[index].szSprite, token.string, sizeof( pList[index].szSprite )); // parse rectangle @@ -1066,8 +1134,6 @@ get actual screen info */ static int pfnGetScreenInfo( SCREENINFO *pscrinfo ) { - int i; - // setup screen info clgame.scrInfo.iRealWidth = scr_width->integer; clgame.scrInfo.iRealHeight = scr_height->integer; @@ -1087,12 +1153,6 @@ static int pfnGetScreenInfo( SCREENINFO *pscrinfo ) clgame.scrInfo.iFlags &= ~SCRINFO_VIRTUALSPACE; } - // TODO: build real table of fonts widthInChars - // TODO: load half-life credits font from wad - for( i = 0; i < 256; i++ ) - clgame.scrInfo.charWidths[i] = SMALLCHAR_WIDTH; - clgame.scrInfo.iCharHeight = SMALLCHAR_HEIGHT; - if( !pscrinfo ) return 0; *pscrinfo = clgame.scrInfo; // copy screeninfo out @@ -1278,35 +1338,45 @@ returns drawed chachter width (in real screen pixels) */ static int pfnDrawCharacter( int x, int y, int number, int r, int g, int b ) { - float size, frow, fcol; - float ax, ay, aw, ah; - int fontWidth, fontHeight; - rgba_t color; - number &= 255; if( !re ) return 0; - if( number <= ' ' ) return 0; + if( number < 32 ) return 0; if( y < -clgame.scrInfo.iCharHeight ) return 0; - ax = x; - ay = y; - aw = clgame.scrInfo.charWidths[number]; - ah = clgame.scrInfo.iCharHeight; - SPR_AdjustSize( &ax, &ay, &aw, &ah ); - re->GetParms( &fontWidth, &fontHeight, NULL, 0, clgame.ds.hHudFont ); + if( clgame.use_qfont ) + { + pfnSPR_Set( clgame.hHudFont, r, g, b, 255 ); + pfnSPR_DrawAdditive( 0, x, y, -1, -1, &clgame.fontRc[number] ); + } + else + { + float size, frow, fcol; + float ax, ay, aw, ah; + int fontWidth, fontHeight; + rgba_t color; - MakeRGBA( color, r, g, b, 255 ); - re->SetColor( color ); + ax = x; + ay = y; + aw = clgame.scrInfo.charWidths[number]; + ah = clgame.scrInfo.iCharHeight; + + re->GetParms( &fontWidth, &fontHeight, NULL, 0, clgame.hHudFont ); + SPR_AdjustSize( &ax, &ay, &aw, &ah ); + + MakeRGBA( color, r, g, b, 255 ); + re->SetColor( color ); - frow = (number >> 4)*0.0625f + (0.5f / (float)fontWidth); - fcol = (number & 15)*0.0625f + (0.5f / (float)fontHeight); - size = 0.0625f - (1.0f / (float)fontWidth); + frow = (number >> 4) * 0.0625f + (0.5f / (float)fontWidth); + fcol = (number & 15) * 0.0625f + (0.5f / (float)fontHeight); + size = 0.0625f - (1.0f / (float)fontWidth); + + re->SetParms( clgame.hHudFont, kRenderTransAdd, 0 ); + re->DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + size, frow + size, clgame.hHudFont ); + } - re->DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + size, frow + size, clgame.ds.hHudFont ); re->SetColor( NULL ); // don't forget reset color - return clgame.scrInfo.charWidths[number]; } diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index e5e0db4b..bf73aea3 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -5,6 +5,7 @@ #include "common.h" #include "client.h" +#include "byteorder.h" cvar_t *scr_viewsize; cvar_t *scr_centertime; @@ -77,7 +78,9 @@ void SCR_DrawPic( float x, float y, float width, float height, string_t shader ) re->GetParms( &w, &h, NULL, 0, shader ); width = w, height = h; } + SCR_AdjustSize( &x, &y, &width, &height ); + re->SetParms( shader, kRenderNormal, 0 ); re->DrawStretchPic( x, y, width, height, 0, 0, 1, 1, shader ); } @@ -108,6 +111,7 @@ void SCR_DrawChar( int x, int y, float w, float h, int ch ) fcol = (ch & 15)*0.0625f + (0.5f / 256.0f); size = 0.0625f - (1.0f / 256.0f); + re->SetParms( cls.clientFont, kRenderNormal, 0 ); re->DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + size, frow + size, cls.clientFont ); } @@ -133,6 +137,7 @@ void SCR_DrawSmallChar( int x, int y, int ch ) fcol = (ch & 15)*0.0625f + (0.5f / 256.0f); size = 0.0625f - (1.0f / 256.0f); + re->SetParms( cls.consoleFont, kRenderNormal, 0 ); re->DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, fcol, frow, fcol + size, frow + size, cls.consoleFont ); } @@ -435,6 +440,66 @@ void SCR_UpdateScreen( void ) clgame.dllFuncs.pfnFrame( cl.time ); } +void SCR_LoadCreditsFont( void ) +{ + int fontWidth, fontHeight; + + if( !re ) return; + + re->GetParms( &fontWidth, &fontHeight, NULL, 0, clgame.hHudFont ); + + // setup creditsfont + if( fontWidth != fontHeight ) + { + byte *buffer; + size_t length; + qfont_t *src; + + // half-life font with variable chars witdh + buffer = FS_LoadFile( "gfx/creditsfont.fnt", &length ); + + if( buffer && length >= sizeof( qfont_t )) + { + int i; + + src = (qfont_t *)buffer; + clgame.scrInfo.iCharHeight = LittleLong( src->rowheight ); + clgame.use_qfont = true; + + // build rectangles + for( i = 0; i < 256; i++ ) + { + clgame.fontRc[i].left = LittleShort( src->fontinfo[i].startoffset ) % fontWidth; + clgame.fontRc[i].right = clgame.fontRc[i].left + LittleShort( src->fontinfo[i].charwidth ); + clgame.fontRc[i].top = LittleShort( src->fontinfo[i].startoffset ) / fontWidth; + clgame.fontRc[i].bottom = clgame.fontRc[i].top + LittleLong( src->rowheight ); + clgame.scrInfo.charWidths[i] = LittleLong( src->fontinfo[i].charwidth ); + } + } + if( buffer ) Mem_Free( buffer ); + } + else + { + // quake font + int i, w; + + // all quake fonts like quad 16x16 fields + clgame.scrInfo.iCharHeight = fontHeight / 16; + clgame.use_qfont = false; + w = fontWidth / 16; + + for( i = 0; i < 256; i++ ) + { + // ugly hack to adjust fat and thin letters + if( i == 'm' || i == 'M' || i == 'w' || i == 'W' ) + clgame.scrInfo.charWidths[i] = w; + else if( i == '!' || i == '.' || i == 'i' || i == 'I' || i == 'l' || i == '|' || i == ',' ) + clgame.scrInfo.charWidths[i] = w * 0.5f; + else clgame.scrInfo.charWidths[i] = w * 0.75f; + } + } +} + void SCR_RegisterShaders( void ) { if( re ) @@ -443,16 +508,17 @@ void SCR_RegisterShaders( void ) cls.consoleFont = re->RegisterShader( va( "gfx/fonts/%s", con_font->string ), SHADER_FONT ); cls.clientFont = re->RegisterShader( va( "gfx/fonts/%s", cl_font->string ), SHADER_FONT ); cls.netIcon = re->RegisterShader( "#net.png", SHADER_NOMIP ); // FIXME: INTRESOURCE + cls.pauseIcon = re->RegisterShader( "gfx/paused", SHADER_NOMIP ); // FIXME: INTRESOURCE cls.fillShader = re->RegisterShader( "*white", SHADER_FONT ); // used for FillRGBA cls.particle = re->RegisterShader( "*particle", SHADER_FONT ); // Q1 particlefont - + cls.loadingBar = re->RegisterShader( "gfx/lambda", SHADER_NOMIP ); // FIXME: INTRESOURCE + clgame.hHudFont = re->RegisterShader( "gfx/creditsfont", SHADER_NOMIP ); + if( host.developer ) - cls.consoleBack = re->RegisterShader( "gfx/conback", SHADER_NOMIP ); - else cls.consoleBack = re->RegisterShader( "gfx/loading", SHADER_NOMIP ); + cls.consoleBack = re->RegisterShader( "cached/conback", SHADER_NOMIP ); + else cls.consoleBack = re->RegisterShader( "cached/loading", SHADER_NOMIP ); - // TODO: load a font with a variable charwidths Mem_Set( &clgame.ds, 0, sizeof( clgame.ds )); // reset a draw state - clgame.ds.hHudFont = re->RegisterShader( "gfx/creditsfont", SHADER_NOMIP ); } // vid_state has changed @@ -494,7 +560,10 @@ void SCR_Init( void ) Cmd_AddCommand( "viewpos", SCR_Viewpos_f, "prints current player origin" ); SCR_RegisterShaders(); + SCR_LoadCreditsFont(); + UI_Init(); + if( host.developer && FS_CheckParm( "-toconsole" )) Cbuf_AddText( "toggleconsole\n" ); else UI_SetActiveMenu( UI_MAINMENU ); diff --git a/engine/client/client.h b/engine/client/client.h index 18723e53..009b7d7a 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -216,8 +216,6 @@ typedef struct char centerPrint[2048]; int centerPrintLines; - HSPRITE hHudFont; - // crosshair members HSPRITE hCrosshair; wrect_t rcCrosshair; @@ -231,6 +229,7 @@ typedef struct byte *mempool; // client edicts pool byte *private; // client.dll private pool string maptitle; // display map title + string itemspath; // path to items description for auto-complete func union { @@ -252,6 +251,10 @@ typedef struct draw_stuff_t ds; // draw2d stuff (hud, weaponmenu etc) SCREENINFO scrInfo; // actual screen info + HSPRITE hHudFont; // handle to creditsfont + wrect_t fontRc[256]; // rectangles + bool use_qfont; // use half-life creditsfont with variable charWidth + client_textmessage_t *titles; // title messages, not network messages int numTitles; @@ -280,14 +283,17 @@ typedef struct netchan_t netchan; int serverProtocol; // in case we are doing some kind of version hack - int challenge; // from the server to use for connecting + + // internal shaders shader_t consoleFont; // current console font shader_t clientFont; // current client font shader_t consoleBack; // console background shader_t fillShader; // used for emulate FillRGBA to avoid wrong draw-sort shader_t particle; // used for drawing quake1 particles (SV_ParticleEffect) shader_t netIcon; // netIcon displayed bad network connection + shader_t pauseIcon; // draw 'paused' when game in-pause + shader_t loadingBar; // 'loading' progress bar file_t *download; // file transfer from server string downloadname; diff --git a/engine/common.h b/engine/common.h index 2b26f143..68af6e49 100644 --- a/engine/common.h +++ b/engine/common.h @@ -225,7 +225,7 @@ void CL_StudioFxTransform( edict_t *ent, float transform[4][4] ); void CL_GetEntitySpatialization( int entnum, vec3_t origin, vec3_t velocity ); bool CL_GetAttachment( int entityIndex, int number, vec3_t origin, vec3_t angles ); bool CL_SetAttachment( int entityIndex, int number, vec3_t origin, vec3_t angles ); -void CL_StudioEvent( dstudioevent_t *event, edict_t *ent ); +void CL_StudioEvent( mstudioevent_t *event, edict_t *ent ); bool CL_GetComment( const char *demoname, char *comment ); trace_t CL_TraceLine( const vec3_t start, const vec3_t end ); lerpframe_t *CL_GetLerpFrame( int entityIndex ); diff --git a/engine/common/con_utils.c b/engine/common/con_utils.c index 512bf5da..e3d29e06 100644 --- a/engine/common/con_utils.c +++ b/engine/common/con_utils.c @@ -468,7 +468,8 @@ bool Cmd_GetItemsList( const char *s, char *completedname, int length ) string matchbuf; int i, numitems; - t = FS_Search( va( "scripts/items/%s*.txt", s ), true ); + if( !clgame.itemspath[0] ) return false; // not in game yet + t = FS_Search( va( "%s/%s*.txt", clgame.itemspath, s ), true ); if( !t ) return false; FS_FileBase( t->filenames[0], matchbuf ); diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 3fb7eb57..4a57ed10 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -2328,14 +2328,19 @@ int pfnRegUserMsg( const char *pszName, int iSize ) return svc_bad; } - if( sv.state == ss_active ) - Host_Error( "REG_USER_MSG can only be done in spawn functions\n" ); - // register new message com.strncpy( svgame.msg[i].name, pszName, sizeof( svgame.msg[i].name )); svgame.msg[i].size = iSize; svgame.msg[i].number = i; // paranoid mode :-) + if( sv.state == ss_active ) + { + MSG_WriteByte( &sv.multicast, svc_usermessage ); + MSG_WriteString( &sv.multicast, pszName ); + MSG_WriteByte( &sv.multicast, i ); + MSG_WriteByte( &sv.multicast, (byte)iSize ); + MSG_Send( MSG_ALL, vec3_origin, NULL ); + } return i; } diff --git a/engine/uimenu/ui_local.h b/engine/uimenu/ui_local.h index e410f87b..afc507ff 100644 --- a/engine/uimenu/ui_local.h +++ b/engine/uimenu/ui_local.h @@ -50,11 +50,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define UI_CHECKBOX_PRESSED "gfx/shell/cb_down" #define UI_CHECKBOX_ENABLED "gfx/shell/cb_checked" +#define UI_CURSOR_SIZE 40 + #define UI_MAX_MENUDEPTH 8 #define UI_MAX_MENUITEMS 64 -#define UI_CURSOR_SIZE 40 - #define UI_PULSE_DIVISOR 75 #define UI_BLINK_TIME 250 #define UI_BLINK_MASK 499 diff --git a/launch/imagelib/imagelib.h b/launch/imagelib/imagelib.h index c4a4dfbd..626ede29 100644 --- a/launch/imagelib/imagelib.h +++ b/launch/imagelib/imagelib.h @@ -161,33 +161,6 @@ typedef struct flat_s short desc[2]; // probably not used } flat_t; -#define QCHAR_WIDTH 16 -#define QFONT_WIDTH 16 // valve fonts used contant sizes -#define QFONT_HEIGHT ((128 - 32) / 16) - -/* -======================================================================== - -.QFONT image format - -======================================================================== -*/ - -typedef struct -{ - short startoffset; - short charwidth; -} charset_t; - -typedef struct -{ - int width; - int height; - int rowcount; - int rowheight; - charset_t fontinfo[256]; - byte data[4]; // variable sized -} qfont_t; /* ======================================================================== diff --git a/launch/imagelib/img_wad.c b/launch/imagelib/img_wad.c index fba836c8..9254af2a 100644 --- a/launch/imagelib/img_wad.c +++ b/launch/imagelib/img_wad.c @@ -68,11 +68,11 @@ bool Image_LoadFNT( const char *name, const byte *buffer, size_t filesize ) return false; Mem_Copy( &font, buffer, sizeof( font )); - // swap lumps - font.width = LittleShort( font.width ); - font.height = LittleShort( font.height ); - font.rowcount = LittleShort( font.rowcount ); - font.rowheight = LittleShort( font.rowheight ); + // swap header + font.width = LittleLong( font.width ); + font.height = LittleLong( font.height ); + font.rowcount = LittleLong( font.rowcount ); + font.rowheight = LittleLong( font.rowheight ); for( i = 0; i < 256; i++ ) { @@ -81,7 +81,7 @@ bool Image_LoadFNT( const char *name, const byte *buffer, size_t filesize ) } // last sixty four bytes - what the hell ???? - size = sizeof(qfont_t) - 4 + (128 * font.width * QCHAR_WIDTH) + sizeof( short ) + 768 + 64; + size = sizeof( qfont_t ) - 4 + ( 128 * font.width * QCHAR_WIDTH ) + sizeof( short ) + 768 + 64; if( size != filesize ) { @@ -96,14 +96,10 @@ bool Image_LoadFNT( const char *name, const byte *buffer, size_t filesize ) image.height = font.height; } - image.depth = 1; - image.type = PF_INDEXED_32; // 32-bit palette - if(!Image_LumpValidSize( name )) return false; fin = buffer + sizeof( font ) - 4; - image.size = image.width * image.height; - pal = fin + image.size; + pal = fin + (image.width * image.height); numcolors = BuffLittleShort( pal ), pal += sizeof( short ); image.flags |= IMAGE_HAS_ALPHA; // fonts always have transparency @@ -124,6 +120,9 @@ bool Image_LoadFNT( const char *name, const byte *buffer, size_t filesize ) return false; } + image.depth = 1; + image.type = PF_INDEXED_32; // 32-bit palette + return FS_AddMipmapToPack( fin, image.width, image.height ); } @@ -136,10 +135,10 @@ bool Image_LoadMDL( const char *name, const byte *buffer, size_t filesize ) { byte *fin; size_t pixels; - dstudiotexture_t *pin; + mstudiotexture_t *pin; int i, flags; - pin = (dstudiotexture_t *)buffer; + pin = (mstudiotexture_t *)buffer; flags = LittleLong( pin->flags ); // Valve never used endian functions for studiomodels... diff --git a/launch/memlib.c b/launch/memlib.c index 4ecc7eae..a74e1daf 100644 --- a/launch/memlib.c +++ b/launch/memlib.c @@ -1411,7 +1411,9 @@ void _mem_printlist( size_t minallocationsize ) for( pool = poolchain; pool; pool = pool->next ) { // poolnames can contain color symbols, make sure what color is reset - Msg( "%5luk (%5luk actual) %s (^7%+3li byte change)\n", (dword) ((pool->totalsize + 1023) / 1024), (dword)((pool->realsize + 1023) / 1024), pool->name, (long)pool->totalsize - pool->lastchecksize ); + if( ((long)pool->totalsize - pool->lastchecksize ) != 0 ) + Msg( "%5luk (%5luk actual) %s (^7%+3li byte change)\n", (dword)((pool->totalsize + 1023) / 1024), (dword)((pool->realsize + 1023) / 1024), pool->name, (long)pool->totalsize - pool->lastchecksize ); + else Msg( "%5luk (%5luk actual) %s\n", (dword)((pool->totalsize + 1023) / 1024), (dword)((pool->realsize + 1023) / 1024), pool->name ); pool->lastchecksize = pool->totalsize; for( mem = pool->chain; mem; mem = mem->next ) if( mem->size >= minallocationsize ) diff --git a/launch/soundlib/snd_ogg.c b/launch/soundlib/snd_ogg.c index 8e34ca12..2d0de18c 100644 --- a/launch/soundlib/snd_ogg.c +++ b/launch/soundlib/snd_ogg.c @@ -308,7 +308,6 @@ bool Sound_LoadOGG( const char *name, const byte *buffer, size_t filesize ) ov_decode_t ov_decode; ov_callbacks_t ov_callbacks = { ovcm_read, ovcm_seek, ovc_close, ovcm_tell }; long done = 0, ret; - const char *comm; int dummy; // load the file @@ -361,14 +360,41 @@ bool Sound_LoadOGG( const char *name, const byte *buffer, size_t filesize ) if( vc ) { - comm = vorbis_comment_query( vc, "LOOP_START", 0 ); - if( comm ) + const char *start, *end, *looplength; + + start = vorbis_comment_query( vc, "LOOP_START", 0 ); // DarkPlaces, and some Japanese app + if( start ) { - // FXIME: implement - Msg( "ogg 'cue' %d\n", com.atoi(comm) ); - //sound.loopstart = bound( 0, com.atoi( comm ), sound.samples ); - } - } + end = vorbis_comment_query( vc, "LOOP_END", 0 ); + if( !end ) looplength = vorbis_comment_query( vc, "LOOP_LENGTH", 0 ); + } + else + { + // RPG Maker VX + start = vorbis_comment_query( vc, "LOOPSTART", 0 ); + if( start ) + { + looplength = vorbis_comment_query( vc, "LOOPLENGTH", 0 ); + if( !looplength ) end = vorbis_comment_query( vc, "LOOPEND", 0 ); + } + else + { + // Sonic Robo Blast 2 + start = vorbis_comment_query( vc, "LOOPPOINT", 0 ); + } + } + + if( start ) + { + sound.loopstart = (uint)bound( 0, com.atof( start ), sound.samples ); + if( end ) sound.samples = (uint)bound( 0, com.atof( end ), sound.samples ); + else if( looplength ) + { + size_t length = com.atof( looplength ); + sound.samples = (uint)bound( 0, sound.loopstart + length, sound.samples ); + } + } + } // close file ov_clear( &vf ); diff --git a/physic/cm_studio.c b/physic/cm_studio.c index 83d1db02..5be26626 100644 --- a/physic/cm_studio.c +++ b/physic/cm_studio.c @@ -11,9 +11,9 @@ struct { - dstudiohdr_t *hdr; - dstudiomodel_t *submodel; - dstudiobodyparts_t *bodypart; + studiohdr_t *hdr; + mstudiomodel_t *submodel; + mstudiobodyparts_t *bodypart; matrix4x4 rotmatrix; matrix4x4 bones[MAXSTUDIOBONES]; cplane_t planes[12]; @@ -27,10 +27,10 @@ struct =============================================================================== */ -int CM_StudioExtractBbox( dstudiohdr_t *phdr, int sequence, float *mins, float *maxs ) +int CM_StudioExtractBbox( studiohdr_t *phdr, int sequence, float *mins, float *maxs ) { - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)phdr + phdr->seqindex); + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex); if( sequence == -1 ) return 0; VectorCopy( pseqdesc[sequence].bbmin, mins ); @@ -41,15 +41,15 @@ int CM_StudioExtractBbox( dstudiohdr_t *phdr, int sequence, float *mins, float * int CM_StudioBodyVariations( model_t handle ) { - dstudiohdr_t *pstudiohdr; - dstudiobodyparts_t *pbodypart; + studiohdr_t *pstudiohdr; + mstudiobodyparts_t *pbodypart; int i, count; - pstudiohdr = (dstudiohdr_t *)CM_Extradata( handle ); + pstudiohdr = (studiohdr_t *)CM_Extradata( handle ); if( !pstudiohdr ) return 0; count = 1; - pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex); + pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex); // each body part has nummodels variations so there are as many total variations as there // are in a matrix of each part by each other part @@ -87,9 +87,9 @@ void CM_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, con { int i, j; float value; - dstudiobonecontroller_t *pbonecontroller; + mstudiobonecontroller_t *pbonecontroller; - pbonecontroller = (dstudiobonecontroller_t *)((byte *)studio.hdr + studio.hdr->bonecontrollerindex); + pbonecontroller = (mstudiobonecontroller_t *)((byte *)studio.hdr + studio.hdr->bonecontrollerindex); for( j = 0; j < studio.hdr->numbonecontrollers; j++ ) { @@ -145,12 +145,12 @@ CM_StudioCalcBoneQuaterion ==================== */ -void CM_StudioCalcBoneQuaterion( int frame, float s, dstudiobone_t *pbone, dstudioanim_t *panim, float *adj, float *q ) +void CM_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) { int j, k; vec4_t q1, q2; vec3_t angle1, angle2; - dstudioanimvalue_t *panimvalue; + mstudioanimvalue_t *panimvalue; for( j = 0; j < 3; j++ ) { @@ -160,7 +160,7 @@ void CM_StudioCalcBoneQuaterion( int frame, float s, dstudiobone_t *pbone, dstud } else { - panimvalue = (dstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); k = frame; // debug @@ -232,17 +232,17 @@ CM_StudioCalcBonePosition ==================== */ -void CM_StudioCalcBonePosition( int frame, float s, dstudiobone_t *pbone, dstudioanim_t *panim, float *adj, float *pos ) +void CM_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) { int j, k; - dstudioanimvalue_t *panimvalue; + mstudioanimvalue_t *panimvalue; for( j = 0; j < 3; j++ ) { pos[j] = pbone->value[j]; // default; if( panim->offset[j] != 0.0f ) { - panimvalue = (dstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); k = frame; @@ -298,11 +298,11 @@ CM_StudioCalcRotations ==================== */ -void CM_StudioCalcRotations( edict_t *e, float pos[][3], vec4_t *q, dstudioseqdesc_t *pseqdesc, dstudioanim_t *panim, float f ) +void CM_StudioCalcRotations( edict_t *e, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) { int i; int frame; - dstudiobone_t *pbone; + mstudiobone_t *pbone; float adj[MAXSTUDIOCONTROLLERS]; float s, dadt = 1.0f; // noInterp @@ -315,7 +315,7 @@ void CM_StudioCalcRotations( edict_t *e, float pos[][3], vec4_t *q, dstudioseqde s = (f - frame); // add in programtic controllers - pbone = (dstudiobone_t *)((byte *)studio.hdr + studio.hdr->boneindex); + pbone = (mstudiobone_t *)((byte *)studio.hdr + studio.hdr->boneindex); CM_StudioCalcBoneAdj( dadt, adj, e->v.controller, e->v.controller ); @@ -342,7 +342,7 @@ StudioEstimateFrame ==================== */ -float CM_StudioEstimateFrame( edict_t *e, dstudioseqdesc_t *pseqdesc ) +float CM_StudioEstimateFrame( edict_t *e, mstudioseqdesc_t *pseqdesc ) { double f; @@ -417,16 +417,16 @@ CM_StudioGetAnim ==================== */ -dstudioanim_t *CM_StudioGetAnim( cmodel_t *m_pSubModel, dstudioseqdesc_t *pseqdesc ) +mstudioanim_t *CM_StudioGetAnim( cmodel_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) { - dstudioseqgroup_t *pseqgroup; + mstudioseqgroup_t *pseqgroup; cache_user_t *paSequences; size_t filesize; byte *buf; - pseqgroup = (dstudioseqgroup_t *)((byte *)studio.hdr + studio.hdr->seqgroupindex) + pseqdesc->seqgroup; + pseqgroup = (mstudioseqgroup_t *)((byte *)studio.hdr + studio.hdr->seqgroupindex) + pseqdesc->seqgroup; if( pseqdesc->seqgroup == 0 ) - return (dstudioanim_t *)((byte *)studio.hdr + pseqgroup->data + pseqdesc->animindex); + return (mstudioanim_t *)((byte *)studio.hdr + pseqgroup->data + pseqdesc->animindex); paSequences = (cache_user_t *)m_pSubModel->submodels; @@ -455,7 +455,7 @@ dstudioanim_t *CM_StudioGetAnim( cmodel_t *m_pSubModel, dstudioseqdesc_t *pseqde Mem_Copy( paSequences[pseqdesc->seqgroup].data, buf, filesize ); Mem_Free( buf ); } - return (dstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); + return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); } /* @@ -468,9 +468,9 @@ void CM_StudioSetupBones( edict_t *e ) int i, oldseq; double f; - dstudiobone_t *pbones; - dstudioseqdesc_t *pseqdesc; - dstudioanim_t *panim; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; static float pos[MAXSTUDIOBONES][3]; static vec4_t q[MAXSTUDIOBONES]; @@ -486,7 +486,7 @@ void CM_StudioSetupBones( edict_t *e ) oldseq = e->v.sequence; // TraceCode can't change sequence if( e->v.sequence >= studio.hdr->numseq ) e->v.sequence = 0; - pseqdesc = (dstudioseqdesc_t *)((byte *)studio.hdr + studio.hdr->seqindex) + e->v.sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)studio.hdr + studio.hdr->seqindex) + e->v.sequence; f = CM_StudioEstimateFrame( e, pseqdesc ); @@ -521,7 +521,7 @@ void CM_StudioSetupBones( edict_t *e ) } } - pbones = (dstudiobone_t *)((byte *)studio.hdr + studio.hdr->boneindex); + pbones = (mstudiobone_t *)((byte *)studio.hdr + studio.hdr->boneindex); for( i = 0; i < studio.hdr->numbones; i++ ) { @@ -543,7 +543,7 @@ StudioCalcAttachments static void CM_StudioCalcAttachments( edict_t *e, int iAttachment, float *org, float *ang ) { int i; - dstudioattachment_t *pAtt; + mstudioattachment_t *pAtt; vec3_t axis[3]; vec3_t localOrg, localAng; @@ -556,7 +556,7 @@ static void CM_StudioCalcAttachments( edict_t *e, int iAttachment, float *org, f iAttachment = bound( 0, iAttachment, studio.hdr->numattachments ); // calculate attachment points - pAtt = (dstudioattachment_t *)((byte *)studio.hdr + studio.hdr->attachmentindex); + pAtt = (mstudioattachment_t *)((byte *)studio.hdr + studio.hdr->attachmentindex); for( i = 0; i < studio.hdr->numattachments; i++ ) { @@ -623,7 +623,7 @@ bool CM_StudioSetup( edict_t *e ) if( mod && mod->type == mod_studio && mod->extradata ) { - studio.hdr = (dstudiohdr_t *)mod->extradata; + studio.hdr = (studiohdr_t *)mod->extradata; CM_StudioSetUpTransform( e ); CM_StudioSetupBones( e ); return true; @@ -740,7 +740,7 @@ bool CM_StudioTrace( edict_t *e, const vec3_t start, const vec3_t end, trace_t * for( i = 0; i < studio.hdr->numhitboxes; i++ ) { - dstudiobbox_t *phitbox = (dstudiobbox_t *)((byte*)studio.hdr + studio.hdr->hitboxindex) + i; + mstudiobbox_t *phitbox = (mstudiobbox_t *)((byte*)studio.hdr + studio.hdr->hitboxindex) + i; Matrix4x4_Invert_Simple( m, studio.bones[phitbox->bone] ); Matrix4x4_VectorTransform( m, start, start_l ); @@ -776,7 +776,7 @@ bool CM_StudioTrace( edict_t *e, const vec3_t start, const vec3_t end, trace_t * } else { - dstudiobone_t *pbone = (dstudiobone_t *)((byte*)studio.hdr + studio.hdr->boneindex) + outBone; + mstudiobone_t *pbone = (mstudiobone_t *)((byte*)studio.hdr + studio.hdr->boneindex) + outBone; // MsgDev( D_INFO, "Bone name %s\n", pbone->name ); // debug VectorLerp( start, tr->flFraction, end, tr->vecEndPos ); @@ -821,10 +821,10 @@ void CM_GetBonePosition( edict_t* e, int iBone, float *org, float *ang ) void CM_StudioModel( cmodel_t *mod, byte *buffer ) { - dstudiohdr_t *phdr; - dstudioseqdesc_t *pseqdesc; + studiohdr_t *phdr; + mstudioseqdesc_t *pseqdesc; - phdr = (dstudiohdr_t *)buffer; + phdr = (studiohdr_t *)buffer; if( phdr->version != STUDIO_VERSION ) { MsgDev( D_ERROR, "CM_StudioModel: %s has wrong version number (%i should be %i)\n", loadmodel->name, phdr->version, STUDIO_VERSION ); @@ -832,7 +832,7 @@ void CM_StudioModel( cmodel_t *mod, byte *buffer ) } loadmodel->type = mod_studio; - pseqdesc = (dstudioseqdesc_t *)((byte *)phdr + phdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex); loadmodel->numframes = pseqdesc[0].numframes; loadmodel->registration_sequence = cm.registration_sequence; diff --git a/public/mathlib.h b/public/mathlib.h index 926832d7..70212f0d 100644 --- a/public/mathlib.h +++ b/public/mathlib.h @@ -30,39 +30,26 @@ #define PLANE_Z 2 #define PLANE_NONAXIAL 3 -#define METERS_PER_INCH 0.0254f #define EQUAL_EPSILON 0.001f #define STOP_EPSILON 0.1f #define ON_EPSILON 0.1f -#define RAD2DEG( x ) ((float)(x) * (float)(180.f / M_PI)) -#define DEG2RAD( x ) ((float)(x) * (float)(M_PI / 180.f)) -#define METER2INCH(x) (float)(x * (1.0f/METERS_PER_INCH)) -#define INCH2METER(x) (float)(x * (METERS_PER_INCH/1.0f)) #define RAD_TO_STUDIO (32768.0 / M_PI) #define STUDIO_TO_RAD (M_PI / 32768.0) #define nanmask (255<<23) #define Q_rint(x) ((x) < 0 ? ((int)((x)-0.5f)) : ((int)((x)+0.5f))) #define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) -#define RANDOM_LONG(MIN, MAX) ((rand() & 32767) * (((MAX)-(MIN)) * (1.0f / 32767.0f)) + (MIN)) -#define RANDOM_FLOAT(MIN,MAX) (((float)rand() / RAND_MAX) * ((MAX)-(MIN)) + (MIN)) -#define NUMVERTEXNORMALS 162 // quake avertex normals #define VectorIsNAN(v) (IS_NAN(v[0]) || IS_NAN(v[1]) || IS_NAN(v[2])) -#define VectorToPhysic(v) { v[0] = INCH2METER(v[0]), v[1] = INCH2METER(v[1]), v[2] = INCH2METER(v[2]); } -#define VectorToServer(v) { v[0] = METER2INCH(v[0]), v[1] = METER2INCH(v[1]), v[2] = METER2INCH(v[2]); } #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) #define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) #define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) -#define Vector4Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) #define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) #define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) #define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) #define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) #define VectorScale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale)) -#define Vector4Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale),(out)[3] = (in)[3] * (scale)) -#define VectorMultiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2]) #define VectorCompare(v1,v2) ((v1)[0]==(v2)[0] && (v1)[1]==(v2)[1] && (v1)[2]==(v2)[2]) #define VectorDivide( in, d, out ) VectorScale( in, (1.0f / (d)), out ) #define VectorMax(a) ( max((a)[0], max((a)[1], (a)[2])) ) @@ -76,45 +63,18 @@ #define VectorSet(v, x, y, z) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z)) #define Vector4Set(v, a, b, c, d) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c),(v)[3] = (d)) #define VectorClear(x) ((x)[0]=(x)[1]=(x)[2]=0) -#define Vector4Clear(x) ((x)[0]=(x)[1]=(x)[2]=(x)[3]=0) #define Vector2Lerp( v1, lerp, v2, c ) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1])) #define VectorLerp( v1, lerp, v2, c ) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2])) #define VectorNormalize( v ) { float ilength = (float)com.sqrt(DotProduct(v, v));if (ilength) ilength = 1.0f / ilength;v[0] *= ilength;v[1] *= ilength;v[2] *= ilength; } #define VectorNormalize2( v, dest ) {float ilength = (float)com.sqrt(DotProduct(v,v));if (ilength) ilength = 1.0f / ilength;dest[0] = v[0] * ilength;dest[1] = v[1] * ilength;dest[2] = v[2] * ilength; } #define VectorNormalizeFast( v ) {float ilength = (float)rsqrt(DotProduct(v,v)); v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } +#define VectorNormalizeLength( v ) VectorNormalizeLength2((v), (v)) #define VectorNegate(x, y) ((y)[0] = -(x)[0], (y)[1] = -(x)[1], (y)[2] = -(x)[2]) #define VectorM(scale1, b1, c) ((c)[0] = (scale1) * (b1)[0],(c)[1] = (scale1) * (b1)[1],(c)[2] = (scale1) * (b1)[2]) #define VectorMA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2]) -#define VectorMAM(scale1, b1, scale2, b2, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2]) -#define VectorMAMAM(scale1, b1, scale2, b2, scale3, b3, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0] + (scale3) * (b3)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1] + (scale3) * (b3)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2] + (scale3) * (b3)[2]) -#define VectorMAMAMAM(scale1, b1, scale2, b2, scale3, b3, scale4, b4, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0] + (scale3) * (b3)[0] + (scale4) * (b4)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1] + (scale3) * (b3)[1] + (scale4) * (b4)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2] + (scale3) * (b3)[2] + (scale4) * (b4)[2]) -#define VectorReflect( a, r, b, c ) do{ double d; d = DotProduct((a), (b)) * -(1.0 + (r)); VectorMA((a), (d), (b), (c)); } while( 0 ) -#define BoxesOverlap(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1] && (a)[2] <= (d)[2] && (b)[2] >= (c)[2]) -#define BoxInsideBox(a,b,c,d) ((a)[0] >= (c)[0] && (b)[0] <= (d)[0] && (a)[1] >= (c)[1] && (b)[1] <= (d)[1] && (a)[2] >= (c)[2] && (b)[2] <= (d)[2]) -#define TriangleOverlapsBox( a, b, c, d, e ) (min((a)[0], min((b)[0], (c)[0])) < (e)[0] && max((a)[0], max((b)[0], (c)[0])) > (d)[0] && min((a)[1], min((b)[1], (c)[1])) < (e)[1] && max((a)[1], max((b)[1], (c)[1])) > (d)[1] && min((a)[2], min((b)[2], (c)[2])) < (e)[2] && max((a)[2], max((b)[2], (c)[2])) > (d)[2]) -#define TriangleNormal( a, b, c, n) ((n)[0] = ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]), (n)[1] = ((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2]), (n)[2] = ((a)[0] - (b)[0]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[0] - (b)[0])) #define MakeRGBA( out, x, y, z, w ) Vector4Set( out, x, y, z, w ) -#define Square(x) ((x)*(x)) _inline float anglemod(const float a){ return(360.0/65536) * ((int)(a*(65536/360.0)) & 65535); } -// NOTE: this code contain bug, what may invoked infinity loop -_inline int nearest_pow( int size ) -{ - int i = 2; - - while( 1 ) - { - i <<= 1; - if( size == i ) return i; - if( size > i && size < (i <<1)) - { - if( size >= ((i+(i<<1))/2)) - return i<<1; - else return i; - } - } -} - /* ================= rsqrt @@ -137,48 +97,6 @@ _inline float rsqrt( float number ) return y; } -// remap a value in the range [A,B] to [C,D]. -_inline float RemapVal( float val, float A, float B, float C, float D ) -{ - return C + (D - C) * (val - A) / (B - A); -} - -_inline float ApproachVal( float target, float value, float speed ) -{ - float delta = target - value; - - if( delta > speed ) - value += speed; - else if( delta < -speed ) - value -= speed; - else value = target; - - return value; -} - -_inline static bool VectorCompareEpsilon( const vec3_t v1, const vec3_t v2, const float epsilon ) -{ - vec3_t d; - - VectorSubtract( v1, v2, d ); - d[0] = fabs( d[0] ); - d[1] = fabs( d[1] ); - d[2] = fabs( d[2] ); - - if( d[0] > epsilon || d[1] > epsilon || d[2] > epsilon ) - return false; - return true; -} - - -_inline void VectorBound( const float min, vec3_t v, const float max ) -{ - v[0] = bound(min, v[0], max); - v[1] = bound(min, v[1], max); - v[2] = bound(min, v[2], max); -} - -// FIXME: convert to #define _inline float VectorNormalizeLength2( const vec3_t v, vec3_t out ) { float length, ilength; @@ -197,16 +115,17 @@ _inline float VectorNormalizeLength2( const vec3_t v, vec3_t out ) return length; } -#define VectorNormalizeLength( v ) VectorNormalizeLength2((v), (v)) _inline bool VectorIsNull( const vec3_t v ) { - int i; - float result = 0; + int i; + float result = 0.0f; - if(!v) return true; - for (i = 0; i< 3; i++) result += v[i]; - if(result != 0) return false; + if( !v ) return true; + for( i = 0; i< 3; i++ ) + result += v[i]; + if( result != 0.0f ) + return false; return true; } @@ -391,36 +310,6 @@ _inline void AngleVectorsFLU(const vec3_t angles, vec3_t forward, vec3_t left, v } } -// FIXME: get rid of this -_inline void MatrixAngles( matrix3x3 matrix, vec3_t angles ) -{ - vec3_t forward, right, up; - float xyDist; - - forward[0] = matrix[0][0]; - forward[1] = matrix[0][2]; - forward[2] = matrix[0][1]; - right[0] = matrix[1][0]; - right[1] = matrix[1][2]; - right[2] = matrix[1][1]; - up[2] = matrix[2][1]; - - xyDist = com.sqrt( forward[0] * forward[0] + forward[1] * forward[1] ); - - if ( xyDist > EQUAL_EPSILON ) // enough here to get angles? - { - angles[1] = RAD2DEG( com.atan2( forward[1], forward[0] )); - angles[0] = RAD2DEG( com.atan2( -forward[2], xyDist )); - angles[2] = RAD2DEG( com.atan2( -right[2], up[2] )); - } - else - { - angles[1] = RAD2DEG( com.atan2( right[0], -right[1] ) ); - angles[0] = RAD2DEG( com.atan2( -forward[2], xyDist ) ); - angles[2] = 0; - } -} - /* ==================== AngleQuaternion @@ -429,8 +318,8 @@ AngleQuaternion */ _inline void AngleQuaternion( float *angles, vec4_t q ) { - float angle; - float sr, sp, sy, cr, cp, cy; + float angle; + float sr, sp, sy, cr, cp, cy; // FIXME: rescale the inputs to 1/2 angle angle = angles[2] * 0.5; @@ -454,21 +343,22 @@ QuaternionSlerp */ _inline void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) { - int i; float omega, cosom, sinom, sclp, sclq; + int i; // decide if one of the quaternions is backwards float a = 0; float b = 0; - for (i = 0; i < 4; i++) + for( i = 0; i < 4; i++ ) { a += (p[i]-q[i])*(p[i]-q[i]); b += (p[i]+q[i])*(p[i]+q[i]); } - if (a > b) + + if( a > b ) { - for (i = 0; i < 4; i++) + for( i = 0; i < 4; i++ ) { q[i] = -q[i]; } @@ -476,21 +366,23 @@ _inline void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; - if ((1.0 + cosom) > 0.000001) + if(( 1.0 + cosom ) > 0.000001 ) { - if ((1.0 - cosom) > 0.000001) + if(( 1.0 - cosom ) > 0.000001 ) { omega = com.acos( cosom ); sinom = com.sin( omega ); - sclp = com.sin( (1.0 - t)*omega) / sinom; - sclq = com.sin( t*omega ) / sinom; + sclp = com.sin(( 1.0 - t ) * omega ) / sinom; + sclq = com.sin( t * omega ) / sinom; } else { sclp = 1.0 - t; sclq = t; } - for (i = 0; i < 4; i++) qt[i] = sclp * p[i] + sclq * q[i]; + + for( i = 0; i < 4; i++ ) + qt[i] = sclp * p[i] + sclq * q[i]; } else { @@ -498,12 +390,11 @@ _inline void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) qt[1] = q[0]; qt[2] = -q[3]; qt[3] = q[2]; - sclp = com.sin( (1.0 - t) * (0.5 * M_PI)); - sclq = com.sin( t * (0.5 * M_PI)); - for (i = 0; i < 3; i++) - { + sclp = com.sin(( 1.0 - t ) * ( 0.5 * M_PI )); + sclq = com.sin( t * ( 0.5 * M_PI )); + + for( i = 0; i < 3; i++ ) qt[i] = sclp * p[i] + sclq * qt[i]; - } } } @@ -535,26 +426,6 @@ _inline bool BoundsAndSphereIntersect( const vec3_t mins, const vec3_t maxs, con return true; } -_inline bool PlaneIntersect( vec3_t p_n, vec_t p_d, vec3_t l_o, vec3_t l_n, vec3_t out ) -{ - float dot, t; - - dot = DotProduct( p_n, l_n ); - - if( dot > -0.001 ) - return false; - - t = (p_d - (l_o[0] * p_n[0]) - (l_o[1] * p_n[1]) - (l_o[2] * p_n[2])) / dot; - - if( out ) - { - out[0] = l_o[0] + (t * l_n[0]); - out[1] = l_o[1] + (t * l_n[1]); - out[2] = l_o[2] + (t * l_n[2]); - } - return true; -} - _inline static int PlaneTypeForNormal( const vec3_t normal ) { if( normal[0] == 1.0 ) return PLANE_X; @@ -579,40 +450,9 @@ _inline static int SignbitsForPlane( const vec3_t normal ) return bits; } -#define PlaneDist(point,plane) ((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) +#define PlaneDist(point,plane) ((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) #define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) -#define NUM_HULL_ROUNDS (sizeof(hull_table) / sizeof(word)) -#define HULL_PRECISION 4 -static word hull_table[] = { 0, 4, 8, 16, 18, 24, 28, 30, 32, 40, 48, 54, 56, 60, 64, 72, 80, 112, 120, 128, 140, 176 }; - -_inline void CM_RoundUpHullSize( vec3_t size ) -{ - int i, j; - - for(i = 0; i < 3; i++) - { - bool negative = false; - float result, value; - - value = ceil(size[i] + 0.5f); // round it - if(value < 0) negative = true; - value = fabs( value ); // make positive - - // lookup hull table - for(j = 0; j < NUM_HULL_ROUNDS; j++) - { - result = value - hull_table[j]; - if(result <= HULL_PRECISION) - { - result = negative ? -hull_table[j] : hull_table[j]; - break; - } - } - size[i] = result; // copy new value - } -} - /* ================= RadiusFromBounds @@ -630,91 +470,6 @@ _inline float RadiusFromBounds( vec3_t mins, vec3_t maxs ) return VectorLength( corner ); } -/* -==================== -RotatePointAroundVector -==================== -*/ -_inline void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) -{ - float t0, t1; - float angle, c, s; - vec3_t vr, vu, vf; - - angle = DEG2RAD( degrees ); - com.sincos( angle, &s, &c ); - VectorCopy( dir, vf ); - VectorVectors( vf, vr, vu ); - - t0 = vr[0] * c + vu[0] * -s; - t1 = vr[0] * s + vu[0] * c; - dst[0] = (t0 * vr[0] + t1 * vu[0] + vf[0] * vf[0]) * point[0] - + (t0 * vr[1] + t1 * vu[1] + vf[0] * vf[1]) * point[1] - + (t0 * vr[2] + t1 * vu[2] + vf[0] * vf[2]) * point[2]; - - t0 = vr[1] * c + vu[1] * -s; - t1 = vr[1] * s + vu[1] * c; - dst[1] = (t0 * vr[0] + t1 * vu[0] + vf[1] * vf[0]) * point[0] - + (t0 * vr[1] + t1 * vu[1] + vf[1] * vf[1]) * point[1] - + (t0 * vr[2] + t1 * vu[2] + vf[1] * vf[2]) * point[2]; - - t0 = vr[2] * c + vu[2] * -s; - t1 = vr[2] * s + vu[2] * c; - dst[2] = (t0 * vr[0] + t1 * vu[0] + vf[2] * vf[0]) * point[0] - + (t0 * vr[1] + t1 * vu[1] + vf[2] * vf[1]) * point[1] - + (t0 * vr[2] + t1 * vu[2] + vf[2] * vf[2]) * point[2]; -} - -// assumes "src" is normalized -_inline void PerpendicularVector( vec3_t dst, const vec3_t src ) -{ - // LordHavoc: optimized to death and beyond - int pos; - float minelem; - - if( src[0] ) - { - dst[0] = 0; - if( src[1] ) - { - dst[1] = 0; - if( src[2] ) - { - dst[2] = 0; - pos = 0; - minelem = fabs( src[0] ); - if( fabs(src[1]) < minelem ) - { - pos = 1; - minelem = fabs( src[1] ); - } - if( fabs( src[2]) < minelem ) - pos = 2; - - dst[pos] = 1; - dst[0] -= src[pos] * src[0]; - dst[1] -= src[pos] * src[1]; - dst[2] -= src[pos] * src[2]; - - // normalize the result - VectorNormalize( dst ); - } - else dst[2] = 1; - } - else - { - dst[1] = 1; - dst[2] = 0; - } - } - else - { - dst[0] = 1; - dst[1] = 0; - dst[2] = 0; - } -} - /* ================= SimpleSpline diff --git a/public/qfiles_ref.h b/public/qfiles_ref.h index 56a7a56b..754dfbad 100644 --- a/public/qfiles_ref.h +++ b/public/qfiles_ref.h @@ -41,6 +41,33 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps] #define TYPE_STRDATA 72 // stringdata type (stringtable marked as TYPE_BINDATA) #define TYPE_SCRIPT 73 // .qc scripts (xash ext) +/* +======================================================================== + +.QFONT image format + +======================================================================== +*/ +#define QCHAR_WIDTH 16 +#define QFONT_WIDTH 16 // valve fonts used contant sizes +#define QFONT_HEIGHT ((128 - 32) / 16) + +typedef struct +{ + short startoffset; + short charwidth; +} charset_t; + +typedef struct +{ + int width; + int height; + int rowcount; + int rowheight; + charset_t fontinfo[256]; + byte data[4]; // variable sized +} qfont_t; + /* ============================================================================== @@ -153,7 +180,7 @@ typedef struct mip_s uint offsets[4]; // four mip maps stored } mip_t; -#include "studio_ref.h" +#include "studio.h" /* ======================================================================== diff --git a/public/render_api.h b/public/render_api.h index a2be16a4..1b8fa0ca 100644 --- a/public/render_api.h +++ b/public/render_api.h @@ -13,6 +13,7 @@ #define SHADER_NOMIP 3 // 2d images #define SHADER_GENERIC 4 // generic shader #define SHADER_DECAL 5 +#define SHADER_SPRITE 6 // dlight flags #define DLIGHT_ONLYENTS BIT( 0 ) @@ -220,7 +221,7 @@ typedef struct render_imp_s // client fundamental callbacks void (*UpdateScreen)( void ); // update screen while loading - void (*StudioEvent)( dstudioevent_t *event, edict_t *ent ); + void (*StudioEvent)( mstudioevent_t *event, edict_t *ent ); void (*StudioFxTransform)( edict_t *ent, float matrix[4][4] ); void (*ShowCollision)( cmdraw_t callback ); // debug long (*WndProc)( void *hWnd, uint uMsg, uint wParam, long lParam ); diff --git a/release.bat b/release.bat index 9999428b..43275fc1 100644 --- a/release.bat +++ b/release.bat @@ -29,15 +29,9 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% vid_gl/vid_gl.dsp %CONFIG%"vid_gl - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% server/server.dsp %CONFIG%"server - Win32 Release" %build_target% -if errorlevel 1 set BUILD_ERROR=1 - %MSDEV% spirit/spirit.dsp %CONFIG%"spirit - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% snd_al/snd_al.dsp %CONFIG%"snd_al - Win32 Release" %build_target% -if errorlevel 1 set BUILD_ERROR=1 - %MSDEV% snd_dx/snd_dx.dsp %CONFIG%"snd_dx - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 @@ -70,9 +64,7 @@ if exist engine\engine.plg del /f /q engine\engine.plg if exist launch\launch.plg del /f /q launch\launch.plg if exist physic\physic.plg del /f /q physic\physic.plg if exist vid_gl\vid_gl.plg del /f /q vid_gl\vid_gl.plg -if exist server\server.plg del /f /q server\server.plg if exist spirit\spirit.plg del /f /q spirit\spirit.plg -if exist snd_al\snd_al.plg del /f /q snd_al\snd_al.plg if exist snd_dx\snd_dx.plg del /f /q snd_dx\snd_dx.plg if exist xtools\xtools.plg del /f /q xtools\xtools.plg diff --git a/server/cbase.h b/server/cbase.h deleted file mode 100644 index f9d1a9dc..00000000 --- a/server/cbase.h +++ /dev/null @@ -1,38 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -// stdafx.h -//======================================================================= -#ifndef CBASE_H -#define CBASE_H - -class CBaseEntity; -class CBaseLogic; -class CBaseBrush; -class CBaseAnimating; -class CBaseMonster; -class CBasePlayerWeapon; -class CSquadMonster; -class CBaseMonster; -class CCineMonster; -class CBasePlayer; -class CSound; - -#include "hierarchy.h" -#include "globals.h" -#include "utils.h" -#include "saverestore.h" -#include "schedule.h" -#include "studio_ref.h" -#include "defaults.h" -#include "monsterevent.h" -#include "baseentity.h" -#include "baselogic.h" -#include "basesprite.h" -#include "baseinfo.h" -#include "baseanimating.h" -#include "baseitem.h" -#include "basebrush.h" -#include "basemonster.h" -#include "baseworld.h" - -#endif //CBASE_H \ No newline at end of file diff --git a/server/ents/basebeams.h b/server/ents/basebeams.h deleted file mode 100644 index cf72b566..00000000 --- a/server/ents/basebeams.h +++ /dev/null @@ -1,115 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef BASEBEAMS_H -#define BASEBEAMS_H - -#include "beam_def.h" - -#define SF_BEAM_TEMPORARY 0x8000 -#define SF_BEAM_TRIPPED 0x80000 // bit who indicated "trip" action - -class CBeam : public CBaseLogic -{ -public: - void Spawn( void ); - int ObjectCaps( void ) - { - int flags = 0; - if ( pev->spawnflags & SF_BEAM_TEMPORARY ) - flags = FCAP_DONT_SAVE; - return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; - } - - void Touch( CBaseEntity *pOther ); - - // These functions are here to show the way beams are encoded as entities. - // Encoding beams as entities simplifies their management in the client/server architecture - inline void SetType( int type ) { pev->rendermode = type; } - inline void SetFlags( int flags ) { pev->renderfx |= flags; } - inline void SetStartPos( const Vector& pos ) { pev->origin = pos; } - inline void SetEndPos( const Vector& pos ) { pev->oldorigin = pos; } - inline void SetStartEntity( edict_t *pEnt ) { pev->aiment = pEnt; } - inline void SetEndEntity( edict_t *pEnt ) { pev->owner = pEnt; } - - inline void SetStartAttachment( int attachment ) { pev->colormap = (pev->colormap & 0xFF00)>>8 | attachment; } - inline void SetEndAttachment( int attachment ) { pev->colormap = (pev->colormap & 0xFF) | (attachment<<8); } - - inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } - inline void SetWidth( int width ) { pev->scale = width; } - inline void SetNoise( int amplitude ) { pev->body = amplitude; } - inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } - inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } - inline void SetFrame( float frame ) { pev->frame = frame; } - inline void SetScrollRate( int speed ) { pev->animtime = speed; } - - inline int GetType( void ) { return pev->rendermode; } - inline int GetFlags( void ) { return pev->renderfx; } - inline edict_t *GetStartEntity( void ) { return pev->owner; } - inline edict_t *GetEndEntity( void ) { return pev->aiment; } - - const Vector &GetStartPos( void ); - const Vector &GetEndPos( void ); - - Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam - - inline int GetTexture( void ) { return pev->modelindex; } - inline int GetWidth( void ) { return pev->scale; } - inline int GetNoise( void ) { return pev->body; } - inline Vector GetColor( void ) { return Vector( pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z ); } - inline int GetBrightness( void ) { return pev->renderamt; } - inline int GetFrame( void ) { return pev->frame; } - inline int GetScrollRate( void ) { return pev->animtime; } - - CBaseEntity* GetTripEntity( TraceResult *ptr ); - - // Call after you change start/end positions - void RelinkBeam( void ); - void SetObjectCollisionBox( void ); - - void DoSparks( const Vector &start, const Vector &end ); - CBaseEntity *RandomTargetname( const char *szName ); - void BeamDamage( TraceResult *ptr ); - // Init after BeamCreate() - void BeamInit( const char *pSpriteName, int width ); - void PointsInit( const Vector &start, const Vector &end ); - void PointEntInit( const Vector &start, edict_t *pEnd ); - void EntsInit( edict_t *pStart, edict_t *pEnd ); - void HoseInit( const Vector &start, const Vector &direction ); - - static CBeam *BeamCreate( const char *pSpriteName, int width ); - - inline void LiveForTime( float time ) { SetThink( Remove ); SetNextThink( time ); } - inline void BeamDamageInstant( TraceResult *ptr, float damage ) - { - pev->dmg = damage; - pev->dmgtime = gpGlobals->time - 1; - BeamDamage(ptr); - } -}; - -class CLaser : public CBeam -{ -public: - void Spawn( void ); - void PostSpawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - void SetObjectCollisionBox( void ); - void TurnOn( void ); - void TurnOff( void ); - void FireAtPoint( Vector startpos, TraceResult &point ); - - void Think( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CSprite *m_pStartSprite; - CSprite *m_pEndSprite; -}; - -#endif //BASEBEAMS_H \ No newline at end of file diff --git a/server/ents/basebrush.cpp b/server/ents/basebrush.cpp deleted file mode 100644 index 92f15222..00000000 --- a/server/ents/basebrush.cpp +++ /dev/null @@ -1,861 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// basebreak.cpp - base for all brush -// entities. -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "sfx.h" -#include "cbase.h" -#include "decals.h" -#include "client.h" -#include "soundent.h" -#include "saverestore.h" -#include "gamerules.h" -#include "basebrush.h" -#include "defaults.h" -#include "player.h" - -//======================================================================= -// STATIC BREACABLE BRUSHES -//======================================================================= -#define DAMAGE_SOUND(x, y, z)EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, x[RANDOM_LONG(0, ARRAYSIZE(x)-1)], y, ATTN_NORM, 0, z) - -//spawn objects -const char *CBaseBrush::pSpawnObjects[] = -{ - NULL, // 0 - "item_battery", // 1 - "item_healthkit", // 2 - "weapon_9mmhandgun", // 3 - "ammo_9mmclip", // 4 - "weapon_9mmAR", // 5 - "ammo_9mmAR", // 6 - "ammo_m203", // 7 - "weapon_shotgun", // 8 - "ammo_buckshot", // 9 - "weapon_crossbow", // 10 - "ammo_crossbow", // 11 - "weapon_357", // 12 - "ammo_357", // 13 - "weapon_rpg", // 14 - "ammo_rpgclip", // 15 - "ammo_gaussclip", // 16 - "weapon_handgrenade", // 17 - "weapon_gauss", // 18 -}; - -//material sounds -const char *CBaseBrush::pSoundsWood[] = -{ - "materials/wood/wood1.wav", - "materials/wood/wood2.wav", - "materials/wood/wood3.wav", - "materials/wood/wood4.wav", -}; - -const char *CBaseBrush::pSoundsFlesh[] = -{ - "materials/flesh/flesh1.wav", - "materials/flesh/flesh2.wav", - "materials/flesh/flesh3.wav", - "materials/flesh/flesh4.wav", - "materials/flesh/flesh5.wav", - "materials/flesh/flesh6.wav", - "materials/flesh/flesh7.wav", - "materials/flesh/flesh8.wav", -}; - -const char *CBaseBrush::pSoundsMetal[] = -{ - "materials/metal/metal1.wav", - "materials/metal/metal2.wav", - "materials/metal/metal3.wav", - "materials/metal/metal4.wav", - "materials/metal/metal5.wav", -}; - -const char *CBaseBrush::pSoundsCrete[] = -{ - "materials/crete/concrete1.wav", - "materials/crete/concrete2.wav", - "materials/crete/concrete3.wav", - "materials/crete/concrete4.wav", - "materials/crete/concrete5.wav", - "materials/crete/concrete6.wav", - "materials/crete/concrete7.wav", - "materials/crete/concrete8.wav", -}; - -const char *CBaseBrush::pSoundsGlass[] = -{ - "materials/glass/glass1.wav", - "materials/glass/glass2.wav", - "materials/glass/glass3.wav", - "materials/glass/glass4.wav", - "materials/glass/glass5.wav", - "materials/glass/glass6.wav", - "materials/glass/glass7.wav", - "materials/glass/glass8.wav", -}; - -const char *CBaseBrush::pSoundsCeil[] = -{ - "materials/ceil/ceiling1.wav", - "materials/ceil/ceiling2.wav", - "materials/ceil/ceiling3.wav", - "materials/ceil/ceiling4.wav", -}; - -const char **CBaseBrush::MaterialSoundList( Materials precacheMaterial, int &soundCount ) -{ - const char **pSoundList = NULL; - - switch ( precacheMaterial ) - { - case None: - soundCount = 0; - break; - case Bones: - case Flesh: - pSoundList = pSoundsFlesh; - soundCount = ARRAYSIZE(pSoundsFlesh); - break; - case CinderBlock: - case Concrete: - case Rocks: - pSoundList = pSoundsCrete; - soundCount = ARRAYSIZE(pSoundsCrete); - break; - case Glass: - case Computer: - case UnbreakableGlass: - pSoundList = pSoundsGlass; - soundCount = ARRAYSIZE(pSoundsGlass); - break; - case MetalPlate: - case AirDuct: - case Metal: - pSoundList = pSoundsMetal; - soundCount = ARRAYSIZE(pSoundsMetal); - break; - case CeilingTile: - pSoundList = pSoundsCeil; - soundCount = ARRAYSIZE(pSoundsCeil); - break; - case Wood: - pSoundList = pSoundsWood; - soundCount = ARRAYSIZE(pSoundsWood); - break; - default: - soundCount = 0; - break; - } - return pSoundList; -} - -void CBaseBrush::MaterialSoundPrecache( Materials precacheMaterial ) -{ - const char **pSoundList; - int i, soundCount = 0; - - pSoundList = MaterialSoundList( precacheMaterial, soundCount ); - for ( i = 0; i < soundCount; i++ ) UTIL_PrecacheSound( (char *)pSoundList[i] ); -} - -void CBaseBrush::PlayRandomSound( edict_t *pEdict, Materials soundMaterial, float volume ) -{ - const char **pSoundList; - int soundCount = 0; - - pSoundList = MaterialSoundList( soundMaterial, soundCount ); - if ( soundCount ) EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0, soundCount-1) ], volume, 1.0 ); -} - -void CBaseBrush :: AxisDir( void ) -{ - // make backward compatibility - if( pev->movedir != g_vecZero ) return; - - // don't change this! - if( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS )) - pev->movedir = Vector ( 0, 0, 1 ); // around z-axis - else if( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS )) - pev->movedir = Vector ( 1, 0, 0 ); // around x-axis - else pev->movedir = Vector ( 0, 1, 0 ); // around y-axis - - // check for reverse rotation - if( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS )) - pev->movedir *= -1; -} - -void CBaseBrush::KeyValue( KeyValueData* pkvd ) -{ - // as default all brushes can select material - // and set strength (0 = unbreakable) - if( FStrEq( pkvd->szKeyName, "material" )) - { - int i = atoi( pkvd->szValue); - - if ((i < 0) || (i >= LastMaterial)) - m_Material = Wood; - else m_Material = (Materials)i; - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "strength" )) - { - pev->health = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "spawnobject" )) - { - int namelen = strlen(pkvd->szValue) - 1; - int obj = atoi( pkvd->szValue ); - - // custom spawn object - if( namelen > 2 ) m_iSpawnObject = ALLOC_STRING( pkvd->szValue ); - else if ( obj > 0 && obj < ARRAYSIZE(pSpawnObjects)) - m_iSpawnObject = MAKE_STRING( pSpawnObjects[obj] ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "gibmodel" )) - { - m_iGibModel = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "volume")) - { - // 0.0 - silence, 1.0 - loudest( obsolete ) - m_flVolume = atof( pkvd->szValue ); - if( m_flVolume > 1.0 ) m_flVolume = 1.0; - if( m_flVolume < 0.0 ) m_flVolume = 0.0; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - m_flRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "movesound" ) || FStrEq( pkvd->szKeyName, "sounds" )) - { - m_iMoveSound = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "stopsound" )) - { - m_iStopSound = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "contents" )) - { - pev->skin = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -//Base functions -TYPEDESCRIPTION CBaseBrush::m_SaveData[] = -{ - DEFINE_FIELD( CBaseBrush, m_flVolume, FIELD_FLOAT ), // volume of sounds - DEFINE_FIELD( CBaseBrush, m_pitch, FIELD_FLOAT ), // pitch of sound - DEFINE_FIELD( CBaseBrush, m_Material, FIELD_INTEGER ), // brush material - DEFINE_FIELD( CBaseBrush, m_iMagnitude, FIELD_INTEGER ), // explosion magnitude - DEFINE_FIELD( CBaseBrush, m_iMoveSound, FIELD_STRING ), // sound scheme like Quake - DEFINE_FIELD( CBaseBrush, m_iStartSound, FIELD_STRING ), // sound scheme like Quake - DEFINE_FIELD( CBaseBrush, m_iStopSound, FIELD_STRING ), // sound scheme like Quake - DEFINE_FIELD( CBaseBrush, m_iSpawnObject, FIELD_STRING ), // spawnobject index - DEFINE_FIELD( CBaseBrush, m_iGibModel, FIELD_STRING ), // custom gibname - DEFINE_FIELD( CBaseBrush, m_vecPlayerPos, FIELD_VECTOR ), // for controllable entity like tank - DEFINE_FIELD( CBaseBrush, m_pController, FIELD_CLASSPTR ), // for controllable entity like tank - DEFINE_FIELD( CBaseBrush, m_flRadius, FIELD_FLOAT ), // volume of sounds - DEFINE_FIELD( CBaseBrush, m_flAccel, FIELD_FLOAT ), // volume of sounds - DEFINE_FIELD( CBaseBrush, m_flDecel, FIELD_FLOAT ), // volume of sounds -}; -IMPLEMENT_SAVERESTORE( CBaseBrush, CBaseLogic ); - -void CBaseBrush::Spawn( void ) -{ - Precache(); - - if( !m_flVolume ) m_flVolume = 1.0; // just enable full volume - - // breacable brush (if mapmaker just set material - just play material sound) - if( IsBreakable()) - pev->takedamage = DAMAGE_YES; - else pev->takedamage = DAMAGE_NO; - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - if( !m_pParent ) pev->flags |= FL_WORLDBRUSH; -} - -void CBaseBrush::Precache( void ) -{ - const char *pGibName = ""; - - switch (m_Material) - { - case Bones: - pGibName = "models/gibs/bones.mdl"; - break; - case Flesh: - pGibName = "models/gibs/flesh.mdl"; - UTIL_PrecacheSound("materials/flesh/bustflesh1.wav"); - UTIL_PrecacheSound("materials/flesh/bustflesh2.wav"); - break; - case Concrete: - pGibName = "models/gibs/concrete.mdl"; - UTIL_PrecacheSound("materials/crete/bustcrete1.wav"); - UTIL_PrecacheSound("materials/crete/bustcrete2.wav"); - break; - case Rocks: - pGibName = "models/gibs/rock.mdl"; - UTIL_PrecacheSound("materials/crete/bustcrete1.wav"); - UTIL_PrecacheSound("materials/crete/bustcrete2.wav"); - break; - case CinderBlock: - pGibName = "models/gibs/cinder.mdl"; - UTIL_PrecacheSound("materials/crete/bustcrete1.wav"); - UTIL_PrecacheSound("materials/crete/bustcrete2.wav"); - break; - case Computer: - pGibName = "models/gibs/computer.mdl"; - UTIL_PrecacheSound("materials/metal/bustmetal1.wav"); - UTIL_PrecacheSound("materials/metal/bustmetal2.wav"); - break; - case Glass: - case UnbreakableGlass: - pGibName = "models/gibs/glass.mdl"; - UTIL_PrecacheSound("materials/glass/bustglass1.wav"); - UTIL_PrecacheSound("materials/glass/bustglass2.wav"); - break; - case MetalPlate: - pGibName = "models/gibs/metalplate.mdl"; - UTIL_PrecacheSound("materials/metal/bustmetal1.wav"); - UTIL_PrecacheSound("materials/metal/bustmetal2.wav"); - break; - case Metal: - pGibName = "models/gibs/metal.mdl"; - UTIL_PrecacheSound("materials/metal/bustmetal1.wav"); - UTIL_PrecacheSound("materials/metal/bustmetal2.wav"); - break; - case AirDuct: - pGibName = "models/gibs/vent.mdl"; - UTIL_PrecacheSound("materials/metal/bustmetal1.wav"); - UTIL_PrecacheSound("materials/metal/bustmetal2.wav"); - break; - case CeilingTile: - pGibName = "models/gibs/ceiling.mdl"; - UTIL_PrecacheSound("materials/ceil/bustceiling1.wav"); - UTIL_PrecacheSound("materials/ceil/bustceiling2.wav"); - break; - case Wood: - pGibName = "models/gibs/wood.mdl"; - UTIL_PrecacheSound("materials/wood/bustcrate1.wav"); - UTIL_PrecacheSound("materials/wood/bustcrate2.wav"); - break; - case None: - default: - if( pev->health > 0 ) // mapmaker forget set material ? - { - DevMsg("\n======/Xash SmartField System/======\n\n"); - DevMsg("Please set material for %s,\n", STRING(pev->classname)); - DevMsg("if we want make this breakable\n"); - } - break; - } - - MaterialSoundPrecache( m_Material ); - if(IsBreakable( )) - { - if( !FStringNull( m_iGibModel ) || !FStringNull( pGibName )) - m_idShard = UTIL_PrecacheModel( m_iGibModel, pGibName ); // precache model - if( m_iSpawnObject ) UTIL_PrecacheEntity( m_iSpawnObject ); - } - UTIL_PrecacheModel( pev->model ); // can use *.mdl for any brush -} - -void CBaseBrush :: DamageSound( void ) -{ - float fvol; - int pitch; - - if (RANDOM_LONG(0,2)) pitch = PITCH_NORM; - else pitch = 95 + RANDOM_LONG(0,34); - - fvol = RANDOM_FLOAT(m_flVolume/1.5, m_flVolume); - - switch (m_Material) - { - case None: break; - case Bones: - case Flesh: - DAMAGE_SOUND(pSoundsFlesh, fvol, pitch ); - break; - case CinderBlock: - case Concrete: - case Rocks: - DAMAGE_SOUND(pSoundsCrete, fvol, pitch ); - break; - case Computer: - case Glass: - case UnbreakableGlass: - DAMAGE_SOUND(pSoundsGlass, fvol, pitch ); - break; - case MetalPlate: - case AirDuct: - case Metal: - DAMAGE_SOUND(pSoundsMetal, fvol, pitch ); - break; - case CeilingTile: - DAMAGE_SOUND(pSoundsCeil, fvol, pitch ); - break; - case Wood: - DAMAGE_SOUND(pSoundsWood, fvol, pitch ); - break; - default: break; - } -} - -void CBaseBrush::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - switch( m_Material )//apply effects for some materials (may be extended in future) - { - case Computer: - { - if(RANDOM_LONG(0,1))UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark5.wav", flVolume, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark6.wav", flVolume, ATTN_NORM); break; - } - } - break; - case Glass: - { - if(pev->health == 0)//unbreakable glass - { - if( RANDOM_LONG(0,1))UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - UTIL_DecalTrace(ptr, DECAL_BPROOF1); - } - else UTIL_DecalTrace(ptr, DECAL_GLASSBREAK1 + RANDOM_LONG(0, 2));//breakable glass - } - break; - case UnbreakableGlass: - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - break; - } - CBaseLogic::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -int CBaseBrush :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecTemp; - - if ( pevAttacker == pevInflictor ) - { - vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - if((pevAttacker->flags & FL_CLIENT) && (pev->spawnflags & SF_BREAK_CROWBAR) && (bitsDamageType & DMG_CLUB)) - flDamage = pev->health; //old valve flag - } - else vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - - if (!IsBreakable()) - { - DamageSound(); - return 0; - } - // Breakables take double damage from the crowbar - if ( bitsDamageType & DMG_CLUB ) flDamage *= 1.2; - else if( bitsDamageType & DMG_CRUSH ) flDamage *= 2; - else if( bitsDamageType & DMG_BLAST ) flDamage *= 3; - else if( bitsDamageType & DMG_BULLET && m_Material == Glass )flDamage *= 0.5; - else if( bitsDamageType & DMG_BULLET && m_Material == Wood )flDamage *= 0.7; - else flDamage = 0; //don't give any other damage - - DmgType = bitsDamageType;//member damage type - - g_vecAttackDir = vecTemp.Normalize(); - pev->health -= flDamage; - - if (pev->health <= 0) - { - Killed( pevAttacker, GIB_NORMAL ); - Die(); - return 0; - } - DamageSound(); - - return 1; -} - -void CBaseBrush :: Blocked( CBaseEntity *pOther ) -{ - if(m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE)//tell parent - m_pParent->Blocked( pOther ); - - if(!pOther->IsPlayer() && !pOther->IsMonster())//crash breakable - { - if(IsBreakable())TakeDamage( pev, pev, 5, DMG_CRUSH ); - } -} - -BOOL CBaseBrush :: IsBreakable( void ) -{ - return (pev->health > 0 && m_Material != UnbreakableGlass); -} - -void CBaseBrush::Die( void ) -{ - Vector vecSpot, vecVelocity; - char cFlag = 0; - int pitch, soundbits = NULL; - float fvol; - - pitch = 95 + RANDOM_LONG( 0, 29 ); - if( pitch > 97 && pitch < 103 ) pitch = PITCH_NORM; - - fvol = RANDOM_FLOAT(0.85, 1.0) + (abs( pev->health ) / 100.0); - if( fvol > 1.0 ) fvol = 1.0; - - switch (m_Material) - { - case None: break; //just in case - case Bones: - case Flesh: - if(RANDOM_LONG(0,1) ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/flesh/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); - else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/flesh/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch); - cFlag = BREAK_FLESH; - soundbits = bits_SOUND_MEAT; - break; - case CinderBlock: - case Concrete: - case Rocks: - if(RANDOM_LONG(0,1) ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/crete/bustcrete1.wav", fvol, ATTN_NORM, 0, pitch); - else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/crete/bustcrete2.wav", fvol, ATTN_NORM, 0, pitch); - cFlag = BREAK_CONCRETE; - soundbits = bits_SOUND_WORLD; - break; - case Computer: - case Metal: - case AirDuct: - case MetalPlate: - if(RANDOM_LONG(0,1) ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/metal/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); - else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/metal/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch); - cFlag = BREAK_METAL; - soundbits = bits_SOUND_WORLD; - break; - case Glass: - if( RANDOM_LONG(0,1) ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/glass/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); - else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/glass/bustglass2.wav", fvol, ATTN_NORM, 0, pitch); - cFlag = BREAK_GLASS; - soundbits = bits_SOUND_WORLD; - break; - - case Wood: - if( RANDOM_LONG(0,1) ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/wood/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); - else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/wood/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch); - cFlag = BREAK_WOOD; - soundbits = bits_SOUND_WORLD; - break; - case CeilingTile: - if( RANDOM_LONG(0,1) ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/ceil/bustceiling1.wav",fvol, ATTN_NORM, 0, pitch); - else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/ceil/bustceiling1.wav",fvol, ATTN_NORM, 0, pitch); - cFlag = BREAK_CONCRETE; - soundbits = bits_SOUND_GARBAGE; - break; - } - - if (DmgType & DMG_CLUB)//direction from crowbar - vecVelocity = g_vecAttackDir * clamp(pev->dmg * -10, -1024, 1024); - else vecVelocity = UTIL_RandomVector() * clamp(pev->dmg * 10, 1, 240); - - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - float time = RANDOM_FLOAT(25, 100); - - if(soundbits) CSoundEnt::InsertSound(soundbits, pev->origin, 128, 0.5);//make noise for ai - SFX_MakeGibs( m_idShard, vecSpot, pev->size, vecVelocity, time, cFlag); - - //what the hell does this ? - UTIL_FindBreakable( this ); - - // If I'm getting removed, don't fire something that could fire myself - pev->targetname = 0; - - pev->solid = SOLID_NOT; - UTIL_FireTargets( pev->target, NULL, NULL, USE_TOGGLE ); - pev->target = 0; - SetThink( Remove ); - SetNextThink( 0.1 ); - - pev->effects |= EF_NODRAW; - pev->takedamage = DAMAGE_NO; - - //make explosion - if( m_iMagnitude ) UTIL_Explode( Center(), edict(), m_iMagnitude ); - if( m_iSpawnObject ) CBaseEntity::Create( (char *)STRING(m_iSpawnObject), Center(), pev->angles, edict() ); - - // Fire targets on break - - UTIL_Remove( this ); -} - -int CBaseBrush :: DamageDecal( int bitsDamageType ) -{ - if ( m_Material == Glass ) - return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2); - if ( m_Material == Glass && pev->health <= 0) - return DECAL_BPROOF1; - if ( m_Material == UnbreakableGlass ) - return DECAL_BPROOF1; - if ( m_Material == Wood ) - return DECAL_GUNSHOT1 + RANDOM_LONG(0,4); - if ( m_Material == Computer ) - return DECAL_BIGSHOT1 + RANDOM_LONG(0,4); - return CBaseEntity::DamageDecal( bitsDamageType ); -} - -//======================================================================= -// moving breakable brushes -//======================================================================= -//material moving sounds -const char *CPushable::pPushWood[] = -{ - "materials/wood/pushwood1.wav", - "materials/wood/pushwood2.wav", - "materials/wood/pushwood3.wav", -}; - -const char *CPushable::pPushFlesh[] = -{ - "materials/flesh/pushflesh1.wav", - "materials/flesh/pushflesh2.wav", - "materials/flesh/pushflesh3.wav", -}; -const char *CPushable::pPushMetal[] = -{ - "materials/metal/pushmetal1.wav", - "materials/metal/pushmetal2.wav", - "materials/metal/pushmetal3.wav", -}; -const char *CPushable::pPushCrete[] = -{ - "materials/crete/pushstone1.wav", - "materials/crete/pushstone2.wav", - "materials/crete/pushstone3.wav", -}; -const char *CPushable::pPushGlass[] = -{ - "materials/glass/pushglass1.wav", - "materials/glass/pushglass2.wav", - "materials/glass/pushglass3.wav", -}; -const char *CPushable::pPushCeil[] = -{ - "materials/ceil/ceiling1.wav", - "materials/ceil/ceiling2.wav", - "materials/ceil/ceiling3.wav", -}; - -void CPushable :: Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_PUSHSTEP; - pev->solid = SOLID_BBOX; - UTIL_SetModel( ENT(pev), pev->model ); - UTIL_SetSize( pev, pev->absmin, pev->absmax ); - - if (!m_flVolume)m_flVolume = 1.0;//just enable full volume - - //breacable brush (if mapmaker just set material - just play material sound) - if(m_Material != None) - pev->takedamage = DAMAGE_YES; - else pev->takedamage = DAMAGE_NO; - - pev->speed = MatFrictionTable( m_Material ); - SetBits( pev->flags, FL_FLOAT ); - pev->origin.z += 1; // Pick up off of the floor - UTIL_SetOrigin( this, pev->origin ); - - // Multiply by area of the box's cross-section (assume 1000 units^3 standard volume) - pev->skin = MatByoancyTable( pev, m_Material ); - pev->frags = 0; -} - -void CPushable :: Precache( void ) -{ - CBaseBrush::Precache(); - PushSoundPrecache( m_Material ); -} - -const char **CPushable::PushSoundList( Materials precacheMaterial, int &soundCount ) -{ - const char **pSoundList = NULL; - - switch ( precacheMaterial ) - { - case None: - soundCount = 0; - break; - case Bones: - case Flesh: - pSoundList = pPushFlesh; - soundCount = ARRAYSIZE(pPushFlesh); - break; - case CinderBlock: - case Concrete: - case Rocks: - pSoundList = pPushCrete; - soundCount = ARRAYSIZE(pPushCrete); - break; - case Computer: - case Glass: - pSoundList = pPushGlass; - soundCount = ARRAYSIZE(pPushGlass); - break; - case MetalPlate: - case AirDuct: - case Metal: - pSoundList = pPushMetal; - soundCount = ARRAYSIZE(pPushMetal); - break; - case CeilingTile: - pSoundList = pPushCeil; - soundCount = ARRAYSIZE(pPushCeil); - break; - case Wood: - pSoundList = pPushWood; - soundCount = ARRAYSIZE(pPushWood); - break; - default: - soundCount = 0; - break; - } - return pSoundList; -} - -void CPushable::PushSoundPrecache( Materials precacheMaterial ) -{ - const char **pPushList; - int i, soundCount = 0; - - pPushList = PushSoundList( precacheMaterial, soundCount ); - for ( i = 0; i < soundCount; i++ ) UTIL_PrecacheSound( (char *)pPushList[i] ); -} - -int CPushable::PlayPushSound( edict_t *pEdict, Materials soundMaterial, float volume ) -{ - const char **pPushList; - int soundCount = 0; - int m_lastPushSnd = 0; - - pPushList = PushSoundList( soundMaterial, soundCount ); - if ( soundCount ) - { - m_lastPushSnd = RANDOM_LONG(0, soundCount-1); - EMIT_SOUND( pEdict, CHAN_WEAPON, pPushList[ m_lastPushSnd ], volume, 1.0 ); - } - return m_lastPushSnd; -} - -void CPushable::StopPushSound( edict_t *pEdict, Materials soundMaterial, int m_lastPushSnd ) -{ - const char **pPushList; - int soundCount = 0; - - pPushList = PushSoundList( soundMaterial, soundCount ); - if ( soundCount ) STOP_SOUND( pEdict, CHAN_WEAPON, pPushList[ m_lastPushSnd ] ); -} - -void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if(useType == USE_SHOWINFO) - { - DEBUGHEAD; - } - else if ( pActivator && pActivator->IsPlayer() && pActivator->pev->velocity != g_vecZero ) - Move( pActivator, 0 ); -} - -void CPushable :: Touch( CBaseEntity *pOther ) -{ - if ( pOther == g_pWorld ) return; - Move( pOther, 1 ); -} - -void CPushable :: Move( CBaseEntity *pOther, int push ) -{ - entvars_t* pevToucher = pOther->pev; - int playerTouch = 0; - - // Is entity standing on this pushable ? - if ( FBitSet(pevToucher->flags, FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev ) - { - // Only push if floating - if ( pev->waterlevel > 0 && pev->watertype > CONTENTS_FLYFIELD ) - pev->velocity.z += pevToucher->velocity.z * 0.1; - return; - } - - - if ( pOther->IsPlayer() ) - { - // Don't push unless the player is pushing forward and NOT use (pull) - if ( push && !(pevToucher->button & (IN_FORWARD|IN_MOVERIGHT|IN_MOVELEFT|IN_BACK)) ) - return; - if ( !push && !(pevToucher->button & IN_BACK) ) - return; - playerTouch = 1; - } - - float factor; - - if ( playerTouch ) - { - // Don't push away from jumping/falling players unless in water - if( !(pevToucher->flags & FL_ONGROUND) ) - { - if ( pev->waterlevel < 1 || pev->watertype <= CONTENTS_FLYFIELD ) - return; - else factor = 0.1; - } - else factor = 1; - } - else factor = 0.25; - - if (!push) factor = factor*0.5; - - pev->velocity.x += pevToucher->velocity.x * factor; - pev->velocity.y += pevToucher->velocity.y * factor; - - float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y ); - if ( push && (length > MaxSpeed()) ) - { - pev->velocity.x = (pev->velocity.x * MaxSpeed() / length ); - pev->velocity.y = (pev->velocity.y * MaxSpeed() / length ); - } - if ( playerTouch ) - { - pevToucher->velocity.x = pev->velocity.x; - pevToucher->velocity.y = pev->velocity.y; - if ( (gpGlobals->time - pev->frags) > 0.7 ) - { - pev->frags = gpGlobals->time; - if ( length > 0 && FBitSet(pev->flags, FL_ONGROUND) ) - m_lastSound = PlayPushSound( edict(), m_Material, m_flVolume ); - else StopPushSound( edict(), m_Material, m_lastSound ); - } - } -} -LINK_ENTITY_TO_CLASS( func_pushable, CPushable ); \ No newline at end of file diff --git a/server/ents/basebrush.h b/server/ents/basebrush.h deleted file mode 100644 index a803b3ee..00000000 --- a/server/ents/basebrush.h +++ /dev/null @@ -1,210 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// basebrush.h - base for all brush -// entities. -//======================================================================= -#ifndef BASEBRUSH_H -#define BASEBRUSH_H - -//ANY BRUSH MAY BE SET MATERIAL -typedef enum { - Glass = 0, //glass.mdl - Wood, //wood.mdl - Metal, //metal.mdl - Flesh, //flesh.mdl - CinderBlock, //cinder.mdl - CeilingTile, //ceiling.mdl - Computer, //computer.mdl - UnbreakableGlass, //galss.mdl - Rocks, //rock.mdl - Bones, //bones.mdl - Concrete, //concrete.mdl - MetalPlate, //metalplate.mdl - AirDuct, //vent.mdl - None, //very strange pos - LastMaterial, //just in case -}Materials; - -//gibs physics -typedef enum { - Bounce = 0, // bounce at collision - Noclip, // no collisions - Sticky, // sticky physic - Fly, // fly - Toss, // toss - WalkStep, // monsters walk -} Physics; - -static float MatFrictionTable( Materials mat) -{ - float friction = 0; - - switch(mat) - { - case CinderBlock: - case Concrete: - case Rocks: friction = 300; break; - case Glass: friction = 200; break; - case MetalPlate: - case Metal: friction = 60; break; - case Wood: friction = 250; break; - case None: - default: friction = 100; break; - } - return friction; -} - -static float MatByoancyTable( entvars_t *pev, Materials mat) -{ - float byoancy = 0; - - switch(mat) - { - case CinderBlock: - case Concrete: - case Rocks: byoancy = 0; break; - case Glass: byoancy = 5; break; - case MetalPlate: - case Metal: byoancy = 1; break; - case Wood: byoancy = 30; break; - case None: - default: byoancy = 100; break; - } - return ( byoancy * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005; -} - -static float MatMassTable( entvars_t *pev, Materials mat) -{ - float mass = 0; - - switch(mat) - { - case CinderBlock: - case Concrete: - case Rocks: mass = 2; break; - case Glass: mass = 1.2; break; - case MetalPlate: - case Metal: mass = 1.5; break; - case Wood: mass = 0.8; break; - case None: - default: mass = 1; break; - } - return (pev->size.Length() * mass); -} - -static float MatVolume( Materials mat ) -{ - float volume = 0; - switch(mat) - { - case None: volume = 0.9; //unbreakable - case Bones: //bones.mdl - case Flesh: volume = 0.2; break; //flesh.mdl - case CinderBlock: //cinder.mdl - case Concrete: //concrete.mdl - case Rocks: volume = 0.25; break; //rock.mdl - case Computer: //computer.mdl - case Glass: volume = 0.3; break; //glass.mdl - case MetalPlate: //metalplate.mdl - case Metal: //metal.mdl - case AirDuct: volume = 0.1; break; //vent.mdl - case CeilingTile: //ceiling.mdl - case Wood: volume = 0.15; break; //wood.mdl - default: volume = 0.2; break; - } - - return volume; -} - -extern DLL_GLOBAL Vector g_vecAttackDir; -#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) - -class CBaseBrush : public CBaseLogic -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - - void Blocked( CBaseEntity *pOther ); - virtual void AxisDir( void ); - virtual 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 DamageDecal( int bitsDamageType ); - - BOOL IsBreakable( void ); - - void EXPORT Die( void ); - virtual CBaseBrush *MyBrushPointer( void ) { return this; } - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - static TYPEDESCRIPTION m_SaveData[]; - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static void MaterialSoundPrecache( Materials precacheMaterial ); - static void PlayRandomSound( edict_t *pEdict, Materials soundMaterial, float volume ); - static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount ); - - static const char *pSoundsWood[]; - static const char *pSoundsFlesh[]; - static const char *pSoundsMetal[]; - static const char *pSoundsCrete[]; - static const char *pSoundsGlass[]; - static const char *pSoundsCeil[]; - - //spawnobject name - static const char *pSpawnObjects[]; - - void DamageSound( void ); - - Materials m_Material; - CBasePlayer* m_pController; // player pointer - Vector m_vecPlayerPos; // player position - int m_iMoveSound; // move sound or preset - int m_iStartSound; // start sound or preset - int m_iStopSound; // stop sound or preset - int m_idShard; // index of gibs - int m_iMagnitude; // explosion magnitude - int m_iSpawnObject; // spawnobject name - int m_iGibModel; // custom gib model - int DmgType; // temp container for right calculate damage - float m_flVolume; // moving brushes has volume of move sound - float m_flBlockedTime; // don't save this - float m_flRadius; // sound radius or pendulum radius - float m_flAccel; // declared here because rotating brushes use this - float m_flDecel; // declared here because rotating brushes use this - int m_pitch; // sound pitch -}; - -class CPushable : public CBaseBrush -{ -public: - void Spawn ( void ); - void Precache( void ); - void Touch ( CBaseEntity *pOther ); - void Move( CBaseEntity *pMover, int push ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int ObjectCaps( void ) { return (CBaseBrush :: ObjectCaps() | FCAP_CONTINUOUS_USE); } - virtual BOOL IsPushable( void ) { return TRUE; } - - inline float MaxSpeed( void ) { return pev->speed; } - - static const char *pPushWood[]; - static const char *pPushFlesh[]; - static const char *pPushMetal[]; - static const char *pPushCrete[]; - static const char *pPushGlass[]; - static const char *pPushCeil[]; //fixme - - static void PushSoundPrecache( Materials precacheMaterial ); - static int PlayPushSound( edict_t *pEdict, Materials soundMaterial, float volume ); - static void StopPushSound( edict_t *pEdict, Materials soundMaterial, int m_lastPushSnd ); - static const char **PushSoundList( Materials precacheMaterial, int &soundCount ); - - int m_lastSound; // no need to save/restore, just keeps the same sound from playing twice in a row -}; - -#include "basemover.h" - -#endif // BASEBRUSH_H diff --git a/server/ents/baseentity.cpp b/server/ents/baseentity.cpp deleted file mode 100644 index 3f6e6fbc..00000000 --- a/server/ents/baseentity.cpp +++ /dev/null @@ -1,921 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// baseentity.cpp - base class -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "saverestore.h" -#include "client.h" -#include "nodes.h" -#include "decals.h" -#include "gamerules.h" -#include "game.h" -#include "damage.h" -#include "defaults.h" -#include "bullets.h" - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern DLL_GLOBAL Vector g_vecAttackDir; -extern void SetObjectCollisionBox( entvars_t *pev ); -extern BOOL NewLevel; -extern CGraph WorldGraph; - -//======================================================================= -// decent mechanisms -//======================================================================= -void CBaseEntity::DontThink( void ) -{ - m_fNextThink = 0; - if ( m_pParent == NULL && m_pChild == NULL ) - { - pev->nextthink = 0; - m_fPevNextThink = 0; - } -} - -void CBaseEntity :: SetEternalThink( void ) -{ - if ( pev->movetype == MOVETYPE_PUSH ) - { - pev->nextthink = pev->ltime + 1E6; - m_fPevNextThink = pev->nextthink; - } - CBaseEntity *pChild; - for ( pChild = m_pChild; pChild != NULL; pChild = pChild->m_pNextChild ) - pChild->SetEternalThink( ); -} - -void CBaseEntity :: SetNextThink( float delay, BOOL correctSpeed ) -{ - if ( m_pParent || m_pChild ) - { - if ( pev->movetype == MOVETYPE_PUSH ) - m_fNextThink = pev->ltime + delay; - else m_fNextThink = gpGlobals->time + delay; - - SetEternalThink( ); - UTIL_MarkChild( this, correctSpeed, FALSE ); - } - else - { - // set nextthink as normal. - if ( pev->movetype == MOVETYPE_PUSH ) - pev->nextthink = pev->ltime + delay; - else pev->nextthink = gpGlobals->time + delay; - m_fPevNextThink = m_fNextThink = pev->nextthink; - } -} - -void CBaseEntity :: AbsoluteNextThink( float time, BOOL correctSpeed ) -{ - if ( m_pParent || m_pChild ) - { - m_fNextThink = time; - SetEternalThink( ); - UTIL_MarkChild( this, correctSpeed, FALSE ); - } - else - { - // set nextthink as normal. - pev->nextthink = time; - m_fPevNextThink = m_fNextThink = pev->nextthink; - } -} - -void CBaseEntity :: ThinkCorrection( void ) -{ - if ( pev->nextthink != m_fPevNextThink ) - { - m_fNextThink += pev->nextthink - m_fPevNextThink; - m_fPevNextThink = pev->nextthink; - } -} - -//======================================================================= -// set parent (void ) dinamically link parents -//======================================================================= -void CBaseEntity :: SetParent( int m_iNewParent, int m_iAttachment ) -{ - if( !m_iNewParent ) // unlink entity from chain - { - ResetParent(); - return; - } - - CBaseEntity* pParent; - - if(!m_iAttachment) //try to extract aiment from name - { - char *name = (char*)STRING(m_iNewParent); - for (char *c = name; *c; c++) - { - if (*c == '.') - { - m_iAttachment = atoi(c+1); - name[strlen(name)-2] = 0; - pParent = UTIL_FindEntityByTargetname( NULL, name); - SetParent( pParent, m_iAttachment); - return; - } - } - } - pParent = UTIL_FindEntityByTargetname( NULL, STRING(m_iNewParent)); - SetParent( pParent, m_iAttachment ); -} - -//======================================================================= -// set parent main function -//======================================================================= -void CBaseEntity :: SetParent( CBaseEntity* pParent, int m_iAttachment ) -{ - m_pParent = pParent; - - if( !m_pParent ) - { - ALERT( at_console, "=========/Xash Parent System Info:/=========\n" ); - if( pev->targetname ) - ALERT( at_warning, "Not found parent for %s with name %s\n", STRING( pev->classname ), STRING( pev->targetname )); - else ALERT( at_warning, "Not found parent for %s\n", STRING( pev->classname )); - ResetParent(); // lose parent or not found parent - return; - } - - // check for himself parent - if( m_pParent == this ) - { - ALERT( at_console, "=========/Xash Parent System Info:/=========\n"); - if( pev->targetname ) ALERT( at_error, "%s with name %s has illegal parent\n", STRING(pev->classname), STRING(pev->targetname) ); - else ALERT( at_error, "%s has illegal parent\n", STRING(pev->classname) ); - SHIFT; - ResetParent();//clear parent - return; - } - - CBaseEntity *pCurChild = m_pParent->m_pChild; - while ( pCurChild ) //check that this entity isn't already in the list of children - { - if( pCurChild == this ) break; - pCurChild = pCurChild->m_pNextChild; - } - - if( !pCurChild ) - { - m_pNextChild = m_pParent->m_pChild; // may be null: that's fine by me. - m_pParent->m_pChild = this; - - if( m_iAttachment ) - { - if( pFlags & PF_POINTENTITY || pev->flags & FL_MONSTER ) - { - pev->colormap = ((pev->colormap & 0xFF00)>>8) | m_iAttachment; - pev->aiment = m_pParent->edict(); - pev->movetype = MOVETYPE_FOLLOW; - } - else //error - { - ALERT(at_console, "=========/Xash Parent System Info:/=========\n"); - if( pev->targetname ) - ALERT( at_error, "%s with name %s not following with aiment %d!(yet)\n", STRING(pev->classname), STRING(pev->targetname), m_iAttachment ); - else ALERT( at_error, "%s not following with aiment %d!(yet)\n", STRING(pev->classname), m_iAttachment ); - SHIFT; - } - return; - } - else//appllayed to origin - { - if (pev->movetype == MOVETYPE_NONE) - { - if (pev->solid == SOLID_BSP) - pev->movetype = MOVETYPE_PUSH; - else pev->movetype = MOVETYPE_NOCLIP; - SetBits (pFlags, PF_MOVENONE);//member movetype - } - if(m_pParent->pev->movetype == MOVETYPE_WALK)//parent is walking monster? - { - SetBits (pFlags, PF_POSTORG);//copy pos from parent every frame - pev->solid = SOLID_NOT;//set non solid - } - pParentOrigin = m_pParent->pev->origin; - pParentAngles = m_pParent->pev->angles; - } - - if (m_pParent->m_vecSpawnOffset != g_vecZero) - { - UTIL_AssignOrigin(this, pev->origin + m_pParent->m_vecSpawnOffset); - m_vecSpawnOffset = m_vecSpawnOffset + m_pParent->m_vecSpawnOffset; - } - OffsetOrigin = pev->origin - pParentOrigin; - OffsetAngles = pev->angles - pParentAngles; - - if((m_pParent->pFlags & PF_ANGULAR && OffsetOrigin != g_vecZero) || m_pParent->pFlags & PF_POINTENTITY) - { - SetBits (pFlags, PF_POSTORG);//magic stuff - //GetPInfo( this ); - } - - if(g_serveractive)//maybe parent is moving ? - { - pev->velocity += m_pParent->pev->velocity; - pev->avelocity += m_pParent->pev->avelocity; - } - } -} - -//======================================================================= -// reset parent (void ) dinamically unlink parents -//======================================================================= -void CBaseEntity :: ResetParent( void ) -{ - if( pFlags & PF_MOVENONE ) // this entity was static e.g. func_wall - { - ClearBits( pFlags, PF_MOVENONE ); - pev->movetype = MOVETYPE_NONE; - } - - if( !g_pWorld ) return; //??? - - CBaseEntity* pTemp; - - for( pTemp = g_pWorld; pTemp->m_pLinkList != NULL; pTemp = pTemp->m_pLinkList ) - { - if( this == pTemp->m_pLinkList ) - { - pTemp->m_pLinkList = this->m_pLinkList; // save pointer - this->m_pLinkList = NULL; - break; - } - } - - if ( m_pParent ) - { - pTemp = m_pParent->m_pChild; - - if ( pTemp == this ) - { - m_pParent->m_pChild = this->m_pNextChild; - } - else - { - while ( pTemp->m_pNextChild ) - { - if ( pTemp->m_pNextChild == this ) - { - pTemp->m_pNextChild = this->m_pNextChild; - break; - } - pTemp = pTemp->m_pNextChild; - } - } - } - - if (m_pNextChild) - { - CBaseEntity* pCur = m_pChild; - CBaseEntity* pNext; - while (pCur != NULL) - { - pNext = pCur->m_pNextChild; - //bring children to a stop - UTIL_SetChildVelocity (pCur, g_vecZero, MAX_CHILDS); - UTIL_SetChildAvelocity(pCur, g_vecZero, MAX_CHILDS); - pCur->m_pParent = NULL; - pCur->m_pNextChild = NULL; - pCur = pNext; - } - } -} - -//======================================================================= -// setup physics (execute once at spawn) -//======================================================================= -void CBaseEntity :: SetupPhysics( void ) -{ - // rebuild all parents - if ( pFlags & PF_LINKCHILD ) LinkChild( this ); - - if ( gpGlobals->changelevel ) - m_physinit = FALSE; // rebuild parents on next level - - if ( m_physinit ) return; - SetParent(); //set all parents - m_physinit = true; - - if ( !gpGlobals->changelevel ) - { - PostSpawn();//post spawn - } -} - -void CBaseEntity :: RestorePhysics( void ) -{ - if( m_iParent ) SetParent(); -} - -void CBaseEntity :: ClearPointers( void ) -{ - m_pParent = NULL; - m_pChild = NULL; - m_pNextChild = NULL; - m_pLinkList = NULL; -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target vector -//========================================================= -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) -{ - TraceResult tr; - Vector vecLookerOrigin; - - vecLookerOrigin = EyePosition(); // look through the caller's 'eyes' - - UTIL_TraceLine( vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, ENT( pev ), &tr ); - - if (tr.flFraction != 1.0) - return FALSE; - return TRUE;// line of sight is valid. -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target -//========================================================= -BOOL CBaseEntity :: FVisible( CBaseEntity *pEntity ) -{ - TraceResult tr; - Vector vecLookerOrigin; - Vector vecTargetOrigin; - - if( FBitSet( pEntity->pev->flags, FL_NOTARGET )) - return FALSE; - - // don't look through water - if(( pev->waterlevel != 3 && pEntity->pev->waterlevel == 3 ) || ( pev->waterlevel == 3 && pEntity->pev->waterlevel != 3 )) - return FALSE; - - vecLookerOrigin = pev->origin + pev->view_ofs; // look through the caller's 'eyes' - vecTargetOrigin = pEntity->EyePosition(); - - UTIL_TraceLine( vecLookerOrigin, vecTargetOrigin, ignore_monsters, ignore_glass, ENT( pev ), &tr ); - - if( tr.flFraction != 1.0 && tr.pHit != ENT( pEntity->pev )) - return FALSE; - return TRUE; -} - -//======================================================================= -// fire bullets -//======================================================================= -void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) -{ - static int tracerCount; - int tracer; - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - if ( pevAttacker == NULL ) - pevAttacker = pev; // the default attacker is ourselves - - ClearMultiDamage(); - gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB; - - for (ULONG iShot = 1; iShot <= cShots; iShot++) - { - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT( -0.5f, 0.5f ) + RANDOM_FLOAT( -0.5f, 0.5f ); - y = RANDOM_FLOAT( -0.5f, 0.5f ) + RANDOM_FLOAT( -0.5f, 0.5f ); - z = x*x+y*y; - } while ( z > 1 ); - - Vector vecDir = vecDirShooting + x * vecSpread.x * vecRight + y * vecSpread.y * vecUp; - Vector vecEnd; - - vecEnd = vecSrc + vecDir * flDistance; - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( pev )/*pentIgnore*/, &tr ); - - tracer = 0; - if( iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0 ) - { - Vector vecTracerSrc; - - if ( IsPlayer() ) - { - // adjust tracer position for player - vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16; - } - else - { - vecTracerSrc = vecSrc; - } - - if ( iTracerFreq != 1 ) // guns that always trace also always decal - tracer = 1; - switch( iBulletType ) - { - case BULLET_MP5: - case BULLET_9MM: - case BULLET_12MM: - case BULLET_357: - case BULLET_556: - case BULLET_762: - case BULLET_BUCKSHOT: - default: - MESSAGE_BEGIN( MSG_PAS, gmsg.TempEntity, vecTracerSrc ); - WRITE_BYTE( TE_TRACER ); - WRITE_COORD( vecTracerSrc.x ); - WRITE_COORD( vecTracerSrc.y ); - WRITE_COORD( vecTracerSrc.z ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - MESSAGE_END(); - break; - } - } - // do damage, paint decals - if ( tr.flFraction != 1.0 ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if ( iDamage ) - { - pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - else switch(iBulletType) - { - default: - case BULLET_9MM: - pEntity->TraceAttack(pevAttacker, _9MM_DMG, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_MP5: - pEntity->TraceAttack(pevAttacker, _MP5_DMG, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_12MM: - pEntity->TraceAttack(pevAttacker, _12MM_DMG, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_556: - pEntity->TraceAttack(pevAttacker, _556_DMG, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_762: - pEntity->TraceAttack(pevAttacker, _762_DMG, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_BUCKSHOT: - pEntity->TraceAttack(pevAttacker, BUCKSHOT_DMG, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_357: - pEntity->TraceAttack(pevAttacker, _357_DMG, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_NONE: // FIX - pEntity->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB); - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - // only decal glass - if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0) - { - UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); - } - - break; - } - } - // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); - } - ApplyMultiDamage(pev, pevAttacker); -} - -//======================================================================= -// traceing operations -//======================================================================= -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if (BloodColor() == DONT_BLEED) - return; - - if (flDamage == 0) - return; - - if (!(bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR))) - return; - - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - float flNoise; - int cCount; - int i; - - if (flDamage < 10) - { - flNoise = 0.1; - cCount = 1; - } - else if (flDamage < 25) - { - flNoise = 0.2; - cCount = 2; - } - else - { - flNoise = 0.3; - cCount = 4; - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr); - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} - -void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - - if ( pev->takedamage ) - { - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - - int blood = BloodColor(); - - if ( blood != DONT_BLEED ) - { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - } - } -} - -//======================================================================= -// take damage\health -//======================================================================= -int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) -{ - if( !pev->takedamage ) return 0; - if ( pev->health >= pev->max_health ) return 0; - - pev->health += flHealth; - pev->health = min(pev->health, pev->max_health); - - return 1; -} - -int CBaseEntity :: TakeArmor( float flArmor, int suit ) -{ - if(!pev->takedamage) return 0; - if (pev->armorvalue >= MAX_NORMAL_BATTERY) return 0; - - pev->armorvalue += flArmor; - pev->armorvalue = min(pev->armorvalue, MAX_NORMAL_BATTERY); - - return 1; -} - -int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecTemp; - - if (!pev->takedamage) return 0; - - // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. - // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). - if ( pevAttacker == pevInflictor ) - { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); - } - else // an actual missile was involved. - { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); - } - - // this global is still used for glass and other non-monster killables, along with decals. - g_vecAttackDir = vecTemp.Normalize(); - - // save damage based on the target's armor level - - // figure momentum add (don't let hurt brushes or other triggers move player) - if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) ) - { - Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; - vecDir = vecDir.Normalize(); - - float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; - - if (flForce > 1000.0) flForce = 1000.0; - pev->velocity = pev->velocity + vecDir * flForce; - } - - // do the damage - pev->health -= flDamage; - if (pev->health <= 0) - { - Killed( pevAttacker, GIB_NORMAL ); - return 0; - } - return 1; -} - -int CBaseEntity :: DamageDecal( int bitsDamageType ) -{ - if ( pev->rendermode == kRenderTransAlpha ) - return -1; - - if ( pev->rendermode != kRenderNormal ) - return DECAL_BPROOF1; - - return DECAL_GUNSHOT1 + RANDOM_LONG(0, 4); -} - -//======================================================================= -// killed/create operations -//======================================================================= -CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) -{ - edict_t *pent; - int istr = ALLOC_STRING(szName); - CBaseEntity *pEntity; - - pent = CREATE_NAMED_ENTITY( istr ); - if( FNullEnt( pent )) return NULL; - - pEntity = Instance( pent ); - pEntity->SetObjectClass( ); - pEntity->pev->owner = pentOwner; - pEntity->pev->origin = vecOrigin; - pEntity->pev->angles = vecAngles; - DispatchSpawn( pEntity->edict() ); - - return pEntity; -} - -CBaseEntity * CBaseEntity::CreateGib( char *szName, char *szModel ) -{ - edict_t *pent; - CBaseEntity *pEntity; - string_t model = MAKE_STRING( szModel ); - int istr = ALLOC_STRING(szName); - - pent = CREATE_NAMED_ENTITY( istr ); - if( FNullEnt( pent )) return NULL; - - pEntity = Instance( pent ); - DispatchSpawn( pEntity->edict() ); - pEntity->SetObjectClass( ED_NORMAL ); - - if( !FStringNull( model )) - { - UTIL_SetModel( pEntity->edict(), szModel ); - Msg( "szModel %s\n", szModel ); - } - return pEntity; -} - -void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->takedamage = DAMAGE_NO; - pev->deadflag = DEAD_DEAD; - UTIL_Remove( this ); -} - -void CBaseEntity::UpdateOnRemove( void ) -{ - ResetParent(); - - if ( FBitSet( pev->flags, FL_GRAPHED ) ) - { - for (int i = 0 ; i < WorldGraph.m_cLinks ; i++ ) - { - if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev ) - WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL; - } - } - if( pev->globalname ) gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD ); -} - -//======================================================================= -// three methods of remove entity -//======================================================================= -void CBaseEntity :: Remove( void ) -{ - UpdateOnRemove(); - if( pev->health > 0 ) - pev->health = 0; - REMOVE_ENTITY( ENT( pev )); -} - -void CBaseEntity :: PVSRemove( void ) -{ - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict()))) SetThink( Remove ); - SetNextThink( 0.1 ); -} - -void CBaseEntity :: Fadeout( void ) -{ - if (pev->rendermode == kRenderNormal) - { - pev->renderamt = 255; - pev->rendermode = kRenderTransTexture; - } - - pev->solid = SOLID_NOT; - pev->avelocity = g_vecZero; - - if ( pev->renderamt > 7 ) - { - pev->renderamt -= 7; - SetNextThink( 0.1 ); - } - else - { - pev->renderamt = 0; - SetNextThink( 0.2 ); - SetThink( Remove ); - } -} - -//======================================================================= -// global save\restore data -//======================================================================= -TYPEDESCRIPTION CBaseEntity::m_SaveData[] = -{ - DEFINE_FIELD( CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR ), - - //parent system saves - DEFINE_FIELD( CBaseEntity, m_iParent, FIELD_STRING ), - DEFINE_FIELD( CBaseEntity, m_pParent, FIELD_CLASSPTR ), - DEFINE_FIELD( CBaseEntity, m_pChild, FIELD_CLASSPTR ), - DEFINE_FIELD( CBaseEntity, m_pNextChild, FIELD_CLASSPTR ), - DEFINE_FIELD( CBaseEntity, OffsetOrigin, FIELD_VECTOR ), - DEFINE_FIELD( CBaseEntity, OffsetAngles, FIELD_VECTOR ), - DEFINE_FIELD( CBaseEntity, pFlags, FIELD_INTEGER ), - DEFINE_FIELD( CBaseEntity, m_physinit, FIELD_BOOLEAN ), - - //local child coordinates - DEFINE_FIELD( CBaseEntity, PostOrigin, FIELD_VECTOR ), - DEFINE_FIELD( CBaseEntity, PostAngles, FIELD_VECTOR ), - DEFINE_FIELD( CBaseEntity, PostVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CBaseEntity, PostAvelocity, FIELD_VECTOR ), - - //think time - DEFINE_FIELD( CBaseEntity, m_fNextThink, FIELD_TIME ), - DEFINE_FIELD( CBaseEntity, m_fPevNextThink, FIELD_TIME ), - - DEFINE_FIELD( CBaseEntity, m_iStyle, FIELD_INTEGER ), - DEFINE_FIELD( CBaseEntity, m_iClassType, FIELD_INTEGER ), - DEFINE_FIELD( CBaseEntity, m_iAcessLevel, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseEntity, m_pfnThink, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseEntity, m_pfnTouch, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseEntity, m_pfnUse, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseEntity, m_pfnBlocked, FIELD_FUNCTION ), -}; - -int CBaseEntity::Save( CSave &save ) -{ - ThinkCorrection(); - - if ( save.WriteEntVars( "ENTVARS", pev ) ) - { - if (pev->targetname) - return save.WriteFields( STRING(pev->targetname), "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - else return save.WriteFields( STRING(pev->classname ), "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - } - return 0; -} - -int CBaseEntity :: Restore( CRestore &restore ) -{ - int status; - - status = restore.ReadEntVars( "ENTVARS", pev ); - if( status ) status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE( m_SaveData )); - - // restore edict class here - SetObjectClass( m_iClassType ); - - if( pev->modelindex != 0 && !FStringNull( pev->model )) - { - Vector mins = pev->mins; - Vector maxs = pev->maxs; // Set model is about to destroy these - - UTIL_PrecacheModel( pev->model ); - UTIL_SetModel( ENT( pev ), pev->model ); - UTIL_SetSize( pev, mins, maxs ); - } - return status; -} - -//======================================================================= -// collisoin boxes -//======================================================================= -void CBaseEntity::SetObjectCollisionBox( void ) -{ - ::SetObjectCollisionBox( pev ); -} - -int CBaseEntity :: Intersects( CBaseEntity *pOther ) -{ - if ( pOther->pev->absmin.x > pev->absmax.x || - pOther->pev->absmin.y > pev->absmax.y || - pOther->pev->absmin.z > pev->absmax.z || - pOther->pev->absmax.x < pev->absmin.x || - pOther->pev->absmax.y < pev->absmin.y || - pOther->pev->absmax.z < pev->absmin.z ) - return FALSE; - return TRUE; -} - -//======================================================================= -// Dormant operations -//======================================================================= -void CBaseEntity :: MakeDormant( void ) -{ - SetBits( pev->flags, FL_DORMANT ); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - SetBits( pev->effects, EF_NODRAW ); - DontThink(); - UTIL_SetOrigin( this, pev->origin ); -} - -int CBaseEntity :: IsDormant( void ) -{ - return FBitSet( pev->flags, FL_DORMANT ); -} - -BOOL CBaseEntity :: IsInWorld( void ) -{ - if (pev->origin.x >= MAP_HALFSIZE) return FALSE; - if (pev->origin.y >= MAP_HALFSIZE) return FALSE; - if (pev->origin.z >= MAP_HALFSIZE) return FALSE; - if (pev->origin.x <= -MAP_HALFSIZE) return FALSE; - if (pev->origin.y <= -MAP_HALFSIZE) return FALSE; - if (pev->origin.z <= -MAP_HALFSIZE) return FALSE; - if (pev->velocity.x >= MAX_VELOCITY) return FALSE; - if (pev->velocity.y >= MAX_VELOCITY) return FALSE; - if (pev->velocity.z >= MAX_VELOCITY) return FALSE; - if (pev->velocity.x <= -MAX_VELOCITY) return FALSE; - if (pev->velocity.y <= -MAX_VELOCITY) return FALSE; - if (pev->velocity.z <= -MAX_VELOCITY) return FALSE; - - return TRUE; -} \ No newline at end of file diff --git a/server/ents/baseentity.h b/server/ents/baseentity.h deleted file mode 100644 index 174c3580..00000000 --- a/server/ents/baseentity.h +++ /dev/null @@ -1,335 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef BASEENTITY_H -#define BASEENTITY_H - -#include "entity_state.h" - -class CBaseEntity -{ -public: - // Constructor. Set engine to use C/C++ callback functions - // pointers to engine data - entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it - - // path corners - CBaseEntity *m_pGoalEnt;// path corner we are heading towards - CBaseEntity *m_pLink;// used for temporary link-list operations. - - float m_fNextThink; - float m_fPevNextThink; - float flTravelTime; // time to moving brushes - int m_iClassType; // edict classtype - int m_iStyle; - int m_iAcessLevel;// acess level for retinal sacners - - //=================================================================================================== - // Xash BaseEntity - //=================================================================================================== - - // Gets the interface to the collideable representation of the entity - virtual void SetModelIndex( int index ); - virtual int GetModelIndex( void ) const; - - // Returns a CBaseAnimating if the entity is derived from CBaseAnimating. - virtual CBaseAnimating* GetBaseAnimating() { return NULL; } - - void SetName( string_t newTarget ); - void SetParent( string_t newParent, CBaseEntity *pActivator ); - virtual void ChangeCamera( string_t newcamera ) {} - -public: - //=================================================================================================== - // Xash Parent System 0.2 beta - //=================================================================================================== - - Vector PostOrigin; //child postorigin - Vector PostAngles; //child postangles - Vector PostVelocity; //child postvelocity - Vector PostAvelocity; //child postavelocity - Vector OffsetOrigin; //spawn offset origin - Vector OffsetAngles; //spawn offset angles - Vector pParentAngles; //temp container - Vector pParentOrigin; //temp container - Vector m_vecSpawnOffset; //temp container - int pFlags; //xash flags - BOOL m_physinit; //physics initializator - - virtual void SetParent ( void ) { SetParent(m_iParent); } - void SetParent ( int m_iNewParent, int m_iAttachment = 0 ); - void SetParent ( CBaseEntity* pParent, int m_iAttachment = 0 ); - void ResetParent( void ); - - virtual void SetupPhysics( void ); // setup parent system and physics - - CBaseEntity *m_pParent; // pointer to parent entity - CBaseEntity *m_pChild; // pointer to children(may be this) - CBaseEntity *m_pNextChild; // link to next chlidren - CBaseEntity *m_pLinkList; // list of linked childrens - - string_t m_iParent;//name of parent - virtual void SetNextThink( float delay, BOOL correctSpeed = FALSE ); - virtual void AbsoluteNextThink( float time, BOOL correctSpeed = FALSE ); - void SetEternalThink( void ); - void DontThink( void ); - virtual void ThinkCorrection( void ); - - //phys metods - virtual void SetAngularImpulse( float impulse ){} - virtual void SetLinearImpulse( float impulse ) {} - - // initialization functions - virtual void Spawn( void ) { return; } - virtual void Precache( void ) { return; } - virtual void KeyValue( KeyValueData* pkvd) - { - if (FStrEq(pkvd->szKeyName, "parent")) - { - m_iParent = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "style")) - { - m_iStyle = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "angle")) - { - // quake legacy - if( pev->angles == g_vecZero ) - pev->angles[1] = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else pkvd->fHandled = FALSE; - } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return m_pParent?m_pParent->ObjectCaps()&FCAP_ACROSS_TRANSITION:FCAP_ACROSS_TRANSITION; } - virtual void Activate( void ) {} - virtual void PostActivate( void ) {} - virtual void PostSpawn( void ) {} - virtual void DesiredAction( void ) {} - virtual void StartMessage( CBasePlayer *pPlayer ) {} - virtual void SetObjectClass( int iClassType = ED_SPAWNED ) - { - m_iClassType = iClassType; - } - - virtual BOOL IsItem( void ) { return FALSE; } - virtual BOOL IsAmmo( void ) { return FALSE; } - virtual BOOL IsWeapon( void ) { return FALSE; } - - // Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box) - virtual void SetObjectCollisionBox( void ); - - void UTIL_AutoSetSize( void )//automatically set collision box - { - dstudiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t*)GET_MODEL_PTR( ENT(pev) ); - - if (pstudiohdr == NULL) - { - ALERT(at_console,"Unable to fetch model pointer!\n"); - return; - } - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - UTIL_SetSize(pev,pseqdesc[ pev->sequence ].bbmin,pseqdesc[ pev->sequence ].bbmax); - } - - // Classify - returns the type of group (e.g., "alien monster", or "human military" so that monsters - // on the same side won't attack each other, even if they have different classnames. - virtual int Classify ( void ) { return CLASS_NONE; }; - virtual void DeathNotice ( entvars_t *pevChild ) {}// monster maker children use this to tell the monster maker that they have died. - - - // global concept of "entities with states", so that state_watchers and - // mastership (mastery? masterhood?) can work universally. - virtual STATE GetState ( void ) { return STATE_OFF; }; - - // For team-specific doors in multiplayer, etc: a master's state depends on who wants to know. - virtual STATE GetState ( CBaseEntity* pEnt ) { return GetState(); }; - - static TYPEDESCRIPTION m_SaveData[]; - - virtual void ClearPointers( void ); - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual int TakeArmor( float flArmor, int suit = 0 ); - virtual int TakeItem( int iItem ) { return 0; } - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual int BloodColor( void ) { return DONT_BLEED; } - virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;} - virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;} - virtual CBaseBrush *MyBrushPointer( void ) { return NULL; } - virtual void AddPoints( int score, BOOL bAllowNegativeScore ) {} - virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ) {} - virtual BOOL AddPlayerItem( CBasePlayerWeapon *pItem ) { return 0; } - virtual BOOL RemovePlayerItem( CBasePlayerWeapon *pItem ) { return 0; } - virtual int GiveAmmo( int iAmount, char *szName, int iMax ) { return -1; }; - virtual float GetDelay( void ) { return 0; } - virtual int IsMoving( void ) { return pev->velocity != g_vecZero; } - virtual void RestorePhysics( void ); - virtual void OverrideReset( void ) {} - virtual int DamageDecal( int bitsDamageType ); - // This is ONLY used by the node graph to test movement through a door - virtual void SetToggleState( int state ) {} - virtual void StartSneaking( void ) {} - virtual void StopSneaking( void ) {} - virtual BOOL OnControls( entvars_t *pev ) { return FALSE; } - virtual BOOL IsSneaking( void ) { return FALSE; } - virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; } - virtual BOOL IsBSPModel( void ) { return pev->solid == SOLID_BSP || pev->movetype == MOVETYPE_PUSHSTEP; } - virtual BOOL ReflectGauss( void ) { return ( IsBSPModel() && !pev->takedamage ); } - virtual BOOL HasTarget( string_t targetname ) { return FStrEq(STRING(targetname), STRING(pev->targetname) ); } - virtual BOOL IsInWorld( void ); - virtual BOOL IsPlayer( void ) { return FALSE; } - virtual BOOL IsPushable( void ) { return FALSE; } - virtual BOOL IsMonster( void ) { return (pev->flags & FL_MONSTER ? TRUE : FALSE); } - virtual BOOL IsNetClient( void ) { return FALSE; } - virtual BOOL IsFuncScreen( void ) { return FALSE; } - virtual const char *TeamID( void ) { return ""; } - - virtual CBaseEntity *GetNext( void ) { return NULL; } - virtual CBaseEntity *GetPrev( void ) { return NULL; } - - // fundamental callbacks - void (CBaseEntity ::*m_pfnThink)(void); - void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther ); - void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther ); - - virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)(); }; - virtual void Touch( CBaseEntity *pOther ) { if (m_pfnTouch) (this->*m_pfnTouch)( pOther ); }; - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - if (m_pfnUse) (this->*m_pfnUse)( pActivator, pCaller, useType, value ); - } - virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); }; - - // allow engine to allocate instance data - void *operator new( size_t stAllocateBlock, entvars_t *pev ) - { - return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock); - }; - - // don't use this. -#if _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher - void operator delete(void *pMem, entvars_t *pev) - { - pev->flags |= FL_KILLME; - }; -#endif - - virtual void UpdateOnRemove( void ); - - // common member functions - void EXPORT Remove( void ); - void EXPORT Fadeout( void ); - void EXPORT PVSRemove( void ); - void EXPORT SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); } - - void FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL ); - - virtual CBaseEntity *Respawn( void ) { return NULL; } - - // Do the bounding boxes of these two intersect? - int Intersects( CBaseEntity *pOther ); - void MakeDormant( void ); - int IsDormant( void ); - BOOL IsLockedByMaster( void ) { return FALSE; } - - static CBaseEntity *Instance( edict_t *pent ) - { - if ( !pent ) pent = ENT(0); - CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent); - return pEnt; - } - - static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); } - static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); } - - CBaseMonster *GetMonsterPointer( entvars_t *pevMonster ) - { - CBaseEntity *pEntity = Instance( pevMonster ); - if ( pEntity ) return pEntity->MyMonsterPointer(); - return NULL; - } - CBaseMonster *GetMonsterPointer( edict_t *pentMonster ) - { - CBaseEntity *pEntity = Instance( pentMonster ); - if ( pEntity ) return pEntity->MyMonsterPointer(); - return NULL; - } - - - // Ugly code to lookup all functions to make sure they are exported when set. -#ifdef _DEBUG - void FunctionCheck( void *pFunction, char *name ) - { - if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) ) - ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction ); - } - - BASEPTR ThinkSet( BASEPTR func, char *name ) - { - m_pfnThink = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name ); - return func; - } - ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) - { - m_pfnTouch = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnTouch)))), name ); - return func; - } - USEPTR UseSet( USEPTR func, char *name ) - { - m_pfnUse = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name ); - return func; - } - ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) - { - m_pfnBlocked = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name ); - return func; - } - -#endif - // used by monsters that are created by the MonsterMaker - virtual void UpdateOwner( void ) { return; }; - static CBaseEntity *Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL ); - static CBaseEntity *CBaseEntity::CreateGib( char *szName, char *szModel ); - - virtual BOOL FBecomeProne( void ) {return FALSE;}; - edict_t *edict() { return ENT( pev ); }; - EOFFSET eoffset( ) { return OFFSET( pev ); }; - int entindex( ) { return ENTINDEX( edict() ); }; - - virtual Vector Center( ) { return (pev->absmax + pev->absmin) * 0.5; }; // center point of entity - virtual Vector EyePosition( ) { return pev->origin + pev->view_ofs; }; // position of eyes - virtual Vector EarPosition( ) { return pev->origin + pev->view_ofs; }; // position of ears - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ); }; // position to shoot at - - virtual int Illumination( ) { return GETENTITYILLUM( ENT( pev ) ); }; - - virtual BOOL FVisible ( CBaseEntity *pEntity ); - virtual BOOL FVisible ( const Vector &vecOrigin ); -}; - -inline void CBaseEntity::SetModelIndex( int index ) -{ - pev->modelindex = index; -} - -inline int CBaseEntity::GetModelIndex( void ) const -{ - return pev->modelindex; -} - -#endif //BASEENTITY_H \ No newline at end of file diff --git a/server/ents/basefunc.cpp b/server/ents/basefunc.cpp deleted file mode 100644 index e37cdbe8..00000000 --- a/server/ents/basefunc.cpp +++ /dev/null @@ -1,2360 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// basefunc.cpp - brush based entities: tanks, -// cameras, vehicles etc -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "sfx.h" -#include "decals.h" -#include "client.h" -#include "saverestore.h" -#include "gamerules.h" -#include "basebrush.h" -#include "defaults.h" -#include "player.h" - -//======================================================================= -// STATIC BRUSHES -//======================================================================= - -//======================================================================= -// func_wall - standard not moving wall. affect to physics -//======================================================================= -class CFuncWall : public CBaseBrush -{ -public: - void Spawn( void ); - void TurnOn( void ); - void TurnOff( void ); - void Precache( void ){ CBaseBrush::Precache(); } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); -LINK_ENTITY_TO_CLASS( func_static, CFuncWall ); -LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWall ); -LINK_ENTITY_TO_CLASS( func_illusionary, CFuncWall ); - -void CFuncWall :: Spawn( void ) -{ - CBaseBrush::Spawn(); - - if( FClassnameIs( pev, "func_illusionary" )) - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - UTIL_SetModel( ENT(pev), pev->model ); - - // Smart field system ® - if (!FStringNull( pev->angles ) && FStringNull( pev->origin )) - { - pev->angles = g_vecZero; - ALERT( at_console, "\n======/Xash SmartField System/======\n\n"); - ALERT( at_console, "Create origin brush for %s,\nif we want correctly set angles\n\n", STRING( pev->classname )); - } - pev->angles[1] = 0 - pev->angles[1]; - - if( pev->spawnflags & SF_START_ON ) - TurnOn(); - else TurnOff(); -} - -void CFuncWall :: TurnOff( void ) -{ - if(FClassnameIs(pev, "func_wall_toggle" )) - { - pev->solid = SOLID_NOT; - pev->effects |= EF_NODRAW; - UTIL_SetOrigin( this, pev->origin ); - } - else pev->frame = 0; - - m_iState = STATE_OFF; -} - -void CFuncWall :: TurnOn( void ) -{ - if(FClassnameIs(pev, "func_wall_toggle" )) - { - pev->solid = SOLID_BSP; - pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( this, pev->origin ); - } - else pev->frame = 1; - - m_iState = STATE_ON; -} - -void CFuncWall :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE ) - { - if( pev->frame ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) TurnOn(); - else if ( useType == USE_OFF ) TurnOff(); - else if ( useType == USE_SET ) // make wall invisible - { - pev->solid = SOLID_NOT; - pev->effects |= EF_NODRAW; - UTIL_SetOrigin( this, pev->origin ); - } - else if ( useType == USE_RESET ) // make wall visible - { - if(!( pev->spawnflags & SF_NOTSOLID )) - pev->solid = SOLID_BSP; - pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( this, pev->origin ); - } - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n" ); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "State: %s, Visible: %s\n", GetStringForState( GetState()), pev->effects & EF_NODRAW ? "No" : "Yes" ); - ALERT( at_console, "Contents: %s, Texture frame: %.f\n", GetContentsString( pev->skin ), pev->frame ); - } -} - -//======================================================================= -// func_breakable - generic breakable brush. -//======================================================================= -class CFuncBreakable : public CBaseBrush -{ -public: - void Spawn( void ); - void Precache( void ){ CBaseBrush::Precache(); } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( func_breakable, CFuncBreakable ); - -void CFuncBreakable :: Spawn( void ) -{ - CBaseBrush::Spawn(); - UTIL_SetModel( ENT( pev ), pev->model ); - - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY )) - pev->takedamage = DAMAGE_NO; - else pev->takedamage = DAMAGE_YES; -} - -void CFuncBreakable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsBreakable( )) - { - Die(); // simple huh ? - } -} - -//======================================================================= -// func_lamp - switchable brush light. -//======================================================================= -class CFuncLamp : public CBaseBrush -{ -public: - void Spawn( void ); - void Precache( void ){ CBaseBrush::Precache(); } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual 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 EXPORT Flicker( void ); - void Die( void ); -}; - -LINK_ENTITY_TO_CLASS( func_lamp, CFuncLamp ); - -void CFuncLamp :: Spawn( void ) -{ - m_Material = Glass; - CBaseBrush::Spawn(); - UTIL_SetModel( ENT( pev ), pev->model ); - - if( pev->spawnflags & SF_START_ON ) - Use( this, this, USE_ON, 0 ); - else Use( this, this, USE_OFF, 0 ); -} - -void CFuncLamp :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if(IsLockedByMaster( useType )) return; - if(m_iState == STATE_DEAD && useType != USE_SHOWINFO)return;//lamp is broken - - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_OFF) useType = USE_ON; - else useType = USE_OFF; - } - if (useType == USE_ON) - { - if(m_flDelay)//make flickering delay - { - pev->frame = 0;//light texture is on - m_iState = STATE_TURN_ON; - LIGHT_STYLE(m_iStyle, "mmamammmmammamamaaamammma"); - SetThink( Flicker ); - SetNextThink(m_flDelay); - } - else - { //instantly enable - m_iState = STATE_ON; - pev->frame = 0;//light texture is on - LIGHT_STYLE(m_iStyle, "k"); - UTIL_FireTargets( pev->target, this, this, USE_ON );//lamp enable - } - } - else if (useType == USE_OFF) - { - pev->frame = 1; // light texture is off - LIGHT_STYLE( m_iStyle, "a" ); - UTIL_FireTargets( pev->target, this, this, USE_OFF ); // lamp disable - m_iState = STATE_OFF; - } - else if ( useType == USE_SET ) - { - Die(); // broke lamp with sfx - } - else if ( useType == USE_RESET ) // broke lamp silent - { - pev->frame = 1; // light texture is off - LIGHT_STYLE( m_iStyle, "a" ); - m_iState = STATE_DEAD; - pev->health = 0; - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, Light style %d\n", GetStringForState( GetState()), m_iStyle ); - ALERT( at_console, "Texture frame: %.f. Health %.f\n", pev->frame, pev->health ); - } -} - -void CFuncLamp::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if(m_iState == STATE_DEAD) return; - const char *pTextureName; - Vector start = pevAttacker->origin + pevAttacker->view_ofs; - Vector end = start + vecDir * 1024; - edict_t *pWorld = ptr->pHit; - if ( pWorld )pTextureName = TRACE_TEXTURE( pWorld, start, end ); - if ( strstr( pTextureName, "+0~" ) || strstr( pTextureName, "~" )) // take damage only at light texture - { - UTIL_Sparks( ptr->vecEndPos ); - pev->oldorigin = ptr->vecEndPos;//save last point of damage - pev->takedamage = DAMAGE_YES;//inflict damage only at light texture - } - else pev->takedamage = DAMAGE_NO; - CBaseLogic::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} -int CFuncLamp::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( bitsDamageType & DMG_BLAST ) flDamage *= 3; - else if ( bitsDamageType & DMG_CLUB) flDamage *= 2; - else if ( bitsDamageType & DMG_SONIC ) flDamage *= 1.2; - else if ( bitsDamageType & DMG_SHOCK ) flDamage *= 10; // !!!! over voltage - else if ( bitsDamageType & DMG_BULLET) flDamage *= 0.5;// half damage at bullet - pev->health -= flDamage;//calculate health - - if ( pev->health <= 0 ) - { - Die(); - return 0; - } - CBaseBrush::DamageSound(); - - return 1; -} - -void CFuncLamp::Die( void ) -{ - // lamp is random choose die style - if( m_iState == STATE_OFF ) - { - pev->frame = 1; // light texture is off - LIGHT_STYLE( m_iStyle, "a" ); - DontThink(); - } - else - { // simple randomization - pev->impulse = RANDOM_LONG(1, 2); - SetThink( Flicker ); - SetNextThink( 0.1 + (RANDOM_LONG( 1, 2 ) * 0.1 )); - } - - m_iState = STATE_DEAD; // lamp is die - pev->health = 0; // set health to NULL - pev->takedamage = DAMAGE_NO; - UTIL_FireTargets( pev->target, this, this, USE_OFF ); // lamp broken - - switch ( RANDOM_LONG( 0, 1 )) - { - case 0: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "materials/glass/bustglass1.wav", 0.7, ATTN_IDLE ); break; - case 1: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "materials/glass/bustglass2.wav", 0.8, ATTN_IDLE ); break; - } - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - - // spawn glass gibs - SFX_MakeGibs( m_idShard, vecSpot, pev->size, g_vecZero, 50, BREAK_GLASS ); -} - -void CFuncLamp :: Flicker( void ) -{ - if ( m_iState == STATE_TURN_ON ) // flickering on enable - { - LIGHT_STYLE( m_iStyle, "k" ); - UTIL_FireTargets( pev->target, this, this, USE_ON );//Lamp enabled - m_iState = STATE_ON; - DontThink(); - return; - } - if ( pev->impulse == 1 ) // fadeout on break - { - pev->frame = 1; // light texture is off - LIGHT_STYLE( m_iStyle, "a" ); - SetThink( NULL ); - return; - } - if ( pev->impulse == 2 ) // broken flickering - { - //make different flickering - switch ( RANDOM_LONG( 0, 3 )) - { - case 0: LIGHT_STYLE(m_iStyle, "abcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); break; - case 1: LIGHT_STYLE(m_iStyle, "acaaabaaaaaaaaaaaaaaaaaaaaaaaaaaa"); break; - case 2: LIGHT_STYLE(m_iStyle, "aaafbaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); break; - case 3: LIGHT_STYLE(m_iStyle, "aaaaaaaaaaaaagaaaaaaaaacaaaacaaaa"); break; - } - pev->frags = RANDOM_FLOAT(0.5, 10); - UTIL_Sparks( pev->oldorigin ); - switch ( RANDOM_LONG( 0, 2 )) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "materials/spark1.wav", 0.4, ATTN_IDLE ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "materials/spark2.wav", 0.3, ATTN_IDLE ); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "materials/spark3.wav", 0.35, ATTN_IDLE ); break; - } - if( pev->frags > 6.5f ) pev->impulse = 1; // stop sparking obsolete - } - SetNextThink( pev->frags ); -} - -//======================================================================= -// func_conveyor - conveyor belt -//======================================================================= -class CFuncConveyor : public CBaseBrush -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void UpdateSpeed( float speed ); -}; -LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ); - -void CFuncConveyor :: Spawn( void ) -{ - SetObjectClass( ED_BSPBRUSH ); - - CBaseBrush::Spawn(); - UTIL_LinearVector( this ); // movement direction - - if( !m_pParent ) pev->flags |= FL_WORLDBRUSH; - UTIL_SetModel( ENT(pev), STRING( pev->model )); - - if( pev->spawnflags & SF_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->skin = 0; - } - - // smart field system ® - if( pev->speed == 0 ) pev->speed = 100; - pev->frags = pev->speed; // save initial speed - if( pev->spawnflags & SF_START_ON || FStringNull( pev->targetname )) - Use( this, this, USE_ON, 0 ); -} - -// HACKHACK -- This is ugly, but encode the speed in the rendercolor to avoid adding more data to the network stream -void CFuncConveyor :: UpdateSpeed( float speed ) -{ - // Encode it as an integer with 4 fractional bits - int speedCode = (int)(fabs(speed) * 16.0); - - if ( speed < 0 ) - pev->rendercolor.x = 1; - else - pev->rendercolor.x = 0; - - pev->rendercolor.y = (speedCode >> 8); - pev->rendercolor.z = (speedCode & 0xFF); -} - -void CFuncConveyor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if(IsLockedByMaster( useType )) return; - - if( useType == USE_TOGGLE ) - { - if( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if( useType == USE_ON ) - { - pev->speed = pev->frags; // restore speed - UpdateSpeed( pev->speed ); - UTIL_FireTargets( pev->target, this, this, USE_ON, pev->speed ); - if(!( pev->spawnflags & SF_NOTSOLID )) // don't push - pev->solid = SOLID_BSP; - m_iState = STATE_ON; - } - else if( useType == USE_OFF ) - { - pev->speed = 0.0f; - UpdateSpeed( pev->speed ); - UTIL_FireTargets( pev->target, this, this, USE_OFF, pev->speed ); - pev->solid = SOLID_NOT; - m_iState = STATE_OFF; - } - else if( useType == USE_SET ) // set new speed - { - if( value != 0.0f ) pev->frags = value; // set new speed ( can be negative ) - else pev->frags = -pev->frags; // just reverse - if( m_iState == STATE_ON ) - { - pev->speed = pev->frags; - UpdateSpeed( pev->speed ); - } - } - else if( useType == USE_RESET ) // restore default speed - { - pev->frags = 100.0f; - if( m_iState == STATE_ON ) pev->speed = pev->frags; - } - else if( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n" ); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "State: %s, Conveyor speed %f\n\n", GetStringForState( GetState()), pev->speed ); - } -} - -//======================================================================= -// func_mirror - breakable mirror brush (engine feature) -//======================================================================= -class CFuncMirror : public CBaseBrush -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - STATE GetState( void ) { return (pev->effects & EF_NODRAW) ? STATE_OFF : STATE_ON; } -}; -LINK_ENTITY_TO_CLASS( func_mirror, CFuncMirror ); - -void CFuncMirror :: Spawn( void ) -{ - m_Material = Glass; - CBaseBrush::Spawn(); - - // setup mirror - SetObjectClass( ED_PORTAL ); - pev->oldorigin = pev->origin; -} - -void CFuncMirror :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE ) - { - if( GetState() == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) - { - pev->effects &= ~EF_NODRAW; - } - else if ( useType == USE_OFF ) - { - pev->effects |= EF_NODRAW; - } - if( useType == USE_SET ) Die(); - if( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, halth %g\n\n", GetStringForState( GetState()), pev->health ); - } -} - -//======================================================================= -// func_monitor - A monitor that renders the view from a camera entity. -//======================================================================= -class CFuncMonitor : public CBaseBrush -{ -public: - void Spawn( void ); - void Precache( void ){ CBaseBrush::Precache(); } - void StartMessage( CBasePlayer *pPlayer ); - void ChangeCamera( string_t newcamera ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual BOOL IsFuncScreen( void ) { return TRUE; } - virtual STATE GetState( void ) { return pev->body ? STATE_ON:STATE_OFF; }; - virtual int ObjectCaps( void ); - BOOL OnControls( entvars_t *pevTest ); - CBaseEntity *pCamera; -}; -LINK_ENTITY_TO_CLASS( func_monitor, CFuncMonitor ); - -void CFuncMonitor::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "camera")) - { - pev->target = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "type")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "mode")) - { - pev->skin = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseBrush::KeyValue( pkvd ); -} - -void CFuncMonitor :: Spawn() -{ - m_Material = Computer; - CBaseBrush::Spawn(); - - if(pev->spawnflags & SF_NOTSOLID)//make illusionary wall - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - UTIL_SetModel(ENT(pev), pev->model ); - - //enable monitor - if(pev->spawnflags & SF_START_ON)pev->body = 1; -} - -int CFuncMonitor :: ObjectCaps( void ) -{ - if ( pev->impulse ) - return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; - else return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); -} - -void CFuncMonitor::StartMessage( CBasePlayer *pPlayer ) -{ - // send monitor index - ChangeCamera( pev->target ); -} - -void CFuncMonitor::ChangeCamera( string_t newcamera ) -{ - pCamera = UTIL_FindEntityByTargetname( NULL, STRING( newcamera )); - - if( pCamera ) pev->sequence = pCamera->entindex(); - else if( pev->body ) pev->frame = 1; // noise if not found camera - - // member newcamera name - pev->target = newcamera; -} - -void CFuncMonitor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if(IsLockedByMaster( useType )) return; - - if (useType == USE_TOGGLE) - { - if(pev->body) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON)pev->body = 1; - else if (useType == USE_OFF) - { - pev->body = 0; - pev->frame = 0; - } - else if ( useType == USE_SET ) - { - if( pActivator->IsPlayer()) - { - if ( value ) - { - UTIL_SetView( pActivator, iStringNull, 0 ); - } - else if ( pev->body ) - { - UTIL_SetView( pev->target, CAMERA_ON ); - m_pController = (CBasePlayer*)pActivator; - m_pController->m_pMonitor = this; - - if (m_pParent) - m_vecPlayerPos = m_pController->pev->origin - m_pParent->pev->origin; - else m_vecPlayerPos = m_pController->pev->origin; - } - } - } - else if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - Msg( "State: %s, Mode: %s\n", GetStringForState( GetState()), pev->skin ? "Color" : "B&W"); - Msg( "Type: %s. Camera Name: %s\n", pev->impulse ? "Duke Nukem Style" : "Half-Life 2 Style", STRING( pev->target) ); - } -} - -BOOL CFuncMonitor :: OnControls( entvars_t *pevTest ) -{ - if(m_pParent && ((m_vecPlayerPos + m_pParent->pev->origin) - pevTest->origin).Length() <= 30) - return TRUE; - else if((m_vecPlayerPos - pevTest->origin).Length() <= 30 ) - return TRUE; - return FALSE; -} - -//======================================================================= -// func_teleport - classic XASH portal -//======================================================================= -class CFuncTeleport : public CFuncMonitor -{ -public: - void Spawn( void ); - void Touch ( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void StartMessage( CBasePlayer *pPlayer ); -}; -LINK_ENTITY_TO_CLASS( func_portal, CFuncTeleport ); -LINK_ENTITY_TO_CLASS( trigger_teleport, CFuncTeleport ); - -void CFuncTeleport :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - UTIL_SetModel(ENT(pev), pev->model); - if (FClassnameIs(pev, "func_portal")) //portal mode - { - pev->impulse = 0;//can't use teleport - pev->body = 1;//enabled - } - else SetBits( pev->effects, EF_NODRAW );//classic mode -} - -void CFuncTeleport::StartMessage( CBasePlayer *pPlayer ) -{ - ChangeCamera( pev->target ); -} - -void CFuncTeleport :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "landmark" )) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "firetarget" )) - { - pev->netname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CFuncTeleport :: Touch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - CBaseEntity *pTarget = NULL; - - // only teleport monsters or clients or projectiles - if( !FBitSet( pevToucher->flags, FL_CLIENT|FL_MONSTER|FL_PROJECTILE ) && !pOther->IsPushable()) - return; - if( IsLockedByMaster( pOther )) return; - - pTarget = UTIL_FindEntityByTargetname( pTarget, STRING( pev->target )); - if( !pTarget ) return; - - CBaseEntity *pLandmark = UTIL_FindEntityByTargetname( NULL, STRING( pev->message )); - if ( pLandmark ) - { - Vector vecOriginOffs = pTarget->pev->origin - pLandmark->pev->origin; - - if( pOther->pev->flags & FL_PROJECTILE ) - { - pOther->pev->angles = UTIL_VecToAngles( pOther->pev->velocity ); - } - - // do we need to rotate the entity? - if ( pLandmark->pev->angles != pTarget->pev->angles ) - { - Vector vecVA; - float ydiff = pTarget->pev->angles.y - pLandmark->pev->angles.y; - - // set new angle to face - pOther->pev->angles.y -= ydiff; - if( pOther->IsPlayer()) - { - pOther->pev->angles.x = pOther->pev->v_angle.x; - pOther->pev->fixangle = TRUE; - } - - // set new velocity - vecVA = UTIL_VecToAngles( pOther->pev->velocity ); - vecVA.y += ydiff; - UTIL_MakeVectors(vecVA); - pOther->pev->velocity = gpGlobals->v_forward * pOther->pev->velocity.Length(); - pOther->pev->velocity.z = -pOther->pev->velocity.z; - - // set new origin - Vector vecPlayerOffs = pOther->pev->origin - pLandmark->pev->origin; - vecVA = UTIL_VecToAngles(vecPlayerOffs); - UTIL_MakeVectors(vecVA); - vecVA.y += ydiff; - UTIL_MakeVectors(vecVA); - Vector vecPlayerOffsNew = gpGlobals->v_forward * vecPlayerOffs.Length(); - vecPlayerOffsNew.z = -vecPlayerOffsNew.z; - vecOriginOffs = vecOriginOffs + vecPlayerOffsNew - vecPlayerOffs; - } - UTIL_SetOrigin( pOther, pOther->pev->origin + vecOriginOffs ); - } - else - { - Vector tmp = pTarget->pev->origin; - - if( pOther->IsPlayer( )) - tmp.z -= pOther->pev->mins.z; // make origin adjustments - tmp.z++; - UTIL_SetOrigin( pOther, tmp ); - UTIL_MakeVectors( pTarget->pev->angles ); - pOther->pev->angles = pTarget->pev->angles; - pOther->pev->velocity = gpGlobals->v_forward * 300; - if( pOther->IsPlayer( )) - { - pOther->pev->v_angle = pTarget->pev->angles; - pOther->pev->fixangle = TRUE; - } - } - - ChangeCamera( pev->target ); // update PVS - pevToucher->flags &= ~FL_ONGROUND; - pevToucher->fixangle = TRUE; - pevToucher->teleport_time = gpGlobals->time + 0.7; - - UTIL_FireTargets( pev->netname, pOther, this, USE_TOGGLE ); // fire target -} - -//======================================================================= -// ANGULAR MOVING BRUSHES -//======================================================================= -//======================================================================= -// func_rotate - typically non moving wall. affect to physics -//======================================================================= -class CFuncRotating : public CBaseBrush -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - void Touch ( CBaseEntity *pOther ); - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void PostActivate ( void ); - - void RampPitchVol ( void ); - void SetSpeed( float newspeed ); - void SetAngularImpulse( float impulse ); - float flDegree; -}; -LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ); - -void CFuncRotating :: KeyValue( KeyValueData* pkvd) -{ - if( FStrEq( pkvd->szKeyName, "spintime" )) - { - pev->frags = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if( FStrEq( pkvd->szKeyName, "spawnorigin" )) - { - Vector tmp; - UTIL_StringToVector( tmp, pkvd->szValue ); - if( tmp != g_vecZero ) pev->origin = tmp; - pkvd->fHandled = TRUE; - } - else CBaseBrush::KeyValue( pkvd ); -} - -void CFuncRotating :: Precache( void ) -{ - CBaseBrush::Precache(); - int m_sounds = UTIL_LoadSoundPreset( m_iMoveSound ); - - switch( m_sounds ) - { - case 1: - pev->noise3 = UTIL_PrecacheSound( "fans/fan1.wav" ); - break; - case 2: - pev->noise3 = UTIL_PrecacheSound( "fans/fan2.wav" ); - break; - case 3: - pev->noise3 = UTIL_PrecacheSound( "fans/fan3.wav" ); - break; - case 4: - pev->noise3 = UTIL_PrecacheSound( "fans/fan4.wav" ); - break; - case 5: - pev->noise3 = UTIL_PrecacheSound( "fans/fan5.wav" ); - break; - case 0: - pev->noise3 = UTIL_PrecacheSound( "common/null.wav" ); - break; - default: - pev->noise3 = UTIL_PrecacheSound( m_sounds ); - break; - } -} - -void CFuncRotating :: Spawn( void ) -{ - Precache(); - CBaseBrush::Spawn(); - - if ( pev->spawnflags & SF_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_EMPTY; - pev->movetype = MOVETYPE_PUSH; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - - SetBits (pFlags, PF_ANGULAR);//enetity has angular velocity - m_iState = STATE_OFF; - m_pitch = PITCH_NORM - 1; - pev->dmg_save = 0;//cur speed is NULL - pev->button = pev->speed;//member start speed - - AxisDir(); - - UTIL_SetOrigin(this, pev->origin); - UTIL_SetModel( ENT(pev), pev->model ); -} - -void CFuncRotating :: Touch ( CBaseEntity *pOther ) -{ - // don't hurt toucher - just apply velocity him - entvars_t *pevOther = pOther->pev; - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * pev->dmg; -} - -void CFuncRotating :: Blocked( CBaseEntity *pOther ) -{ - if(m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE) m_pParent->Blocked( pOther ); - - UTIL_AssignAngles(this, pev->angles ); - if ( gpGlobals->time < m_flBlockedTime)return; - m_flBlockedTime = gpGlobals->time + 0.1; - - if((m_iState == STATE_OFF || m_iState == STATE_TURN_OFF) && pev->avelocity.Length() < 350) - { - SetAngularImpulse(-(pev->dmg_save + RANDOM_FLOAT( 5, 10))); - return; - } - - if(pOther->TakeDamage( pev, pev, fabs(pev->speed), DMG_CRUSH ))//blocked entity died ? - { - SetAngularImpulse(-(pev->dmg_save + RANDOM_FLOAT( 10, 20))); - UTIL_FireTargets( pev->target, this, this, USE_SET );//damage - } - else if (RANDOM_LONG(0,1)) - { - SetSpeed( 0 );//fan damaged - disable it - UTIL_FireTargets( pev->target, this, this, USE_SET ); - //fan damaged( we can use counter and master for bloked broken fan) - } - if(!pOther->IsPlayer() && !pOther->IsMonster())//crash fan - { - if(IsBreakable())//if set strength - give damage myself - CBaseBrush::TakeDamage( pev, pev, fabs(pev->speed/100), DMG_CRUSH );//if we give damage - } -} - -void CFuncRotating :: PostActivate () -{ - if( pev->spawnflags & SF_START_ON ) - SetSpeed( pev->speed ); - ClearBits( pev->spawnflags, SF_START_ON ); - - if(m_iState == STATE_ON ) // restore sound if needed - EMIT_SOUND_DYN( ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise3), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH | SND_CHANGE_VOL, m_pitch); - SetNextThink( 0.05 ); // force to think -} - -void CFuncRotating :: RampPitchVol ( void ) -{ - float fpitch; - int pitch; - float speedfactor = fabs(pev->dmg_save/pev->button); - - m_flVolume = speedfactor; //slowdown volume ramps down to 0 - fpitch = PITCHMIN + (PITCHMAX - PITCHMIN) * speedfactor; - - pitch = (int)fpitch; - if( pitch == PITCH_NORM ) pitch = PITCH_NORM-1; - - // normalize volume and pitch - if( m_flVolume > 1.0 ) m_flVolume = 1.0; - if( m_flVolume < 0.0 ) m_flVolume = 0.0; - if( pitch < PITCHMIN ) pitch = PITCHMIN; - if( pitch > 255 ) pitch = 255; - m_pitch = pitch;//refresh pitch - - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, (char *)STRING(pev->noise3), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH|SND_CHANGE_VOL, m_pitch ); -} - -void CFuncRotating :: SetSpeed( float newspeed ) -{ - float speedfactor = fabs(pev->dmg_save/pev->speed);//speedfactor - pev->armortype = gpGlobals->time; //starttime - pev->armorvalue = newspeed - pev->dmg_save; //speed offset - pev->scale = pev->dmg_save; //cur speed - - //any speed change is turn on - //may be it's wrong, but nice working :) - if((pev->dmg_save > 0 && newspeed < 0) || (pev->dmg_save < 0 && newspeed > 0))//detect fast reverse - { - if(m_iState != STATE_OFF)pev->dmg_take = pev->frags * speedfactor;//fast reverse - else pev->dmg_take = pev->frags;//get normal time - m_iState = STATE_TURN_ON; - } - else if(newspeed == 0) - { - m_iState = STATE_TURN_OFF; - pev->dmg_take = pev->frags * 2.5 * speedfactor;//spin down is longer - } - else //just change speed, not zerocrossing - { - m_iState = STATE_TURN_ON; - pev->dmg_take = pev->frags;//get normal time - } - SetNextThink( 0.05 );//force to think -} - -void CFuncRotating :: SetAngularImpulse( float impulse ) -{ - if( fabs(impulse) < 20)pev->scale = fabs(impulse / MAX_AVELOCITY); - else pev->scale = 0.01;//scale factor - - m_iState = STATE_OFF;//impulse disable fan - pev->dmg_save = pev->dmg_save + impulse;//add our impulse to curspeed - - //normalize avelocity - if(pev->dmg_save > MAX_AVELOCITY)pev->dmg_save = MAX_AVELOCITY; - pev->max_health = MatFrictionTable( m_Material);//set friction coefficient - - SetNextThink(0.05);//pushable entity must thinking for apply velocity -} - -void CFuncRotating :: Think( void ) -{ - if(m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF) - { - flDegree = (gpGlobals->time - pev->armortype)/pev->dmg_take; - - if (flDegree >= 1)//full spin - { - if(m_iState == STATE_TURN_ON) - { - m_iState = STATE_ON; - pev->dmg_save = pev->speed;//normalize speed - UTIL_SetAvelocity(this, pev->movedir * pev->speed);//set normalized avelocity - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise3), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH | SND_CHANGE_VOL, m_pitch); - UTIL_FireTargets( pev->target, this, this, USE_ON );//fan is full on - } - if(m_iState == STATE_TURN_OFF) - { - m_iState = STATE_OFF; - if (pev->movedir == Vector(0,0,1)) - SetAngularImpulse(RANDOM_FLOAT(3.9, 6.8) * -pev->dmg_save); - //set small negative impulse for pretty phys effect :) - } - } - else - { - //calc new speed every frame - pev->dmg_save = pev->scale + pev->armorvalue * flDegree; - UTIL_SetAvelocity(this, pev->movedir * pev->dmg_save); - RampPitchVol(); //play pitched sound - } - } - if(m_iState == STATE_OFF)//apply impulse and friction - { - if(pev->dmg_save > 0)pev->dmg_save -= pev->max_health * pev->scale + 0.01; - else if(pev->dmg_save < 0)pev->dmg_save += pev->max_health * pev->scale + 0.01; - UTIL_SetAvelocity(this, pev->movedir * pev->dmg_save); - RampPitchVol(); //play pitched sound - } - //ALERT(at_console, "pev->avelocity %.2f %.2f %.2f\n", pev->avelocity.x, pev->avelocity.y, pev->avelocity.z); - SetNextThink( 0.05 ); - - if(pev->avelocity.Length() < 0.5)//watch for speed - { - UTIL_SetAvelocity(this, g_vecZero);//stop - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise3), 0, 0, SND_STOP, m_pitch); - DontThink();//break thinking - UTIL_FireTargets( pev->target, this, this, USE_OFF );//fan is full stopped - } -} - -void CFuncRotating :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if(IsLockedByMaster( useType )) return; - - if ( useType == USE_TOGGLE ) - { - if( m_iState == STATE_TURN_OFF || m_iState == STATE_OFF ) - useType = USE_ON; - else useType = USE_OFF; - } - if ( useType == USE_ON ) SetSpeed( pev->speed ); - else if( useType == USE_OFF ) SetSpeed( 0 ); - else if ( useType == USE_SET ) // reverse speed - { - // write new speed - if( value ) - { - if( pev->speed < 0 ) - pev->speed = -value; - if( pev->speed > 0 ) - pev->speed = value; - } - else pev->speed = -pev->speed; // just reverse - // apply speed immediately if fan no off or not turning off - if( m_iState != STATE_OFF && m_iState != STATE_TURN_OFF ) SetSpeed( pev->speed ); - } - else if ( useType == USE_RESET ) // set angular impulse. use with caution! - { - float imp; - if( value ) imp = value; - else imp = pev->speed; - SetAngularImpulse( imp / 10 ); - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, CurSpeed %.1f\n", GetStringForState( GetState()), pev->dmg_save ); - ALERT( at_console, "SpinTime: %.2f, MaxSpeed %.f\n", pev->frags, pev->speed ); - } -} - -//======================================================================= -// func_pendulum - swinging brush (thanks for Lazarus Q2 mod) -//======================================================================= -//======================================================================= -// func_pendulum - swinging brush -//======================================================================= -class CPendulum : public CBaseBrush -{ -public: - void Spawn ( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void Blocked( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); - void SetImpulse( float speed ); - void SetSwing( float speed ); - void PostActivate( void ); - - int dir;//FIXME -}; -LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum ); - -void CPendulum :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "distance" )) - { - pev->scale = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "damp" )) - { - pev->max_health = atof( pkvd->szValue ) * 0.01f; - if( pev->max_health > 0.01 ) pev->max_health = 0.01f; - pkvd->fHandled = TRUE; - } - else CBaseBrush::KeyValue( pkvd ); -} - -void CPendulum :: Precache( void ) -{ - CBaseBrush::Precache(); - int m_sounds = UTIL_LoadSoundPreset( m_iMoveSound ); - - switch (m_sounds) - { - case 1: - pev->noise3 = UTIL_PrecacheSound ( "pendulum/swing1.wav" ); - break; - case 2: - pev->noise3 = UTIL_PrecacheSound ( "pendulum/swing2.wav" ); - break; - case 0: - pev->noise3 = UTIL_PrecacheSound ( "common/null.wav" ); - break; - default: - pev->noise3 = UTIL_PrecacheSound( m_sounds ); - break; - } -} - -void CPendulum :: Spawn( void ) -{ - Precache(); - CBaseBrush::Spawn(); - - if ( pev->spawnflags & SF_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_PUSH; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - - SetBits ( pFlags, PF_ANGULAR ); - dir = 1; // evil stuff... - m_iState = STATE_OFF; - pev->dmg_save = 0; // cur speed is NULL - UTIL_AngularVector( this ); - - UTIL_SetOrigin( this, pev->origin ); - UTIL_SetModel( ENT( pev ), pev->model ); -} - -void CPendulum :: PostActivate( void ) -{ - if ( pev->spawnflags & SF_START_ON ) - SetSwing( pev->speed ); - ClearBits( pev->spawnflags, SF_START_ON ); - - if( m_iState == STATE_ON ) SetNextThink( 0.05 ); // force to think -} - -void CPendulum :: Touch ( CBaseEntity *pOther ) -{ - //don't hurt toucher - just apply velocity him - entvars_t *pevOther = pOther->pev; - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * pev->dmg; -} - -void CPendulum::Blocked( CBaseEntity *pOther ) -{ - // what can do pendulum on blocking ? - // Nothing :) - pev->armortype = gpGlobals->time; -} - -void CPendulum :: SetImpulse( float speed ) -{ - if( dir == pev->impulse ) return; - dir = pev->impulse; - - SetSwing( speed ); -} - -void CPendulum :: SetSwing( float speed ) -{ - if( m_iState == STATE_OFF ) - pev->armorvalue = speed; // save our speed - else pev->armorvalue = pev->armorvalue + speed; // apply impulse - - // silence normalize speed if needed - if( pev->armorvalue > MAX_AVELOCITY ) - pev->armorvalue = MAX_AVELOCITY; - - // normalize speed at think time - // calc min distance at this speed - float factor = MAX_AVELOCITY * 0.01f; // max avelocity * think time - float mindist = ( pev->armorvalue / factor ) * 2; // full minimal dist - - if( mindist > pev->scale ) - { - pev->scale = mindist; // set minimal distance for this speed - if( m_iState == STATE_OFF ) - { - ALERT( at_warning, "\n======/Xash SmartFiled System/======\n\n"); - ALERT( at_warning, "%s has too small distance for current speed!\n", STRING( pev->classname )); - ALERT( at_warning, "Smart field normalize distance to %.f\n\n", pev->scale ); - } - } - - if( m_iState == STATE_OFF ) - pev->dmg_take = pev->scale * 0.5; // calc half distance - else pev->dmg_take = pev->dmg_take + sqrt( speed ); - pev->dmg_save = pev->armorvalue; // at center speed is maximum - - // random choose starting dir - if ( m_iState == STATE_OFF ) - { - if( RANDOM_LONG( 0, 1 )) - pev->impulse = -1; // backward - else pev->impulse = 1; // forward - m_iState = STATE_ON; - } - SetNextThink( 0.01); // force to think -} - -void CPendulum :: Think( void ) -{ - float m_flDegree = (gpGlobals->time - pev->armortype) / pev->frags; - float m_flAngle = UTIL_CalcDistance( pev->angles ); - float m_flAngleOffset = pev->dmg_take - m_flAngle; - float m_flStep = (( pev->armorvalue * 0.01 ) / ( pev->dmg_take * 0.01 )) / M_PI; - float m_damping = pev->max_health; - - if( m_iState == STATE_TURN_OFF ) - m_damping = 0.09; // HACKHACK to disable pendulum - - - if( m_flDegree >= 1 && m_flAngleOffset <= 0.5f ) // extremum point - { - // recalc time - pev->armortype = gpGlobals->time; - pev->frags = pev->dmg_take / pev->armorvalue; - pev->impulse = -pev->impulse; // change movedir - } - - if( pev->avelocity.Length() > pev->armorvalue * 0.6 && m_damping ) // apply damp - { - pev->armorvalue -= pev->armorvalue * m_damping; - pev->dmg_take -= pev->dmg_take * m_damping; - } - - if( pev->avelocity.Length() > pev->armorvalue * 0.95 && pev->dmg_take > 5.0f ) // zerocrossing - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise3 ), m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - UTIL_FireTargets( pev->target, this, this, USE_OFF ); - } - - pev->dmg_save = pev->armorvalue * ( m_flAngleOffset / pev->dmg_take ); - UTIL_SetAvelocity( this, pev->movedir * pev->dmg_save * pev->impulse ); - - SetNextThink( 0.01f ); - if( pev->avelocity.Length() < 0.5f && pev->dmg_take < 2.0f ) // watch for speed and dist - { - UTIL_SetAvelocity( this, g_vecZero );//stop - UTIL_AssignAngles( this, pev->angles ); - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise3 ), 0, 0, SND_STOP, m_pitch ); - DontThink(); // break thinking - UTIL_FireTargets( pev->target, this, this, USE_OFF ); // pendulum is full stopped - m_iState = STATE_OFF; - } -} - -void CPendulum :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if(IsLockedByMaster( useType )) return; - - if ( useType == USE_TOGGLE ) - { - if( m_iState == STATE_OFF ) - useType = USE_ON; - else useType = USE_OFF; - } - if ( useType == USE_ON ) SetSwing( pev->speed ); - else if ( useType == USE_OFF ) m_iState = STATE_TURN_OFF; - else if ( useType == USE_SET ) - { - if( value ) pev->speed = value; - else SetImpulse( pev->speed ); // any idea ??? - } - else if ( useType == USE_RESET ) SetImpulse( pev->speed ); - else if ( useType == USE_SHOWINFO) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "State: %s, CurSpeed %.1f\n", GetStringForState( GetState()), pev->dmg_save ); - ALERT( at_console, "Distance: %.2f, Swing Time %.f\n", pev->dmg_take, pev->frags ); - } -} - -//======================================================================= -// func_clock - simply rotating clock from Quake1.Scourge Of Armagon -//======================================================================= -class CFuncClock : public CBaseLogic -{ -public: - void Spawn ( void ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void Think( void ); - void PostActivate( void ); - void KeyValue( KeyValueData *pkvd ); - Vector curtime, finaltime; - int bellcount;//calc hours -}; -LINK_ENTITY_TO_CLASS( func_clock, CFuncClock ); - -void CFuncClock :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "type")) - { - switch(atoi( pkvd->szValue )) - { - case 1: pev->impulse = MINUTES; break; // minutes - case 2: pev->impulse = HOURS; break; // hours - case 0: // default: - default: pev->impulse = SECONDS; break; // seconds - } - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "curtime")) - { - UTIL_StringToVector( curtime, pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "event")) - { - pev->netname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } -} - -void CFuncClock :: Spawn ( void ) -{ - pev->solid = SOLID_NOT; - UTIL_SetModel( ENT(pev), pev->model ); - - // NOTE: I'm doesn't have better idea than it - // So, field "angles" setting movedir only - // Turn your brush into your fucking worldcraft! - UTIL_AngularVector( this ); - SetBits( pFlags, PF_ANGULAR ); - - if( pev->impulse == HOURS ) //d o time operations - { - // normalize our time - if( curtime.x > 11 ) curtime.x = 0; - if( curtime.y > 59 ) curtime.y = 0; - if( curtime.z > 59 ) curtime.z = 0; - - // member full hours - pev->team = curtime.x; - - // calculate seconds - finaltime.z = curtime.z * ( SECONDS / 60 ); // seconds - finaltime.y = curtime.y * ( MINUTES / 60 ) + finaltime.z; - finaltime.x = curtime.x * ( HOURS / 12 ) + finaltime.y; - } -} - -void CFuncClock :: PostActivate( void ) -{ - // NOTE: We should be sure what all entities has be spawned - // else we called this from Activate() - - if( pev->frags ) return; - if( pev->impulse == HOURS && curtime != g_vecZero ) // it's hour entity and time set - { - // try to find minutes and seconds entity - CBaseEntity *pEntity = NULL; - while( pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, pev->size.z )) - { - if( FClassnameIs( pEntity, "func_clock" )) - { - //write start hours, minutes and seconds - if( pEntity->pev->impulse == HOURS ) pEntity->pev->dmg_take = finaltime.x; - if( pEntity->pev->impulse == MINUTES ) pEntity->pev->dmg_take = finaltime.y; - if( pEntity->pev->impulse == SECONDS ) pEntity->pev->dmg_take = finaltime.z; - } - } - } - pev->frags = 1; // clock init - m_iState = STATE_ON;// always on - - SetNextThink( 0 ); // force to think -} - -void CFuncClock :: Think ( void ) -{ - float seconds, ang, pos; - - seconds = gpGlobals->time + pev->dmg_take; - pos = seconds / pev->impulse; - pos = pos - floor( pos ); - ang = 360 * pos; - - UTIL_SetAngles( this, pev->movedir * ang ); - - if(pev->impulse == HOURS) // play bell sound - { - pev->button = pev->angles.Length() / 30; // half hour - if ( pev->team != pev->button ) // new hour - { - // member new hour - bellcount = pev->team = pev->button; - if( bellcount == 0 ) bellcount = 12; // merge for 0.00.00 - UTIL_FireTargets( pev->netname, this, this, USE_SET, bellcount ); // send hours info - UTIL_FireTargets( pev->netname, this, this, USE_ON );//activate bell or logic_generator - } - } - - SetNextThink( 1 ); // refresh at one second -} - -//======================================================================= -// func_healthcharger - brush healthcharger -//======================================================================= -class CWallCharger : public CBaseBrush -{ -public: - void Spawn( ); - void Precache( void ); - void Think (void); - void KeyValue( KeyValueData* pkvd); - virtual int ObjectCaps( void ) - { - int flags = CBaseBrush:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; - if(m_iState == STATE_DEAD) return flags; - return flags | FCAP_CONTINUOUS_USE; - } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - float m_flNextCharge; - float m_flSoundTime; -}; -LINK_ENTITY_TO_CLASS(func_healthcharger, CWallCharger); -LINK_ENTITY_TO_CLASS(func_recharge, CWallCharger); - -void CWallCharger :: KeyValue( KeyValueData* pkvd) -{ - if( FStrEq( pkvd->szKeyName, "chargetime" )) - { - //affect only in multiplayer - pev->speed = atof( pkvd->szValue ); - if( pev->speed <= 0 ) pev->speed = 1.0f; - pkvd->fHandled = TRUE; - } - else CBaseBrush::KeyValue( pkvd ); -} - -void CWallCharger::Spawn( void ) -{ - Precache(); - CBaseBrush::Spawn(); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(this, pev->origin); - UTIL_SetSize(pev, pev->mins, pev->maxs); - UTIL_SetModel(ENT(pev), pev->model ); - - if( pev->speed <= 0 ) - pev->speed = 1.0f; - m_iState = STATE_OFF; - pev->frame = 0; - - // set capacity - if ( FClassnameIs( this, "func_recharge" )) - pev->frags = SUIT_CHARGER_CAP; - else pev->frags = HEATH_CHARGER_CAP; - - pev->dmg_save = pev->frags; -} - -void CWallCharger::Precache( void ) -{ - CBaseBrush::Precache(); - if ( FClassnameIs( this, "func_recharge" )) - { - UTIL_PrecacheSound( "items/suitcharge1.wav" ); - UTIL_PrecacheSound( "items/suitchargeno1.wav" ); - UTIL_PrecacheSound( "items/suitchargeok1.wav" ); - } - else - { - UTIL_PrecacheSound( "items/medshot4.wav" ); - UTIL_PrecacheSound( "items/medshotno1.wav" ); - UTIL_PrecacheSound( "items/medcharge4.wav" ); - } -} - -void CWallCharger::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if(IsLockedByMaster( useType )) return; - - if(useType == USE_SHOWINFO)//show info - { - ALERT(at_console, "======/Xash Debug System/======\n"); - ALERT(at_console, "classname: %s\n", STRING(pev->classname)); - ALERT(at_console, "State: %s, Volume %.1f\n", GetStringForState( GetState()), m_flVolume ); - ALERT(at_console, "Texture frame: %.f. ChargeLevel: %.f\n", pev->frame, pev->dmg_save); - } - else if(pActivator && pActivator->IsPlayer()) // take health - { - if( pev->dmg_save <= 0 ) - { - if( m_iState == STATE_IN_USE || m_iState == STATE_ON ) - { - pev->frame = 1; - if( FClassnameIs( this, "func_recharge" )) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" ); - else STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" ); - m_iState = STATE_DEAD;//recharge in multiplayer - if( IsMultiplayer( )) - SetNextThink( 3.0f ); //delay before recahrge - else DontThink(); - } - } - - if(( m_iState == STATE_DEAD ) || (!(((CBasePlayer *)pActivator)->pev->weapons & ITEM_SUIT ))) - { - if ( m_flSoundTime <= gpGlobals->time ) - { - m_flSoundTime = gpGlobals->time + 0.62; - if( FClassnameIs( this, "func_recharge" )) - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/suitchargeno1.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - else EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/medshotno1.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - - } - return; - } - SetNextThink( 0.25f ); // time before disable - - if ( m_flNextCharge >= gpGlobals->time ) return; - - if ( m_iState == STATE_OFF ) - { - m_iState = STATE_ON; - if ( FClassnameIs( this, "func_recharge" )) - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/suitchargeok1.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - else EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/medshot4.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - - m_flSoundTime = 0.56 + gpGlobals->time; - } - if ( m_iState == STATE_ON && m_flSoundTime <= gpGlobals->time ) - { - m_iState = STATE_IN_USE; - if ( FClassnameIs( this, "func_recharge" )) - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/suitcharge1.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - else EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/medcharge4.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - } - - if ( FClassnameIs( this, "func_recharge" )) - { - if ( m_hActivator->pev->armorvalue < 100 ) - { - UTIL_FireTargets( pev->target, this, this, USE_OFF, pev->dmg_save ); // decrement counter - pev->dmg_save--; - m_hActivator->pev->armorvalue++; - } - } - else - { - if ( pActivator->TakeHealth(1, DMG_GENERIC )) - { - UTIL_FireTargets( pev->target, this, this, USE_OFF, pev->dmg_save ); // decrement counter - pev->dmg_save--; - } - } - m_flNextCharge = gpGlobals->time + 0.1; - } -} - -void CWallCharger :: Think( void ) -{ - if ( m_iState == STATE_IN_USE || m_iState == STATE_ON ) - { - if ( FClassnameIs( this, "func_recharge" )) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" ); - else STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" ); - - m_iState = STATE_OFF; - DontThink(); - return; - } - - if( m_iState == STATE_DEAD && IsMultiplayer( )) // recharge - { - pev->dmg_save++; // ressurection - UTIL_FireTargets( pev->target, this, this, USE_ON, pev->dmg_save ); // increment counter - if(pev->dmg_save >= pev->frags) - { - //take full charge - if ( FClassnameIs( this, "func_recharge" )) - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/suitchargeok1.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - else EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "items/medshot4.wav", m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); - pev->dmg_save = pev->frags; // normalize - pev->frame = 0; // enable - m_iState = STATE_OFF; // can use - DontThink(); - return; - } - } - SetNextThink( pev->speed ); -} - -//======================================================================= -// func_button - standard linear button from Quake1 -//======================================================================= -class CBaseButton : public CBaseMover -{ -public: - void Spawn( void ); - void PostSpawn( void ); - void Precache( void ); - virtual void KeyValue( KeyValueData* pkvd); - virtual int ObjectCaps( void ) - { - int flags = CBaseMover:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; - if(m_iState == STATE_DEAD) return flags; - return flags | FCAP_IMPULSE_USE | FCAP_ONLYDIRECT_USE; - } - void EXPORT ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ShowInfo ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ButtonTouch( CBaseEntity *pOther ); - void EXPORT ButtonReturn( void ); - void EXPORT ButtonDone( void ); - void ButtonActivate( void ); -}; -LINK_ENTITY_TO_CLASS( func_button, CBaseButton ); - -void CBaseButton::KeyValue( KeyValueData *pkvd ) -{ - // rename standard fields for button - if (FStrEq(pkvd->szKeyName, "locksound" )) - { - m_iStopSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pushsound" )) - { - m_iStartSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "offtarget" )) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "value" )) - { - m_flValue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseMover::KeyValue( pkvd ); -} - -void CBaseButton::Precache( void ) -{ - CBaseBrush::Precache();//precache damage sound - - int m_sounds = UTIL_LoadSoundPreset(m_iStartSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise = UTIL_PrecacheSound ("buttons/blip1.wav");break; - case 2: pev->noise = UTIL_PrecacheSound ("buttons/blip2.wav");break; - case 3: pev->noise = UTIL_PrecacheSound ("buttons/blip3.wav");break; - case 4: pev->noise = UTIL_PrecacheSound ("buttons/blip4.wav");break; - case 5: pev->noise = UTIL_PrecacheSound ("buttons/blip5.wav");break; - case 6: pev->noise = UTIL_PrecacheSound ("buttons/blip6.wav");break; - case 0: pev->noise = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - if (!FStringNull(m_sMaster))//button has master - { - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - switch (m_sounds)//load locked sounds - { - case 1: pev->noise3 = UTIL_PrecacheSound ("buttons/latchlocked1.wav");break; - case 2: pev->noise3 = UTIL_PrecacheSound ("buttons/latchlocked2.wav");break; - case 0: pev->noise3 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise3 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - } -} - -void CBaseButton::Spawn( ) -{ - Precache(); - CBaseBrush::Spawn(); - - if(pev->spawnflags & SF_NOTSOLID)//not solid button - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->skin = CONTENTS_EMPTY; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - UTIL_SetModel(ENT(pev), pev->model); - - //determine work style - if(m_iMode == 0)//classic HL button - only USE - { - SetUse ( ButtonUse ); - SetTouch ( NULL ); - } - if(m_iMode == 1)//classic QUAKE button - only TOUCH - { - SetUse ( ShowInfo );//show info only - SetTouch ( ButtonTouch ); - } - if(m_iMode == 2)//combo button - USE and TOUCH - { - SetUse ( ButtonUse ); - SetTouch ( ButtonTouch ); - } - - //as default any button is toggleable, but if mapmaker set waittime > 0 - //button will transformed into timebased button - //if waittime is -1 - button forever stay pressed - if(m_flWait == 0) pev->impulse = 1;//toggleable button - - if (m_flLip == 0) m_flLip = 4;//standart offset from Quake1 - - m_iState = STATE_OFF; // disable at spawn - UTIL_LinearVector( this ); // movement direction - - m_vecPosition1 = pev->origin; - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - - // Is this a non-moving button? - if( pev->speed == 0 ) m_vecPosition2 = m_vecPosition1; -} - -void CBaseButton :: PostSpawn( void ) -{ - if (m_pParent) m_vecPosition1 = pev->origin - m_pParent->pev->origin; - else m_vecPosition1 = pev->origin; - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - - // Is this a non-moving button? - if ( pev->speed == 0 ) m_vecPosition2 = m_vecPosition1; -} - -void CBaseButton :: ShowInfo ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( useType == USE_SHOWINFO ) // show info - { - DEBUGHEAD; - ALERT( at_console, "State: %s, Speed %.2f\n", GetStringForState( GetState()), pev->speed ); - ALERT( at_console, "Texture frame: %.f. WaitTime: %.2f\n", pev->frame, m_flWait ); - } -} - -void CBaseButton :: ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator;//save our activator - - if(IsLockedByMaster( useType )) // passed only USE_SHOWINFO - { - EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise3 ), 1, ATTN_NORM ); - return; - } - if( useType == USE_SHOWINFO ) // show info - { - ALERT( at_console, "======/Xash Debug System/======\n" ); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "State: %s, Speed %.2f\n", GetStringForState( GetState()), pev->speed ); - ALERT( at_console, "Texture frame: %.f. WaitTime: %.2f\n", pev->frame, m_flWait ); - } - else if( m_iState != STATE_DEAD ) // activate button - { - // NOTE: STATE_DEAD is better method for simulate m_flWait -1 without fucking SetThink() - if( pActivator && pActivator->IsPlayer( )) // code for player - { - if( pev->impulse == 1 ) // toggleable button - { - if ( m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF ) - return; // buton in-moving - else if ( m_iState == STATE_ON ) // button is active, disable - { - ButtonReturn(); - } - else if( m_iState == STATE_OFF ) // activate - { - ButtonActivate(); - } - } - else // time based button - { - // can activate only disabled button - if( m_iState == STATE_OFF ) ButtonActivate(); - else return; // does nothing :) - } - } - else // activate button from other entity - { - // NOTE: Across activation just passed fire through - UTIL_FireTargets( pev->target, pActivator, pCaller, useType, m_flValue ); - } - } -} - -void CBaseButton:: ButtonTouch( CBaseEntity *pOther ) -{ - //make delay before retouching - if ( gpGlobals->time < m_flBlockedTime ) return; - m_flBlockedTime = gpGlobals->time + 1.0f; - - if( pOther->IsPlayer( )) ButtonUse ( pOther, this, USE_TOGGLE, 1.0f ); // player always sending 1 -} - -void CBaseButton::ButtonActivate( void ) -{ - ASSERT( m_iState == STATE_OFF ); - m_iState = STATE_TURN_ON; - - EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); - - if ( pev->speed ) - { - SetMoveDone( ButtonDone ); - LinearMove( m_vecPosition2, pev->speed); - } - else ButtonDone(); // immediately switch -} - -void CBaseButton::ButtonDone( void ) -{ - if ( m_iState == STATE_TURN_ON ) // turn on - { - m_iState = STATE_ON; - pev->frame = 1; // change skin - - if ( pev->impulse ) - UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON, m_flValue ); // fire target - else UTIL_FireTargets( pev->target, m_hActivator, this, USE_TOGGLE, m_flValue ); // fire target - - if ( m_flWait == -1 ) - { - m_iState = STATE_DEAD; // keep button in this position - return; - } - - if ( pev->impulse == 0 ) // time base button - { - SetThink( ButtonReturn ); - SetNextThink( m_flWait ); - } - } - - if ( m_iState == STATE_TURN_OFF ) // turn off - { - m_iState = STATE_OFF; // just change state :) - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_OFF, m_flValue ); // fire target - } -} - -void CBaseButton::ButtonReturn( void ) -{ - ASSERT( m_iState == STATE_ON ); - m_iState = STATE_TURN_OFF; - pev->frame = 0; // use normal textures - - // make sound for toggleable button - if ( pev->impulse ) - { - EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); - UTIL_FireTargets( pev->target, m_hActivator, this, USE_OFF, m_flValue ); // fire target - } - if ( pev->speed ) - { - SetMoveDone( ButtonDone ); - LinearMove( m_vecPosition1, pev->speed ); - } - else ButtonDone(); // immediately switch -} - -//======================================================================= -// func_lever - momentary rotating button -//======================================================================= -class CFuncLever : public CBaseMover -{ -public: - void Spawn ( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) - { - int flags = CBaseMover:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; - if(m_iState == STATE_DEAD) return flags; - return flags | FCAP_CONTINUOUS_USE; - } - - BOOL MaxRange( void ) - { - if(pev->impulse == 1 && m_flMoveDistance > 0) return TRUE; - if(pev->impulse == -1 && m_flMoveDistance < 0) return TRUE; - return FALSE; - } - BOOL BackDir( void )//determine start direction - { - if( pev->dmg_save && m_flMoveDistance < 0) return TRUE; - if(!pev->dmg_save && m_flMoveDistance > 0) return TRUE; - return FALSE; - } - void PlayMoveSound( void ); - void CalcValue( void ); - void Think( void ); - - float mTimeToReverse, SendTime, nextplay; -}; -LINK_ENTITY_TO_CLASS( func_lever, CFuncLever ); - -void CFuncLever::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "backspeed")) - { - pev->dmg_save = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesound")) - { - m_iMoveSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsound")) - { - m_iStopSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseMover::KeyValue( pkvd ); -} - -void CFuncLever::Precache( void ) -{ - int m_sounds = UTIL_LoadSoundPreset(m_iMoveSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise = UTIL_PrecacheSound ("buttons/lever1.wav");break; - case 2: pev->noise = UTIL_PrecacheSound ("buttons/lever2.wav");break; - case 3: pev->noise = UTIL_PrecacheSound ("buttons/lever3.wav");break; - case 4: pev->noise = UTIL_PrecacheSound ("buttons/lever4.wav");break; - case 5: pev->noise = UTIL_PrecacheSound ("buttons/lever5.wav");break; - case 0: pev->noise = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - switch (m_sounds)//load locked sounds - { - case 1: pev->noise2 = UTIL_PrecacheSound ("buttons/lstop1.wav");break; - case 0: pev->noise2 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise2 = UTIL_PrecacheSound( m_sounds ); break;//custom sound or sentence - } -} - -void CFuncLever::Spawn( void ) -{ - Precache(); - if( pev->spawnflags & SF_NOTSOLID ) // not solid button - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->skin = CONTENTS_EMPTY; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - UTIL_SetModel( ENT( pev ), pev->model ); - UTIL_SetOrigin( this, pev->origin ); - - AxisDir(); - SetBits (pFlags, PF_ANGULAR); - - //Smart field system ® - if( pev->speed == 0 ) pev->speed = 100;//check null speed - if( pev->speed > 800) pev->speed = 800;//check max speed - if( fabs(m_flMoveDistance) < pev->speed/2) - { - if(m_flMoveDistance > 0)m_flMoveDistance = -pev->speed/2; - if(m_flMoveDistance < 0)m_flMoveDistance = pev->speed/2; - if(m_flMoveDistance ==0)m_flMoveDistance = 45; - } - //check for direction (right direction will be set at first called use) - if(BackDir())pev->impulse = -1;//backward dir - else pev->impulse = 1;//forward dir -} - -void CFuncLever::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - if(IsLockedByMaster( useType ))//strange stuff... - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise2), 1, ATTN_NORM); - return; - } - if(useType == USE_SHOWINFO) - { - ALERT(at_console, "======/Xash Debug System/======\n"); - ALERT(at_console, "classname: %s\n", STRING(pev->classname)); - ALERT(at_console, "State: %s, Value %.2f\n", GetStringForState( GetState()), pev->ideal_yaw ); - ALERT(at_console, "Distance: %.f. Speed %.2f\n", m_flMoveDistance, pev->speed ); - } - else if(m_iState != STATE_DEAD) - { - if(pActivator && pActivator->IsPlayer())//code only for player - { - if(gpGlobals->time > mTimeToReverse && !pev->dmg_save)//don't switch if backspeed set - pev->impulse = -pev->impulse; - mTimeToReverse = gpGlobals->time + 0.3;//max time to change dir - - pev->frags = pev->speed;//send speed - m_iState = STATE_IN_USE;//in use - SetNextThink(0.01); - } - } -} - -void CFuncLever::Think( void ) -{ - UTIL_SetAvelocity(this, pev->movedir * pev->frags * pev->impulse);//set speed and dir - if(m_iState == STATE_TURN_OFF && pev->dmg_save)pev->frags = -pev->dmg_save;//backspeed - if(!pev->dmg_save)pev->frags -= pev->frags * 0.05; - CalcValue(); - PlayMoveSound(); - - //wacthing code - if(pev->avelocity.Length() < 0.5)m_iState = STATE_OFF;//watch min speed - if(pev->ideal_yaw <= 0.01)//min range - { - if(pev->dmg_save && m_iState != STATE_IN_USE) - { - UTIL_SetAvelocity(this, g_vecZero); - m_iState = STATE_OFF;//off - } - else if(!MaxRange())UTIL_SetAvelocity(this, g_vecZero); - } - if(pev->ideal_yaw >= 0.99)//max range - { - if(pev->dmg_save && m_iState == STATE_IN_USE) - { - UTIL_SetAvelocity(this, g_vecZero); - if(pev->spawnflags & SF_START_ON)//Stay open flag - m_iState = STATE_DEAD;//dead - else m_iState = STATE_TURN_OFF;//must return - } - else if(MaxRange() && m_iState == STATE_IN_USE) - { - UTIL_SetAvelocity(this, g_vecZero); - if(pev->spawnflags & SF_START_ON)//Stay open flag - m_iState = STATE_DEAD;//dead - else m_iState = STATE_OFF;//dist is out - } - } - if(m_iState == STATE_IN_USE)m_iState = STATE_TURN_OFF;//try disable - - SetNextThink(0.01); - - if(m_iState == STATE_OFF || m_iState == STATE_DEAD)//STATE_DEAD is one end way - { - if(pev->dmg_save)//play sound only auto return - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise2), 1, ATTN_NORM); - UTIL_SetAvelocity(this, g_vecZero); - UTIL_AssignAngles( this, pev->angles ); - DontThink();//break thinking - } - //ALERT(at_console, "Ideal Yaw %f\n", pev->ideal_yaw); -} - -void CFuncLever::CalcValue( void ) -{ - //calc value to send - //pev->ideal_yaw = UTIL_CalcDistance(pev->angles) / fabs(m_flMoveDistance); - pev->ideal_yaw = pev->angles.Length() / fabs(m_flMoveDistance); - if(pev->ideal_yaw >= 1)pev->ideal_yaw = 1;//normalize value - else if(pev->ideal_yaw <= 0)pev->ideal_yaw = 0;//normalize value - - if(gpGlobals->time > SendTime) - { - UTIL_FireTargets( pev->target, this, this, USE_SET, pev->ideal_yaw );//send value - SendTime = gpGlobals->time + 0.01;//time to nextsend - } -} - -void CFuncLever::PlayMoveSound( void ) -{ - if(m_iState == STATE_TURN_OFF && pev->dmg_save ) - nextplay = fabs((pev->dmg_save * 0.01) / (m_flMoveDistance * 0.01)); - else nextplay = fabs((pev->frags * 0.01) / (m_flMoveDistance * 0.01)); - nextplay = 1/(nextplay * 5); - - if(gpGlobals->time > m_flBlockedTime) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - m_flBlockedTime = gpGlobals->time + nextplay; - } -} - -//======================================================================= -// func_ladder - makes an area vertically negotiable -//======================================================================= -class CLadder : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); -}; -LINK_ENTITY_TO_CLASS( func_ladder, CLadder ); - -void CLadder :: Precache( void ) -{ - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_LADDER; - pev->effects |= EF_NODRAW; -} - -void CLadder :: Spawn( void ) -{ - Precache(); - - UTIL_SetModel( ENT( pev ), pev->model ); // set size and link into world - pev->movetype = MOVETYPE_PUSH; -} - -//======================================================================= -// func_scaner - retinal scaner -//======================================================================= -class CFuncScaner : public CBaseBrush -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void PostActivate( void ); - void Think( void ); - BOOL VisionCheck( void ); - BOOL CanSee(CBaseEntity *pLooker ); - CBaseEntity *pSensor; - CBaseEntity *pLooker; -}; -LINK_ENTITY_TO_CLASS( func_scaner, CFuncScaner ); - -void CFuncScaner::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "sensor" )) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "acesslevel" )) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "sensitivity" )) - { - pev->health = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CFuncScaner :: Precache( void ) -{ - CBaseBrush::Precache(); - - UTIL_PrecacheSound( "buttons/blip1.wav" ); - UTIL_PrecacheSound( "buttons/blip2.wav" ); - UTIL_PrecacheSound( "buttons/button7.wav" ); - UTIL_PrecacheSound( "buttons/button11.wav" ); -} - -void CFuncScaner :: Spawn( void ) -{ - Precache(); - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - if( !pev->health ) pev->health = 15; - UTIL_SetModel( ENT( pev ), pev->model ); - UTIL_SetOrigin( this, pev->origin ); - m_flDelay = 0.1; - - SetNextThink( 1 ); -} - -void CFuncScaner :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, Acess Level %d\n", GetStringForState( GetState()), pev->impulse ); - ALERT( at_console, "FOV: %g\n", pev->health ); - } - else if ( useType == USE_SET ) - { - if ( value ) - { - pev->armorvalue = (int)value; // set new acess level for looker - pev->frame = 1; - } - } -} - -void CFuncScaner :: Think( void ) -{ - if ( VisionCheck() && m_iState != STATE_ON && m_iState != STATE_DEAD ) - { - if ( pev->armorvalue ) - { - m_iState = STATE_DEAD; - pLooker->m_iAcessLevel = (int)pev->armorvalue; - pev->armorvalue = 0; - // change acess level sound - EMIT_SOUND( edict(), CHAN_BODY, "buttons/blip2.wav", 1.0, ATTN_NORM ); - } - else if ( m_iState == STATE_OFF ) // scaner is off - { - // ok, we have seen entity - if( pLooker->pev->flags & FL_CLIENT ) m_flDelay = 0.1; - else m_flDelay = 0.9; - m_iState = STATE_TURN_ON; - } - else if( m_iState == STATE_TURN_ON ) // scaner is turn on - { - EMIT_SOUND( edict(), CHAN_BODY, "buttons/blip1.wav", 1.0, ATTN_NORM ); - pev->frame = 1; - m_flDelay = 0.3; - pev->button++; - if( pev->button > 9 ) - { - m_iState = STATE_ON; - pev->team = pLooker->m_iAcessLevel; // save our level acess - pev->button = 0; - } - } - } - else if ( m_iState == STATE_ON ) // scaner is on - { - EMIT_SOUND( edict(), CHAN_BODY, "buttons/blip1.wav", 1.0, ATTN_NORM ); - m_flDelay = 0.1; - pev->button++; - if( pev->button > 9 ) - { - m_iState = STATE_OFF; - pev->frame = 0; - pev->button = 0; - m_flDelay = 2.0; - - if( pev->team >= pev->impulse ) // acees level is math or higher ? - { - EMIT_SOUND( edict(), CHAN_BODY, "buttons/button7.wav", 1.0, ATTN_NORM ); - UTIL_FireTargets( pev->target, this, this, USE_TOGGLE ); - } - else - { - EMIT_SOUND( edict(), CHAN_BODY, "buttons/button11.wav", 1.0, ATTN_NORM ); - UTIL_FireTargets( pev->netname, this, this, USE_TOGGLE ); - } - } - } - else if ( m_iState == STATE_TURN_ON ) - { - EMIT_SOUND( edict(), CHAN_BODY, "buttons/button11.wav", 1.0, ATTN_NORM ); - m_iState = STATE_OFF; - pev->button = 0; - pev->frame = 0; - m_flDelay = 2.0; - } - else if ( m_iState == STATE_DEAD ) - { - m_iState = STATE_OFF; - pev->button = 0; - m_flDelay = 2.0; - } - - // is this a sensible rate? - SetNextThink( m_flDelay ); -} - -void CFuncScaner :: PostActivate( void ) -{ - if ( pev->message ) - { - pSensor = UTIL_FindEntityByTargetname( NULL, STRING( pev->message )); - if( !pSensor ) pSensor = this; - } - else pSensor = this; -} - -BOOL CFuncScaner :: VisionCheck( void ) -{ - pLooker = UTIL_FindEntityInSphere( NULL, pSensor->pev->origin, 30 ); - - if ( pLooker ) - { - while( pLooker != NULL ) - { - if( pLooker && pLooker->pev->flags & ( FL_MONSTER|FL_CLIENT )) - return CanSee( pLooker ); // looker found - pLooker = UTIL_FindEntityInSphere( pLooker, pSensor->pev->origin, 30 ); - } - } - return FALSE;//no lookers -} - -BOOL CFuncScaner :: CanSee( CBaseEntity *pLooker ) -{ - if( !pSensor || !pLooker ) return FALSE; - - if (( pLooker->EyePosition() - pSensor->pev->origin ).Length() > 30 ) - return FALSE; - - // copied from CBaseMonster's FInViewCone function - Vector2D vec2LOS; - float flDot, flComp = cos( pev->health / 2 * M_PI / 180.0 ); - - UTIL_MakeVectors ( pLooker->pev->angles ); - vec2LOS = ( pSensor->pev->origin - pLooker->pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - flDot = DotProduct ( vec2LOS , gpGlobals->v_forward.Make2D() ); - - if (flDot <= flComp) return FALSE; - return TRUE; -} \ No newline at end of file diff --git a/server/ents/basefx.cpp b/server/ents/basefx.cpp deleted file mode 100644 index d79bcfdf..00000000 --- a/server/ents/basefx.cpp +++ /dev/null @@ -1,2913 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#include "extdll.h" -#include "defaults.h" -#include "utils.h" -#include "cbase.h" -#include "basebeams.h" -#include "baseweapon.h" -#include "decals.h" -#include "basebrush.h" -#include "shake.h" -#include "monsters.h" -#include "client.h" -#include "player.h" -#include "soundent.h" - -//======================================================================= -// main functions () -//======================================================================= -class CBaseParticle : public CBaseLogic -{ -public: - void Spawn( void ); - void Precache( void ){ pev->netname = UTIL_PrecacheAurora( pev->message ); } - void KeyValue( KeyValueData *pkvd ); - void PostActivate( void ){ Switch(); } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Switch( void ); -}; - -void CBaseParticle :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "aurora" )) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CBaseParticle::Switch( void ) -{ - int renderfx = (m_iState ? kRenderFxAurora : kRenderFxNone ); - if( pev->target ) - { - CBaseEntity *pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ), m_hActivator ); - while ( pTarget ) - { - UTIL_SetAurora( pTarget, pev->netname ); - pTarget->pev->renderfx = renderfx; - pTarget = UTIL_FindEntityByTargetname( pTarget, STRING( pev->target ), m_hActivator ); - } - } - else - { - UTIL_SetAurora( this, pev->netname ); - pev->renderfx = renderfx; - } -} - -void CBaseParticle::Spawn( void ) -{ - Precache(); - - SetObjectClass( ED_NORMAL ); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - if( pev->spawnflags & SF_START_ON || FStringNull( pev->targetname )) - m_iState = STATE_ON; - else m_iState = STATE_OFF; -} - -void CBaseParticle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if ( useType == USE_TOGGLE ) - { - if( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) - { - m_iState = STATE_ON; - Switch(); - } - else if ( useType == USE_OFF ) - { - m_iState = STATE_OFF; - Switch(); - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - Msg( "State: %s, ParticleName: %s\n", GetStringForState( GetState()), STRING( pev->netname )); - if ( pev->target ) Msg( "Attach to: %s\n", STRING( pev->target )); - else Msg( "\n" ); - } -} -LINK_ENTITY_TO_CLASS( env_particle, CBaseParticle ); - -//========================================================= -// env_sky, an unreal tournament - style sky effect -//========================================================= -class CEnvSky : public CBaseLogic -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( env_sky, CEnvSky ); - -void CEnvSky :: Spawn( void ) -{ - // Xash3D engine feature - SetObjectClass( ED_SKYPORTAL ); -} - -//========================================================= -// UTIL_ScreenFade (fade screen) -//========================================================= -#define SF_FADE_IN 0x0001 // Fade in, not out -#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend -#define SF_FADE_ALL 0x0004 // fade all clients -#define SF_FADE_CAMERA 0x0008 // fading only for camera - -class CFade : public CBaseLogic -{ -public: - void Spawn( void ) { m_iState = STATE_OFF; } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); -}; -LINK_ENTITY_TO_CLASS( env_fade, CFade ); - -void CFade::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "duration" )) - { - pev->dmg_take = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "holdtime" )) - { - pev->dmg_save = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "Fadecolor: %g %g %g, Fadealpha: %g, Fadetime: %g\n", pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->dmg_take ); - ALERT( at_console, "HoldTime %g, Mode: %s, Modulate: %s\n", pev->dmg_save, pev->spawnflags & SF_FADE_IN ? "FADE IN" : "FADE OUT", pev->spawnflags & SF_FADE_MODULATE ? "YES" : "NO" ); - } - else - { - // setup fade flags - int fadeFlags = 0; - if ( pev->spawnflags & SF_FADE_IN ) - fadeFlags |= FFADE_IN; - else fadeFlags |= FFADE_OUT; - if ( pev->spawnflags & SF_FADE_MODULATE ) fadeFlags |= FFADE_MODULATE; - if ( pev->spawnflags & SF_FADE_CAMERA ) fadeFlags |= FFADE_CUSTOMVIEW; - - // apply fade - if ( pev->spawnflags & SF_FADE_ALL ) - UTIL_ScreenFadeAll( pev->rendercolor, pev->dmg_take, pev->dmg_save, pev->renderamt, fadeFlags ); - else UTIL_ScreenFade( pev->rendercolor, pev->dmg_take, pev->dmg_save, pev->renderamt, fadeFlags ); - } -} - -//===================================================== -// env_customhud: change player hud -//===================================================== -class CEnvHud : public CBaseLogic -{ - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData* ); - void SetHUD( int hud_num ); - void ResetHUD( void ); - char* GetStringForMode( void ); -}; - -void CEnvHud :: KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "hud" )) - { - pev->skin = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CEnvHud :: SetHUD( int hud_num ) -{ - if( m_hActivator != NULL ) - { - m_iState = STATE_ON; - ((CBasePlayer *)((CBaseEntity *)m_hActivator))->m_iWarHUD = pev->skin = hud_num; - } -} - -void CEnvHud :: ResetHUD( void ) -{ - if( m_hActivator != NULL ) - { - m_iState = STATE_OFF; - ((CBasePlayer *)((CBaseEntity *)m_hActivator))->m_iWarHUD = 0; - ((CBasePlayer *)((CBaseEntity *)m_hActivator))->fadeNeedsUpdate = 1; - } -} - -void CEnvHud :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( pActivator && pActivator->IsPlayer( )) // only at player - { - m_hActivator = pActivator; // save activator - } - else if( !IsMultiplayer( )) - { - m_hActivator = UTIL_PlayerByIndex( 1 ); - } - else - { - ALERT( at_warning, "%s: %s activator not player. Ignored.\n", STRING( pev->classname ), STRING( pev->targetname )); - return; - } - - if ( useType == USE_TOGGLE ) - { - if ( m_iState == STATE_OFF ) - useType = USE_ON; - else useType = USE_OFF; - } - - if ( useType == USE_ON ) SetHUD( pev->skin ); - else if ( useType == USE_OFF ) ResetHUD(); - else if ( useType == USE_SET ) - { - if ( value ) SetHUD( value ); - else ResetHUD(); - } - else if ( useType == USE_RESET ) ResetHUD(); - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n" ); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "State: %s, HUD Mode: %s\n", GetStringForState( GetState()), GetStringForMode()); - SHIFT; - } -} - -char* CEnvHud :: GetStringForMode( void ) -{ - switch(pev->skin) - { - case 0: return "Disable Custom HUD"; - case 1: return "Draw Redeemer HUD"; - case 2: return "Draw Redeemer Underwater HUD"; - case 3: return "Draw Redeemer Noise Screen"; - case 4: return "Draw Security Camera Screen"; - default: return "Draw None"; - } -} -LINK_ENTITY_TO_CLASS( env_customhud, CEnvHud ); - -//======================================================================= -// env_zoom - change fov for player -//======================================================================= -class CEnvZoom : public CBaseLogic -{ - void Spawn (void ){ if( !pev->frags ) pev->frags = 90.0f; } - void EXPORT Think( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData* pkvd ); - void SetFadeTime( void ); -}; - -LINK_ENTITY_TO_CLASS( env_zoom, CEnvZoom ); - -void CEnvZoom::KeyValue( KeyValueData* pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "duration" )) - { - pev->takedamage = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "fov" )) - { - pev->frags = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CEnvZoom::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !pActivator || !pActivator->IsPlayer()) - pActivator = UTIL_PlayerByIndex( 1 ); - m_hActivator = pActivator; // save activator - - if( m_iState == STATE_ON ) return; - if( useType == USE_TOGGLE || useType == USE_ON ) SetFadeTime(); - else if( useType == USE_OFF ) - ((CBasePlayer *)pActivator)->pev->fov = 90.0f; - else if( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, Fade time %.00f\n", GetStringForState( GetState()), pev->takedamage ); - ALERT( at_console, "Current FOV: %g, Final FOV: %g\n", ((CBasePlayer *)pActivator)->pev->fov, pev->frags ); - } -} - -void CEnvZoom::SetFadeTime( void ) -{ - float CurFOV; - float Length; - - if( pev->takedamage == 0 ) // instant apply fov - { - ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov = pev->frags; - return; - } - else - { - CurFOV = ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov; - if( CurFOV == 0.0f ) - CurFOV = ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov = 90.0f; - - if( CurFOV > pev->frags ) Length = CurFOV - pev->frags; - else if( CurFOV < pev->frags ) - { - Length = pev->frags - CurFOV; - pev->body = 1; // increment fov - } - else return; // no change - - pev->health = pev->takedamage / Length; - SetNextThink ( pev->health ); - } -} - -void CEnvZoom::Think( void ) -{ - if( Q_rint(((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov ) == Q_rint( pev->frags )) - { - // time is expired - SetThink( NULL ); - DontThink(); - m_iState = STATE_OFF; - // fire target after finished // transmit final fov - UTIL_FireTargets( pev->target, m_hActivator, this, USE_TOGGLE, pev->frags ); - return; - } - else - { - if( pev->body ) ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov += 0.5f * gpGlobals->frametime; - else ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov -= 0.5f * gpGlobals->frametime; - } - m_iState = STATE_ON; - SetNextThink ( pev->health ); -} - -//===================================================== -// env_render: change render parameters -//===================================================== - -#define SF_RENDER_MASKFX (1<<0) -#define SF_RENDER_MASKAMT (1<<1) -#define SF_RENDER_MASKMODE (1<<2) -#define SF_RENDER_MASKCOLOR (1<<3) - -class CRenderFxManager : public CBaseLogic -{ -public: - void Affect( void ); - void KeyValue( KeyValueData *pkvd ); - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - m_hActivator = pActivator; Affect(); - } -}; -LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ); - -void CRenderFxManager :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "fadetime")) - { - pev->speed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CRenderFxManager::Affect( void ) -{ - BOOL first = TRUE; - - if(FStringNull(pev->target)) return; - CBaseEntity* pTarget = UTIL_FindEntityByTargetname( NULL, STRING(pev->target), m_hActivator); - - while ( pTarget != NULL ) - { - entvars_t *pevTarget = pTarget->pev; - - if (pev->speed == 0) // aplly settings instantly ? - { - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) ) - pevTarget->renderamt = pev->renderamt; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) ) - pevTarget->rendercolor = pev->rendercolor; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) ) - pevTarget->renderfx = pev->renderfx; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) ) - pevTarget->rendermode = pev->rendermode; - - pevTarget->scale = pev->scale; - pevTarget->framerate = pev->framerate; - if (first) UTIL_FireTargets( pev->netname, pTarget, this, USE_TOGGLE ); - } - else - { - if (!pevTarget->renderamt && !pevTarget->rendermode) pevTarget->renderamt = 255; - pevTarget->renderfx = pev->renderfx; - pevTarget->rendermode = pev->rendermode; - CBaseEntity *pFader = Create( "faderent", pev->origin, pev->angles, pTarget->edict()); - pFader->pev->renderamt = pevTarget->renderamt; - pFader->pev->rendercolor = pevTarget->rendercolor; - pFader->pev->scale = pevTarget->scale; - if (pFader->pev->scale == 0) pFader->pev->scale = 1; - pFader->pev->spawnflags = pev->spawnflags; - - if (first) pFader->pev->target = pev->netname; - - pFader->pev->max_health = pev->framerate - pevTarget->framerate; - pFader->pev->health = pev->renderamt - pevTarget->renderamt; - pFader->pev->movedir.x = pev->rendercolor.x - pevTarget->rendercolor.x; - pFader->pev->movedir.y = pev->rendercolor.y - pevTarget->rendercolor.y; - pFader->pev->movedir.z = pev->rendercolor.z - pevTarget->rendercolor.z; - - if ( pev->scale ) pFader->pev->frags = pev->scale - pevTarget->scale; - else pFader->pev->frags = 0; - - pFader->pev->dmgtime = gpGlobals->time; - pFader->pev->speed = pev->speed; - pFader->SetNextThink( 0 ); - pFader->Spawn(); - } - - first = FALSE;//not a first target - pTarget = UTIL_FindEntityByTargetname( pTarget, STRING(pev->target), m_hActivator ); - } -} - -//========================================================= -// display message -//========================================================= -class CMessage : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - CBaseEntity *pPlayer = NULL; - - if ( IsMultiplayer() ) UTIL_ShowMessageAll( STRING(pev->message) ); - else - { - if ( pActivator && pActivator->IsPlayer() ) pPlayer = pActivator; - else pPlayer = UTIL_PlayerByIndex( 1 ); - } - - if ( pPlayer ) UTIL_ShowMessage( STRING(pev->message), pPlayer ); - if ( pev->spawnflags & 1 ) UTIL_Remove( this ); - } -}; -LINK_ENTITY_TO_CLASS( env_message, CMessage ); - -//========================================================= -// set global fog on a map -//========================================================= -class CEnvFog : public CBaseLogic -{ -public: - void PostActivate( void ); - void KeyValue( KeyValueData *pkvd ); - void TurnOn( void ); - void TurnOff( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( env_fog, CEnvFog ); - -void CEnvFog :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "startdist" )) - { - pev->dmg_take = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "enddist" )) - { - pev->dmg_save = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "fadetime" )) - { - m_flDelay = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CEnvFog :: PostActivate ( void ) -{ - if ( pev->spawnflags & SF_START_ON ) - { - TurnOn(); - ClearBits(pev->spawnflags, SF_START_ON); - } -} - -void CEnvFog :: TurnOn ( void ) -{ - m_iState = STATE_ON; - UTIL_SetFogAll(pev->rendercolor, m_flDelay, pev->dmg_take, pev->dmg_save ); -} - -void CEnvFog :: TurnOff ( void ) -{ - m_iState = STATE_OFF; - UTIL_SetFogAll(pev->rendercolor, -m_flDelay, pev->dmg_take, pev->dmg_save ); -} - -void CEnvFog :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE ) - { - if ( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) TurnOn(); - else if ( useType == USE_OFF ) TurnOff(); -} - -//========================================================= -// env_rain, custom client weather effects -//========================================================= -class CEnvRain : public CPointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ) - { - if ( FStrEq( pkvd->szKeyName, "radius" )) - { - pev->armorvalue = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "mode" )) - { - pev->button = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - } - void Precache( void ) - { - if( pev->button ) - { - // snow - UTIL_PrecacheModel( "sprites/snowflake.spr" ); - } - else - { - // it's a rainy day :) - UTIL_PrecacheModel( "sprites/hi_rain.spr" ); - UTIL_PrecacheModel( "sprites/waterring.spr" ); - } - } - void Spawn() { Precache(); } -}; -LINK_ENTITY_TO_CLASS( env_rain, CEnvRain ); - -//========================================================= -// UTIL_RainModify (set new rain or snow) -//========================================================= -void CEnvRainModify::Spawn() -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NODRAW; - - if( IsMultiplayer() || FStringNull( pev->targetname )) - SetBits( pev->spawnflags, SF_START_ON ); -} -LINK_ENTITY_TO_CLASS( env_rainmodify, CEnvRainModify ); - -TYPEDESCRIPTION CEnvRainModify::m_SaveData[] = -{ - DEFINE_FIELD( CEnvRainModify, randXY, FIELD_RANGE ), - DEFINE_FIELD( CEnvRainModify, windXY, FIELD_RANGE ), -}; -IMPLEMENT_SAVERESTORE( CEnvRainModify, CPointEntity ); - -void CEnvRainModify::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "drips" )) - { - pev->button = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "fadetime")) - { - pev->dmg = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "rand" )) - { - randXY = RandomRange( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "wind" )) - { - windXY = RandomRange( pkvd->szValue ); - pkvd->fHandled = TRUE; - } -} - -void CEnvRainModify::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "Wind X: %g Y: %g. Rand X: %g Y: %g\n", windXY[1], windXY[0], randXY[1], randXY[0] ); - ALERT( at_console, "Fade time %g. Drips per second %d\n", pev->dmg, pev->button ); - } - else if( !pev->spawnflags & SF_START_ON ) - { - for ( int i = 0; i < gpGlobals->maxClients; i++ ) - { - CBasePlayer *pPlayer = (CBasePlayer *)UTIL_PlayerByIndex( i+1 ); - - if( FNullEnt( pPlayer->pev )) continue; - - if ( pev->dmg ) - { - pPlayer->Rain_ideal_dripsPerSecond = pev->button; - pPlayer->Rain_ideal_randX = randXY[1]; - pPlayer->Rain_ideal_randY = randXY[0]; - pPlayer->Rain_ideal_windX = windXY[1]; - pPlayer->Rain_ideal_windY = windXY[0]; - pPlayer->Rain_endFade = gpGlobals->time + pev->dmg; - pPlayer->Rain_nextFadeUpdate = gpGlobals->time + 1; - } - else - { - pPlayer->Rain_dripsPerSecond = pev->button; - pPlayer->Rain_randX = randXY[1]; - pPlayer->Rain_randY = randXY[0]; - pPlayer->Rain_windX = windXY[1]; - pPlayer->Rain_windY = windXY[0]; - pPlayer->rainNeedsUpdate = 1; - } - } - } -} - -//======================================================================= -// env_sprite - classic HALF-LIFE sprites -//======================================================================= -void CSprite::Spawn( void ) -{ - Precache(); - - UTIL_SetModel( ENT(pev), pev->model ); - - // Smart Field System © - if( !pev->renderamt ) pev->renderamt = 200; // light transparency - if( !pev->framerate ) pev->framerate = Frames(); // play sequence at one second - if( !pev->rendermode ) pev->rendermode = kRenderTransAdd; - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - pev->frame = 0; - SetBits( pFlags, PF_POINTENTITY ); - - pev->angles.x = -pev->angles.x; - pev->angles.y = 180 - pev->angles.y; - pev->angles[1] = 0 - pev->angles[1]; - TurnOff(); -} - -void CSprite::PostSpawn( void ) -{ - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target )); - if( m_pGoalEnt ) UTIL_SetOrigin( this, m_pGoalEnt->pev->origin ); -} - -void CSprite::Think( void ) -{ - SetNextThink( 0 ); - - if( pev->spawnflags & SF_TEMPSPRITE && gpGlobals->time > pev->dmg_take ) UTIL_Remove(this); - else if( pev->framerate ) Animate( pev->framerate * (gpGlobals->time - pev->dmgtime) ); - - Move(); - pev->dmgtime = gpGlobals->time; -} - -void CSprite::Move( void ) -{ - // Not moving on a path, return - if( !m_pGoalEnt ) return; - - // Subtract movement from the previous frame - pev->frags -= pev->speed * gpGlobals->frametime; - - // Have we moved enough to reach the target? - if ( pev->frags <= 0 ) - { - // Fire the passtarget if there is one - if ( m_pGoalEnt->pev->message ) - { - UTIL_FireTargets( m_pGoalEnt->pev->message, this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_FIREONCE ) ) - m_pGoalEnt->pev->message = 0; - } - - if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_TELEPORT ) ) - { - m_pGoalEnt = m_pGoalEnt->GetNext(); - if ( m_pGoalEnt ) UTIL_AssignOrigin( this, m_pGoalEnt->pev->origin ); - } - - if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_WAITFORTRIG ) ) - { - TurnOff(); //wait for retrigger - return; - } - - // Time to go to the next target - m_pGoalEnt = m_pGoalEnt->GetNext(); - - // Set up next corner - if ( !m_pGoalEnt ) UTIL_SetVelocity( this, g_vecZero ); - else - { - pev->target = m_pGoalEnt->pev->targetname; // save last corner - pev->armorvalue = m_pGoalEnt->pev->speed; - - Vector delta = m_pGoalEnt->pev->origin - pev->origin; - pev->frags = delta.Length(); - pev->movedir = delta.Normalize(); - m_flDelay = gpGlobals->time + m_pGoalEnt->GetDelay(); - } - } - - if ( m_flDelay > gpGlobals->time ) - pev->speed = UTIL_Approach( 0, pev->speed, 5 * gpGlobals->frametime ); - else pev->speed = UTIL_Approach( pev->armorvalue, pev->speed, 5 * gpGlobals->frametime ); - - float fraction = 2 * gpGlobals->frametime; - UTIL_SetVelocity( this, ((pev->movedir * pev->speed) * fraction) + (pev->velocity * (1-fraction))); -} - -void CSprite::TurnOff( void ) -{ - SetBits( pev->effects, EF_NODRAW ); - m_iState = STATE_OFF; - if( m_pGoalEnt ) m_pGoalEnt = m_pGoalEnt->GetPrev(); - UTIL_SetVelocity( this, g_vecZero ); - DontThink(); -} - -void CSprite::TurnOn( void ) -{ - pev->dmgtime = gpGlobals->time; - ClearBits( pev->effects, EF_NODRAW ); - pev->frame = 0; - m_iState = STATE_ON; - - pev->armorvalue = pev->speed; - m_flDelay = gpGlobals->time; - pev->frags = 0; - - Move(); - SetNextThink( 0 ); -} - -void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pActivator = m_hActivator; - - if ( useType == USE_TOGGLE ) - { - if( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) TurnOn(); - else if ( useType == USE_OFF ) TurnOff(); - else if ( useType == USE_SET ) ClearBits( pev->effects, EF_NODRAW ); - else if ( useType == USE_RESET ) SetBits( pev->effects, EF_NODRAW ); - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, speed %g\n", GetStringForState( GetState()), pev->speed ); - if( m_pGoalEnt ) - ALERT( at_console, "NextPath: %s, framerate %g\n", STRING( m_pGoalEnt->pev->targetname ), pev->framerate ); - else ALERT( at_console, "NextPath: no path, framerate %g\n", pev->framerate ); - } -} -LINK_ENTITY_TO_CLASS( env_glow, CSprite ); -LINK_ENTITY_TO_CLASS( env_sprite, CSprite ); - -//================================================================= -// env_model: like env_sprite, except you can specify a sequence. -//================================================================= -#define SF_DROPTOFLOOR 4 - -class CEnvModel : public CBaseAnimating -{ - void Spawn( void ); - void Precache( void ){ UTIL_PrecacheModel( pev->model ); } - void EXPORT Animate( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void SetAnim( void ); -}; -LINK_ENTITY_TO_CLASS( env_model, CEnvModel ); - -void CEnvModel::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "mode")) - { - pev->button = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszSequence")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseAnimating::KeyValue( pkvd ); -} - -void CEnvModel :: Spawn( void ) -{ - Precache(); - UTIL_SetModel( ENT(pev), pev->model ); - UTIL_SetOrigin( this, pev->origin ); - - pev->takedamage = DAMAGE_NO; - if ( !( pev->spawnflags & SF_NOTSOLID )) - { - pev->solid = SOLID_SLIDEBOX; - UTIL_AutoSetSize(); - } - - if ( pev->spawnflags & SF_DROPTOFLOOR ) - { - pev->origin.z += 1; - DROP_TO_FLOOR ( ENT(pev) ); - } - - InitBoneControllers(); - ResetSequenceInfo( ); - m_iState = STATE_OFF; - if(pev->spawnflags & SF_START_ON) Use( this, this, USE_ON, 0 ); -} - -void CEnvModel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE ) - { - if( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) - { - SetAnim(); - SetThink( Animate ); - SetNextThink( 0.1 ); - m_iState = STATE_ON; - } - else if ( useType == USE_OFF ) - { - m_iState = STATE_OFF; - DontThink(); - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - } -} - -void CEnvModel::SetAnim( void ) -{ - pev->sequence = LookupSequence( STRING( pev->netname )); - if (pev->sequence == -1)pev->sequence = 0; - pev->frame = 0; - ResetSequenceInfo(); -} - -void CEnvModel::Animate( void ) -{ - SetNextThink( 0.1 ); - StudioFrameAdvance(); - - if (m_fSequenceFinished ) - { - if(pev->button) - { - //pev->frame = 0; - m_iState = STATE_OFF; - DontThink(); - } - else SetAnim(); - } -} - -//======================================================================= -// env_counter - digital 7 segment indicator as default -//======================================================================= -class CDecLED : public CBaseLogic -{ -public: - void Spawn( void ); - void CheckState( void ); - void Precache( void ){ UTIL_PrecacheModel( pev->model, "sprites/decimal.spr" ); } - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - float Frames( void ) { return MODEL_FRAMES( pev->modelindex ) - 1; } - float flashtime; - float curframe( void ) - { - if( pev->frame - floor( pev->frame ) > 0.5f ) - return ceil( pev->frame ); - return floor( pev->frame ); - } -}; -LINK_ENTITY_TO_CLASS( env_counter, CDecLED ); -LINK_ENTITY_TO_CLASS( logic_indicator, CDecLED ); // Xash 0.2 name - -void CDecLED :: Spawn( void ) -{ - Precache( ); - UTIL_SetModel( ENT(pev), pev->model, "sprites/decimal.spr" ); - - // Smart Field System © - if( !pev->rendermode ) pev->rendermode = kRenderTransAdd; - if( !pev->frags ) pev->frags = Frames(); - if( !pev->impulse ) pev->impulse = -1; - - CheckState(); - - pev->solid = SOLID_NOT; - pev->effects = EF_NOINTERP; // g-cont. criticall stuff, don't touch! - pev->movetype = MOVETYPE_NONE; - pev->angles.x = -pev->angles.x; - pev->angles.y = 180 - pev->angles.y; - pev->angles[1] = 0 - pev->angles[1]; -} - -void CDecLED :: CheckState( void ) -{ - switch( pev->skin ) - { - case 1: - if( pev->impulse >= curframe() ) - m_iState = STATE_ON; - else m_iState = STATE_OFF; - break; - case 2: - if( pev->impulse <= curframe() ) - m_iState = STATE_ON; - else m_iState = STATE_OFF; - break; - default: - if( pev->impulse == curframe() ) - m_iState = STATE_ON; - else m_iState = STATE_OFF; - break; - } -} - -void CDecLED :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "maxframe" )) - { - pev->frags = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "keyframe" )) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "type" )) - { - pev->skin = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CDecLED :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_ON || useType == USE_TOGGLE ) - { - if( pev->frame >= pev->frags ) - { - UTIL_FireTargets( pev->target, pActivator, this, useType, value ); - pev->frame = 0; - } - else pev->frame++; - - pev->effects &= ~EF_NODRAW; - flashtime = gpGlobals->time + 0.5f; - } - else if ( useType == USE_OFF ) - { - if( pev->frame <= 0.0f ) - { - UTIL_FireTargets( pev->target, pActivator, this, useType, value ); - pev->frame = pev->frags; - } - else pev->frame--; - - pev->effects &= ~EF_NODRAW; - flashtime = gpGlobals->time + 0.5f; - } - else if ( useType == USE_SET ) // set custom frame - { - if ( value != 0.0f ) - { - pev->frame = fmod( value, pev->frags + 1.0f ); - float next = value / ( pev->frags + 1.0f ); - if( (int)next ) UTIL_FireTargets( pev->target, pActivator, this, useType, (int)next ); - - pev->effects &= ~EF_NODRAW; - flashtime = gpGlobals->time + 0.5f; - } - else if( gpGlobals->time > flashtime ) - { - if( pev->effects & EF_NODRAW ) - { - pev->effects &= ~EF_NODRAW; - } - else - { - pev->effects |= EF_NODRAW; - } - } - } - else if ( useType == USE_RESET ) // immediately reset - { - pev->frame = 0; - pev->effects &= ~EF_NODRAW; - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - Msg( "Current frame: %.0f, Keyframe %d\n", pev->frame, pev->impulse ); - Msg( "State: %s, Maxframe %g\n", GetStringForState( GetState()), pev->frags ); - } - CheckState(); -} - -//======================================================================= -// env_shake - earthquake (screen shake) -//======================================================================= -class CShake : public CBaseLogic -{ -public: - void Spawn( void ){ m_iState = STATE_OFF; } - void Think( void ) { m_iState = STATE_OFF; }; - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - if( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - Msg( "State: %s, Amplitude: %g, Frequency: %g\n", GetStringForState( GetState()), pev->scale, pev->dmg_save ); - Msg( "Radius: %g, Duration: %d\n", pev->dmg, pev->dmg_take ); - } - else - { - UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() ); - m_iState = STATE_ON; - SetNextThink( Duration() ); - } - } - void KeyValue( KeyValueData *pkvd ) - { - if (FStrEq(pkvd->szKeyName, "amplitude" )) - { - SetAmplitude( atof(pkvd->szValue )); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "frequency" )) - { - SetFrequency( atof( pkvd->szValue )); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - SetRadius( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); - } - - inline float Amplitude( void ) { return pev->scale; } - inline float Frequency( void ) { return pev->dmg_save; } - inline float Duration( void ) { return pev->dmg_take; } - inline float Radius( void ) { return pev->dmg; } - inline void SetAmplitude( float amplitude ) { pev->scale = amplitude; } - inline void SetFrequency( float frequency ) { pev->dmg_save = frequency; } - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetRadius( float radius ) { pev->dmg = radius; } -}; -LINK_ENTITY_TO_CLASS( env_shake, CShake ); - -//======================================================================= -// env_sparks - classic HALF-LIFE sparks -//======================================================================= -class CEnvSpark : public CBaseLogic -{ -public: - void Spawn(void); - void Think(void); - void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS(env_spark, CEnvSpark); - -void CEnvSpark::Spawn(void) -{ - if( !m_flDelay ) m_flDelay = 1.0; // Smart field system ® - if( pev->spawnflags & SF_START_ON ) Use( this, this, USE_ON, 0 ); -} - -void CEnvSpark::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE) - { - if ( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) - { - m_iState = STATE_ON; - SetNextThink( m_flDelay ); - } - else if ( useType == USE_OFF ) - { - m_iState = STATE_OFF; - DontThink(); - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, MaxDelay %.2f\n\n", GetStringForState( GetState()), m_flDelay ); - } -} - -void CEnvSpark::Think( void ) -{ - float flVolume = RANDOM_FLOAT ( 0.25 , 0.75 ) * 0.4; // random volume range - switch( RANDOM_LONG( 0, 5 )) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark1.wav", flVolume, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark2.wav", flVolume, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark3.wav", flVolume, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark4.wav", flVolume, ATTN_NORM); break; - case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark5.wav", flVolume, ATTN_NORM); break; - case 5: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark6.wav", flVolume, ATTN_NORM); break; - } - - UTIL_Sparks( pev->origin + pev->size * 0.5 ); - if( m_iState == STATE_ON ) SetNextThink( 0.1 + RANDOM_FLOAT( 0, m_flDelay )); //!!! -} - -//========================================================= -// env_explosion (classic explode ) -//========================================================= -class CEnvExplosion : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Precache( void ) { if( pev->message ) pev->button = UTIL_PrecacheModel( pev->message ); } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Explode( void ); -}; -LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion ); - -void CEnvExplosion::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->dmg = atoi(pkvd->szValue); - if(pev->dmg < 10) pev->dmg = 10; - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "sprite")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE || useType == USE_ON ) - { - Explode(); - } - else if ( useType == USE_SET ) - { - pev->dmg = value; - if( pev->dmg < 10 ) pev->dmg = 10; - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "Radius %g\n", pev->dmg ); - SHIFT; - } -} - -void CEnvExplosion::Explode( void ) -{ - TraceResult tr; - Vector vecSpot = pev->origin;// trace starts here! - UTIL_TraceLine ( vecSpot + Vector( 0, 0, 8 ), vecSpot + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), &tr); - - // Pull out of the wall a bit - if ( tr.flFraction != 1.0 && tr.vecPlaneNormal[2] < 0.7f ) - pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (pev->dmg - 24) * 0.6); - int iContents = UTIL_PointContents ( pev->origin ); - - entvars_t *pevOwner; - if ( pev->owner ) pevOwner = VARS( pev->owner ); - else pevOwner = NULL; - pev->owner = NULL; // can't traceline attack owner if this is set - - if ( pev->dmg <= 0 ) - pev->dmg = 100; // Smart field system ® - - - if( iContents == CONTENTS_WATER ) - { - SFX_Explode( g_sModelIndexWExplosion, pev->origin, pev->dmg, TE_EXPLFLAG_NONE ); - RadiusDamage ( pev->origin, pev, pevOwner, pev->dmg / 2, pev->dmg * 2.5, CLASS_NONE, DMG_BLAST ); - } - else - { - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, pev->dmg * 5, 3.0 ); - // custom sprite - if( pev->button ) SFX_Explode( pev->button, pev->origin, pev->dmg, TE_EXPLFLAG_NONE ); - else SFX_Explode( g_sModelIndexFireball, pev->origin, pev->dmg, TE_EXPLFLAG_NONE ); - RadiusDamage ( pev->origin, pev, pevOwner, pev->dmg, pev->dmg * 2.5, CLASS_NONE, DMG_BLAST ); - - CBaseEntity *pWreckage = Create( "smokeent", pev->origin, pev->angles ); - pWreckage->SetNextThink( 0.2 ); - pWreckage->pev->impulse = ( pev->dmg - 50) * 0.6; - pWreckage->pev->dmgtime = gpGlobals->time + 1.5; - - int sparkCount = RANDOM_LONG( 0, 3 ); //make sparks - for ( int i = 0; i < sparkCount; i++ ) - Create( "sparkleent", pev->origin, tr.vecPlaneNormal, NULL ); - - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) UTIL_DecalTrace( &tr, DECAL_SCORCH1 ); - else UTIL_DecalTrace( &tr, DECAL_SCORCH2 ); - } - - if( pev->spawnflags & SF_FIREONCE ) UTIL_Remove( this ); -} - -//========================================================= -// gibs (sprite or models gib) -//========================================================= -void CGib :: Spawn( const char *szGibModel ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->friction = 0.55; // deading the bounce a bit - pev->renderamt = 255; - pev->rendermode = kRenderNormal; - pev->renderfx = kRenderFxNone; - pev->solid = SOLID_TRIGGER; - pev->classname = MAKE_STRING( "gib" ); - - SetObjectClass( ED_NORMAL ); - UTIL_SetModel( ENT( pev ), szGibModel ); - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - m_lifeTime = MAX_GIB_LIFETIME; - - - m_material = None; - m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain). -} - -void CGib :: WaitTillLand ( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - if ( pev->velocity == g_vecZero ) - { - if(m_lifeTime == -1) //waiting for pvs - { - SetThink( PVSRemove ); - SetNextThink( MAX_GIB_LIFETIME ); - } - else - { - SetThink( Fadeout ); - SetNextThink( m_lifeTime ); - } - if(m_bloodColor != DONT_BLEED) - { - CSoundEnt::InsertSound ( bits_SOUND_MEAT, pev->origin, 384, 25 ); - } - } - else SetNextThink( 0.5 ); -} - -void CGib :: BounceGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - if ( pOther != g_pWorld) UTIL_FireTargets( pev->target, pOther, this, USE_ON ); - else UTIL_FireTargets( pev->target, pOther, this, USE_SET ); //world touch - - if( pev->flags & FL_ONGROUND ) - { - pev->velocity = pev->velocity * 0.9; - pev->angles.x = 0; - pev->angles.z = 0; - pev->avelocity.x = 0; - pev->avelocity.z = 0; - } - else - { - if (m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) - { - vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); //move up a bit, and trace down. - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - m_cBloodDecals--; - } - if ( m_material != None && RANDOM_LONG(0,2) == 0 ) - { - float volume; - float zvel = fabs(pev->velocity.z); - volume = 0.8 * min(1.0, ((float)zvel) / 450.0); - CBaseBrush::PlayRandomSound( edict(), (Materials)m_material, volume ); - } - } -} - -void CGib :: StickyGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - if(m_lifeTime == -1) //waiting for pvs - { - SetThink( PVSRemove ); - SetNextThink( MAX_GIB_LIFETIME ); - } - else - { - SetThink( Fadeout ); - SetNextThink( m_lifeTime ); - } - - if ( pOther != g_pWorld ) - { - UTIL_FireTargets( pev->target, pOther, this, USE_ON ); - UTIL_Remove( this ); - return; - } - else UTIL_FireTargets( pev->target, pOther, this, USE_SET ); //world touch - - UTIL_TraceLine ( pev->origin, pev->origin + pev->velocity * 32, ignore_monsters, ENT(pev), & tr); - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - - pev->velocity = tr.vecPlaneNormal * -1; - pev->angles = UTIL_VecToAngles ( pev->velocity ); - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; -} - -CGib *CGib :: CreateGib( CBaseEntity *pVictim, const char *szGibModel, int gibtype ) -{ - CGib *pGib = GetClassPtr( (CGib *)NULL ); - pGib->Spawn( szGibModel ); - - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)(GET_MODEL_PTR( ENT(pGib->pev) )); - if (! pstudiohdr) return NULL; - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex); - - if ( pVictim ) //spawn at gibbed monster - { - if(gibtype == 1) //skull gib - { - pGib->pev->body = 0; //spawn skull - pGib->pev->origin = pVictim->pev->origin + pVictim->pev->view_ofs; - - edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pGib->edict()); - - if ( RANDOM_LONG ( 0, 100 ) <= 5 && pentPlayer ) - { - // 5% chance head will be thrown at player's face. - entvars_t *pevPlayer; - - pevPlayer = VARS( pentPlayer ); - pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300; - pGib->pev->velocity.z += 100; - } - else pGib->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - } - else - { - pGib->pev->body = RANDOM_LONG(1, pbodypart->nummodels - 1); //random gibs - - // spawn the gib somewhere in the monster's bounding volume - pGib->pev->origin.x = pVictim->pev->absmin.x + pVictim->pev->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.y = pVictim->pev->absmin.y + pVictim->pev->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.z = pVictim->pev->absmin.z + pVictim->pev->size.z * (RANDOM_FLOAT ( 0 , 1 ) ) + 1; - - // make the gib fly away from the attack vector - pGib->pev->velocity = g_vecAttackDir * -1; - - // mix in some noise - pGib->pev->velocity.x += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.y += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.z += RANDOM_FLOAT ( -0.25, 0.25 ); - - pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT ( 300, 400 ); - } - - //shared settings - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - pGib->m_bloodColor = (CBaseEntity::Instance(pVictim->edict()))->BloodColor(); - - if ( pVictim->pev->health > -50) pGib->pev->velocity = pGib->pev->velocity * 0.7; - else if ( pVictim->pev->health > -200) pGib->pev->velocity = pGib->pev->velocity * 2; - else pGib->pev->velocity = pGib->pev->velocity * 4; - - //LimitVelocity - float length = pGib->pev->velocity.Length(); - if ( length > (MAX_VELOCITY / 2)) - pGib->pev->velocity = pGib->pev->velocity.Normalize() * MAX_VELOCITY / 2; - } - - // global settings - UTIL_SetSize ( pGib->pev, g_vecZero, g_vecZero ); - - if(gibtype == 0 || gibtype == 1) //normal random gibs - { - pGib->pev->solid = SOLID_BBOX; - pGib->SetTouch( BounceGibTouch ); - pGib->SetThink( WaitTillLand ); - pGib->SetNextThink( 4 ); - } - if(gibtype == 2) //sticky gib - { - pGib->pev->movetype = MOVETYPE_TOSS; - pGib->SetTouch( StickyGibTouch ); - } - return pGib; -} - -//========================================================= -// env_shooter (sprite or models shooter) -//========================================================= -class CEnvShooter : public CBaseLogic -{ - void Precache( void ) { if(ParseGibFile()) Setup(); } - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - int ParseGibFile( void ); - void Setup( void ); - void Think( void ); - CBaseEntity *CreateGib( Vector vecPos, Vector vecVel ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - //this is will be restoring on precache - no need to save - Materials m_Material; - Physics m_Physics; - string_t entity; - - RandomRange velocity; - RandomRange variance; - RandomRange lifetime; -}; -LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ); - -void CEnvShooter::Spawn( void ) -{ - Precache(); - pev->effects = EF_NODRAW; - if ( m_flDelay == 0 ) m_flDelay = 0.1; - UTIL_LinearVector( this );//movement direction -} - -void CEnvShooter :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "file")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "gibcount")) - { - pev->impulse = pev->button = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "gibname")) - { - m_sSet = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "gibtarget")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - - -void CEnvShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - SetNextThink( 0 ); -} - -void CEnvShooter :: Think ( void ) -{ - TraceResult tr; //don't create stack monsters - UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); - Vector mins = pev->origin - Vector( 34, 34, 0 ); - Vector maxs = pev->origin + Vector( 34, 34, 0 ); - maxs.z = pev->origin.z; - mins.z = tr.vecEndPos.z; - - CBaseEntity *pList[2]; - if (UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER )) - { - // don't build a stack of monsters! - SetNextThink( m_flDelay ); - return; - } - Vector vecShootDir = pev->movedir; - vecShootDir = vecShootDir + gpGlobals->v_up * variance.Random(); - vecShootDir = vecShootDir + gpGlobals->v_right * variance.Random(); - vecShootDir = vecShootDir + gpGlobals->v_forward * variance.Random(); - vecShootDir = vecShootDir.Normalize(); - CBaseEntity *pGib = CreateGib(pev->origin, vecShootDir * velocity.Random() ); - - if ( pGib )UTIL_FireTargets( pev->target, pGib, this, USE_TOGGLE, 0 ); - if(pev->button > 0) pev->impulse--; - - if ( pev->impulse <= 0 ) - { - if ( pev->spawnflags & SF_FIREONCE ) - { - UTIL_Remove( this ); - return; - } - else - { - pev->impulse = pev->button; - DontThink(); - } - } - SetNextThink( m_flDelay ); -} - - -void CEnvShooter :: Setup( void ) -{ - //Smart field system ® - if(!FStringNull( m_sMaster )) UTIL_PrecacheModel( m_sMaster ); - if(!FStringNull( entity )) UTIL_PrecacheEntity( entity ); - if(velocity.m_flMax == 0) velocity.m_flMax = 100; - if(velocity.m_flMax > MAX_VELOCITY) velocity.m_flMax = MAX_VELOCITY; - if(lifetime.Random() == 0)lifetime = RandomRange( -1.0 ); - if(pev->scale == 0)pev->scale = 1; - CBaseBrush::MaterialSoundPrecache( m_Material ); - - //setup physics - pev->solid = SOLID_SLIDEBOX; - switch( m_Physics ) - { - case Noclip: pev->team = MOVETYPE_NOCLIP; pev->solid = SOLID_NOT; break; - case Bounce: pev->team = MOVETYPE_BOUNCE; break; - case Sticky: pev->team = MOVETYPE_TOSS; pev->solid = SOLID_BBOX; break; - case Fly: pev->team = MOVETYPE_FLY; break; - case Toss: pev->team = MOVETYPE_TOSS; break; - } -} - -int CEnvShooter :: ParseGibFile( void ) -{ - char *token; - char *afile = (char *)LOAD_FILE( STRING( pev->message ), NULL ); - const char *pfile = afile; - - if( !pfile ) - { - ALERT( at_warning, "Gib script file for %s not found!\n", STRING( pev->targetname )); - return 0; - } - else - { - while( pfile ) - { - token = COM_ParseToken( &pfile ); - - if ( !FStriCmp( token, "model" )) - { - token = COM_ParseToken( &pfile ); - m_sMaster = ALLOC_STRING( token ); - } - else if ( !FStriCmp( token, "entity" )) - { - token = COM_ParseToken( &pfile ); - entity = ALLOC_STRING( token ); - } - else if ( !FStriCmp( token, "speed" )) - { - token = COM_ParseToken( &pfile ); - velocity = RandomRange((char *)STRING(ALLOC_STRING(token))); - } - else if ( !FStriCmp( token, "variance" )) - { - token = COM_ParseToken( &pfile ); - variance = RandomRange((char *)STRING(ALLOC_STRING(token))); - } - else if ( !FStriCmp( token, "livetime" )) - { - token = COM_ParseToken( &pfile ); - lifetime = RandomRange((char *)STRING(ALLOC_STRING(token))); - } - else if ( !FStriCmp( token, "friction" )) - { - token = COM_ParseToken( &pfile ); - RandomRange((char *)STRING(ALLOC_STRING(token))); - pev->friction = RANDOM_FLOAT( m_flMin, m_flMax ); - } - else if ( !FStriCmp( token, "scale" )) - { - token = COM_ParseToken( &pfile ); - RandomRange((char *)STRING(ALLOC_STRING(token))); - pev->scale = RANDOM_FLOAT( m_flMin, m_flMax ); - } - else if ( !FStriCmp( token, "body" )) - { - token = COM_ParseToken( &pfile ); - RandomRange((char *)STRING(ALLOC_STRING(token))); - pev->body = RANDOM_FLOAT( m_flMin, m_flMax - 1 ); - } - else if ( !FStriCmp( token, "skin" )) - { - token = COM_ParseToken( &pfile ); - RandomRange((char *)STRING(ALLOC_STRING(token))); - pev->skin = RANDOM_FLOAT( m_flMin, m_flMax ); - } - else if ( !FStriCmp( token, "frame" )) - { - token = COM_ParseToken( &pfile ); - RandomRange((char *)STRING(ALLOC_STRING(token))); - pev->frame = RANDOM_FLOAT( m_flMin, m_flMax ); - } - else if ( !FStriCmp( token, "alpha" )) - { - token = COM_ParseToken( &pfile ); - RandomRange((char *)STRING(ALLOC_STRING(token))); - pev->renderamt = RANDOM_FLOAT( m_flMin, m_flMax ); - } - else if ( !FStriCmp( token, "color" )) - { - token = COM_ParseToken( &pfile ); - UTIL_StringToVector((float *)pev->rendercolor, token ); - } - else if ( !FStriCmp( token, "rendermode" )) - { - token = COM_ParseToken( &pfile ); - if ( !FStriCmp( token, "normal" )) pev->rendermode = kRenderNormal; - else if ( !FStriCmp( token, "color" )) pev->rendermode = kRenderTransColor; - else if ( !FStriCmp( token, "texture" )) pev->rendermode = kRenderTransTexture; - else if ( !FStriCmp( token, "glow" )) pev->rendermode = kRenderGlow; - else if ( !FStriCmp( token, "solid" )) pev->rendermode = kRenderTransAlpha; - else if ( !FStriCmp( token, "additive" )) pev->rendermode = kRenderTransAdd; - } - else if ( !FStriCmp( token, "sfx" )) - { - token = COM_ParseToken( &pfile ); - if ( !FStriCmp( token, "hologramm" )) pev->renderfx = kRenderFxHologram; - else if ( !FStriCmp( token, "glowshell" )) pev->renderfx = kRenderFxGlowShell; - } - else if ( !FStriCmp( token, "size" )) - { - UTIL_StringToVector((float*)pev->size, token); - pev->size = pev->size/2; - } - else if ( !FStriCmp( token, "material" )) - { - token = COM_ParseToken( &pfile ); - if ( !FStriCmp( token, "none" )) m_Material = None; - else if ( !FStriCmp( token, "bones" )) m_Material = Bones; - else if ( !FStriCmp( token, "flesh" )) m_Material = Flesh; - else if ( !FStriCmp( token, "cinder block" )) m_Material = CinderBlock; - else if ( !FStriCmp( token, "concrete" )) m_Material = Concrete; - else if ( !FStriCmp( token, "rocks" )) m_Material = Rocks; - else if ( !FStriCmp( token, "computer" )) m_Material = Computer; - else if ( !FStriCmp( token, "glass" )) m_Material = Glass; - else if ( !FStriCmp( token, "metalplate" )) m_Material = MetalPlate; - else if ( !FStriCmp( token, "metal" )) m_Material = Metal; - else if ( !FStriCmp( token, "airduct" )) m_Material = AirDuct; - else if ( !FStriCmp( token, "ceiling tile" )) m_Material = CeilingTile; - else if ( !FStriCmp( token, "wood" )) m_Material = Wood; - } - else if ( !FStriCmp( token, "physics" )) - { - token = COM_ParseToken( &pfile ); - if ( !FStriCmp( token, "bounce" )) m_Physics = Bounce; - else if ( !FStriCmp( token, "sticky" )) m_Physics = Sticky; - else if ( !FStriCmp( token, "noclip" )) m_Physics = Noclip; - else if ( !FStriCmp( token, "fly" )) m_Physics = Fly; - else if ( !FStriCmp( token, "toss" )) m_Physics = Toss; - } - } - - COM_FreeFile( afile ); - - if( FStringNull( m_sMaster) && FStringNull( entity )) - { - ALERT( at_warning, "model or entity not specified for %s\n", STRING( pev->targetname )); - return 0; - } - return 1; - } -} - -CBaseEntity *CEnvShooter :: CreateGib ( Vector vecPos, Vector vecVel ) -{ - if( !FStringNull( entity ))//custom precached entity - { - CBaseEntity *pEnt = CBaseEntity::CreateGib( (char *)STRING( entity ), (char *)STRING( m_sMaster)); - //CBaseEntity *pEnt = CBaseEntity::Create( (char *)STRING( entity ), pev->origin, g_vecZero, edict() ); - //if(!pEnt && pEnt->edict()) return NULL; - if(!pEnt) return NULL; - - //UTIL_SetOrigin( pEnt, vecPos ); - pEnt->pev->origin = vecPos; - pEnt->pev->velocity = vecVel; - pEnt->pev->renderamt = pev->renderamt; - //pEnt->pev->model = m_sMaster; - pEnt->pev->rendermode = pev->rendermode; - pEnt->pev->rendercolor = pev->rendercolor; - pEnt->pev->renderfx = pev->renderfx; - pEnt->pev->target = pev->netname; - pEnt->pev->skin = pev->skin; - pEnt->pev->body = pev->body; - pEnt->pev->scale = pev->scale; - pEnt->pev->frame = pev->frame; - pEnt->pev->friction = pev->friction; - pEnt->pev->movetype = pev->team; - pEnt->pev->solid = pev->solid; - pEnt->pev->targetname = m_sSet; - - //UTIL_SetModel(ENT(pEnt->pev), m_sMaster ); - return pEnt; - } - else if(m_Physics == Bounce || m_Physics == Sticky) // normal or sticky gib - { - CGib *pGib = CGib::CreateGib( NULL, (char *)STRING( m_sMaster ), m_Physics ); - if(!pGib && pGib->edict()) return NULL; - - pGib->pev->body = pev->body; - pGib->pev->origin = vecPos; - pGib->pev->velocity = vecVel; - pGib->m_material = m_Material; - pGib->pev->rendermode = pev->rendermode; - pGib->pev->renderamt = pev->renderamt; - pGib->pev->rendercolor = pev->rendercolor; - pGib->pev->renderfx = pev->renderfx; - pGib->pev->target = pev->netname; - pGib->pev->friction = pev->friction; - pGib->pev->scale = pev->scale; - pGib->pev->skin = pev->skin; - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - pGib->m_lifeTime = pev->health; - pGib->pev->scale = pev->scale; - pGib->pev->frame = pev->frame; - pGib->pev->targetname = m_sSet; - - return pGib; - } - else //not custom entity, other physics type - { - CShot *pShot = CShot::CreateShot ( (char *)STRING( m_sMaster ), pev->size ); - if(!pShot && pShot->edict()) return NULL; - - pShot->pev->origin = vecPos; - pShot->pev->velocity = vecVel; - pShot->pev->renderamt = pev->renderamt; - pShot->pev->rendermode = pev->rendermode; - pShot->pev->rendercolor = pev->rendercolor; - pShot->pev->renderfx = pev->renderfx; - pShot->pev->target = pev->netname; - pShot->pev->skin = pev->skin; - pShot->pev->body = pev->body; - pShot->pev->scale = pev->scale; - pShot->pev->frame = pev->frame; - pShot->pev->framerate = pev->framerate; - pShot->pev->friction = pev->friction; - pShot->pev->movetype = pev->team; - pShot->pev->targetname = m_sSet; - - if (pev->health || pev->health == -1) - { - //animate it - if (pShot->pev->framerate && pShot->Frames() > 1.0) - { - pShot->AnimateAndDie( 10 ); - pShot->pev->dmg_take = gpGlobals->time + pev->health; - pShot->SetNextThink( 0 ); - pShot->pev->dmgtime = gpGlobals->time; - } - else if( pev->health ) - { - pShot->SetThink( Fadeout ); - pShot->SetNextThink(pev->health); - } - else - { - pShot->SetThink( PVSRemove ); - pShot->SetNextThink( MAX_GIB_LIFETIME ); - } - } - return pShot; - } - return NULL; -} - -//========================================================= -// LRC - Decal effect -//========================================================= -class CEnvDecal : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); -}; - -LINK_ENTITY_TO_CLASS( env_decal, CEnvDecal ); - -void CEnvDecal :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CEnvDecal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( useType == USE_SHOWINFO) - { - DEBUGHEAD; - Msg("Decal name %s\n\n", GetStringForDecalName( pev->message )); - } - else - { - int m_decal = UTIL_LoadDecalPreset( pev->message ); - switch(m_decal) - { - case 1: pev->skin = gDecals[ DECAL_GUNSHOT1 + RANDOM_LONG(0,4)].index; break; - case 2: pev->skin = gDecals[ DECAL_BLOOD1 + RANDOM_LONG(0,5)].index; break; - case 3: pev->skin = gDecals[ DECAL_YBLOOD1 + RANDOM_LONG(0,5)].index; break; - case 4: pev->skin = gDecals[ DECAL_GLASSBREAK1 + RANDOM_LONG(0,2)].index; break; - case 5: pev->skin = gDecals[ DECAL_BIGSHOT1 + RANDOM_LONG(0,4)].index; break; - case 6: pev->skin = gDecals[ DECAL_SCORCH1 + RANDOM_LONG(0,1)].index; break; - case 7: pev->skin = gDecals[ DECAL_SPIT1 + RANDOM_LONG(0,1)].index; break; - default: pev->skin = DECAL_INDEX(STRING(m_decal)); break; - } - - Vector vecPos = pev->origin; - UTIL_MakeVectors(pev->angles); - Vector vecOffs = gpGlobals->v_forward; - vecOffs = vecOffs.Normalize() * MAP_HALFSIZE; - TraceResult trace; - UTIL_TraceLine( vecPos, vecPos+vecOffs, ignore_monsters, NULL, &trace ); - if (trace.flFraction == 1.0) return; // didn't hit anything, oh well - int entityIndex = (short)ENTINDEX(trace.pHit); - SFX_Decal( trace.vecEndPos, pev->skin, entityIndex, (int)VARS(trace.pHit)->modelindex ); - } -} - -//========================================================= -// env_warpball -//========================================================= -#define SF_REMOVE_ON_FIRE 0x0001 -#define SF_KILL_CENTER 0x0002 - -class CEnvWarpBall : public CBaseLogic -{ -public: - void Precache( void ); - void Spawn( void ) { Precache(); } - void KeyValue( KeyValueData *pkvd ); - void Think( void ); - void Affect( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - Vector vecOrigin; -}; -LINK_ENTITY_TO_CLASS( env_warpball, CEnvWarpBall ); - -void CEnvWarpBall :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->button = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "warp_target")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "damage_delay")) - { - pev->frags = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CEnvWarpBall::Precache( void ) -{ - UTIL_PrecacheModel( "sprites/lgtning.spr" ); - UTIL_PrecacheModel( "sprites/Fexplo1.spr" ); - UTIL_PrecacheSound( "debris/beamstart2.wav" ); - UTIL_PrecacheSound( "debris/beamstart7.wav" ); -} - -void CEnvWarpBall::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pActivator = m_hActivator; //save it for later - - if (useType == USE_TOGGLE || useType == USE_ON) Affect(); - else if( useType == USE_SET && value > 10) pev->button = value; - else if( useType == USE_RESET ) pev->button = 100; //default radius - else if( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "Radius: %d, Warp target %s\n\n", pev->button, STRING( pev->message )); - } -} - -void CEnvWarpBall::Affect( void ) -{ - int iTimes = 0; - int iDrawn = 0; - TraceResult tr; - Vector vecDest; - CBeam *pBeam; - CBaseEntity *pEntity = UTIL_FindEntityByTargetname ( NULL, STRING(pev->message)); - edict_t *pos; - - if(pEntity)//target found ? - { - vecOrigin = pEntity->pev->origin; - pos = pEntity->edict(); - } - else - { //use as center - vecOrigin = pev->origin; - pos = edict(); - } - EMIT_SOUND( pos, CHAN_BODY, "debris/beamstart2.wav", 1, ATTN_NORM ); - UTIL_ScreenShake( vecOrigin, 6, 160, 1.0, pev->button ); - CSprite *pSpr = CSprite::SpriteCreate( "sprites/Fexplo1.spr", vecOrigin, TRUE ); - pSpr->SetTransparency(kRenderGlow, 77, 210, 130, 255, kRenderFxNoDissipation); - pSpr->AnimateAndDie( 18 ); - - EMIT_SOUND( pos, CHAN_ITEM, "debris/beamstart7.wav", 1, ATTN_NORM ); - int iBeams = RANDOM_LONG(20, 40); - while (iDrawn < iBeams && iTimes < (iBeams * 3)) - { - vecDest = pev->button * (Vector(RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1)).Normalize()); - UTIL_TraceLine( vecOrigin, vecOrigin + vecDest, ignore_monsters, NULL, &tr); - if (tr.flFraction != 1.0) - { - // we hit something. - iDrawn++; - pBeam = CBeam::BeamCreate("sprites/lgtning.spr", 200); - pBeam->PointsInit( vecOrigin, tr.vecEndPos ); - pBeam->SetColor( 20, 243, 20 ); - pBeam->SetNoise( 65 ); - pBeam->SetBrightness( 220 ); - pBeam->SetWidth( 30 ); - pBeam->SetScrollRate( 35 ); - pBeam->SetThink( Remove ); - pBeam->pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.5, 1.6); - } - iTimes++; - } - - if ( pev->spawnflags & SF_REMOVE_ON_FIRE ) - UTIL_Remove( this ); - else SetNextThink( pev->frags ); -} - -void CEnvWarpBall::Think( void ) -{ - UTIL_FireTargets( pev->target, this, this, USE_TOGGLE ); - - if ( pev->spawnflags & SF_KILL_CENTER ) // Blue-Shift strange feature - { - CBaseEntity *pMonster = NULL; - while ((pMonster = UTIL_FindEntityInSphere( pMonster, vecOrigin, 72 )) != NULL) - { - if ( FBitSet( pMonster->pev->flags, FL_MONSTER ) || FBitSet( pMonster->pev->flags, FL_CLIENT )) - pMonster->TakeDamage ( pev, pev, 100, DMG_GENERIC ); - } - } - if ( pev->spawnflags & SF_REMOVE_ON_FIRE ) UTIL_Remove( this ); -} - -//======================================================================= -// base beams () -//======================================================================= -LINK_ENTITY_TO_CLASS( beam, CBeam ); - -void CBeam::Spawn( void ) -{ - pev->solid = SOLID_NOT; -} - -const Vector &CBeam::GetStartPos( void ) -{ - int type = GetType(); - - if( type == BEAM_ENTS ) - { - edict_t *pent = GetStartEntity(); - - if ( pent ) - return pent->v.origin; - } - return pev->origin; -} - -const Vector &CBeam::GetEndPos( void ) -{ - int type = GetType(); - - if( type == BEAM_ENTS || type == BEAM_ENTPOINT ) - { - edict_t *pent = GetEndEntity(); - - if ( pent ) - return pent->v.oldorigin; - } - return pev->oldorigin; -} - -CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) -{ - // Create a new entity with CBeam private data - CBeam *pBeam = GetClassPtr( (CBeam *)NULL ); - pBeam->pev->classname = MAKE_STRING( "beam" ); - pBeam->BeamInit( pSpriteName, width ); - - return pBeam; -} - -void CBeam::BeamInit( const char *pSpriteName, int width ) -{ - SetObjectClass( ED_BEAM ); - - SetColor( 255, 255, 255 ); - SetBrightness( 255 ); - SetNoise( 0 ); - SetFrame( 0 ); - SetScrollRate( 0 ); - pev->model = MAKE_STRING( pSpriteName ); - SetTexture( UTIL_PrecacheModel( pev->model ) ); - SetWidth( width ); - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; -} - -void CBeam::PointsInit( const Vector &start, const Vector &end ) -{ - SetType( BEAM_POINTS ); - SetStartPos( start ); - SetEndPos( end ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - -void CBeam::HoseInit( const Vector &start, const Vector &direction ) -{ - SetType( BEAM_HOSE ); - SetStartPos( start ); - SetEndPos( direction ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - -void CBeam::PointEntInit( const Vector &start, edict_t *pEnd ) -{ - SetType( BEAM_ENTPOINT ); - SetStartPos( start ); - SetEndEntity( pEnd ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - -void CBeam::EntsInit( edict_t *pStart, edict_t *pEnd ) -{ - SetType( BEAM_ENTS ); - SetStartEntity( pStart ); - SetEndEntity( pEnd ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - -void CBeam::RelinkBeam( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->mins.x = min( startPos.x, endPos.x ); - pev->mins.y = min( startPos.y, endPos.y ); - pev->mins.z = min( startPos.z, endPos.z ); - pev->maxs.x = max( startPos.x, endPos.x ); - pev->maxs.y = max( startPos.y, endPos.y ); - pev->maxs.z = max( startPos.z, endPos.z ); - pev->mins = pev->mins - pev->origin; - pev->maxs = pev->maxs - pev->origin; - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( this, pev->origin ); -} - -void CBeam::SetObjectCollisionBox( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->absmin.x = min( startPos.x, endPos.x ); - pev->absmin.y = min( startPos.y, endPos.y ); - pev->absmin.z = min( startPos.z, endPos.z ); - pev->absmax.x = max( startPos.x, endPos.x ); - pev->absmax.y = max( startPos.y, endPos.y ); - pev->absmax.z = max( startPos.z, endPos.z ); -} - -void CBeam::Touch( CBaseEntity *pOther ) -{ - if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) ) - { - if ( pev->owner ) - { - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - pOwner->Use( pOther, this, USE_TOGGLE, 0 ); - } - } -} - -CBaseEntity* CBeam::GetTripEntity( TraceResult *ptr ) -{ - CBaseEntity* pTrip; - - if (ptr->flFraction == 1.0 || ptr->pHit == NULL) return NULL; - - pTrip = CBaseEntity::Instance(ptr->pHit); - if (pTrip == NULL) return NULL; - - if (pTrip->pev->flags & (FL_CLIENT | FL_MONSTER ) && !pTrip->IsPushable())//physics ents can move too - return pTrip; - return NULL; -} - -void CBeam::BeamDamage( TraceResult *ptr ) -{ - RelinkBeam(); - if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) - { - CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit); - if ( pHit ) - { - if ( pev->dmg > 0 ) - { - ClearMultiDamage(); - pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pev, pev ); - if ( pev->dmg > 40 && pHit->IsBSPModel())//wall damage - { - UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); - } - } - else pHit->TakeHealth( -(pev->dmg * (gpGlobals->time - pev->dmgtime)), DMG_GENERIC ); - } - } - pev->dmgtime = gpGlobals->time; -} - -CBaseEntity *CBeam::RandomTargetname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) pEntity = pNewEntity; - } - return pEntity; -} - -void CBeam::DoSparks( const Vector &start, const Vector &end ) -{ - if ( pev->dmg > 100 ) UTIL_Sparks( start ); - if ( pev->dmg > 40 ) UTIL_Sparks( end ); -} - -//======================================================================= -// env_beam - toggleable beam -//======================================================================= -class CEnvBeam : public CBeam -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - void Think( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int IsPointEntity( CBaseEntity *pEnt ); - - void BeamUpdatePoints( void ); - void BeamUpdateVars( void ); - - CBaseEntity *pEnd; -}; -LINK_ENTITY_TO_CLASS( env_beam, CEnvBeam ); - -void CEnvBeam::Precache( void ) -{ - pev->team = UTIL_PrecacheModel( pev->message, "sprites/laserbeam.spr" ); - CBeam::Precache(); -} - -int CEnvBeam::IsPointEntity( CBaseEntity *pEnt ) -{ - if( pEnt->pev->modelindex && ( pEnt->m_iClassType != ED_BEAM )) - return 0; - return 1; -} - -void CEnvBeam::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "endpoint")) - { - pev->netname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sprite")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "width")) - { - SetWidth( atoi(pkvd->szValue)); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "noisewidth")) - { - SetNoise( atoi(pkvd->szValue)); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shade")) - { - pev->frags = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBeam::KeyValue( pkvd ); -} - -void CEnvBeam::BeamUpdateVars( void ) -{ - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; - SetTexture( pev->team ); - - BeamUpdatePoints(); - SetFrame( 0 ); - SetScrollRate( pev->speed ); - if ( pev->frags == 1 ) SetFlags( FBEAM_SHADEIN ); - if ( pev->frags == 2 ) SetFlags( FBEAM_SHADEOUT ); - if ( pev->renderamt == 255 ) SetFlags( FBEAM_SOLID ); - else SetFlags( 0 ); -} - -void CEnvBeam::Activate( void ) -{ - BeamUpdateVars(); - CBeam::Activate(); -} - - -void CEnvBeam::BeamUpdatePoints( void ) -{ - int beamType; - - pEnd = UTIL_FindEntityByTargetname ( NULL, STRING(pev->netname) ); - if( !pEnd ) return; - - int pointEnd = IsPointEntity( pEnd ); - - beamType = BEAM_ENTS; - - if ( !pointEnd ) - beamType = BEAM_ENTPOINT; - else beamType = BEAM_POINTS; - - SetType( beamType ); - - if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE ) - { - SetStartPos( pev->origin ); - if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE ) - SetEndPos( pEnd->pev->origin ); - else SetEndEntity( ENT( pEnd->pev ) ); - } - else - { - SetStartEntity( ENT( pev ) ); - SetEndEntity( ENT( pEnd->pev ) ); - } - - RelinkBeam(); -} - -void CEnvBeam::Spawn( void ) -{ - SetObjectClass( ED_BEAM ); - UTIL_SetModel( edict(), "sprites/null.spr" ); // beam start point - pev->solid = SOLID_NOT; // remove model & collisions - - Precache(); - - if( FStringNull( pev->netname )) - { - ALERT( at_warning, "%s end entity not found!\n", STRING( pev->classname )); - UTIL_Remove( this ); - return; - } - - pev->dmgtime = gpGlobals->time; - if( pev->rendercolor == g_vecZero ) pev->rendercolor = Vector( 255, 255, 255 ); - if( pev->spawnflags & SF_START_ON ) Use( this, this, USE_ON, 0 ); -} - -void CEnvBeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - m_iState = STATE_ON; - BeamUpdatePoints(); - pev->effects &= ~EF_NODRAW; - SetNextThink( 0 ); - pev->dmgtime = gpGlobals->time; - } - else if (useType == USE_OFF) - { - m_iState = STATE_OFF; - pev->effects |= EF_NODRAW; - DontThink(); - } - else if(useType == USE_SET) //set new damage level - { - pev->dmg = value; - } - else if(useType == USE_RESET) //set new brightness - { - if(value)pev->renderamt = value; - BeamUpdateVars(); - } - else if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - Msg( "State: %s, Damage %g\n", GetStringForState( GetState()), pev->dmg ); - Msg("Beam model %s\n", STRING( pev->message )); - } -} - -void CEnvBeam::Think( void ) -{ - if ( pev->dmg || !FStringNull( pev->target )) // apply damage & trip entity - { - TraceResult tr; - UTIL_TraceLine( pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr ); - BeamDamage( &tr ); - - CBaseEntity* pTrip = GetTripEntity( &tr ); - if (pTrip) - { - if (!FBitSet(pev->spawnflags, SF_BEAM_TRIPPED)) - { - UTIL_FireTargets(pev->target, pTrip, this, USE_TOGGLE); - pev->spawnflags |= SF_BEAM_TRIPPED; - } - } - else pev->spawnflags &= ~SF_BEAM_TRIPPED; - } - SetNextThink( 0.1 ); -} - -//======================================================================= -// env_laser - classic HALF-LIFE laser -//======================================================================= -LINK_ENTITY_TO_CLASS( env_laser, CLaser ); - -TYPEDESCRIPTION CLaser::m_SaveData[] = -{ - DEFINE_FIELD( CLaser, m_pStartSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( CLaser, m_pEndSprite, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CLaser, CBeam ); - -void CLaser::Spawn( void ) -{ - SetObjectClass( ED_BEAM ); - pev->frame = 0; - pev->solid = SOLID_NOT; // Remove model & collisions - Precache(); -} - -void CLaser::Activate( void ) -{ - if ( m_pStartSprite && m_pEndSprite ) - EntsInit( m_pStartSprite->edict(), m_pEndSprite->edict() ); -} - -void CLaser::SetObjectCollisionBox( void ) -{ - if ( m_pStartSprite && m_pEndSprite ) - { - const Vector &startPos = m_pStartSprite->pev->origin, &endPos = m_pEndSprite->pev->origin; - pev->absmin.x = min( startPos.x, endPos.x ); - pev->absmin.y = min( startPos.y, endPos.y ); - pev->absmin.z = min( startPos.z, endPos.z ); - pev->absmax.x = max( startPos.x, endPos.x ); - pev->absmax.y = max( startPos.y, endPos.y ); - pev->absmax.z = max( startPos.z, endPos.z ); - } - else - { - pev->absmin = g_vecZero; - pev->absmax = g_vecZero; - } -} - -void CLaser::PostSpawn( void ) -{ - if ( !FStringNull( pev->netname )) - { - m_pStartSprite = CSprite::SpriteCreate( STRING( pev->netname ), pev->origin, TRUE ); - if ( m_pStartSprite ) m_pStartSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); - else m_pStartSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE ); - } - else m_pStartSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE ); - m_pEndSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE ); - - if ( pev->spawnflags & SF_START_ON ) - { - TurnOn(); - } - else - { - TurnOff(); - } -} - -void CLaser::Precache( void ) -{ - UTIL_PrecacheModel( pev->message, "sprites/laserbeam.spr" ); - if( pev->netname ) UTIL_PrecacheModel( pev->netname ); -} - -void CLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sprite")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "startsprite")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "width")) - { - SetWidth( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "noisewidth")) - { - SetNoise( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBeam::KeyValue( pkvd ); -} - -void CLaser::TurnOff( void ) -{ - SetBits(pev->effects, EF_NODRAW ); - m_iState = STATE_OFF; - if ( m_pStartSprite ) - { - m_pStartSprite->TurnOff(); - UTIL_SetVelocity(m_pStartSprite, g_vecZero); - } - if ( m_pEndSprite ) - { - m_pEndSprite->TurnOff(); - UTIL_SetVelocity(m_pEndSprite, g_vecZero); - } - DontThink(); -} - -void CLaser::TurnOn( void ) -{ - ClearBits( pev->effects, EF_NODRAW ); - - if ( m_pStartSprite ) - m_pStartSprite->TurnOn(); - - if ( m_pEndSprite ) - m_pEndSprite->TurnOn(); - - pev->dmgtime = gpGlobals->time; - m_iState = STATE_ON; - SetScrollRate( pev->speed ); - SetFlags( FBEAM_SHADEOUT ); - SetNextThink( 0 ); -} - -void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) TurnOn(); - else if ( useType == USE_OFF ) TurnOff(); - else if ( useType == USE_SET ) // set new damage level - { - pev->dmg = value; - } - else if( useType == USE_RESET ) // set new brightness - { - if( value ) pev->renderamt = value; - RelinkBeam(); - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, Damage %g\n", GetStringForState( GetState()), pev->dmg ); - ALERT( at_console, "Laser model %s\n", STRING( pev->message )); - } -} - -void CLaser::FireAtPoint( Vector startpos, TraceResult &tr ) -{ - if ( m_pStartSprite && m_pEndSprite ) - { - UTIL_SetVelocity( m_pStartSprite, ( startpos - m_pStartSprite->pev->origin ) * 100 ); - UTIL_SetVelocity( m_pEndSprite, ( tr.vecEndPos - m_pEndSprite->pev->origin ) * 100 ); - } - - BeamDamage( &tr ); - DoSparks( startpos, tr.vecEndPos ); -} - -void CLaser:: Think( void ) -{ - Vector startpos = pev->origin; - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecProject = startpos + gpGlobals->v_forward * MAP_HALFSIZE; - UTIL_TraceLine( startpos, vecProject, dont_ignore_monsters, ignore_glass, NULL, &tr ); - FireAtPoint( startpos, tr ); - if( m_iState == STATE_ON ) SetNextThink( 0.01 ); //!!! -} - -//========================================================= -// env_lightning - random zap strike -//========================================================= -class CEnvLightning : public CBeam -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Think( void ); - void RandomPoint( Vector &vecSrc ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void BeamDamage( TraceResult *ptr ); -}; -LINK_ENTITY_TO_CLASS( env_lightning, CEnvLightning ); - -void CEnvLightning::Precache( void ) -{ - pev->team = UTIL_PrecacheModel( pev->message, "sprites/laserbeam.spr" ); - CBeam::Precache(); -} - -void CEnvLightning::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lifetime"))//beam lifetime (leave blank for toggle beam) - { - pev->armorvalue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sprite")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "width")) - { - pev->button = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "noisewidth")) - { - pev->impulse = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->frags = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBeam::KeyValue( pkvd ); -} - -void CEnvLightning::BeamDamage( TraceResult *ptr ) -{ - RelinkBeam(); - if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) - { - CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit); - if ( pHit ) - { - if (pev->dmg > 0) - { - ClearMultiDamage(); - pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pev, pev ); - if ( pev->dmg > 40 && pHit->IsBSPModel())//wall damage - { - UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); - } - } - else pHit->TakeHealth( -(pev->dmg * (gpGlobals->time - pev->dmgtime)), DMG_GENERIC ); - } - } - pev->dmgtime = gpGlobals->time; -} - -void CEnvLightning::RandomPoint( Vector &vecSrc ) -{ - int iLoops = 0; - - for (iLoops = 0; iLoops < 10; iLoops++) - { - Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir1 = vecDir1.Normalize(); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * pev->frags, ignore_monsters, ENT(pev), &tr1 ); - - if ((tr1.vecEndPos - vecSrc).Length() < pev->frags * 0.1) continue; - if (tr1.flFraction == 1.0) continue; - - SFX_Zap ( pev, vecSrc, tr1.vecEndPos ); - DoSparks( vecSrc, tr1.vecEndPos ); - BeamDamage( &tr1 ); - UTIL_FireTargets( pev->target, this, this, USE_TOGGLE ); - break; - } -} - -void CEnvLightning::Spawn( void ) -{ - UTIL_SetModel(edict(), "sprites/null.spr");//beam start point - pev->solid = SOLID_NOT; // Remove model & collisions - Precache(); - - pev->dmgtime = gpGlobals->time; - if (pev->rendercolor == g_vecZero) pev->rendercolor = Vector(255, 255, 255); - if(pev->spawnflags & SF_START_ON) Use( this, this, USE_ON, 0 ); -} - -void CEnvLightning::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - m_iState = STATE_ON; - pev->effects &= ~EF_NODRAW; - SetNextThink( 0 ); - pev->dmgtime = gpGlobals->time; - } - else if (useType == USE_OFF) - { - m_iState = STATE_OFF; - pev->effects |= EF_NODRAW; - DontThink(); - } - else if(useType == USE_SET) - { - } - else if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, MaxDelay %.2f\n\n", GetStringForState( GetState()), m_flDelay ); - } -} - -void CEnvLightning::Think( void ) -{ - RandomPoint( pev->origin ); - SetNextThink( pev->armorvalue + RANDOM_FLOAT( 0, m_flDelay ) ); -} - -//======================================================================= -// env_beamring - make ring from beams -//======================================================================= -class CEnvBeamRing : public CBeam -{ -public: - void Spawn( void ); - void Think( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( env_beamring, CEnvBeamRing ); - -void CEnvBeamRing::Precache( void ) -{ - pev->team = UTIL_PrecacheModel( pev->message, "sprites/laserbeam.spr" ); - CBeam::Precache(); -} - -void CEnvBeamRing::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lifetime"))//beam lifetime (leave blank for toggle beam) - { - pev->armorvalue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sprite")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "width")) - { - pev->button = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "noisewidth")) - { - pev->impulse = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->frags = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBeam::KeyValue( pkvd ); -} - -void CEnvBeamRing::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - m_iState = STATE_ON; - pev->effects &= ~EF_NODRAW; - SetNextThink( 0 ); - pev->dmgtime = gpGlobals->time; - } - else if (useType == USE_OFF) - { - m_iState = STATE_OFF; - pev->effects |= EF_NODRAW; - DontThink(); - } - else if(useType == USE_SET) - { - } - else if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, MaxDelay %.2f\n\n", GetStringForState( GetState()), m_flDelay ); - } -} - -void CEnvBeamRing::Spawn( void ) -{ - UTIL_SetModel(edict(), "sprites/null.spr");//beam start point - pev->solid = SOLID_NOT; // Remove model & collisions - Precache(); - - pev->dmgtime = gpGlobals->time; - if (pev->rendercolor == g_vecZero) pev->rendercolor = Vector(255, 255, 255); - if(pev->frags == 0)pev->frags = 20; - - //create second point - Vector vecAngles, vecPos; - vecAngles = pev->angles; - UTIL_MakeVectors(vecAngles); - vecPos = pev->origin + (gpGlobals->v_forward * pev->frags); - CBaseEntity *pRing = CBaseEntity::Create( "info_target", vecPos, vecAngles, edict() ); - if(m_iParent)pRing->m_iParent = m_iParent; - pev->enemy = pRing->edict(); //save our pointer - - if(pev->spawnflags & SF_START_ON) Use( this, this, USE_ON, 0 ); -} - -void CEnvBeamRing::Think( void ) -{ - CBaseEntity *pRing = CBaseEntity::Instance(pev->enemy); - SFX_Ring( pev, pRing->pev ); - SetNextThink( pev->armorvalue + RANDOM_FLOAT( 0, m_flDelay ) ); -} \ No newline at end of file diff --git a/server/ents/baseinfo.cpp b/server/ents/baseinfo.cpp deleted file mode 100644 index 94ab3bab..00000000 --- a/server/ents/baseinfo.cpp +++ /dev/null @@ -1,449 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// baseinfo.cpp - point info entities. -// e.g. info_target -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "player.h" -#include "client.h" - -//======================================================================= -// info_target (target entity) -//======================================================================= - -class CInfoTarget : public CPointEntity -{ -public: - void Spawn( void ) - { - pev->solid = SOLID_NOT; - UTIL_SetModel(ENT(pev),"models/common/null.mdl"); - UTIL_SetSize(pev, g_vecZero, g_vecZero); - SetBits( pFlags, PF_POINTENTITY ); - } -}; - -void CBaseDMStart::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "master")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -STATE CBaseDMStart::GetState( CBaseEntity *pEntity ) -{ - if (UTIL_IsMasterTriggered( pev->netname, pEntity )) - return STATE_ON; - else return STATE_OFF; -} - -class CWallTorch : public CBaseEntity -{ -public: - void Precache( void ) - { - PRECACHE_SOUND( "ambience/fire1.wav" ); - UTIL_PrecacheModel( "models/props/torch1.mdl" ); - UTIL_EmitAmbientSound( ENT(pev), pev->origin, "ambience/fire1.wav", 1.0f, ATTN_NORM, 0, PITCH_NORM ); - } - void Spawn( void ) - { - Precache (); - -// SetObjectClass( ED_NORMAL ); - pev->flags |= FL_PHS_FILTER; // allow phs filter instead pvs - - // setup attenuation radius - pev->armorvalue = 384.0f * ATTN_STATIC; - - UTIL_SetModel( ENT( pev ), "models/props/torch1.mdl" ); - UTIL_SetSize(pev, g_vecZero, g_vecZero); - SetBits( pFlags, PF_POINTENTITY ); - pev->animtime = gpGlobals->time + 0.2; // enable animation - pev->framerate = 0.5f; - } -}; -LINK_ENTITY_TO_CLASS( light_torch_small_walltorch, CWallTorch ); - -//========================================================= -// static infodecal -//========================================================= -class CDecal : public CBaseEntity -{ -public: - void KeyValue( KeyValueData *pkvd ) - { - if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->skin = DECAL_INDEX( pkvd->szValue ); - if ( pev->skin >= 0 ) return; - Msg( "Can't find decal %s\n", pkvd->szValue ); - } - } - void PostSpawn( void ) - { - if ( pev->skin < 0 ) { REMOVE_ENTITY(ENT(pev)); return; } - TraceResult trace; - int entityIndex, modelIndex; - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - entityIndex = (short)ENTINDEX(trace.pHit); - if ( entityIndex > 0 ) - modelIndex = (int)VARS(trace.pHit)->modelindex; - else modelIndex = 0; - g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex ); - SetThink( Remove ); - SetNextThink( 0.3 ); - } -}; - -//========================================================= -// Multiplayer intermission spots. -//========================================================= -class CInfoIntermission : public CPointEntity -{ - void Spawn( void ); - void Think( void ); - void PostActivate( void ); - CBaseEntity *pTarget; - void KeyValue( KeyValueData *pkvd ); - -}; - -void CInfoIntermission :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - UTIL_SetOrigin( this, pev->origin ); - UTIL_SetModel( ENT( pev ), "sprites/null.spr" ); - - SetNextThink( 1 );// let targets spawn! -} - -void CInfoIntermission::PostActivate( void ) -{ - if( FStrEq( STRING( pev->classname ), "info_intermission" )) - pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target )); - if( !pev->speed ) pev->speed = 100; -} - -void CInfoIntermission::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "mangle" )) - { - Vector tmp; - - // Quake1 intermission angles - UTIL_StringToVector( tmp, pkvd->szValue ); - if( tmp != g_vecZero ) pev->angles = tmp; - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "roll" )) - { - // Quake3 portal camera - pev->v_angle[ROLL] = atof( pkvd->szValue ) / 360.0f; - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CInfoIntermission::Think ( void ) -{ - if( pTarget ) - { - UTIL_WatchTarget( this, pTarget ); - SetNextThink( 0 ); - } -} - -//========================================================= -// portal surfaces -//========================================================= -class CPortalSurface : public CPointEntity -{ - void Spawn( void ); - void Think( void ); - void PostActivate( void ); -}; - -void CPortalSurface :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - pev->flags |= FL_PHS_FILTER; // use phs so can collect portal sounds - - SetObjectClass( ED_PORTAL ); - UTIL_SetOrigin( this, pev->origin ); - pev->modelindex = 1; // world - - SetNextThink( 1 );// let targets spawn! -} - -void CPortalSurface :: Think( void ) -{ - if( FNullEnt( pev->owner )) - pev->oldorigin = pev->origin; - else pev->oldorigin = pev->owner->v.origin; - - SetNextThink( 0.1f ); -} - -void CPortalSurface :: PostActivate( void ) -{ - CBaseEntity *pTarget, *pOwner; - - SetNextThink( 0 ); - - if( FStringNull( pev->target )) - return; // mirror - - pOwner = UTIL_FindEntityByTargetname( NULL, STRING( pev->target )); - if( !pOwner ) - { - ALERT( at_warning, "Couldn't find target for %s\n", STRING( pev->classname )); - UTIL_Remove( this ); - return; - } - - pev->owner = pOwner->edict(); - - // q3a swinging camera support - if( pOwner->pev->spawnflags & 1 ) - pev->framerate = 25; - else if( pOwner->pev->spawnflags & 2 ) - pev->framerate = 75; - if( pOwner->pev->spawnflags & 4 ) - pev->effects &= ~EF_ROTATE; - else pev->effects |= EF_ROTATE; - - pev->frame = pOwner->pev->v_angle[ROLL]; // rollangle - - // see if the portal_camera has a target - if( !FStringNull( pOwner->pev->target )) - pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pOwner->pev->target )); - else pTarget = NULL; - - if( pTarget ) - { - pev->movedir = pTarget->pev->origin - pOwner->pev->origin; - pev->movedir.Normalize(); - } - else - { - pev->angles = pOwner->pev->angles; - UTIL_LinearVector( this ); - } -} - -//========================================================= -// info_path - train node path. -//========================================================= -void CInfoPath :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "wait" )) - { - m_flDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq (pkvd->szKeyName, "newspeed" )) - { - if ( pkvd->szValue[0] == '+' ) pev->button = SPEED_INCREMENT; //increase speed - else if ( pkvd->szValue[0] == '-' ) pev->button = SPEED_DECREMENT; //decrease speed - else if ( pkvd->szValue[0] == '*' ) pev->button = SPEED_MULTIPLY; //multiply speed by - else if ( pkvd->szValue[0] == ':' ) pev->button = SPEED_DIVIDE; //divide speed by - else pev->button = SPEED_MASTER; // just set new speed - if( pev->button ) pkvd->szValue++; - pev->speed = atof( pkvd->szValue ); - ALERT( at_console, "pev->button %d, pev->speed %g\n", pev->button, pev->speed ); - pkvd->fHandled = TRUE; - } - else if ( !FClassnameIs( pev, "path_corner" ) && m_cPaths < MAX_MULTI_TARGETS ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iPathName[m_cPaths] = ALLOC_STRING( tmp ); - m_iPathWeight[m_cPaths] = atof( pkvd->szValue ); - m_cPaths++; - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -TYPEDESCRIPTION CInfoPath::m_SaveData[] = -{ DEFINE_FIELD( CInfoPath, m_cPaths, FIELD_INTEGER ), - DEFINE_FIELD( CInfoPath, m_index, FIELD_INTEGER ), - DEFINE_ARRAY( CInfoPath, m_iPathName, FIELD_STRING, MAX_MULTI_TARGETS ), - DEFINE_ARRAY( CInfoPath, m_iPathWeight, FIELD_INTEGER, MAX_MULTI_TARGETS ), - DEFINE_ARRAY( CInfoPath, m_pNextPath, FIELD_CLASSPTR, MAX_MULTI_TARGETS ), - DEFINE_FIELD( CInfoPath, m_pPrevPath, FIELD_CLASSPTR ), -};IMPLEMENT_SAVERESTORE( CInfoPath, CBaseLogic ); - -LINK_ENTITY_TO_CLASS( info_path, CInfoPath ); -LINK_ENTITY_TO_CLASS( path_corner, CInfoPath ); - -void CInfoPath :: Spawn( void ) -{ - if( FClassnameIs( pev, "path_corner" )) - { - // compatible mode - m_iPathName[m_cPaths] = pev->target; - m_iPathWeight[m_cPaths] = 0; - m_cPaths++; - } - - int r_index = 0; - int w_index = m_cPaths - 1; - - while( r_index < w_index ) - { - // we store target with right index in tempname - int name = m_iPathName [r_index]; - int weight = m_iPathWeight[r_index]; - - // target with right name is free, record new value from wrong name - m_iPathName [r_index] = m_iPathName [w_index]; - m_iPathWeight[r_index] = m_iPathWeight[w_index]; - - // ok, we can swap targets - m_iPathName [w_index] = name; - m_iPathWeight[w_index] = weight; - - r_index++; - w_index--; - } - - m_iState = STATE_ON; - m_index = 0; - SetBits( pFlags, PF_POINTENTITY ); - pev->scale = 0.1f; -} - -void CInfoPath :: PostActivate( void ) -{ - // find all paths and save into array - for(int i = 0; i < m_cPaths; i++ ) - { - CBaseEntity *pNext = UTIL_FindEntityByTargetname( NULL, STRING( m_iPathName[i] )); - if( pNext ) // found path - { - m_pNextPath[i] = (CInfoPath*)pNext; // valid path - m_pNextPath[i]->SetPrev( this ); - } - } -} - -CBaseEntity *CInfoPath::GetNext( void ) -{ - int total = 0; - for ( int i = 0; i < m_cPaths; i++ ) - { - total += m_iPathWeight[i]; - } - - if ( total ) // weighted random choose - { - int chosen = RANDOM_LONG( 0, total ); - int curpos = 0; - for ( i = 0; i < m_cPaths; i++ ) - { - curpos += m_iPathWeight[i]; - if ( curpos >= chosen ) - { - m_index = i; - break; - } - } - } - - // validate path - ASSERTSZ( m_pNextPath[m_index] != this, "GetNext: self path!\n"); - if( m_pNextPath[m_index] && m_pNextPath[m_index]->edict() && m_pNextPath[m_index] != this && m_pNextPath[m_index]->m_iState == STATE_ON ) - - return m_pNextPath[m_index]; - return NULL; -} - -CBaseEntity *CInfoPath::GetPrev( void ) -{ - // validate path - ASSERTSZ( m_pPrevPath != this, "GetPrev: self path!\n"); - if(m_pPrevPath && m_pPrevPath->edict() && m_pPrevPath != this && m_pPrevPath->m_iState == STATE_ON ) - return m_pPrevPath; - return NULL; -} - -void CInfoPath::SetPrev( CInfoPath *pPrev ) -{ - if( pPrev && pPrev->edict() && pPrev != this ) - m_pPrevPath = pPrev; -} - -void CInfoPath :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if ( useType == USE_TOGGLE ) - { - if( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) - { - m_iState = STATE_ON; - } - else if ( useType == USE_OFF ) - { - m_iState = STATE_OFF; - } - if ( useType == USE_SET ) // set new path - { - if( value > 0.0f ) - { - m_index = (value - 1); - if( m_index >= m_cPaths ) - m_index = 0; - } - } - else if ( useType == USE_RESET ) - { - m_index = 0; - } - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING(pev->classname)); - ALERT( at_console, "State: %s, number of targets %d, path weight %d\n", GetStringForState( GetState()), m_cPaths- 1, m_iPathWeight[m_index]); - if( m_pPrevPath && m_pPrevPath->edict( )) - ALERT( at_console, "Prev path %s", STRING( m_pPrevPath->pev->targetname )); - if( m_pNextPath[m_index] && m_pNextPath[m_index]->edict( )) - ALERT( at_console, "Prev path %s", STRING( m_pNextPath[m_index]->pev->targetname )); - ALERT( at_console, "\n" ); - } -} - -LINK_ENTITY_TO_CLASS( infodecal, CDecal ); -LINK_ENTITY_TO_CLASS( info_target, CInfoTarget ); -LINK_ENTITY_TO_CLASS( target_position, CPointEntity ); -LINK_ENTITY_TO_CLASS( target_location, CPointEntity ); -LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity ); -LINK_ENTITY_TO_CLASS( info_portal, CPortalSurface ); -LINK_ENTITY_TO_CLASS( misc_portal_surface, CPortalSurface ); -LINK_ENTITY_TO_CLASS( info_player_intermission, CPointEntity ); -LINK_ENTITY_TO_CLASS( info_notnull, CPointEntity ); -LINK_ENTITY_TO_CLASS( info_null, CNullEntity ); -LINK_ENTITY_TO_CLASS( info_texlights, CNullEntity); -LINK_ENTITY_TO_CLASS( info_compile_parameters, CNullEntity); -LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ); -LINK_ENTITY_TO_CLASS( info_camera, CInfoIntermission ); -LINK_ENTITY_TO_CLASS( misc_portal_camera, CInfoIntermission ); -LINK_ENTITY_TO_CLASS( info_player_deathmatch, CBaseDMStart ); -LINK_ENTITY_TO_CLASS( info_player_start, CPointEntity ); -LINK_ENTITY_TO_CLASS( info_landmark, CPointEntity ); \ No newline at end of file diff --git a/server/ents/baseinfo.h b/server/ents/baseinfo.h deleted file mode 100644 index f14aac7b..00000000 --- a/server/ents/baseinfo.h +++ /dev/null @@ -1,108 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef BASEINFO_H -#define BASEINFO_H - -class CPointEntity : public CBaseEntity -{ -public: - void Spawn( void ){ SetBits( pFlags, PF_POINTENTITY ); pev->solid = SOLID_NOT; } - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - -class CNullEntity : public CBaseEntity -{ -public: - void Spawn( void ){ REMOVE_ENTITY( ENT( pev )); } -}; - -class CBaseDMStart : public CPointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - STATE GetState( CBaseEntity *pEntity ); - -private: -}; - -#define SPEED_MASTER 0 -#define SPEED_INCREMENT 1 -#define SPEED_DECREMENT 2 -#define SPEED_MULTIPLY 3 -#define SPEED_DIVIDE 4 - -#define SF_CORNER_WAITFORTRIG 0x1 -#define SF_CORNER_TELEPORT 0x2 -#define SF_CORNER_FIREONCE 0x4 - -class CInfoPath : public CBaseLogic -{ -public: - void Spawn( ); - void KeyValue( KeyValueData* pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void PostActivate( void ); - float GetDelay( void ) { return m_flDelay; } - - void GetSpeed( float *speed ) - { - if( !pev->speed ) return; - float curspeed = *speed; // save our speed - - // operate - if( pev->button == SPEED_INCREMENT ) curspeed += pev->speed; - if( pev->button == SPEED_DECREMENT ) curspeed -= pev->speed; - if( pev->button == SPEED_MULTIPLY ) curspeed *= pev->speed; - if( pev->button == SPEED_DIVIDE ) curspeed /= pev->speed; - if( pev->button == SPEED_MASTER ) curspeed = pev->speed; - // check validate speed - if( curspeed <= -MAX_VELOCITY || curspeed >= MAX_VELOCITY ) - { - curspeed = *speed; // set old value - ALERT( at_console, "\n======/Xash SmartField System/======\n\n" ); - ALERT( at_console, "%s: %s contains invalid speed operation! Check it!\n Speed not changed!\n", STRING( pev->classname ), STRING( pev->targetname )); - } - *speed = curspeed; - } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_cPaths; // the total number of targets in this manager's fire list. - int m_index; // Current target - int m_iPathName[MAX_MULTI_TARGETS]; // list if indexes into global string array - int m_iPathWeight[MAX_MULTI_TARGETS]; // list if weight into global string array - - CInfoPath *Instance( edict_t *pent ) - { - if ( FClassnameIs( pent, "info_path" )) - return (CInfoPath *)GET_PRIVATE( pent ); - return NULL; - } - - CInfoPath *m_pNextPath[MAX_MULTI_TARGETS]; - CInfoPath *m_pPrevPath; - CBaseEntity *GetNext( void ); - CBaseEntity *GetPrev( void ); - void SetPrev( CInfoPath *pPrev ); -}; - -class CLaserSpot : public CBaseEntity // laser spot for different weapons -{ - void Spawn( void ); - void Precache( void ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -public: - void Suspend( float flSuspendTime ); - void Update( CBasePlayer *m_pPlayer ); - void EXPORT Revive( void ); - void UpdateOnRemove( void ); - void Killed( void ){ UTIL_Remove( this ); } - - static CLaserSpot *CreateSpot( entvars_t *pevOwner = NULL ); -}; - -#endif //BASEINFO_H \ No newline at end of file diff --git a/server/ents/baseitem.cpp b/server/ents/baseitem.cpp deleted file mode 100644 index eca63035..00000000 --- a/server/ents/baseitem.cpp +++ /dev/null @@ -1,635 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// item_.cpp - items entities: suit, -// helmet, lighter, etc -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "saverestore.h" -#include "baseweapon.h" -#include "client.h" -#include "player.h" -#include "gamerules.h" -#include "defaults.h" - -extern int gEvilImpulse101; - -//*********************************************************** -// main functions () -//*********************************************************** - -void CItem::Spawn( void ) -{ - Precache(); - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_BBOX; - - UTIL_SetOrigin( this, pev->origin ); - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - SetObjectClass( ED_NORMAL ); - - SetTouch( ItemTouch ); - SetThink( ItemFall ); - - UTIL_SetModel(ENT(pev), pev->model, Model() ); - SetNextThink( 0.1 ); -} - -void CItem::Precache( void ) -{ - UTIL_PrecacheModel( pev->model, Model() ); - UTIL_PrecacheSound( PickSound()); - UTIL_PrecacheSound( FallSound()); -} - -void CItem::ItemTouch( CBaseEntity *pOther ) -{ - //removed this limitation for monsters - if ( !pOther->IsPlayer() ) return; - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - if (!UTIL_IsMasterTriggered(m_sMaster, pPlayer)) return; - if (pPlayer->pev->deadflag != DEAD_NO) return; - - if (AddItem( pPlayer ) != -1 ) - { - UTIL_FireTargets( pev->target, pOther, this, USE_TOGGLE ); - SetTouch( NULL ); - - if( IsItem() && gmsg.ItemPickup ) - { - //show icon for item - MESSAGE_BEGIN( MSG_ONE, gmsg.ItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - } - - // play pickup sound - EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, (char *)PickSound(), 1, ATTN_NORM ); - - // tell the owner item was taken - if (!FNullEnt( pev->owner )) pev->owner->v.impulse = 0; - - // enable respawn in multiplayer - if ( g_pGameRules->IsMultiplayer() && !FBitSet( pev->spawnflags, SF_NORESPAWN )) - Respawn(); - else UTIL_Remove( this ); - } - else if ( gEvilImpulse101 ) UTIL_Remove( this ); -} - -void CItem::ItemFall ( void ) -{ - SetNextThink( 0.1 ); - - if ( pev->flags & FL_ONGROUND ) - { - // clatter if we have an owner (i.e., dropped by someone) - // don't clatter if the item is waiting to respawn (if it's waiting, it is invisible!) - if ( !FNullEnt( pev->owner )) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, (char *)FallSound(), 1, ATTN_NORM); - ItemOnGround(); //do somewhat if needed - } - - // lie flat - pev->angles.x = 0; - pev->angles.z = 0; - - pev->solid = SOLID_TRIGGER; - - if( IsAmmo( )) UTIL_SetSize( pev, Vector( -8, -8, -8 ), Vector( 8, 8, 8 )); - if( IsItem( )) UTIL_SetSize( pev, Vector( -8, -8, -8 ), Vector( 8, 8, 8 )); - else UTIL_AutoSetSize(); - - UTIL_SetOrigin( this, pev->origin ); // link into world. - - SetTouch( ItemTouch ); - SetThink( NULL ); - } -} - -CBaseEntity* CItem::Respawn( void ) -{ - SetTouch( NULL ); - pev->effects |= EF_NODRAW; - - SetThink( Materialize ); - AbsoluteNextThink( ItemRespawnTime( this ) ); - return this; -} - -float CItem::ItemRespawnTime( CItem *pItem ) -{ - //makes different time to respawn for weapons and items - float flRespawnTime; - - if (IsAmmo()) flRespawnTime = RESPAWN_TIME_30SEC; - if (IsItem()) flRespawnTime = RESPAWN_TIME_120SEC; - return gpGlobals->time + flRespawnTime; -} - - -void CItem::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - pev->effects &= ~EF_NODRAW; - pev->renderfx = kRenderFxGlowShell; - pev->renderamt = 40; - pev->frags = 0; - pev->rendercolor.x = RANDOM_LONG(25, 255); - pev->rendercolor.y = RANDOM_LONG(25, 255); - pev->rendercolor.z = RANDOM_LONG(25, 255); - pev->scale = 0.01; - SetNextThink (0.001); - } - if( pev->scale > 1.2 ) pev->frags = 1; - if ( pev->frags == 1 ) - { //set effects for respawn item - if(pev->scale > 1.0) pev->scale -= 0.05; - else - { - pev->renderfx = kRenderFxNone; - pev->frags = 0; - SetTouch( ItemTouch ); - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/respawn.wav", 1, ATTN_NORM, 0, 150 ); - SetThink( NULL ); - DontThink(); - } - } - else pev->scale += 0.05; - SetNextThink (0.001); - -} - -//*********************************************************** -// generic item -//*********************************************************** -class CGenericItem : public CItem -{ - const char *Model( void ){ return "models/items/w_adrenaline.mdl"; } - int AddItem( CBaseEntity *pOther ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - if( pPlayer->pev->deadflag != DEAD_NO ) return -1; - if( pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1 ) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM); - return 0; - } - MESSAGE_BEGIN( MSG_ONE, gmsg.ItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - return -1; - } -}; -LINK_ENTITY_TO_CLASS( item_generic, CGenericItem ); - -//*********************************************************** -// items -//*********************************************************** -class CItemSuit : public CItem -{ - const char *Model( void ){ return "models/items/w_suit.mdl"; } - int AddItem( CBaseEntity *pOther ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - if ( pPlayer->pev->deadflag != DEAD_NO ) - return -1; - - if ( pPlayer->pev->weapons & ITEM_SUIT ) - return -1; - - if( pev->spawnflags & 1 ) // SF_SUIT_SHORTLOGON - EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A0" ); // short version of suit logon, - else EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_AAx" ); // long version of suit logon - - pPlayer->pev->weapons |= ITEM_SUIT; - return 0; - } -}; -LINK_ENTITY_TO_CLASS( item_suit, CItemSuit ); - -class CItemLongJump : public CItem -{ - const char *Model( void ){ return "models/items/w_longjump.mdl"; } - const char *PickSound( void ){ return "buttons/bell1.wav"; } - int AddItem( CBaseEntity *pOther ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - if( pPlayer->pev->weapons & ITEM_SUIT && !pPlayer->m_fLongJump ) - { - pPlayer->m_fLongJump = TRUE;// player now has longjump module - g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); - EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); - return 0; - } - return -1; - } -}; -LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ); - - -class CItemBattery : public CItem -{ - const char *Model( void ){ return "models/items/w_battery.mdl"; } - const char *PickSound( void ){ return "items/gunpickup2.wav"; } - int AddItem( CBaseEntity *pOther ) { return (pOther->TakeArmor( BATTERY_CHARGE, TRUE )) ? 0 : -1; } -}; -LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); - -class CHealthKit : public CItem -{ - const char *Model( void ){ return "models/items/w_medkit.mdl"; } - const char *PickSound( void ){ return "items/smallmedkit1.wav"; } - int AddItem( CBaseEntity *pOther ) { return (pOther->TakeHealth( MEDKIT_CAP, DMG_GENERIC )) ? 0 : -1; } -}; -LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit ); - -class CItemSoda : public CItem -{ -public: - const char *Model( void ){ return "models/can.mdl"; } - const char *FallSound( void ){ return "weapons/g_bounce3.wav"; } - int AddItem( CBaseEntity *pOther ) { pOther->TakeHealth( pev->skin * 1, DMG_GENERIC ); return 1; } -}; -LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ); - -class CItemSecurity : public CItem -{ - const char *Model( void ){ return "models/items/w_security.mdl"; } - const char *PickSound( void ){ return "items/gunpickup2.wav"; } - int AddItem( CBaseEntity *pOther ) { return TRUE; } -}; -LINK_ENTITY_TO_CLASS(item_security, CItemSecurity); - -class CItemArmorVest : public CItem -{ - const char *Model( void ){ return "models/items/w_vest.mdl"; } - const char *PickSound( void ){ return "items/gunpickup2.wav"; } - int AddItem( CBaseEntity *pOther ) { return (pOther->TakeArmor( 60 )) ? 0 : -1; } -}; -LINK_ENTITY_TO_CLASS(item_armorvest, CItemArmorVest); - -class CItemHelmet : public CItem -{ - const char *Model( void ){ return "models/items/w_helmet.mdl"; } - const char *PickSound( void ){ return "items/gunpickup2.wav"; } - int AddItem( CBaseEntity *pOther ) { return (pOther->TakeArmor( 40 )) ? 0 : -1; } -}; -LINK_ENTITY_TO_CLASS(item_helmet, CItemHelmet); - -//*********************************************************** -// ammo -//*********************************************************** -class CGlockAmmo : public CItem -{ - const char *Model( void ){ return "models/ammo/w_9mmclip.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", 250 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); - -class CPythonAmmo : public CItem -{ - const char *Model( void ){ return "models/ammo/w_357ammobox.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", 21 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo ); - -class CSniperAmmo : public CItem -{ - const char *Model( void ){ return "models/ammo/w_m40a1clip.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_357BOX_GIVE, "762", 21 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_762, CSniperAmmo ); - -class CRpgAmmo : public CItem -{ - const char *Model( void ){ return "models/ammo/w_rpgammo.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_RPGCLIP_GIVE, "rockets", 3 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ); - -class CMP5AmmoClip : public CItem -{ - const char *Model( void ){ return "models/ammo/w_9mmARclip.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_MP5CLIP_GIVE, "9mm", 250); } -}; -LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip ); -LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip ); - -class CSawAmmo : public CItem -{ - const char *Model( void ){ return "models/ammo/w_saw_clip.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_CHAINBOX_GIVE, "556", SAW_MAX_CLIP); } -}; -LINK_ENTITY_TO_CLASS( ammo_556, CSawAmmo ); - -class CMP5AmmoGrenade : public CItem -{ - const char *Model( void ){ return "models/ammo/w_argrenade.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_M203BOX_GIVE, "m203", 10 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_m203, CMP5AmmoGrenade ); - -class CGaussAmmo : public CItem -{ - const char *Model( void ){ return "models/ammo/w_gaussammo.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", 100 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); - -class CShotgunAmmoBox : public CItem -{ - const char *Model( void ){ return "models/ammo/w_shotbox.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( 12, "buckshot", 125 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmoBox ); - -class CCrossbowAmmo : public CItem -{ - const char *Model( void ){ return "models/ammo/w_crossbow_clip.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( 5, "bolts", 50 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ); - -class CShotgunAmmoShell : public CItem -{ - const char *Model( void ){ return "models/shellBuck.mdl"; } - const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; } - int AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( 1, "buckshot", 125 ); } -}; -LINK_ENTITY_TO_CLASS( ammo_buckshell, CShotgunAmmoShell ); - -//*********************************************************** -// item_weaponbox - a single entity that can store weapons -// and ammo. -//*********************************************************** -LINK_ENTITY_TO_CLASS( item_weaponbox, CWeaponBox ); - -TYPEDESCRIPTION CWeaponBox::m_SaveData[] = -{ - DEFINE_ARRAY( CWeaponBox, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ), -}; IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ); - -void CWeaponBox::Precache( void ) -{ - UTIL_PrecacheModel( "models/items/w_weaponbox.mdl" ); -} - -void CWeaponBox :: KeyValue( KeyValueData *pkvd ) -{ - if ( m_cAmmoTypes < MAX_AMMO_SLOTS ) - { - PackAmmo( ALLOC_STRING(pkvd->szKeyName), atoi(pkvd->szValue) ); - m_cAmmoTypes++;// count this new ammo type. - - pkvd->fHandled = TRUE; - } - else Msg( "WeaponBox too full! only %d ammotypes allowed\n", MAX_AMMO_SLOTS ); -} - -void CWeaponBox::Spawn( void ) -{ - Precache( ); - - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - UTIL_SetModel( ENT(pev), "models/items/w_weaponbox.mdl" ); -} - -void CWeaponBox::Kill( void ) -{ - CBasePlayerWeapon *pWeapon; - int i; - - // destroy the weapons - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - pWeapon->SetThink( Remove ); - pWeapon->SetNextThink( 0.1 ); - pWeapon = pWeapon->m_pNext; - } - } - - // remove the box - UTIL_Remove( this ); -} - -void CWeaponBox::Touch( CBaseEntity *pOther ) -{ - if ( !(pev->flags & FL_ONGROUND ) ) return; - if ( !pOther->IsPlayer() ) return; - if ( !pOther->IsAlive() ) return; - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - int i; - - // dole out ammo - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) - { - // there's some ammo of this type. - pPlayer->GiveAmmo( m_rgAmmo[ i ], (char *)STRING( m_rgiszAmmo[ i ] ), MaxAmmoCarry( m_rgiszAmmo[ i ] ) ); - - // now empty the ammo from the weaponbox since we just gave it to the player - m_rgiszAmmo[ i ] = iStringNull; - m_rgAmmo[ i ] = 0; - } - } - - // go through my weapons and try to give the usable ones to the player. - // it's important the the player be given ammo first, so the weapons code doesn't refuse - // to deploy a better weapon that the player may pick up because he has no ammo for it. - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - CBasePlayerWeapon *pItem; - - // have at least one weapon in this slot - while ( m_rgpPlayerItems[i] ) - { - pItem = m_rgpPlayerItems[i]; - m_rgpPlayerItems[i] = m_rgpPlayerItems[i]->m_pNext; // unlink this weapon from the box - - if( pPlayer->AddPlayerItem( pItem )) - pItem->AttachToPlayer( pPlayer ); - } - } - } - - EMIT_SOUND( pOther->edict(), CHAN_BODY, "items/gunpickup2.wav", 1, ATTN_NORM ); - - SetTouch( NULL ); - UTIL_Remove( this ); -} - -int CWeaponBox::MaxAmmoCarry( int iszName ) -{ - for( int i = 0; i < MAX_WEAPONS; i++ ) - { - if( CBasePlayerWeapon::ItemInfoArray[i].iszAmmo1 == iszName ) - return CBasePlayerWeapon::ItemInfoArray[i].iMaxAmmo1; - if( CBasePlayerWeapon::ItemInfoArray[i].iszAmmo2 == iszName ) - return CBasePlayerWeapon::ItemInfoArray[i].iMaxAmmo2; - } - - ALERT( at_error, "MaxAmmoCarry() doesn't recognize '%s'!\n", STRING( iszName )); - return -1; -} - -BOOL CWeaponBox::PackWeapon( CBasePlayerWeapon *pWeapon ) -{ - // is one of these weapons already packed in this box? - if ( HasWeapon( pWeapon ) ) return FALSE;// box can only hold one of each weapon type - - if ( pWeapon->m_pPlayer ) - { - // failed to unhook the weapon from the player! - if ( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) return FALSE; - } - - int iWeaponSlot = pWeapon->iItemSlot(); - - if ( m_rgpPlayerItems[ iWeaponSlot ] ) - { - // there's already one weapon in this slot, so link this into the slot's column - pWeapon->m_pNext = m_rgpPlayerItems[ iWeaponSlot ]; - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - } - else - { - // first weapon we have for this slot - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - pWeapon->m_pNext = NULL; - } - - pWeapon->pev->spawnflags |= SF_NORESPAWN;// never respawn - pWeapon->pev->movetype = MOVETYPE_NONE; - pWeapon->pev->solid = SOLID_NOT; - pWeapon->pev->effects = EF_NODRAW; - pWeapon->pev->modelindex = 0; - pWeapon->pev->model = iStringNull; - pWeapon->pev->owner = edict(); - pWeapon->SetThink( NULL );// crowbar may be trying to swing again, etc. - pWeapon->SetTouch( NULL ); - pWeapon->m_pPlayer = NULL; - - return TRUE; -} - -BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) -{ - int iMaxCarry; - - if ( FStringNull( iszName ) ) - { - // error here - Msg( "NULL String in PackAmmo!\n" ); - return FALSE; - } - - iMaxCarry = MaxAmmoCarry( iszName ); - - if ( iMaxCarry != -1 && iCount > 0 ) - { - GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry ); - return TRUE; - } - return FALSE; -} - -int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NULL*/ ) -{ - int i; - - for (i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++) - { - if (stricmp( szName, STRING( m_rgiszAmmo[i])) == 0) - { - if (pIndex) *pIndex = i; - - int iAdd = min( iCount, iMax - m_rgAmmo[i]); - if (iCount == 0 || iAdd > 0) - { - m_rgAmmo[i] += iAdd; - return i; - } - return -1; - } - } - if ( i < MAX_AMMO_SLOTS ) - { - if (pIndex) *pIndex = i; - - m_rgiszAmmo[i] = MAKE_STRING( szName ); - m_rgAmmo[i] = iCount; - return i; - } - - Msg("out of named ammo slots\n"); - return i; -} - -BOOL CWeaponBox::HasWeapon( CBasePlayerWeapon *pCheckItem ) -{ - CBasePlayerWeapon *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while( pItem ) - { - if( FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname ))) - return TRUE; - pItem = pItem->m_pNext; - } - return FALSE; -} - -BOOL CWeaponBox::IsEmpty( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - return FALSE; - } - - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] )) - return FALSE; // still have a bit of this type of ammo - } - return TRUE; -} - -void CWeaponBox::SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector( -16, -16, 0); - pev->absmax = pev->origin + Vector( 16, 16, 16 ); -} \ No newline at end of file diff --git a/server/ents/baseitem.h b/server/ents/baseitem.h deleted file mode 100644 index 676d86ed..00000000 --- a/server/ents/baseitem.h +++ /dev/null @@ -1,69 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ITEMS_H -#define ITEMS_H - - -class CItem : public CBaseLogic -{ -public: - void Spawn( void ); - void Precache( void ); - CBaseEntity* Respawn( void ); - void EXPORT ItemTouch( CBaseEntity *pOther ); - void EXPORT Materialize( void ); - void EXPORT ItemFall( void ); - virtual int AddItem( CBaseEntity *pOther ) { return -1; }; - virtual void ItemOnGround( void ) {}; - float ItemRespawnTime( CItem *pItem ); - - virtual BOOL IsItem( void ) { return !strncmp( STRING(pev->classname), "item_", 5 ); } - virtual BOOL IsAmmo( void ) { return !strncmp( STRING(pev->classname), "ammo_", 5 ); } - virtual BOOL IsWeapon( void ) { return FALSE; } - - //item_generic - virtual const char *Model( void ){ return NULL; } - virtual const char *PickSound( void ){ return "common/null.wav"; } - virtual const char *FallSound( void ){ return "common/null.wav"; } -}; - -class CWeaponBox : public CBaseEntity -{ - void Precache( void ); - void Spawn( void ); - void Touch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - BOOL IsEmpty( void ); - int GiveAmmo( int iCount, char *szName, int iMax, int *pIndex = NULL ); - void SetObjectCollisionBox( void ); -public: - void EXPORT Kill ( void ); - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BOOL HasWeapon( CBasePlayerWeapon *pCheckItem ); - BOOL PackWeapon( CBasePlayerWeapon *pWeapon ); - BOOL PackAmmo( int iszName, int iCount ); - - CBasePlayerWeapon *m_rgpPlayerItems[MAX_ITEM_TYPES];// one slot for each - - int MaxAmmoCarry( int iszName ); - int m_rgiszAmmo[MAX_AMMO_SLOTS];// ammo names - int m_rgAmmo[MAX_AMMO_SLOTS];// ammo quantities - int m_cAmmoTypes;// how many ammo types packed into this box (if packed by a level designer) -}; - -#endif // ITEMS_H diff --git a/server/ents/baselogic.cpp b/server/ents/baselogic.cpp deleted file mode 100644 index e565d638..00000000 --- a/server/ents/baselogic.cpp +++ /dev/null @@ -1,1381 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// logicentity.cpp - all entities with prefix "logic_" -// additional entities for smart system -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "defaults.h" - -// Use CBaseDelay as main function (renamed as CBaseLogic, see declaration in cbase.h). -//======================================================================= -// main functions () -//======================================================================= - -void CBaseLogic :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "delay" )) - { - m_flDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "wait" )) - { - m_flWait = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "master")) - { - m_sMaster = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -BOOL CBaseLogic :: IsLockedByMaster( void ) -{ - if (UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return FALSE; - return TRUE; -} - -BOOL CBaseLogic :: IsLockedByMaster( CBaseEntity *pActivator ) -{ - if (UTIL_IsMasterTriggered(m_sMaster, pActivator)) - return FALSE; - return TRUE; -} - -BOOL CBaseLogic :: IsLockedByMaster( USE_TYPE useType ) -{ - if (UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return FALSE; - else if (useType == USE_SHOWINFO) return FALSE;//pass to debug info - return TRUE; -} - -TYPEDESCRIPTION CBaseLogic::m_SaveData[] = -{ - DEFINE_FIELD( CBaseLogic, m_flDelay, FIELD_FLOAT ), - DEFINE_FIELD( CBaseLogic, m_flWait, FIELD_FLOAT ), - DEFINE_FIELD( CBaseLogic, m_hActivator, FIELD_EHANDLE ), - DEFINE_FIELD( CBaseLogic, m_hTarget, FIELD_EHANDLE ), - DEFINE_FIELD( CBaseLogic, m_iState, FIELD_INTEGER ), - DEFINE_FIELD( CBaseLogic, m_sMaster, FIELD_STRING), - DEFINE_FIELD( CBaseLogic, m_sSet, FIELD_STRING), - DEFINE_FIELD( CBaseLogic, m_sReset, FIELD_STRING), -};IMPLEMENT_SAVERESTORE( CBaseLogic, CBaseEntity ); - -//======================================================================= -// Logic_generator -//======================================================================= -#define NORMAL_MODE 0 -#define RANDOM_MODE 1 -#define RANDOM_MODE_WITH_DEC 2 - -#define SF_RANDOM 0x2 -#define SF_DEC 0x4 - -class CGenerator : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think (void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_iFireCount; - int m_iMaxFireCount; -}; -LINK_ENTITY_TO_CLASS( logic_generator, CGenerator ); - -void CGenerator :: Spawn() -{ - // Xash 0.2 compatible - if( pev->spawnflags & SF_RANDOM ) - pev->button = RANDOM_MODE; - if( pev->spawnflags & SF_DEC ) - pev->button = RANDOM_MODE_WITH_DEC; - - if( pev->button == RANDOM_MODE || pev->button == RANDOM_MODE_WITH_DEC ) - { - // set delay with decceleration - if( !m_flDelay || pev->button == RANDOM_MODE_WITH_DEC ) m_flDelay = 0.005f; - // generate max count automaticallly, if not set on map - if( !m_iMaxFireCount ) m_iMaxFireCount = RANDOM_LONG( 100, 200 ); - } - else - { - // Smart Field System © - if ( !m_iMaxFireCount ) - m_iMaxFireCount = -1; // disable counting for normal mode - } - - if ( pev->spawnflags & SF_START_ON ) - { - m_iState = STATE_ON; // initialy off in random mode - SetNextThink(m_flDelay); - } -} - -TYPEDESCRIPTION CGenerator :: m_SaveData[] = -{ - DEFINE_FIELD( CGenerator, m_iMaxFireCount, FIELD_INTEGER ), - DEFINE_FIELD( CGenerator, m_iFireCount, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CGenerator, CBaseLogic ); - -void CGenerator :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "maxcount" )) - { - m_iMaxFireCount = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - if (FStrEq( pkvd->szKeyName, "mode" )) - { - pev->button = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CGenerator :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE ) - { - if ( m_iState ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) - { - if ( pev->button == RANDOM_MODE || pev->button == RANDOM_MODE_WITH_DEC ) - { - if( pev->button == RANDOM_MODE_WITH_DEC ) m_flDelay = 0.005; - m_iFireCount = RANDOM_LONG( 0, m_iMaxFireCount / 2 ); - } - m_iState = STATE_ON; - SetNextThink( 0 );//immediately start firing targets - } - else if ( useType == USE_OFF ) - { - m_iState = STATE_OFF; - DontThink(); - } - else if ( useType == USE_SET ) - { - // set max count of impulses - m_iMaxFireCount = fabs( value ); - } - else if ( useType == USE_RESET ) - { - // immediately reset - m_iFireCount = 0; - } - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n" ); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "State: %s, Delay time %f\n", GetStringForState( GetState()), m_flDelay ); - ALERT( at_console, "FireCount: %d, Max FireCount: %d\n", m_iFireCount, m_iMaxFireCount ); - } -} - -void CGenerator :: Think( void ) -{ - if ( m_iFireCount != -1 ) - { - // if counter enabled - if( m_iFireCount == m_iMaxFireCount ) - { - m_iState = STATE_OFF; - m_iFireCount = 0; - DontThink(); - return; - } - else m_iFireCount++; - } - - if ( pev->button == RANDOM_MODE_WITH_DEC ) - { - //deceleration for random mode - if( m_iMaxFireCount - m_iFireCount < 40 ) - m_flDelay += 0.005; - } - - UTIL_FireTargets( pev->target, this, this, USE_TOGGLE ); - - SetNextThink( m_flDelay ); -} - - -//======================================================================= -// Logic_watcher -//======================================================================= -#define LOGIC_AND 0 // fire if all objects active -#define LOGIC_OR 1 // fire if any object active -#define LOGIC_NAND 2 // fire if not all objects active -#define LOGIC_NOR 3 // fire if all objects disable -#define LOGIC_XOR 4 // fire if only one (any) object active -#define LOGIC_XNOR 5 // fire if active any number objects, but < then all - -#define W_ON 0 -#define W_OFF 1 -#define W_TURNON 2 -#define W_TURNOFF 3 -#define W_IN_USE 4 - -class CStateWatcher : public CBaseLogic -{ -public: - void Spawn( void ); - void Think( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual STATE GetState( void ) { return m_iState; }; - virtual STATE GetState( CBaseEntity *pActivator ) { return EvalLogic(pActivator) ? STATE_ON : STATE_OFF; }; - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_cTargets; // the total number of targets in this manager's fire list. - int m_iTargetName[MAX_MULTI_TARGETS];// list of indexes into global string array - - BOOL EvalLogic( CBaseEntity *pEntity ); -}; - -LINK_ENTITY_TO_CLASS( logic_watcher, CStateWatcher ); - -TYPEDESCRIPTION CStateWatcher::m_SaveData[] = -{ - DEFINE_FIELD( CStateWatcher, m_cTargets, FIELD_INTEGER ), - DEFINE_ARRAY( CStateWatcher, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ), -};IMPLEMENT_SAVERESTORE(CStateWatcher,CBaseLogic); - -void CStateWatcher :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "mode")) - { - pev->button = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "type")) - { - pev->body = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "offtarget")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else // add this field to the target list - { - // this assumes that additional fields are targetnames and their values are delay values. - if ( m_cTargets < MAX_MULTI_TARGETS ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp ); - m_cTargets++; - pkvd->fHandled = TRUE; - } - } -} - -void CStateWatcher :: Spawn ( void ) -{ - SetNextThink( 0.1 ); -} - -void CStateWatcher :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_SHOWINFO) - { - ALERT(at_console, "======/Xash Debug System/======\n"); - ALERT(at_console, "classname: %s\n", STRING(pev->classname)); - ALERT(at_console, "State: %s, Number of targets %d\n", GetStringForState( GetState()), m_cTargets); - ALERT(at_console, "Limit is %d entities\n", MAX_MULTI_TARGETS); - } -} - -void CStateWatcher :: Think ( void ) -{ - if(EvalLogic(NULL)) - { - if(m_iState == STATE_OFF) - { - m_iState = STATE_ON; - UTIL_FireTargets( pev->target, this, this, USE_ON ); - } - } - else - { - if(m_iState == STATE_ON) - { - m_iState = STATE_OFF; - UTIL_FireTargets( pev->netname, this, this, USE_OFF ); - } - } - SetNextThink( 0.05 ); -} - -BOOL CStateWatcher :: EvalLogic ( CBaseEntity *pActivator ) -{ - int i; - BOOL b; - BOOL xorgot = FALSE; - - CBaseEntity* pEntity; - - for (i = 0; i < m_cTargets; i++) - { - pEntity = UTIL_FindEntityByTargetname(NULL,STRING(m_iTargetName[i]), pActivator); - if (pEntity != NULL); - else continue; - b = FALSE; - - switch (pEntity->GetState()) - { - case STATE_ON: if (pev->body == W_ON) b = TRUE; break; - case STATE_OFF: if (pev->body == W_OFF) b = TRUE; break; - case STATE_TURN_ON: if (pev->body == W_TURNON) b = TRUE; break; - case STATE_TURN_OFF: if (pev->body == W_TURNOFF) b = TRUE; break; - case STATE_IN_USE: if (pev->body == W_IN_USE) b = TRUE; break; - } - // handle the states for this logic mode - if (b) - { - switch (pev->button) - { - case LOGIC_OR: return TRUE; - case LOGIC_NOR: return FALSE; - case LOGIC_XOR: - if(xorgot) return FALSE; - xorgot = TRUE; - break; - case LOGIC_XNOR: - if(xorgot) return TRUE; - xorgot = TRUE; - break; - } - } - else // b is false - { - switch (pev->button) - { - case LOGIC_AND: return FALSE; - case LOGIC_NAND: return TRUE; - } - } - } - - // handle the default cases for each logic mode - switch (pev->button) - { - case LOGIC_AND: - case LOGIC_NOR: return TRUE; - case LOGIC_XOR: return xorgot; - case LOGIC_XNOR: return !xorgot; - default: return FALSE; - } -} - -//======================================================================= -// Logic_manager -//======================================================================= -#define FL_CLONE 0x80000000 -#define SF_LOOP 0x2 - - -class CMultiManager : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void PostActivate( void ); - void Spawn ( void ); - void Think ( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - - int m_cTargets; // the total number of targets in this manager's fire list. - int m_index; // Current target - float m_startTime; // Time we started firing - int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array - float m_flTargetDelay [ MAX_MULTI_TARGETS ];// delay (in seconds) -private: - inline BOOL IsClone( void ) { return (pev->spawnflags & FL_CLONE) ? TRUE : FALSE; } - inline BOOL ShouldClone( void ) - { - if ( IsClone() )return FALSE; - //work in progress and calling again ? - return (m_iState == STATE_ON) ? TRUE : FALSE; - } - - CMultiManager *Clone( void ); -}; -LINK_ENTITY_TO_CLASS( logic_manager, CMultiManager ); - -// Global Savedata for multi_manager -TYPEDESCRIPTION CMultiManager::m_SaveData[] = -{ DEFINE_FIELD( CMultiManager, m_cTargets, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_index, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_startTime, FIELD_TIME ), - DEFINE_ARRAY( CMultiManager, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ), - DEFINE_ARRAY( CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS ), -};IMPLEMENT_SAVERESTORE(CMultiManager, CBaseLogic); - -void CMultiManager :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "delay" )) - { - m_flDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "master" )) - { - m_sMaster = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( m_cTargets < MAX_MULTI_TARGETS ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iTargetName[m_cTargets] = ALLOC_STRING( tmp ); - m_flTargetDelay[m_cTargets] = atof( pkvd->szValue ); - m_cTargets++; - pkvd->fHandled = TRUE; - } -} - -void CMultiManager :: Spawn( void ) -{ - // Sort targets - // Quick and dirty bubble sort - int swapped = 1; - - while ( swapped ) - { - swapped = 0; - for ( int i = 1; i < m_cTargets; i++ ) - { - if ( m_flTargetDelay[i] < m_flTargetDelay[i-1] ) - { - // Swap out of order elements - int name = m_iTargetName[i]; - float delay = m_flTargetDelay[i]; - m_iTargetName[i] = m_iTargetName[i-1]; - m_flTargetDelay[i] = m_flTargetDelay[i-1]; - m_iTargetName[i-1] = name; - m_flTargetDelay[i-1] = delay; - swapped = 1; - } - } - } - - m_iState = STATE_OFF; - m_index = 0; -} - -void CMultiManager :: PostActivate( void ) -{ - if ( pev->spawnflags & SF_START_ON ) - { - Use( this, this, USE_TOGGLE, 0 ); - ClearBits( pev->spawnflags, SF_START_ON ); - } -} - -void CMultiManager :: Think( void ) -{ - float time; - - time = gpGlobals->time - m_startTime; - while ( m_index < m_cTargets && m_flTargetDelay[ m_index ] <= time ) - { - UTIL_FireTargets( m_iTargetName[ m_index ], m_hActivator, this, USE_TOGGLE, pev->frags ); - m_index++; - } - if ( m_index >= m_cTargets )// have we fired all targets? - { - if ( pev->spawnflags & SF_LOOP)//continue firing - { - m_index = 0; - m_startTime = m_flDelay + gpGlobals->time; - } - else - { - m_iState = STATE_OFF; - DontThink(); - return; - } - if ( IsClone() ) - { - UTIL_Remove( this ); - return; - } - } - m_iState = STATE_ON; //continue firing targets - pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; -} - -CMultiManager *CMultiManager::Clone( void ) -{ - CMultiManager *pMulti = GetClassPtr( (CMultiManager *)NULL ); - - edict_t *pEdict = pMulti->pev->pContainingEntity; - memcpy( pMulti->pev, pev, sizeof(*pev) ); - pMulti->pev->pContainingEntity = pEdict; - - pMulti->pev->spawnflags |= FL_CLONE; - pMulti->m_cTargets = m_cTargets; - pMulti->m_flDelay = m_flDelay; - pMulti->m_iState = m_iState; - memcpy( pMulti->m_iTargetName, m_iTargetName, sizeof( m_iTargetName )); - memcpy( pMulti->m_flTargetDelay, m_flTargetDelay, sizeof( m_flTargetDelay )); - - return pMulti; -} - - -void CMultiManager :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if( IsLockedByMaster( useType )) return; - pev->frags = value; // save our value - - if ( useType == USE_TOGGLE ) - { - // we send USE_ON or USE_OF from this - if( m_iState == STATE_OFF ) - useType = USE_ON; - else useType = USE_OFF; - } - if (useType == USE_ON) - { - if ( ShouldClone() ) - { - // create clone if needed - CMultiManager *pClone = Clone(); - pClone->Use( pActivator, pCaller, useType, value ); - return; - } - - if ( m_iState == STATE_OFF ) - { - if( m_hActivator == this ) // ok, manager execute himself - { - // only for follow reason: auto start - m_startTime = m_flDelay + gpGlobals->time; - m_iState = STATE_TURN_ON; - m_index = 0; - SetNextThink( m_flDelay ); - } - else // ok no himself fire and manager on - { - m_startTime = m_flDelay + gpGlobals->time; - m_iState = STATE_TURN_ON; - m_index = 0; - SetNextThink( m_flDelay ); - } - } - } - else if ( useType == USE_OFF ) - { - m_iState = STATE_OFF; - DontThink(); - } - else if ( useType == USE_SET ) - { - m_index = 0; // reset fire index - while ( m_index < m_cTargets ) - { - // firing all targets instantly - UTIL_FireTargets( m_iTargetName[ m_index ], this, this, USE_TOGGLE ); - m_index++; - if(m_hActivator == this) break;//break if current target - himself - } - } - else if ( useType == USE_RESET ) - { - m_index = 0; // reset fire index - m_iState = STATE_TURN_ON; - m_startTime = m_flDelay + gpGlobals->time; - SetNextThink( m_flDelay ); - } - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING(pev->classname)); - ALERT( at_console, "State: %s, number of targets %d\n", GetStringForState( GetState()), m_cTargets); - if( m_iState == STATE_ON ) - ALERT( at_console, "Current target %s, delay time %f\n", STRING(m_iTargetName[ m_index ]), m_flTargetDelay[ m_index ]); - else ALERT( at_console, "No targets for firing.\n"); - } -} -//======================================================================= -// Logic_switcher -//======================================================================= -#define MODE_INCREMENT 0 -#define MODE_DECREMENT 1 -#define MODE_RANDOM_VALUE 2 - -class CSwitcher : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn ( void ); - void Think ( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_cTargets;// the total number of targets in this manager's fire list. - int m_index; // Current target - int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array - int m_iTargetNumber [ MAX_MULTI_TARGETS ];// list of target numbers -}; -LINK_ENTITY_TO_CLASS( logic_switcher, CSwitcher ); - -// Global Savedata for switcher -TYPEDESCRIPTION CSwitcher::m_SaveData[] = -{ DEFINE_FIELD( CSwitcher, m_cTargets, FIELD_INTEGER ), - DEFINE_FIELD( CSwitcher, m_index, FIELD_INTEGER ), - DEFINE_ARRAY( CSwitcher, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ), - DEFINE_ARRAY( CSwitcher, m_iTargetNumber, FIELD_INTEGER, MAX_MULTI_TARGETS ), -};IMPLEMENT_SAVERESTORE(CSwitcher, CBaseLogic); - -void CSwitcher :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "mode" )) - { - pev->button = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "delay" )) - { - m_flDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( m_cTargets < MAX_MULTI_TARGETS ) - { - // add this field to the target list - // this assumes that additional fields are targetnames and their values are delay values. - - char tmp[128]; - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp ); - m_iTargetNumber [ m_cTargets ] = atoi( pkvd->szValue ); - m_cTargets++; - pkvd->fHandled = TRUE; - } -} - -void CSwitcher :: Spawn( void ) -{ - // Sort targets - // Quick and dirty bubble sort - int swapped = 1; - - while ( swapped ) - { - swapped = 0; - for ( int i = 1; i < m_cTargets; i++ ) - { - if ( m_iTargetNumber[i] < m_iTargetNumber[i-1] ) - { - // Swap out of order elements - int name = m_iTargetName[i]; - int number = m_iTargetNumber[i]; - m_iTargetName[i] = m_iTargetName[i-1]; - m_iTargetNumber[i] = m_iTargetNumber[i-1]; - m_iTargetName[i-1] = name; - m_iTargetNumber[i-1] = number; - swapped = 1; - } - } - } - - m_iState = STATE_OFF; - m_index = 0; - - if ( pev->spawnflags & SF_START_ON ) - { - m_iState = STATE_ON; - SetNextThink ( m_flDelay ); - } -} - -void CSwitcher :: Think ( void ) -{ - if ( pev->button == MODE_INCREMENT ) - { - // increase target number - m_index++; - if( m_index >= m_cTargets ) - m_index = 0; - } - else if ( pev->button == MODE_DECREMENT ) - { - m_index--; - if( m_index < 0 ) - m_index = m_cTargets - 1; - } - else if ( pev->button == MODE_RANDOM_VALUE ) - { - m_index = RANDOM_LONG( 0, m_cTargets - 1 ); - } - SetNextThink ( m_flDelay ); -} - -void CSwitcher :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if(IsLockedByMaster( useType )) return; - - if ( useType == USE_SET ) - { - // set new target for activate (direct choose or increment\decrement) - if( pev->spawnflags & SF_START_ON ) - { - m_iState = STATE_ON; - SetNextThink (m_flDelay); - return; - } - - // set maximum priority for direct choose - if( value ) - { - m_index = (value - 1); - if( m_index >= m_cTargets ) - m_index = -1; - return; - } - if( pev->button == MODE_INCREMENT ) - { - m_index++; - if ( m_index >= m_cTargets ) - m_index = 0; - } - else if( pev->button == MODE_DECREMENT ) - { - m_index--; - if ( m_index < 0 ) - m_index = m_cTargets - 1; - } - else if( pev->button == MODE_RANDOM_VALUE ) - { - m_index = RANDOM_LONG( 0, m_cTargets - 1 ); - } - } - else if ( useType == USE_RESET ) - { - // reset switcher - m_iState = STATE_OFF; - DontThink(); - m_index = 0; - return; - } - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING(pev->classname)); - ALERT( at_console, "State: %s, number of targets %d\n", GetStringForState( GetState()), m_cTargets - 1); - ALERT( at_console, "Current target %s, target number %d\n", STRING(m_iTargetName[ m_index ]), m_index ); - } - else if ( m_index != -1 ) // fire any other USE_TYPE and right index - { - UTIL_FireTargets( m_iTargetName[m_index], m_hActivator, this, useType, value ); - } -} - -//======================================================================= -// logic_changetarget -//======================================================================= -class CLogicChangeTarget : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return CBaseLogic::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; -LINK_ENTITY_TO_CLASS( logic_changetarget, CLogicChangeTarget ); -LINK_ENTITY_TO_CLASS( trigger_changetarget, CLogicChangeTarget ); - -void CLogicChangeTarget::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "newtarget" )) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CLogicChangeTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ), pActivator ); - - if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "Current target %s, new target %s\n", STRING( pev->target ), STRING( pev->message )); - ALERT( at_console, "target entity is: %s, current target: %s\n", STRING( pTarget->pev->classname ), STRING( pTarget->pev->target )); - } - else - { - if ( pTarget ) - { - const char *target = STRING( pev->message ); - - if ( FStrEq( target, "*this" ) || FStrEq( target, "*locus" )) // Xash 0.2 compatibility - { - if ( pActivator ) pTarget->pev->target = pActivator->pev->targetname; - else ALERT( at_error, "%s \"%s\" requires a self pointer!\n", STRING( pev->classname ), STRING( pev->targetname )); - } - else - { - if ( pTarget->IsFuncScreen( )) - pTarget->ChangeCamera( pev->message ); - else pTarget->pev->target = pev->message; - } - CBaseMonster *pMonster = pTarget->MyMonsterPointer( ); - if ( pMonster ) pMonster->m_pGoalEnt = NULL; // force to refresh goal entity - } - } -} - -//======================================================================= -// Logic_set -//======================================================================= -#define MODE_LOCAL 0 -#define MODE_GLOBAL_WRITE 1 -#define MODE_GLOBAL_READ 2 - -#define ACT_SAME 0 -#define ACT_PLAYER 1 -#define ACT_THIS 2 - -class CLogicSet : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void PostActivate( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think ( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - string_t m_globalstate; - float m_flValue; -}; -LINK_ENTITY_TO_CLASS( logic_set, CLogicSet ); - -void CLogicSet :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "value" )) - { - m_flValue = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "mode" )) - { - pev->frags = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "globalstate" )) - { - m_globalstate = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "initialstate" )) - { - pev->impulse = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "activator" )) - { - pev->body = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -// Global Savedata -TYPEDESCRIPTION CLogicSet::m_SaveData[] = -{ - DEFINE_FIELD( CLogicSet, m_flValue, FIELD_FLOAT ), - DEFINE_FIELD( CLogicSet, m_globalstate, FIELD_STRING ), -};IMPLEMENT_SAVERESTORE(CLogicSet, CBaseLogic); - -void CLogicSet :: PostActivate ( void ) -{ - m_iState = STATE_OFF; - - if( pev->spawnflags & SF_START_ON ) - { - // write global state - if( pev->frags == MODE_GLOBAL_WRITE ) - Use( this, this, (USE_TYPE)pev->impulse, m_flValue ); - else Use( this, this, USE_TOGGLE, m_flValue ); - } -} - -void CLogicSet :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // get entity global state - GLOBALESTATE curstate = gGlobalState.EntityGetState( m_globalstate ); - - //set activator - if ( pev->body == ACT_SAME ) - m_hActivator = pActivator; - else if ( pev->body == ACT_PLAYER ) - m_hActivator = UTIL_FindEntityByClassname( NULL, "player" ); - else if ( pev->body == ACT_THIS ) - m_hActivator = this; - - // save use type - pev->button = (int)useType; - - if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING(pev->classname)); - ALERT( at_console, "mode %s\n", pev->frags?"Global":"Local"); - if( m_globalstate ) - ALERT( at_console, "Global state: %s = %s\n", STRING( m_globalstate ), GetStringForGlobalState( curstate )); - else ALERT( at_console, "Global state not found\n" ); - } - else // any other USE_TYPE - { - if( pev->frags == MODE_LOCAL ) - { - if( m_flDelay ) - { - m_iState = STATE_ON; - SetNextThink( m_flDelay ); - } - else - { - UTIL_FireTargets( pev->target, m_hActivator, this, useType, m_flValue ); - } - } - else if( pev->frags == MODE_GLOBAL_WRITE && m_globalstate ) - { - // can controlling entity in global mode - if( curstate != GLOBAL_DEAD ) - { - if ( useType == USE_TOGGLE ) - { - if( curstate ) useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_OFF ) pev->impulse = GLOBAL_OFF; - else if ( useType == USE_ON ) pev->impulse = GLOBAL_ON; - else if ( useType == USE_SET ) pev->impulse = GLOBAL_DEAD; - } - else pev->impulse = curstate; // originally loop, isn't true ? :) - - if( m_flDelay ) - { - m_iState = STATE_ON; - SetNextThink( m_flDelay ); - } - else - { - // set global state with prefixes - if ( gGlobalState.EntityInTable( m_globalstate )) - gGlobalState.EntitySetState( m_globalstate, (GLOBALESTATE)pev->impulse ); - else gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, (GLOBALESTATE)pev->impulse ); - // firing targets - UTIL_FireTargets( pev->target, m_hActivator, this, useType, m_flValue ); - } - } - else if( pev->frags == MODE_GLOBAL_READ && gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) - { - // fire only if global mode == GLOBAL_ON - if( m_flDelay ) - { - m_iState = STATE_ON; - SetNextThink(m_flDelay); - } - else UTIL_FireTargets( pev->target, m_hActivator, this, useType, m_flValue ); - } - } -} - -void CLogicSet :: Think ( void ) -{ - if(pev->frags == MODE_GLOBAL_WRITE)//can controlling entity in global mode - { - // set state after delay - if ( gGlobalState.EntityInTable( m_globalstate )) - gGlobalState.EntitySetState( m_globalstate, (GLOBALESTATE)pev->impulse ); - else gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, (GLOBALESTATE)pev->impulse ); - - // firing targets - UTIL_FireTargets( pev->target, m_hActivator, this, (USE_TYPE)pev->button, m_flValue ); - } - else UTIL_FireTargets( pev->target, m_hActivator, this, (USE_TYPE)pev->button, m_flValue ); - - // suhtdown - m_iState = STATE_OFF; - DontThink(); // just in case -} - -//======================================================================= -// Logic_counter -//======================================================================= -class CLogicCounter : public CBaseLogic -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); -}; -LINK_ENTITY_TO_CLASS( logic_counter, CLogicCounter ); - -void CLogicCounter :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "count" )) - { - pev->frags = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - if (FStrEq( pkvd->szKeyName, "maxcount" )) - { - pev->body = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CLogicCounter :: Spawn( void ) -{ - // smart Field System © - if ( pev->frags == 0 ) pev->frags = 2; - if ( pev->body == 0 ) pev->body = 100; - if ( pev->frags == -1 ) pev->frags = RANDOM_LONG( 1, pev->body ); - - // save number of impulses - pev->impulse = pev->frags; - m_iState = STATE_OFF; // always disable -} - -void CLogicCounter :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_SET ) - { - if( value ) pev->impulse = pev->frags = value; // write new value - else pev->impulse = pev->frags = RANDOM_LONG( 1, pev->body ); // write random value - } - else if (useType == USE_RESET) pev->frags = pev->impulse; //restore counter to default - else if (useType == USE_SHOWINFO) - { - ALERT(at_console, "======/Xash Debug System/======\n"); - ALERT(at_console, "classname: %s\n", STRING(pev->classname)); - ALERT(at_console, "start count %d, current count %.f\n",pev->impulse , pev->impulse - pev->frags ); - ALERT(at_console, "left activates: %.f\n", pev->frags); - } - else //any other useType - { - pev->frags--; - if(pev->frags > 0) return; - - pev->frags = 0; //don't reset counter in negative value - UTIL_FireTargets( pev->target, pActivator, this, useType, value ); //activate target - } -} - -//======================================================================= -// Logic_relay -//======================================================================= -class CLogicRelay : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Spawn( void ); - void Think ( void ); -}; -LINK_ENTITY_TO_CLASS( logic_relay, CLogicRelay ); - -void CLogicRelay::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "target2" )) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CLogicRelay :: Spawn( void ) -{ - m_iState = STATE_OFF; // always disable -} - -void CLogicRelay::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; //save activator - pev->button = (int)useType; //save use type - pev->frags = value; //save our value - - if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "target is %s, mtarget %s\n", STRING( pev->target ), STRING( pev->message )); - ALERT( at_console, "new value %.2f\n", pev->frags ); - } - else // activate target - { - if( m_flDelay ) - { - m_iState = STATE_ON; - SetNextThink( m_flDelay ); - } - else SetNextThink( 0 ); // fire target immediately - } -} - -void CLogicRelay::Think ( void ) -{ - if( IsLockedByMaster( )) - UTIL_FireTargets( pev->message, m_hActivator, this, (USE_TYPE)pev->button, pev->frags ); - else UTIL_FireTargets( pev->target, m_hActivator, this, (USE_TYPE)pev->button, pev->frags ); - - // shutdown - m_iState = STATE_OFF; - DontThink(); // just in case -} - -//======================================================================= -// Logic_state -//======================================================================= -class CLogicState : public CBaseLogic -{ -public: - void Spawn( void ); - void Think( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( logic_state, CLogicState ); - - -void CLogicState::Spawn( void ) -{ - if ( pev->spawnflags & SF_START_ON ) - m_iState = STATE_ON; - else m_iState = STATE_OFF; -} - -void CLogicState::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; // save activator - pev->frags = value; // save value - - if(IsLockedByMaster( useType )) return; - - if ( useType == USE_TOGGLE ) - { - // set use type - if( m_iState == STATE_TURN_OFF || m_iState == STATE_OFF ) - useType = USE_ON; - else if( m_iState == STATE_TURN_ON || m_iState == STATE_ON ) - useType = USE_OFF; - } - if ( useType == USE_ON ) - { - //enable entity - if ( m_iState == STATE_TURN_OFF || m_iState == STATE_OFF ) - { - // activate turning off entity - if ( m_flDelay ) - { - // we have time to turning on - m_iState = STATE_TURN_ON; - SetNextThink( m_flDelay ); - } - else - { - // just enable entity - m_iState = STATE_ON; - UTIL_FireTargets( pev->target, pActivator, this, USE_ON, pev->frags ); - DontThink(); // break thinking - } - } - } - else if( useType == USE_OFF ) - { - // disable entity - if ( m_iState == STATE_TURN_ON || m_iState == STATE_ON ) - { - // deactivate turning on entity - if ( m_flWait ) - { - // we have time to turning off - m_iState = STATE_TURN_OFF; - SetNextThink( m_flWait ); - } - else - { - // just disable entity - m_iState = STATE_OFF; - UTIL_FireTargets( pev->target, pActivator, this, USE_OFF, pev->frags ); - DontThink();//break thinking - } - } - } - else if( useType == USE_SET ) - { - // explicit on - m_iState = STATE_ON; - DontThink(); - } - else if ( useType == USE_RESET ) - { - // explicit off - m_iState = STATE_OFF; - DontThink(); - } - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING(pev->classname)); - ALERT( at_console, "time, before enable %.1f, time, before disable %.1f\n", m_flDelay, m_flWait ); - ALERT( at_console, "current state %s\n", GetStringForState( GetState()) ); - } -} - -void CLogicState::Think( void ) -{ - if ( m_iState == STATE_TURN_ON ) - { - m_iState = STATE_ON; - UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON, pev->frags ); - } - else if ( m_iState == STATE_TURN_OFF ) - { - m_iState = STATE_OFF; - UTIL_FireTargets( pev->target, m_hActivator, this, USE_OFF, pev->frags ); - } - DontThink(); -} - -//======================================================================= -// Logic_usetype - sorting different usetypes -//======================================================================= -class CLogicUseType : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( logic_usetype, CLogicUseType ); - -void CLogicUseType::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "toggle" )) - { - pev->target = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "enable" )) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "disable" )) - { - pev->netname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "set" )) - { - m_sSet = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq( pkvd->szKeyName, "reset" )) - { - m_sReset = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CLogicUseType::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsLockedByMaster( useType )) return; - if ( useType == USE_TOGGLE ) UTIL_FireTargets( pev->target, pActivator, this, useType, value ); - else if ( useType == USE_ON ) UTIL_FireTargets( pev->message, pActivator, this, useType, value ); - else if ( useType == USE_OFF ) UTIL_FireTargets( pev->netname, pActivator, this, useType, value ); - else if ( useType == USE_SET ) UTIL_FireTargets( m_sSet, pActivator, this, useType, value ); - else if ( useType == USE_RESET )UTIL_FireTargets( m_sReset, pActivator, this, useType, value ); - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n" ); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "This entity doesn't have displayed settings!\n\n" ); - } -} - -//======================================================================= -// Logic_scale - apply scale for value -//======================================================================= -class CLogicScale : public CBaseLogic -{ -public: - void KeyValue( KeyValueData *pkvd ) - { - if (FStrEq(pkvd->szKeyName, "mode")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); - } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "Mode %s. Scale %.3f.\n\n", pev->impulse ? "Bool" : "Float", pev->scale ); - SHIFT; - } - else - { - if( pev->impulse == 0 ) // bool logic - { - if( value >= 0.99f ) UTIL_FireTargets(pev->target, pActivator, this, USE_ON, 1 ); - if( value <= 0.01f ) UTIL_FireTargets(pev->target, pActivator, this, USE_OFF,0 ); - } - if( pev->impulse == 1 ) // direct scale - UTIL_FireTargets( pev->target, pActivator, this, USE_SET, value * pev->scale ); - if( pev->impulse == 2 ) // inverse sacle - UTIL_FireTargets( pev->target, pActivator, this, USE_SET, pev->scale * ( 1 - value )); - } - } -}; -LINK_ENTITY_TO_CLASS( logic_scale, CLogicScale ); \ No newline at end of file diff --git a/server/ents/baselogic.h b/server/ents/baselogic.h deleted file mode 100644 index 0d0eff54..00000000 --- a/server/ents/baselogic.h +++ /dev/null @@ -1,53 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef BASELOGIC_H -#define BASELOGIC_H - -#define MAX_MULTI_TARGETS 32 // maximum number of targets that can be added in a list - -class CBaseLogic : public CBaseEntity -{ -public: - BOOL IsLockedByMaster( void ); - BOOL IsLockedByMaster( USE_TYPE useType ); - BOOL IsLockedByMaster( CBaseEntity *pActivator ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual void KeyValue( KeyValueData* pkvd); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - virtual STATE GetState( void ) { return m_iState; }; - - float m_flDelay; - float m_flWait; - EHANDLE m_hActivator; - EHANDLE m_hTarget; - STATE m_iState; - string_t m_sMaster; - string_t m_sSet; // used for logic_usetype - string_t m_sReset; // used for logic_usetype - float m_flMin, m_flMax; -}; - -#include "baseinfo.h" - -class CEnvRainModify : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int drips; - RandomRange windXY; - RandomRange randXY; - float fadeTime; -}; - -#endif //BASELOGIC_H \ No newline at end of file diff --git a/server/ents/basemover.cpp b/server/ents/basemover.cpp deleted file mode 100644 index 024bebff..00000000 --- a/server/ents/basemover.cpp +++ /dev/null @@ -1,1396 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// basemover.cpp - base code for linear and -// angular moving brushes e.g. doors, buttons e.t.c -//======================================================================= - -#include "extdll.h" -#include "defaults.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "saverestore.h" -#include "player.h" - -//======================================================================= -// main functions () -//======================================================================= -TYPEDESCRIPTION CBaseMover::m_SaveData[] = -{ - DEFINE_FIELD( CBaseMover, m_flBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CBaseMover, m_iMode, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMover, m_flMoveDistance, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flWait, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flLip, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flHeight, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flValue, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_vecFinalDest, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecPosition1, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecPosition2, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecFloor, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_pfnCallWhenMoveDone, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseMover, m_vecAngle1, FIELD_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecAngle2, FIELD_VECTOR ), - DEFINE_FIELD( CBaseMover, m_flLinearMoveSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flAngularMoveSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_vecFinalAngle, FIELD_VECTOR ), - DEFINE_FIELD( CBaseMover, flTravelTime, FIELD_FLOAT ), -}; IMPLEMENT_SAVERESTORE( CBaseMover, CBaseBrush ); - -void CBaseMover :: AxisDir( void ) -{ - // make backward compatibility - if ( pev->movedir != g_vecZero) return; - if ( FBitSet(pev->spawnflags, 128)) - pev->movedir = Vector ( 0, 0, 1 ); // around z-axis - else if ( FBitSet(pev->spawnflags, 64)) - pev->movedir = Vector ( 1, 0, 0 ); // around x-axis - else pev->movedir = Vector ( 0, 1, 0 ); // around y-axis -} - -void CBaseMover::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lip")) - { - m_flLip = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "waveheight")) - { - //field for volume_water - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "type")) - { - m_iMode = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locksound")) - { - m_iStartSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesound")) - { - m_iMoveSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsound")) - { - m_iStopSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "distance")) - { - m_flMoveDistance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_flHeight = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "waveheight")) - { - // func_water wave height - pev->scale = atof( pkvd->szValue ) * ( 1.0f / 8.0f ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "contents")) - { - // func_water contents - pev->skin = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseBrush::KeyValue( pkvd ); -} - -//======================================================================= -// LinearMove -// -// calculate pev->velocity and pev->nextthink to reach vecDest from -// pev->origin traveling at flSpeed -//======================================================================= -void CBaseMover :: LinearMove( Vector vecInput, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "LinearMove: no speed is defined!"); - - m_flLinearMoveSpeed = flSpeed; - m_vecFinalDest = vecInput; - - SetThink( LinearMoveNow ); - UTIL_SetThink( this ); -} - - -void CBaseMover :: LinearMoveNow( void ) -{ - Vector vecDest; - - if (m_pParent)vecDest = m_vecFinalDest + m_pParent->pev->origin; - else vecDest = m_vecFinalDest; - - // Already there? - if (vecDest == pev->origin) - { - LinearMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDest - pev->origin; - - // divide vector length by speed to get time to reach dest - flTravelTime = vecDestDelta.Length() / m_flLinearMoveSpeed; - - // set nextthink to trigger a call to LinearMoveDone when dest is reached - SetNextThink( flTravelTime ); - SetThink( LinearMoveDone ); - - UTIL_SetVelocity( this, vecDestDelta / flTravelTime ); -} - -//======================================================================= -// After moving, set origin to exact final destination, -// call "move done" function -//======================================================================= -void CBaseMover :: LinearMoveDone( void ) -{ - SetThink(LinearMoveDoneNow); - UTIL_SetThink( this ); -} - -void CBaseMover :: LinearMoveDoneNow( void ) -{ - UTIL_SetVelocity(this, g_vecZero); - if (m_pParent) UTIL_AssignOrigin(this, m_vecFinalDest + m_pParent->pev->origin); - else UTIL_AssignOrigin(this, m_vecFinalDest); - - DontThink(); - if( m_pfnCallWhenMoveDone )(this->*m_pfnCallWhenMoveDone)(); -} - -//======================================================================= -// AngularMove -// -// calculate pev->velocity and pev->nextthink to reach vecDest from -// pev->origin traveling at flSpeed -// Just like LinearMove, but rotational. -//======================================================================= -void CBaseMover :: AngularMove( Vector vecDestAngle, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "AngularMove: no speed is defined!"); - - m_vecFinalAngle = vecDestAngle; - m_flAngularMoveSpeed = flSpeed; - - SetThink( AngularMoveNow ); - UTIL_SetThink( this ); -} - -void CBaseMover :: AngularMoveNow() -{ - Vector vecDestAngle; - - if (m_pParent) vecDestAngle = m_vecFinalAngle + m_pParent->pev->angles; - else vecDestAngle = m_vecFinalAngle; - - // Already there? - if (vecDestAngle == pev->angles) - { - AngularMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDestAngle - pev->angles; - - // divide by speed to get time to reach dest - flTravelTime = vecDestDelta.Length() / m_flAngularMoveSpeed; - - // set nextthink to trigger a call to AngularMoveDone when dest is reached - SetNextThink( flTravelTime ); - SetThink( AngularMoveDone ); - - // scale the destdelta vector by the time spent traveling to get velocity - UTIL_SetAvelocity(this, vecDestDelta / flTravelTime ); -} - -void CBaseMover :: AngularMoveDone( void ) -{ - SetThink( AngularMoveDoneNow ); - UTIL_SetThink( this ); -} - -//======================================================================= -// After rotating, set angle to exact final angle, call "move done" function -//======================================================================= -void CBaseMover :: AngularMoveDoneNow( void ) -{ - UTIL_SetAvelocity(this, g_vecZero); - if (m_pParent) UTIL_AssignAngles(this, m_vecFinalAngle + m_pParent->pev->angles); - else UTIL_AssignAngles(this, m_vecFinalAngle); - - DontThink(); - if ( m_pfnCallWhenMoveDone ) (this->*m_pfnCallWhenMoveDone)(); -} - -//======================================================================= -// ComplexMove -// -// combinate LinearMove and AngularMove -//======================================================================= -void CBaseMover :: ComplexMove( Vector vecInput, Vector vecDestAngle, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "ComplexMove: no speed is defined!"); - - //set shared speed for moving and rotating - m_flLinearMoveSpeed = flSpeed; - m_flAngularMoveSpeed = flSpeed; - - //save local variables into global containers - m_vecFinalDest = vecInput; - m_vecFinalAngle = vecDestAngle; - - SetThink( ComplexMoveNow ); - UTIL_SetThink( this ); -} - -void CBaseMover :: ComplexMoveNow( void ) -{ - Vector vecDest, vecDestAngle; - - if (m_pParent)//calculate destination - { - vecDest = m_vecFinalDest + m_pParent->pev->origin; - vecDestAngle = m_vecFinalAngle + m_pParent->pev->angles; - } - else - { - vecDestAngle = m_vecFinalAngle; - vecDest = m_vecFinalDest; - } - - // Already there? - if (vecDest == pev->origin && vecDestAngle == pev->angles) - { - ComplexMoveDone(); - return; - } - - // Calculate TravelTime and final angles - Vector vecDestLDelta = vecDest - pev->origin; - Vector vecDestADelta = vecDestAngle - pev->angles; - - // divide vector length by speed to get time to reach dest - flTravelTime = vecDestLDelta.Length() / m_flLinearMoveSpeed; - - // set nextthink to trigger a call to LinearMoveDone when dest is reached - SetNextThink( flTravelTime ); - SetThink( ComplexMoveDone ); - - //set linear and angular velocity now - UTIL_SetVelocity( this, vecDestLDelta / flTravelTime ); - UTIL_SetAvelocity(this, vecDestADelta / flTravelTime ); -} - -void CBaseMover :: ComplexMoveDone( void ) -{ - SetThink(ComplexMoveDoneNow); - UTIL_SetThink( this ); -} - -void CBaseMover :: ComplexMoveDoneNow( void ) -{ - UTIL_SetVelocity(this, g_vecZero); - UTIL_SetAvelocity(this, g_vecZero); - - if (m_pParent) - { - UTIL_AssignOrigin(this, m_vecFinalDest + m_pParent->pev->origin); - UTIL_AssignAngles(this, m_vecFinalAngle + m_pParent->pev->angles); - } - else - { - UTIL_AssignOrigin(this, m_vecFinalDest); - UTIL_AssignAngles(this, m_vecFinalAngle); - } - - DontThink(); - if( m_pfnCallWhenMoveDone )(this->*m_pfnCallWhenMoveDone)(); -} - -//======================================================================= -// func_door - classic QUAKE door -//======================================================================= -void CBaseDoor::Spawn( void ) -{ - Precache(); - if(!IsRotatingDoor()) UTIL_LinearVector( this ); - CBaseBrush::Spawn(); - - if ( pev->spawnflags & SF_NOTSOLID ) // make illusionary door - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - - if( IsRotatingDoor( )) - { - // check for clockwise rotation - if ( m_flMoveDistance < 0 ) pev->movedir = pev->movedir * -1; - - AxisDir(); - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - - ASSERTSZ( m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal" ); - - SetBits ( pFlags, PF_ANGULAR ); - } - - UTIL_SetModel( ENT(pev), pev->model ); - UTIL_SetOrigin( this, pev->origin ); - - // determine work style - if ( m_iMode == 0 ) // normal door - only USE - { - SetUse ( DoorUse ); - SetTouch ( NULL ); - pev->team = 1; // info_node identifier. Do not edit!!! - } - - if( m_iMode == 1 ) // classic QUAKE & HL door - only TOUCH - { - SetUse ( ShowInfo );//show info only - SetTouch ( DoorTouch ); - } - - if( m_iMode == 2 ) // combo door - USE and TOUCH - { - SetUse ( DoorUse ); - SetTouch ( DoorTouch ); - } - - // as default any door is toggleable, but if mapmaker set waittime > 0 - // door will de transformed into timebased door - // if waittime is -1 - button forever stay pressed - if ( m_flWait <= 0.0f ) pev->impulse = 1; // toggleable door - if ( m_flLip == 0 ) m_flLip = 4; // standart offset from Quake1 - - if ( pev->speed == 0 ) - pev->speed = 100; // default speed - m_iState = STATE_OFF; -} - -void CBaseDoor :: PostSpawn( void ) -{ - if (m_pParent) m_vecPosition1 = pev->origin - m_pParent->pev->origin; - else m_vecPosition1 = pev->origin; - - // Subtract 2 from size because the engine expands bboxes by 1 in all directions - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - - ASSERTSZ( m_vecPosition1 != m_vecPosition2, "door start/end positions are equal" ); - - if ( FBitSet( pev->spawnflags, SF_START_ON )) - { - if ( m_pParent ) - { - m_vecSpawnOffset = m_vecSpawnOffset + (m_vecPosition2 + m_pParent->pev->origin) - pev->origin; - UTIL_AssignOrigin( this, m_vecPosition2 + m_pParent->pev->origin ); - } - else - { - m_vecSpawnOffset = m_vecSpawnOffset + m_vecPosition2 - pev->origin; - UTIL_AssignOrigin( this, m_vecPosition2 ); - } - Vector vecTemp = m_vecPosition2; - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = vecTemp; - } -} - -void CBaseDoor :: SetToggleState( int state ) -{ - if ( m_iState == STATE_ON ) - { - if ( m_pParent ) UTIL_AssignOrigin( this, m_vecPosition2 + m_pParent->pev->origin ); - else UTIL_AssignOrigin( this, m_vecPosition2 ); - } - else - { - if ( m_pParent ) UTIL_AssignOrigin( this, m_vecPosition1 + m_pParent->pev->origin ); - else UTIL_AssignOrigin( this, m_vecPosition1 ); - } -} - -void CBaseDoor::Precache( void ) -{ - CBaseBrush::Precache(); // precache damage sound - - int m_sounds = UTIL_LoadSoundPreset( m_iMoveSound ); - switch ( m_sounds ) // load movesound sounds (sound will play when door is moving) - { - case 1: pev->noise1 = UTIL_PrecacheSound ("doors/doormove1.wav");break; - case 2: pev->noise1 = UTIL_PrecacheSound ("doors/doormove2.wav");break; - case 3: pev->noise1 = UTIL_PrecacheSound ("doors/doormove3.wav");break; - case 4: pev->noise1 = UTIL_PrecacheSound ("doors/doormove4.wav");break; - case 5: pev->noise1 = UTIL_PrecacheSound ("doors/doormove5.wav");break; - case 6: pev->noise1 = UTIL_PrecacheSound ("doors/doormove6.wav");break; - case 7: pev->noise1 = UTIL_PrecacheSound ("doors/doormove7.wav");break; - case 8: pev->noise1 = UTIL_PrecacheSound ("doors/doormove8.wav");break; - case 9: pev->noise1 = UTIL_PrecacheSound ("doors/doormove9.wav");break; - case 10: pev->noise1 = UTIL_PrecacheSound ("doors/doormove10.wav");break; - case 0: pev->noise1 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise1 = UTIL_PrecacheSound(m_sounds); break; // custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset( m_iStopSound ); - switch ( m_sounds ) // load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop1.wav");break; - case 2: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop2.wav");break; - case 3: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop3.wav");break; - case 4: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop4.wav");break; - case 5: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop5.wav");break; - case 6: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop6.wav");break; - case 7: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop7.wav");break; - case 8: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop8.wav");break; - case 0: pev->noise2 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise2 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - if ( !FStringNull( m_sMaster ))//door has master - { - m_sounds = UTIL_LoadSoundPreset( m_iStartSound ); - switch ( m_sounds ) // load locked sounds - { - case 1: pev->noise3 = UTIL_PrecacheSound ("!NA"); break; - case 2: pev->noise3 = UTIL_PrecacheSound ("!ND"); break; - case 3: pev->noise3 = UTIL_PrecacheSound ("!NF"); break; - case 4: pev->noise3 = UTIL_PrecacheSound ("!NFIRE"); break; - case 5: pev->noise3 = UTIL_PrecacheSound ("!NCHEM"); break; - case 6: pev->noise3 = UTIL_PrecacheSound ("!NRAD"); break; - case 7: pev->noise3 = UTIL_PrecacheSound ("!NCON"); break; - case 8: pev->noise3 = UTIL_PrecacheSound ("!NH"); break; - case 9: pev->noise3 = UTIL_PrecacheSound ("!NG"); break; - case 0: pev->noise3 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise3 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - } -} - -void CBaseDoor::DoorTouch( CBaseEntity *pOther ) -{ - // make delay before retouching - if ( gpGlobals->time < pev->dmgtime ) return; - pev->dmgtime = gpGlobals->time + 1.0f; - m_hActivator = pOther;// remember who activated the door - - if( pOther->IsPlayer( )) - DoorUse ( pOther, this, USE_TOGGLE, 1 ); // player always sending 1 -} - -void CBaseDoor::DoorUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - if ( IsLockedByMaster( useType ))//passed only USE_SHOWINFO - { - EMIT_SOUND( edict(), CHAN_VOICE, STRING( pev->noise3 ), 1, ATTN_NORM ); - return; - } - if ( useType == USE_SHOWINFO ) // show info - { - ALERT(at_console, "======/Xash Debug System/======\n"); - ALERT(at_console, "classname: %s\n", STRING(pev->classname)); - ALERT(at_console, "State: %s, Speed %.2f\n", GetStringForState( GetState()), pev->speed ); - ALERT(at_console, "Texture frame: %.f. WaitTime: %.2f\n", pev->frame, m_flWait); - } - else if ( m_iState != STATE_DEAD ) // activate door - { - // NOTE: STATE_DEAD is better method for simulate m_flWait -1 without fucking SetThink() - if ( m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF ) return; // door in-moving - if ( useType == USE_TOGGLE) - { - if ( m_iState == STATE_OFF ) - useType = USE_ON; - else useType = USE_OFF; - } - if ( useType == USE_ON ) - { - if( m_iState == STATE_OFF ) - DoorGoUp(); - } - else if ( useType == USE_OFF ) - { - if(m_iState == STATE_ON && pev->impulse) DoorGoDown(); - } - else if ( useType == USE_SET ) - { - if ( value ) - { - m_flWait = value; - pev->impulse = 0; - } - } - else if ( useType == USE_RESET ) - { - m_flWait = 0; - pev->impulse = 1; - } - } -} - -void CBaseDoor :: ShowInfo ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if(useType == USE_SHOWINFO)//show info - { - ALERT(at_console, "======/Xash Debug System/======\n"); - ALERT(at_console, "classname: %s\n", STRING(pev->classname)); - ALERT(at_console, "State: %s, Speed %.2f\n", GetStringForState( GetState()), pev->speed ); - ALERT(at_console, "Texture frame: %.f. WaitTime: %.2f\n", pev->frame, m_flWait); - } -} - -void CBaseDoor::DoorGoUp( void ) -{ - // It could be going-down, if blocked. - ASSERT( m_iState == STATE_OFF || m_iState == STATE_TURN_OFF ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1), 1, ATTN_NORM); - - m_iState = STATE_TURN_ON; - SetMoveDone( DoorHitTop ); - - UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON ); - if(IsRotatingDoor()) AngularMove(m_vecAngle2, pev->speed); - else LinearMove(m_vecPosition2, pev->speed); -} - -void CBaseDoor::DoorHitTop( void ) -{ - STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise1 )); - EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise2 ), 1, ATTN_NORM ); - - ASSERT( m_iState == STATE_TURN_ON ); - m_iState = STATE_ON; - - if( m_flWait == -1 ) - { - m_iState = STATE_DEAD; // keep door in this position - return; - } - - if( pev->impulse == 0 ) // time base door - { - SetThink( DoorGoDown ); - SetNextThink( m_flWait ); - } - - // Fire the close target (if startopen is set, then "top" is closed) - if( pev->spawnflags & SF_START_ON ) - UTIL_FireTargets( pev->target, m_hActivator, this, USE_OFF ); - else UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON ); -} - -void CBaseDoor::DoorGoDown( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1), 1, ATTN_NORM); - - ASSERT(m_iState == STATE_ON); - m_iState = STATE_TURN_OFF; - SetMoveDone( DoorHitBottom ); - if(IsRotatingDoor())AngularMove( m_vecAngle1, pev->speed); - else LinearMove(m_vecPosition1, pev->speed); -} - -void CBaseDoor::DoorHitBottom( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise2), 1, ATTN_NORM); - - ASSERT(m_iState == STATE_TURN_OFF); - m_iState = STATE_OFF; - - if ( pev->spawnflags & SF_START_ON ) - UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON ); - else UTIL_FireTargets( pev->target, m_hActivator, this, USE_OFF ); - - UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON ); -} - -void CBaseDoor::Blocked( CBaseEntity *pOther ) -{ - CBaseEntity *pTarget = NULL; - CBaseDoor *pDoor = NULL; - - UTIL_AssignOrigin( this, pev->origin ); - // make delay before retouching - if( gpGlobals->time < m_flBlockedTime ) return; - m_flBlockedTime = gpGlobals->time + 0.5; - - if(m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE) m_pParent->Blocked( pOther); - if ( pev->dmg ) pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); - - if (m_flWait >= 0) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1) ); - if(IsRotatingDoor()) - { - if (m_iState == STATE_TURN_ON) DoorGoUp(); - else if (m_iState == STATE_TURN_OFF) DoorGoDown(); - } - else - { - if (m_iState == STATE_TURN_ON) DoorGoDown(); - else if (m_iState == STATE_TURN_OFF) DoorGoUp(); - } - } - SetNextThink( 0 ); -} -LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ); - -//======================================================================= -// func_door_rotating - classic rotating door -//======================================================================= -void CRotDoor::Spawn( void ) -{ - CBaseDoor::Spawn(); - - if ( FBitSet (pev->spawnflags, SF_START_ON) ) - { - pev->angles = m_vecAngle2; - Vector vecSav = m_vecAngle1; - m_vecAngle2 = m_vecAngle1; - m_vecAngle1 = vecSav; - pev->movedir = pev->movedir * -1; - } -} - -void CRotDoor :: SetToggleState( int state ) -{ - if ( state == STATE_ON ) pev->angles = m_vecAngle2; - else pev->angles = m_vecAngle1; - UTIL_SetOrigin( this, pev->origin ); -} -LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ); - -//======================================================================= -// func_momentary_door -//======================================================================= -void CMomentaryDoor::Precache( void ) -{ - if(IsWater()) return;//no need sounds for water - - CBaseBrush::Precache(); - - int m_sounds = UTIL_LoadSoundPreset(m_iMoveSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove1.wav");break; - case 2: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove2.wav");break; - case 3: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove3.wav");break; - case 4: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove4.wav");break; - case 5: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove5.wav");break; - case 6: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove6.wav");break; - case 0: pev->noise = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop1.wav");break; - case 2: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop2.wav");break; - case 3: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop3.wav");break; - case 4: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop4.wav");break; - case 5: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop5.wav");break; - case 6: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop6.wav");break; - case 7: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop7.wav");break; - case 8: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop8.wav");break; - case 0: pev->noise2 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise2 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } -} - -void CMomentaryDoor::Spawn( void ) -{ - Precache(); - CBaseBrush::Spawn(); - UTIL_LinearVector( this );//movement direction - - if(pev->spawnflags & SF_NOTSOLID)pev->solid = SOLID_NOT; //make illusionary wall - else pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - m_iState = STATE_OFF; - UTIL_SetOrigin(this, pev->origin); - UTIL_SetModel( ENT(pev), pev->model ); - SetTouch( NULL );//just in case -} - -void CMomentaryDoor::PostSpawn( void ) -{ - if (m_pParent) m_vecPosition1 = pev->origin - m_pParent->pev->origin; - else m_vecPosition1 = pev->origin; - - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - - if(pev->spawnflags & SF_START_ON) - { - if (m_pParent) - { - m_vecSpawnOffset = m_vecSpawnOffset + (m_vecPosition2 + m_pParent->pev->origin) - pev->origin; - UTIL_AssignOrigin(this, m_vecPosition2 + m_pParent->pev->origin); - } - else - { - m_vecSpawnOffset = m_vecSpawnOffset + m_vecPosition2 - pev->origin; - UTIL_AssignOrigin(this, m_vecPosition2); - } - Vector vecTemp = m_vecPosition2; - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = vecTemp; - } -} - -void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_ON) value = 1; - else if(useType == USE_OFF) value = 0; - else if(useType == USE_SET); - else if(useType == USE_SHOWINFO)//show info - { - Msg("======/Xash Debug System/======\n"); - Msg("classname: %s\n", STRING(pev->classname)); - Msg("State: %s, Lip %.2f\n", GetStringForState( GetState()), m_flLip ); - SHIFT; - } - else return; - - if ( value > 1.0 )value = 1.0; - - if (IsLockedByMaster()) return; - Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); - - float speed = 0; - Vector delta; - - if (pev->speed) speed = pev->speed; - else - { - // default: get there in 0.1 secs - delta = move - pev->origin; - speed = delta.Length() * 10; - } - - //FIXME: allow for it being told to move at the same speed in the _opposite_ direction! - if ( speed != 0 ) - { - // This entity only thinks when it moves - if ( m_iState == STATE_OFF ) - { - //ALERT(at_console,"USE: start moving to %f %f %f.\n", move.x, move.y, move.z); - m_iState = STATE_ON; - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), 1, ATTN_NORM); - } - - LinearMove( move, speed ); - SetMoveDone( MomentaryMoveDone ); - } -} - -void CMomentaryDoor::MomentaryMoveDone( void ) -{ - m_iState = STATE_OFF; - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise2), 1, ATTN_NORM); -} -LINK_ENTITY_TO_CLASS( func_momentary_door, CMomentaryDoor ); - -//======================================================================= -// func_platform (a lift\elevator) -//======================================================================= -void CBasePlatform::Precache( void ) -{ - CBaseBrush::Precache();//precache damage sound - - int m_sounds = UTIL_LoadSoundPreset(m_iMoveSound); - switch (m_sounds)//load movesound sounds (sound will play when door is moving) - { - case 1: pev->noise = UTIL_PrecacheSound ("plats/bigmove1.wav");break; - case 2: pev->noise = UTIL_PrecacheSound ("plats/bigmove2.wav");break; - case 3: pev->noise = UTIL_PrecacheSound ("plats/elevmove1.wav");break; - case 4: pev->noise = UTIL_PrecacheSound ("plats/elevmove2.wav");break; - case 5: pev->noise = UTIL_PrecacheSound ("plats/elevmove3.wav");break; - case 6: pev->noise = UTIL_PrecacheSound ("plats/freightmove1.wav");break; - case 7: pev->noise = UTIL_PrecacheSound ("plats/freightmove2.wav");break; - case 8: pev->noise = UTIL_PrecacheSound ("plats/heavymove1.wav");break; - case 9: pev->noise = UTIL_PrecacheSound ("plats/rackmove1.wav");break; - case 10: pev->noise = UTIL_PrecacheSound ("plats/railmove1.wav");break; - case 11: pev->noise = UTIL_PrecacheSound ("plats/squeekmove1.wav");break; - case 12: pev->noise = UTIL_PrecacheSound ("plats/talkmove1.wav");break; - case 13: pev->noise = UTIL_PrecacheSound ("plats/talkmove2.wav");break; - case 0: pev->noise = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise1 = UTIL_PrecacheSound ("plats/bigstop1.wav");break; - case 2: pev->noise1 = UTIL_PrecacheSound ("plats/bigstop2.wav");break; - case 3: pev->noise1 = UTIL_PrecacheSound ("plats/freightstop1.wav");break; - case 4: pev->noise1 = UTIL_PrecacheSound ("plats/heavystop2.wav");break; - case 5: pev->noise1 = UTIL_PrecacheSound ("plats/rackstop1.wav");break; - case 6: pev->noise1 = UTIL_PrecacheSound ("plats/railstop1.wav");break; - case 7: pev->noise1 = UTIL_PrecacheSound ("plats/squeekstop1.wav");break; - case 8: pev->noise1 = UTIL_PrecacheSound ("plats/talkstop1.wav");break; - case 0: pev->noise1 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise1 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - UTIL_PrecacheSound( "buttons/button11.wav" );//error sound -} - -void CBasePlatform :: Setup( void ) -{ - Precache(); //precache moving & stop sounds - - pev->angles = g_vecZero; - - if (IsWater()) pev->solid = SOLID_NOT; // special contents (water, slime, e.t.c. ) - else pev->solid = SOLID_BSP; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(this, pev->origin); - UTIL_SetSize(pev, pev->mins, pev->maxs); - UTIL_SetModel(ENT(pev), pev->model ); - // vecPosition1 is the top position, vecPosition2 is the bottom - if (m_pParent) m_vecPosition1 = pev->origin - m_pParent->pev->origin; - else m_vecPosition1 = pev->origin; - m_vecPosition2 = m_vecPosition1; - - if(IsMovingPlatform() || IsComplexPlatform()) - { - m_vecPosition2.z = m_vecPosition2.z + step(); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "moving platform start/end positions are equal\n"); - } - if(IsRotatingPlatform() || IsComplexPlatform()) - { - if ( m_flMoveDistance < 0 ) pev->movedir = pev->movedir * -1; - - AxisDir(); - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating platform start/end positions are equal\n"); - SetBits (pFlags, PF_ANGULAR); - } - if (!IsWater())CBaseBrush::Spawn(); - - if (pev->speed == 0) pev->speed = 150; - m_iState = STATE_OFF; - -} - -void CBasePlatform :: PostSpawn( void ) -{ - if ( FBitSet( pev->spawnflags, SF_START_ON ) ) - { - if (m_pParent) UTIL_AssignOrigin (this, m_vecPosition2 + m_pParent->pev->origin); - else UTIL_AssignOrigin (this, m_vecPosition2); - UTIL_AssignAngles(this, m_vecAngle2); - m_iState = STATE_ON; - } - else - { - if (m_pParent) UTIL_AssignOrigin (this, m_vecPosition1 + m_pParent->pev->origin); - else UTIL_AssignOrigin (this, m_vecPosition1); - UTIL_AssignAngles(this, m_vecAngle1); - m_iState = STATE_OFF; - } -} - -void CBasePlatform :: Spawn( void ) -{ - Setup(); -} - -void CBasePlatform :: PostActivate( void ) -{ - if(m_iState == STATE_TURN_OFF || m_iState == STATE_TURN_ON)//platform "in-moving" ? restore sound! - { - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - } -} - -void CBasePlatform :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - GoUp(); - } - else if ( useType == USE_OFF ) - { - GoDown(); - } - else if ( useType == USE_SET ) - { - GoToFloor( value ); - } - else if ( useType == USE_RESET ) - { - GoToFloor( 1 ); - } - else if (useType == USE_SHOWINFO) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING(pev->classname)); - if( IsWater( )) ALERT( at_console, "Contents: %s, WaveHeight %g\n", GetContentsString( pev->skin ), pev->scale ); - else ALERT( at_console, "State: %s, floor %g\n", GetStringForState( GetState( )), CalcFloor( )); - ALERT( at_console, "distance %g, speed %g\n", m_flMoveDistance, pev->speed ); - - } -} - -void CBasePlatform :: GoToFloor( float floor ) -{ - float curfloor = CalcFloor(); - m_flValue = floor; - - if(curfloor <= 0) return; - if(curfloor == floor) //already there? - { - //pass trough - UTIL_FireTargets( pev->target, m_hActivator, this, USE_RESET, m_flValue ); - return; - } - - m_vecFloor = m_vecPosition1; - m_vecFloor.z = pev->origin.z + (floor * step()) - (curfloor * step()); - - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - - if(floor > curfloor)m_iState = STATE_TURN_ON; - else m_iState = STATE_TURN_OFF; - - SetMoveDone( HitFloor ); - - if(fabs(floor - curfloor) > 1.0) //create floor informator for prop_counter - { - CBaseEntity *pFloor = CBaseEntity::Create( "floorent", pev->origin, g_vecZero, edict() ); - pFloor->pev->target = pev->netname; - pFloor->PostActivate(); - } - LinearMove(m_vecFloor, pev->speed); -} - -void CBasePlatform :: HitFloor( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, STRING( pev->noise )); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, STRING( pev->noise1 ), m_flVolume, ATTN_NORM ); - - ASSERT( m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF ); - UTIL_FireTargets( pev->target, m_hActivator, this, USE_TOGGLE, m_flValue ); - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_SET, m_flValue ); - m_vecPosition2 = pev->origin; // save current floor - if( m_iState == STATE_TURN_ON ) m_iState = STATE_ON; - if( m_iState == STATE_TURN_OFF ) m_iState = STATE_OFF; -} - -void CBasePlatform :: GoDown( void ) -{ - EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM ); - - ASSERT( m_iState == STATE_ON || m_iState == STATE_TURN_ON ); - m_iState = STATE_TURN_OFF; - SetMoveDone( HitBottom ); - - if ( IsRotatingPlatform( )) AngularMove( m_vecAngle1, pev->speed ); - else if ( IsMovingPlatform( )) LinearMove( m_vecPosition1, pev->speed ); - else if ( IsComplexPlatform( )) ComplexMove( m_vecPosition1, m_vecAngle1, pev->speed ); - else HitBottom(); // don't brake platform status -} - -void CBasePlatform :: HitBottom( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, STRING( pev->noise )); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, STRING( pev->noise1 ), m_flVolume, ATTN_NORM ); - - ASSERT( m_iState == STATE_TURN_OFF ); - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_SET, 1 ); - m_iState = STATE_OFF; -} - -void CBasePlatform :: GoUp( void ) -{ - EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM ); - - ASSERT( m_iState == STATE_OFF || m_iState == STATE_TURN_OFF ); - m_iState = STATE_TURN_ON; - SetMoveDone( HitTop ); - - if ( IsRotatingPlatform( )) AngularMove( m_vecAngle2, pev->speed ); - else if ( IsMovingPlatform( )) LinearMove( m_vecPosition2, pev->speed ); - else if ( IsComplexPlatform( )) ComplexMove( m_vecPosition2, m_vecAngle2, pev->speed ); - else HitTop(); // don't brake platform status -} - -void CBasePlatform :: HitTop( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noise1), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_TURN_ON); - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_SET, 2 ); - m_iState = STATE_ON; -} - -void CBasePlatform :: Blocked( CBaseEntity *pOther ) -{ - UTIL_AssignOrigin(this, pev->origin); - //make delay before retouching - if ( gpGlobals->time < m_flBlockedTime) return; - m_flBlockedTime = gpGlobals->time + 0.5; - - if(m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE) m_pParent->Blocked( pOther); - pOther->TakeDamage( pev, pev, 1, DMG_CRUSH ); - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - ASSERT(m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF); - - if ( m_iState == STATE_TURN_ON ) GoDown(); - else if ( m_iState == STATE_TURN_OFF ) GoUp(); - SetNextThink( 0 ); -} - -LINK_ENTITY_TO_CLASS( func_water, CBasePlatform ); -LINK_ENTITY_TO_CLASS( func_platform, CBasePlatform ); -LINK_ENTITY_TO_CLASS( func_platform_rotating, CBasePlatform ); - -//======================================================================= -// func_train (Classic QUAKE Train) -//======================================================================= -TYPEDESCRIPTION CFuncTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrain, pPath, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTrain, pNextPath, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatform ); - -void CFuncTrain :: Spawn( void ) -{ - Precache(); // precache moving & stop sounds - - if(pev->spawnflags & SF_NOTSOLID)//make illusionary train - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - - UTIL_SetOrigin( this, pev->origin ); - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetModel( ENT(pev), pev->model ); - CBaseBrush::Spawn(); - - // determine method for calculating origin - if( pev->origin != g_vecZero ) pev->impulse = 1; - - if (pev->speed == 0) pev->speed = 100; - m_iState = STATE_OFF; -} - -void CFuncTrain :: PostSpawn( void ) -{ - if (!FindPath()) return; - - if ( pev->impulse ) - { - m_vecSpawnOffset = m_vecSpawnOffset + pPath->pev->origin - pev->origin; - if (m_pParent) UTIL_AssignOrigin (this, pPath->pev->origin - m_pParent->pev->origin ); - else UTIL_AssignOrigin (this, pPath->pev->origin ); - } - else - { - m_vecSpawnOffset = m_vecSpawnOffset + (pPath->pev->origin - TrainOrg()) - pev->origin; - if ( m_pParent ) UTIL_AssignOrigin (this, pPath->pev->origin - TrainOrg() - m_pParent->pev->origin ); - else UTIL_AssignOrigin (this, pPath->pev->origin - TrainOrg()); - } -} - -void CFuncTrain :: PostActivate( void ) -{ - if ( m_iState == STATE_ON ) // platform "in-moving" ? restore sound! - { - EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - } - if ( pev->spawnflags & SF_START_ON ) - { - m_iState = STATE_OFF; // restore sound on a next level - SetThink( Next ); // evil stuff... - SetNextThink( 0.1 ); - ClearBits( pev->spawnflags, SF_START_ON );//fire once - } -} - -BOOL CFuncTrain::FindPath( void ) -{ - // find start track - pPath = UTIL_FindEntityByTargetname (NULL, STRING( pev->target )); - if( pPath && pPath->edict( )) - return TRUE; - return FALSE; -} - -BOOL CFuncTrain::FindNextPath( void ) -{ - if( !pPath ) - { - ALERT( at_error, "CFuncTrain::FindNextpath failed\n" ); - return FALSE; - } - - // get pointer to next target - if( pev->speed > 0 ) pNextPath = ((CInfoPath *)pPath)->GetNext(); - if( pev->speed < 0 ) pNextPath = ((CInfoPath *)pPath)->GetPrev(); - - if( pNextPath && pNextPath->edict( )) // validate path - { - // record new value (this will be used after changelevel) - pev->target = pNextPath->pev->targetname; - return TRUE; // path found - } - switch ( m_iMode ) - { - case 1: UpdateSpeed(); break; - case 2: UpdateSpeed(); - default: Stop(); break; - } - return FALSE; -} - -void CFuncTrain::UpdateSpeed( float value ) -{ - // update path if dir changed - if(( value > 0 && pev->speed < 0 ) || ( value < 0 && pev->speed > 0 ) || value == 0 ) - { - if( pNextPath && pNextPath->edict( )) - pPath = pNextPath; - } - - if( value != 0 ) pev->speed = value; // get new speed - else pev->speed = -pev->speed; - - if( m_iState == STATE_ON ) Next(); // re-calculate speed now! -} - -void CFuncTrain::ClearPointers( void ) -{ - CBaseEntity::ClearPointers(); - pPath = NULL; - pNextPath = NULL; -} - -void CFuncTrain::OverrideReset( void ) -{ - // Are we moving? - if ( m_iState == STATE_ON ) - { - if ( FindPath( )) SetBits( pev->spawnflags, SF_START_ON ); // PostActivate member - else Stop(); - } -} - -void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if ( useType == USE_TOGGLE ) - { - if( m_iState == STATE_ON ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) Next(); - else if ( useType == USE_OFF ) Stop(); - else if ( useType == USE_SET ) - { - UpdateSpeed( value ); // set new speed - } - else if ( useType == USE_RESET ) - { - UTIL_FireTargets( pev->netname, pActivator, pCaller, USE_TOGGLE ); // just fire - } - else if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, speed %g\n", GetStringForState( GetState( )), pev->speed ); - if( GetPrev() && GetPrev()->edict( )) ALERT( at_console, "Prev path %s", STRING( GetPrev()->pev->targetname )); - if( GetNext() && GetNext()->edict( )) ALERT( at_console, "Next path %s", STRING( GetNext()->pev->targetname )); - ALERT( at_console, "\n" ); - } -} - -void CFuncTrain :: Next( void ) -{ - if( !FindNextPath( )) return; - - // linear move to next corner. - if ( m_iState == STATE_OFF ) // enable train sound - { - STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noise )); - EMIT_SOUND( edict(), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM ); - } - - ClearBits( pev->effects, EF_NOINTERP ); // enable interpolation - m_iState = STATE_ON; - - if( pev->speed < 0 && FBitSet( pNextPath->pev->spawnflags, SF_CORNER_TELEPORT )) - { - SetBits( pev->effects, EF_NOINTERP ); - if ( m_pParent ) UTIL_AssignOrigin( this, pNextPath->pev->origin - m_pParent->pev->origin ); - else UTIL_AssignOrigin( this, pNextPath->pev->origin ); - Wait(); // Get on with doing the next path corner. - return; - } - - if ( m_pParent ) - { - if ( pev->impulse ) LinearMove( pNextPath->pev->origin - m_pParent->pev->origin, fabs( pev->speed )); - else LinearMove ( pNextPath->pev->origin - TrainOrg() - m_pParent->pev->origin, fabs( pev->speed )); - } - else - { - if ( pev->impulse ) LinearMove( pNextPath->pev->origin, fabs( pev->speed )); - else LinearMove ( pNextPath->pev->origin - TrainOrg(), fabs( pev->speed )); - } - SetMoveDone( Wait ); - -} - -BOOL CFuncTrain :: Teleport( void ) -{ - if( !FindNextPath( )) - return FALSE; - - if( FBitSet( pNextPath->pev->spawnflags, SF_CORNER_TELEPORT )) - { - SetBits( pev->effects, EF_NOINTERP ); - - // determine teleportation point - if( pev->speed > 0 ) - { - pNextPath = pNextPath->GetNext(); - UpdateTargets(); - } - - if( !pNextPath || !pNextPath->edict() ) - return FALSE; // dead end - - if ( m_pParent ) - UTIL_AssignOrigin(this, pNextPath->pev->origin - m_pParent->pev->origin ); - else UTIL_AssignOrigin(this, pNextPath->pev->origin ); - - pPath = pNextPath; - Next(); // Get on with doing the next path corner. - return TRUE; - } - return FALSE; -} - -void CFuncTrain :: Wait( void ) -{ - UpdateTargets(); - if(Teleport( )) return; - - if( pNextPath ) - { - pPath = pNextPath;//move pointer - ((CInfoPath *)pPath)->GetSpeed( &pev->speed ); - if(!Stop(((CInfoPath *)pPath)->GetDelay())) Next(); // go to next corner - } - else Stop(); -} - -void CFuncTrain :: UpdateTargets( void ) -{ - // fire the pass target if there is one - if( !pNextPath || !pNextPath->edict() ) return; - - UTIL_FireTargets( pNextPath->pev->message, this, this, USE_TOGGLE ); - if ( FBitSet( pNextPath->pev->spawnflags, SF_CORNER_FIREONCE )) - pNextPath->pev->message = iStringNull; - UTIL_FireTargets( pev->netname, this, this, USE_TOGGLE ); -} - -BOOL CFuncTrain :: Stop( float flWait ) -{ - if( flWait == 0 ) return FALSE; - m_iState = STATE_OFF; - - if( pPath && pPath->edict() ) - { - UTIL_FireTargets( pPath->pev->message, this, this, USE_TOGGLE ); - if ( FBitSet( pPath->pev->spawnflags, SF_CORNER_FIREONCE )) - pPath->pev->message = iStringNull; - UTIL_FireTargets( pev->netname, this, this, USE_TOGGLE ); - } - - // clear the sound channel. - STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noise )); - EMIT_SOUND( edict(), CHAN_VOICE, STRING( pev->noise1 ), m_flVolume, ATTN_NORM ); - - UTIL_SetVelocity( this, g_vecZero ); - UTIL_SetAvelocity( this, g_vecZero ); - - if( flWait > 0 ) - { - SetNextThink( flWait ); - SetThink( Next ); - } - else if( flWait == -1 ) DontThink(); // wait for retrigger - return TRUE; -} - -void CFuncTrain :: Blocked( CBaseEntity *pOther ) -{ - // Keep "movewith" entities in line - UTIL_AssignOrigin(this, pev->origin); - - if ( gpGlobals->time < m_flBlockedTime) return; - m_flBlockedTime = gpGlobals->time + 0.5; - - if( m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE ) - m_pParent->Blocked( pOther ); - pOther->TakeDamage( pev, pev, 1, DMG_CRUSH ); - STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noise )); - ASSERT(m_iState == STATE_ON); - - Stop( 0.5 ); -} -LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ); \ No newline at end of file diff --git a/server/ents/basemover.cpp.old b/server/ents/basemover.cpp.old deleted file mode 100644 index e399b91d..00000000 --- a/server/ents/basemover.cpp.old +++ /dev/null @@ -1,1855 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// basemover.cpp - base code for linear and -// angular moving brushes e.g. doors, buttons e.t.c -//======================================================================= - -#include "extdll.h" -#include "defaults.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "saverestore.h" -#include "player.h" - -//======================================================================= -// main functions () -//======================================================================= -TYPEDESCRIPTION CBaseMover::m_SaveData[] = -{ - DEFINE_FIELD( CBaseMover, m_flBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CBaseMover, m_iMode, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMover, m_flMoveDistance, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flLip, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flHeight, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flValue, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_vecFinalDest, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecPosition1, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecPosition2, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecFloor, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMover, m_pfnCallWhenMoveDone, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseMover, m_vecAngle1, FIELD_VECTOR ), - DEFINE_FIELD( CBaseMover, m_vecAngle2, FIELD_VECTOR ), - DEFINE_FIELD( CBaseMover, m_flLinearMoveSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_flAngularMoveSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMover, m_vecFinalAngle, FIELD_VECTOR ), - DEFINE_FIELD( CBaseMover, flTravelTime, FIELD_FLOAT ), -}; IMPLEMENT_SAVERESTORE( CBaseMover, CBaseBrush ); - -void CBaseMover :: AxisDir( void ) -{ - if( pev->movedir != g_vecZero ) return; - - // don't change this! - if( FBitSet( pev->spawnflags, SF_DOOR_ROTATE_X )) - pev->movedir = Vector ( 1, 0, 0 ); // around z-axis - else if( FBitSet( pev->spawnflags, SF_DOOR_ROTATE_Z )) - pev->movedir = Vector ( 0, 0, 1 ); // around x-axis - else pev->movedir = Vector ( 0, 1, 0 ); // around y-axis -} - -void CBaseMover::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq(pkvd->szKeyName, "lip" )) - { - m_flLip = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if( FStrEq( pkvd->szKeyName, "waveheight" )) - { - // field for volume_water - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "type")) - { - m_iMode = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) - { - m_iStartSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesound")) - { - m_iMoveSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsound")) - { - m_iStopSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "distance") || FStrEq(pkvd->szKeyName, "rotation")) - { - m_flMoveDistance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_flHeight = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "waveheight")) - { - //func_water wave height - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "contents")) - { - //func_water contents - pev->skin = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseBrush::KeyValue( pkvd ); -} - -//======================================================================= -// LinearMove -// -// calculate pev->velocity and pev->nextthink to reach vecDest from -// pev->origin traveling at flSpeed -//======================================================================= -void CBaseMover :: LinearMove( Vector vecInput, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "LinearMove: no speed is defined!"); - - m_flLinearMoveSpeed = flSpeed; - m_vecFinalDest = vecInput; - - SetThink( LinearMoveNow ); - UTIL_SetThink( this ); -} - - -void CBaseMover :: LinearMoveNow( void ) -{ - Vector vecDest; - - if (m_pParent)vecDest = m_vecFinalDest + m_pParent->pev->origin; - else vecDest = m_vecFinalDest; - - // Already there? - if (vecDest == pev->origin) - { - LinearMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDest - pev->origin; - - // divide vector length by speed to get time to reach dest - flTravelTime = vecDestDelta.Length() / m_flLinearMoveSpeed; - - // set nextthink to trigger a call to LinearMoveDone when dest is reached - SetNextThink( flTravelTime );//, TRUE ); - SetThink( LinearMoveDone ); - - UTIL_SetVelocity( this, vecDestDelta / flTravelTime ); -} - -//======================================================================= -// After moving, set origin to exact final destination, -// call "move done" function -//======================================================================= -void CBaseMover :: LinearMoveDone( void ) -{ - SetThink(LinearMoveDoneNow); - UTIL_SetThink( this ); -} - -void CBaseMover :: LinearMoveDoneNow( void ) -{ - UTIL_SetVelocity(this, g_vecZero); - if (m_pParent) UTIL_AssignOrigin(this, m_vecFinalDest + m_pParent->pev->origin); - else UTIL_AssignOrigin(this, m_vecFinalDest); - - DontThink(); - if( m_pfnCallWhenMoveDone )(this->*m_pfnCallWhenMoveDone)(); -} - -//======================================================================= -// AngularMove -// -// calculate pev->velocity and pev->nextthink to reach vecDest from -// pev->origin traveling at flSpeed -// Just like LinearMove, but rotational. -//======================================================================= -void CBaseMover :: AngularMove( Vector vecDestAngle, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "AngularMove: no speed is defined!"); - - m_vecFinalAngle = vecDestAngle; - m_flAngularMoveSpeed = flSpeed; - - SetThink( AngularMoveNow ); - UTIL_SetThink( this ); -} - -void CBaseMover :: AngularMoveNow() -{ - Vector vecDestAngle; - - if (m_pParent) vecDestAngle = m_vecFinalAngle + m_pParent->pev->angles; - else vecDestAngle = m_vecFinalAngle; - - // Already there? - if (vecDestAngle == pev->angles) - { - AngularMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDestAngle - pev->angles; - - // divide by speed to get time to reach dest - flTravelTime = vecDestDelta.Length() / m_flAngularMoveSpeed; - - // set nextthink to trigger a call to AngularMoveDone when dest is reached - SetNextThink( flTravelTime );//, TRUE ); - SetThink( AngularMoveDone ); - - // scale the destdelta vector by the time spent traveling to get velocity - UTIL_SetAvelocity(this, vecDestDelta / flTravelTime ); -} - -void CBaseMover :: AngularMoveDone( void ) -{ - SetThink( AngularMoveDoneNow ); - UTIL_SetThink( this ); -} - -//======================================================================= -// After rotating, set angle to exact final angle, call "move done" function -//======================================================================= -void CBaseMover :: AngularMoveDoneNow( void ) -{ - UTIL_SetAvelocity(this, g_vecZero); - if (m_pParent) UTIL_AssignAngles(this, m_vecFinalAngle + m_pParent->pev->angles); - else UTIL_AssignAngles(this, m_vecFinalAngle); - - DontThink(); - if ( m_pfnCallWhenMoveDone ) (this->*m_pfnCallWhenMoveDone)(); -} - -//======================================================================= -// ComplexMove -// -// combinate LinearMove and AngularMove -//======================================================================= -void CBaseMover :: ComplexMove( Vector vecInput, Vector vecDestAngle, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "ComplexMove: no speed is defined!"); - - //set shared speed for moving and rotating - m_flLinearMoveSpeed = flSpeed; - m_flAngularMoveSpeed = flSpeed; - - //save local variables into global containers - m_vecFinalDest = vecInput; - m_vecFinalAngle = vecDestAngle; - - SetThink( ComplexMoveNow ); - UTIL_SetThink( this ); -} - -void CBaseMover :: ComplexMoveNow( void ) -{ - Vector vecDest, vecDestAngle; - - if (m_pParent)//calculate destination - { - vecDest = m_vecFinalDest + m_pParent->pev->origin; - vecDestAngle = m_vecFinalAngle + m_pParent->pev->angles; - } - else - { - vecDestAngle = m_vecFinalAngle; - vecDest = m_vecFinalDest; - } - - // Already there? - if (vecDest == pev->origin && vecDestAngle == pev->angles) - { - ComplexMoveDone(); - return; - } - - // Calculate TravelTime and final angles - Vector vecDestLDelta = vecDest - pev->origin; - Vector vecDestADelta = vecDestAngle - pev->angles; - - // divide vector length by speed to get time to reach dest - flTravelTime = vecDestLDelta.Length() / m_flLinearMoveSpeed; - - // set nextthink to trigger a call to LinearMoveDone when dest is reached - SetNextThink( flTravelTime ); - SetThink( ComplexMoveDone ); - - //set linear and angular velocity now - UTIL_SetVelocity( this, vecDestLDelta / flTravelTime ); - UTIL_SetAvelocity(this, vecDestADelta / flTravelTime ); -} - -void CBaseMover :: ComplexMoveDone( void ) -{ - SetThink(ComplexMoveDoneNow); - UTIL_SetThink( this ); -} - -void CBaseMover :: ComplexMoveDoneNow( void ) -{ - UTIL_SetVelocity(this, g_vecZero); - UTIL_SetAvelocity(this, g_vecZero); - - if ( m_pParent ) - { - UTIL_AssignOrigin( this, m_vecFinalDest + m_pParent->pev->origin ); - UTIL_AssignAngles( this, m_vecFinalAngle + m_pParent->pev->angles ); - } - else - { - UTIL_AssignOrigin( this, m_vecFinalDest ); - UTIL_AssignAngles( this, m_vecFinalAngle ); - } - - DontThink(); - if( m_pfnCallWhenMoveDone ) - (this->*m_pfnCallWhenMoveDone)(); -} - -//======================================================================= -// func_door - classic QUAKE door -//======================================================================= -void CBaseDoor::Spawn( ) -{ - Precache(); - if(!IsRotatingDoor()) UTIL_LinearVector( this ); - CBaseBrush::Spawn(); - - //make illusionary door - if(pev->spawnflags & SF_DOOR_PASSABLE || IsWater()) - pev->solid = SOLID_NOT; - else pev->solid = SOLID_BSP; - - pev->movetype = MOVETYPE_PUSH; - - if(IsRotatingDoor()) - { - // check for clockwise rotation - AxisDir(); - - if( FBitSet( pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS )) - pev->movedir = pev->movedir * -1; - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal"); - SetBits (pFlags, PF_ANGULAR); - } - - UTIL_SetModel( ENT(pev), pev->model ); - UTIL_SetOrigin(this, pev->origin); - - // determine work style - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY )) - SetTouch ( NULL ); - else SetTouch ( DoorTouch ); - - // if waittime is -1 - button forever stay pressed - if ( FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN )) - pev->impulse = 1; // toggleable door - - if ( m_flLip == 0 ) m_flLip = 4; // standart offset from Quake1 - if ( !m_flWait ) m_flWait = 2.0f; - if ( pev->speed == 0 ) pev->speed = 100; // default speed - m_iState = STATE_OFF; - - if( IsRotatingDoor() && FBitSet( pev->spawnflags, SF_DOOR_START_OPEN )) - { - pev->angles = m_vecAngle2; - Vector vecSav = m_vecAngle1; - m_vecAngle2 = m_vecAngle1; - m_vecAngle1 = vecSav; - pev->movedir = pev->movedir * -1; - } -} - -void CBaseDoor :: PostSpawn( void ) -{ - if ( m_pParent ) - m_vecPosition1 = pev->origin - m_pParent->pev->origin; - else m_vecPosition1 = pev->origin; - - // Subtract 2 from size because the engine expands bboxes by 1 in all directions - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - - ASSERTSZ( m_vecPosition1 != m_vecPosition2, "door start/end positions are equal" ); - if( FBitSet( pev->spawnflags, SF_DOOR_START_OPEN )) - { - SET_AREAPORTAL( edict(), TRUE ); - - if( m_pParent ) - { - m_vecSpawnOffset = m_vecSpawnOffset + (m_vecPosition2 + m_pParent->pev->origin) - pev->origin; - UTIL_AssignOrigin(this, m_vecPosition2 + m_pParent->pev->origin); - } - else - { - m_vecSpawnOffset = m_vecSpawnOffset + m_vecPosition2 - pev->origin; - UTIL_AssignOrigin(this, m_vecPosition2); - } - Vector vecTemp = m_vecPosition2; - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = vecTemp; - } -} - -void CBaseDoor::Precache( void ) -{ - CBaseBrush::Precache(); // precache damage sound - - int m_sounds = UTIL_LoadSoundPreset(m_iMoveSound); - if(IsWater()) m_sounds = 0; - switch (m_sounds)//load movesound sounds (sound will play when door is moving) - { - case 1: pev->noise1 = UTIL_PrecacheSound ("doors/doormove1.wav");break; - case 2: pev->noise1 = UTIL_PrecacheSound ("doors/doormove2.wav");break; - case 3: pev->noise1 = UTIL_PrecacheSound ("doors/doormove3.wav");break; - case 4: pev->noise1 = UTIL_PrecacheSound ("doors/doormove4.wav");break; - case 5: pev->noise1 = UTIL_PrecacheSound ("doors/doormove5.wav");break; - case 6: pev->noise1 = UTIL_PrecacheSound ("doors/doormove6.wav");break; - case 7: pev->noise1 = UTIL_PrecacheSound ("doors/doormove7.wav");break; - case 8: pev->noise1 = UTIL_PrecacheSound ("doors/doormove8.wav");break; - case 9: pev->noise1 = UTIL_PrecacheSound ("doors/doormove9.wav");break; - case 10: pev->noise1 = UTIL_PrecacheSound ("doors/doormove10.wav");break; - case 0: pev->noise1 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise1 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - if(IsWater()) m_sounds = 0; - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop1.wav");break; - case 2: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop2.wav");break; - case 3: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop3.wav");break; - case 4: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop4.wav");break; - case 5: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop5.wav");break; - case 6: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop6.wav");break; - case 7: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop7.wav");break; - case 8: pev->noise2 = UTIL_PrecacheSound ("doors/doorstop8.wav");break; - case 0: pev->noise2 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise2 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStartSound); - if(IsWater()) m_sounds = 0; - switch (m_sounds)//load locked sounds - { - case 1: pev->noise3 = UTIL_PrecacheSound ("buttons/button1.wav"); break; - case 2: pev->noise3 = UTIL_PrecacheSound ("buttons/button2.wav"); break; - case 3: pev->noise3 = UTIL_PrecacheSound ("buttons/button3.wav"); break; - case 4: pev->noise3 = UTIL_PrecacheSound ("buttons/button4.wav"); break; - case 5: pev->noise3 = UTIL_PrecacheSound ("buttons/button5.wav"); break; - case 6: pev->noise3 = UTIL_PrecacheSound ("buttons/button6.wav"); break; - case 7: pev->noise3 = UTIL_PrecacheSound ("buttons/button7.wav"); break; - case 8: pev->noise3 = UTIL_PrecacheSound ("buttons/button8.wav"); break; - case 9: pev->noise3 = UTIL_PrecacheSound ("buttons/button9.wav"); break; - case 10: pev->noise3 = UTIL_PrecacheSound ("buttons/button10.wav"); break; - case 11: pev->noise3 = UTIL_PrecacheSound ("buttons/button11.wav"); break; - case 12: pev->noise3 = UTIL_PrecacheSound ("buttons/latchlocked1.wav"); break; - case 13: pev->noise3 = UTIL_PrecacheSound ("buttons/latchunlocked1.wav"); break; - case 14: pev->noise3 = UTIL_PrecacheSound ("buttons/buttons/lightswitch2.wav"); break; - case 0: pev->noise3 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise3 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } -} - -void CBaseDoor::DoorTouch( CBaseEntity *pOther ) -{ - //make delay before retouching - if ( gpGlobals->time < pev->dmgtime ) - return; - pev->dmgtime = gpGlobals->time + 1.0; - //m_hActivator = pOther;// remember who activated the door - - if ( !FStringNull( pev->targetname )) - { - // play locked sound - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise3), m_flVolume, ATTN_NORM); - return; - } - - if( pOther->IsPlayer( )) Use( pOther, this, USE_TOGGLE, 1 ); // player always sending 1 -} - -void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - if(IsLockedByMaster( useType ))//passed only USE_SHOWINFO - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise3), m_flVolume, ATTN_NORM); - return; - } - - if ( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - Msg( "State: %s, Speed %g\n", GetStringForState( GetState()), pev->speed ); - Msg( "Texture frame: %g. WaitTime: %g\n", pev->frame, m_flWait); - } - else if ( m_iState != STATE_DEAD ) - { - // activate door - // NOTE: STATE_DEAD is better method for simulate m_flWait -1 without fucking SetThink() - if ( m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF ) - return; // door in-moving - - if ( useType == USE_TOGGLE ) - { - if(m_iState == STATE_OFF) useType = USE_ON; - else useType = USE_OFF; - } - if ( useType == USE_ON ) - { - if( m_iState == STATE_OFF ) - DoorGoUp(); - } - else if( useType == USE_OFF ) - { - if( m_iState == STATE_ON && pev->impulse ) - DoorGoDown(); - } - else if( useType == USE_SET ) - pev->frame = !pev->frame; //change texture - } -} - -void CBaseDoor::DoorGoUp( void ) -{ - // It could be going-down, if blocked. - ASSERT(m_iState == STATE_OFF || m_iState == STATE_TURN_OFF); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1), m_flVolume, ATTN_NORM); - m_iState = STATE_TURN_ON; - SetMoveDone( DoorHitTop ); - SetTouch( NULL ); - - UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON ); - SET_AREAPORTAL( edict(), TRUE ); - - if(IsRotatingDoor()) - { - int sign = 1; - if ( m_hActivator != NULL && !FBitSet( pev->spawnflags, SF_DOOR_ONEWAY ) && pev->movedir.y) - { - // Y axis rotation, move away from the player - Vector vec = m_hActivator->pev->origin - pev->origin; - UTIL_MakeVectors ( m_hActivator->pev->angles ); - Vector vnext = (m_hActivator->pev->origin + (gpGlobals->v_forward * 10)) - pev->origin; - if ( (vec.x * vnext.y - vec.y * vnext.x) < 0 ) sign = -1; - } - AngularMove( m_vecAngle2 * sign, pev->speed ); - } - else LinearMove( m_vecPosition2, pev->speed ); -} - -void CBaseDoor::DoorHitTop( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise2), m_flVolume, ATTN_NORM); - - ASSERT( m_iState == STATE_TURN_ON ); - m_iState = STATE_ON; - - if( pev->impulse == 0 ) // time base door - { - if( m_flWait == -1 ) - m_iState = STATE_DEAD;//keep door in this position - else - { - SetThink( DoorGoDown ); - SetNextThink( m_flWait ); - } - } - else if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY )) SetTouch( DoorTouch ); - - // Fire the close target (if startopen is set, then "top" is closed) - if ( pev->spawnflags & SF_DOOR_START_OPEN ) - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_TOGGLE ); - UTIL_FireTargets( pev->target, m_hActivator, this, USE_TOGGLE ); -} - -void CBaseDoor::DoorGoDown( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_ON); - m_iState = STATE_TURN_OFF; - SetMoveDone( DoorHitBottom ); - if(IsRotatingDoor())AngularMove( m_vecAngle1, pev->speed); - else LinearMove(m_vecPosition1, pev->speed); -} - -void CBaseDoor::DoorHitBottom( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise1) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise2), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_TURN_OFF); - m_iState = STATE_OFF; - - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY )) SetTouch ( NULL ); - else SetTouch( DoorTouch ); - - if (!(pev->spawnflags & SF_DOOR_START_OPEN)) - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_TOGGLE ); - UTIL_FireTargets( pev->target, m_hActivator, this, USE_TOGGLE ); - - SET_AREAPORTAL( edict(), FALSE ); -} - -void CBaseDoor::Blocked( CBaseEntity *pOther ) -{ - UTIL_AssignOrigin( this, pev->origin ); - // make delay before retouching - if( gpGlobals->time < m_flBlockedTime ) return; - m_flBlockedTime = gpGlobals->time + 0.5; - - if( m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE ) m_pParent->Blocked( pOther ); - if( pev->dmg ) pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); - - if( m_flWait >= 0 ) - { - STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noise1 )); - if( m_iState == STATE_TURN_ON ) DoorGoDown(); - else if( m_iState == STATE_TURN_OFF ) DoorGoUp(); - } - - // what the hell does this ? - // UTIL_SynchDoors( this ); - SetNextThink( 0 ); -} -LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ); -LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ); -LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ); - -//======================================================================= -// func_momentary_door -//======================================================================= -void CMomentaryDoor::Precache( void ) -{ - CBaseBrush::Precache(); - - int m_sounds = UTIL_LoadSoundPreset(m_iMoveSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove1.wav");break; - case 2: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove2.wav");break; - case 3: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove3.wav");break; - case 4: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove4.wav");break; - case 5: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove5.wav");break; - case 6: pev->noise = UTIL_PrecacheSound ("materials/doors/doormove6.wav");break; - case 0: pev->noise = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop1.wav");break; - case 2: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop2.wav");break; - case 3: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop3.wav");break; - case 4: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop4.wav");break; - case 5: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop5.wav");break; - case 6: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop6.wav");break; - case 7: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop7.wav");break; - case 8: pev->noise2 = UTIL_PrecacheSound ("materials/doors/doorstop8.wav");break; - case 0: pev->noise2 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise2 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } -} - -void CMomentaryDoor::Spawn( void ) -{ - Precache(); - CBaseBrush::Spawn(); - UTIL_LinearVector( this );//movement direction - - if(pev->spawnflags & SF_NOTSOLID)pev->solid = SOLID_NOT; //make illusionary wall - else pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - m_iState = STATE_OFF; - UTIL_SetOrigin(this, pev->origin); - UTIL_SetModel( ENT(pev), pev->model ); - SetTouch( NULL );//just in case -} - -void CMomentaryDoor::PostSpawn( void ) -{ - if (m_pParent) m_vecPosition1 = pev->origin - m_pParent->pev->origin; - else m_vecPosition1 = pev->origin; - - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - - if(pev->spawnflags & SF_START_ON) - { - if (m_pParent) - { - m_vecSpawnOffset = m_vecSpawnOffset + (m_vecPosition2 + m_pParent->pev->origin) - pev->origin; - UTIL_AssignOrigin(this, m_vecPosition2 + m_pParent->pev->origin); - } - else - { - m_vecSpawnOffset = m_vecSpawnOffset + m_vecPosition2 - pev->origin; - UTIL_AssignOrigin(this, m_vecPosition2); - } - Vector vecTemp = m_vecPosition2; - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = vecTemp; - } -} - -void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_ON) value = 1; - else if(useType == USE_OFF) value = 0; - else if(useType == USE_SET); - else if(useType == USE_SHOWINFO)//show info - { - Msg("======/Xash Debug System/======\n"); - Msg("classname: %s\n", STRING(pev->classname)); - Msg("State: %s, Lip %.2f\n", GetStringForState( GetState()), m_flLip ); - SHIFT; - } - else return; - - if ( value > 1.0 )value = 1.0; - - if (IsLockedByMaster()) return; - Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); - - float speed = 0; - Vector delta; - - if (pev->speed) speed = pev->speed; - else - { - // default: get there in 0.1 secs - delta = move - pev->origin; - speed = delta.Length() * 10; - } - - //FIXME: allow for it being told to move at the same speed in the _opposite_ direction! - if ( speed != 0 ) - { - // This entity only thinks when it moves - if ( m_iState == STATE_OFF ) - { - //ALERT(at_console,"USE: start moving to %f %f %f.\n", move.x, move.y, move.z); - m_iState = STATE_ON; - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - } - - LinearMove( move, speed ); - SetMoveDone( MomentaryMoveDone ); - } -} - -void CMomentaryDoor::MomentaryMoveDone( void ) -{ - m_iState = STATE_OFF; - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise2), m_flVolume, ATTN_NORM); -} -LINK_ENTITY_TO_CLASS( func_momentary_door, CMomentaryDoor ); - -//======================================================================= -// func_platform (a lift\elevator) -//======================================================================= -void CBasePlatform::Precache( void ) -{ - CBaseBrush::Precache();//precache damage sound - - int m_sounds = UTIL_LoadSoundPreset(m_iMoveSound); - switch (m_sounds)//load movesound sounds (sound will play when door is moving) - { - case 1: pev->noise = UTIL_PrecacheSound ("plats/bigmove1.wav");break; - case 2: pev->noise = UTIL_PrecacheSound ("plats/bigmove2.wav");break; - case 3: pev->noise = UTIL_PrecacheSound ("plats/elevmove1.wav");break; - case 4: pev->noise = UTIL_PrecacheSound ("plats/elevmove2.wav");break; - case 5: pev->noise = UTIL_PrecacheSound ("plats/elevmove3.wav");break; - case 6: pev->noise = UTIL_PrecacheSound ("plats/freightmove1.wav");break; - case 7: pev->noise = UTIL_PrecacheSound ("plats/freightmove2.wav");break; - case 8: pev->noise = UTIL_PrecacheSound ("plats/heavymove1.wav");break; - case 9: pev->noise = UTIL_PrecacheSound ("plats/rackmove1.wav");break; - case 10: pev->noise = UTIL_PrecacheSound ("plats/railmove1.wav");break; - case 11: pev->noise = UTIL_PrecacheSound ("plats/squeekmove1.wav");break; - case 12: pev->noise = UTIL_PrecacheSound ("plats/talkmove1.wav");break; - case 13: pev->noise = UTIL_PrecacheSound ("plats/talkmove2.wav");break; - case 0: pev->noise = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - switch (m_sounds)//load pushed sounds (sound will play at activate or pushed button) - { - case 1: pev->noise1 = UTIL_PrecacheSound ("plats/bigstop1.wav");break; - case 2: pev->noise1 = UTIL_PrecacheSound ("plats/bigstop2.wav");break; - case 3: pev->noise1 = UTIL_PrecacheSound ("plats/freightstop1.wav");break; - case 4: pev->noise1 = UTIL_PrecacheSound ("plats/heavystop2.wav");break; - case 5: pev->noise1 = UTIL_PrecacheSound ("plats/rackstop1.wav");break; - case 6: pev->noise1 = UTIL_PrecacheSound ("plats/railstop1.wav");break; - case 7: pev->noise1 = UTIL_PrecacheSound ("plats/squeekstop1.wav");break; - case 8: pev->noise1 = UTIL_PrecacheSound ("plats/talkstop1.wav");break; - case 0: pev->noise1 = UTIL_PrecacheSound ("common/null.wav"); break; - default: pev->noise1 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - UTIL_PrecacheSound( "buttons/button11.wav" );//error sound -} - -void CBasePlatform :: Setup( void ) -{ - Precache(); //precache moving & stop sounds - - pev->angles = g_vecZero; - - pev->solid = SOLID_BSP; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(this, pev->origin); - UTIL_SetSize(pev, pev->mins, pev->maxs); - UTIL_SetModel(ENT(pev), pev->model ); - // vecPosition1 is the top position, vecPosition2 is the bottom - if (m_pParent) m_vecPosition1 = pev->origin - m_pParent->pev->origin; - else m_vecPosition1 = pev->origin; - m_vecPosition2 = m_vecPosition1; - - if(IsMovingPlatform() || IsComplexPlatform()) - { - m_vecPosition2.z = m_vecPosition2.z + step(); - //m_vecPosition2.z = pev->origin.z - m_flHeight; - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "moving platform start/end positions are equal\n"); - } - if(IsRotatingPlatform() || IsComplexPlatform()) - { - if ( m_flMoveDistance < 0 ) pev->movedir = pev->movedir * -1; - - AxisDir(); - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating platform start/end positions are equal\n"); - SetBits (pFlags, PF_ANGULAR); - } - CBaseBrush::Spawn(); - - if (pev->speed == 0) pev->speed = 150; - m_iState = STATE_OFF; - -} - -void CBasePlatform :: PostSpawn( void ) -{ - if ( FBitSet( pev->spawnflags, SF_START_ON ) ) - { - if (m_pParent) UTIL_AssignOrigin (this, m_vecPosition2 + m_pParent->pev->origin); - else UTIL_AssignOrigin (this, m_vecPosition2); - UTIL_AssignAngles(this, m_vecAngle2); - m_iState = STATE_ON; - } - else - { - if (m_pParent) UTIL_AssignOrigin (this, m_vecPosition1 + m_pParent->pev->origin); - else UTIL_AssignOrigin (this, m_vecPosition1); - UTIL_AssignAngles(this, m_vecAngle1); - m_iState = STATE_OFF; - } -} - -void CBasePlatform :: Spawn( void ) -{ - Setup(); -} - -void CBasePlatform :: PostActivate( void ) -{ - if(m_iState == STATE_TURN_OFF || m_iState == STATE_TURN_ON)//platform "in-moving" ? restore sound! - { - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - } -} - -void CBasePlatform :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) GoUp(); - else if ( useType == USE_OFF ) GoDown(); - else if ( useType == USE_SET ) GoToFloor( value ); - else if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - Msg( "State: %s, floor %g\n", GetStringForState( GetState()), CalcFloor()); - Msg( "distance %g, speed %g\n", m_flMoveDistance, pev->speed); - } -} - -void CBasePlatform :: GoToFloor( float floor ) -{ - float curfloor = CalcFloor(); - m_flValue = floor; - - if(curfloor <= 0) return; - if(curfloor == floor) return; //already there? - - m_vecFloor = m_vecPosition1; - m_vecFloor.z = pev->origin.z + (floor * step()) - (curfloor * step()); - - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - - if(floor > curfloor)m_iState = STATE_TURN_ON; - else m_iState = STATE_TURN_OFF; - - SetMoveDone( HitFloor ); - - if(fabs(floor - curfloor) > 1.0) //create floor informator for prop_counter - { - CBaseEntity *pFloor = CBaseEntity::Create( "floorent", pev->origin, g_vecZero, edict() ); - pFloor->pev->target = pev->netname; - pFloor->PostActivate(); - } - LinearMove(m_vecFloor, pev->speed); -} - -void CBasePlatform :: HitFloor( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noise1), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF); - UTIL_FireTargets( pev->target, m_hActivator, this, USE_TOGGLE, m_flValue ); - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_SET, m_flValue ); - m_vecPosition2 = pev->origin; //save current floor - if(m_iState == STATE_TURN_ON) m_iState = STATE_ON; - if(m_iState == STATE_TURN_OFF) m_iState = STATE_OFF; -} - -void CBasePlatform :: GoDown( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_ON || m_iState == STATE_TURN_ON); - m_iState = STATE_TURN_OFF; - SetMoveDone( HitBottom ); - - if(IsRotatingPlatform()) AngularMove( m_vecAngle1, pev->speed ); - else if(IsMovingPlatform()) LinearMove( m_vecPosition1, pev->speed ); - else if(IsComplexPlatform())ComplexMove( m_vecPosition1, m_vecAngle1, pev->speed ); - else HitBottom();//don't brake platform status -} - -void CBasePlatform :: HitBottom( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noise1), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_TURN_OFF); - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_SET, 1 ); - m_iState = STATE_OFF; -} - -void CBasePlatform :: GoUp( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_OFF || m_iState == STATE_TURN_OFF); - m_iState = STATE_TURN_ON; - SetMoveDone( HitTop ); - - if(IsRotatingPlatform()) AngularMove( m_vecAngle2, pev->speed ); - else if(IsMovingPlatform()) LinearMove( m_vecPosition2, pev->speed ); - else if(IsComplexPlatform())ComplexMove( m_vecPosition2, m_vecAngle2, pev->speed ); - else HitTop();//don't brake platform status -} - -void CBasePlatform :: HitTop( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noise1), m_flVolume, ATTN_NORM); - - ASSERT(m_iState == STATE_TURN_ON); - UTIL_FireTargets( pev->netname, m_hActivator, this, USE_SET, 2 ); - m_iState = STATE_ON; -} - -void CBasePlatform :: Blocked( CBaseEntity *pOther ) -{ - UTIL_AssignOrigin(this, pev->origin); - //make delay before retouching - if ( gpGlobals->time < m_flBlockedTime) return; - m_flBlockedTime = gpGlobals->time + 0.5; - - if(m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE) m_pParent->Blocked( pOther); - pOther->TakeDamage( pev, pev, 1, DMG_CRUSH ); - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - ASSERT(m_iState == STATE_TURN_ON || m_iState == STATE_TURN_OFF); - - if (m_iState == STATE_TURN_ON) GoDown(); - else if (m_iState == STATE_TURN_OFF) GoUp(); - SetNextThink( 0 ); -} -LINK_ENTITY_TO_CLASS( func_platform, CBasePlatform ); -LINK_ENTITY_TO_CLASS( func_platrot, CBasePlatform ); - - -//======================================================================= -// func_train (Classic QUAKE Train) -//======================================================================= -TYPEDESCRIPTION CFuncTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrain, pCurPath, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTrain, pNextPath, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatform ); - -void CFuncTrain :: Spawn( void ) -{ - Precache(); //precache moving & stop sounds - CBaseBrush::Spawn(); - - if(pev->spawnflags & SF_DOOR_PASSABLE || IsWater())//make illusionary train - pev->solid = SOLID_NOT; - else pev->solid = SOLID_BSP; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(this, pev->origin); - UTIL_SetSize(pev, pev->mins, pev->maxs); - UTIL_SetModel(ENT(pev), pev->model ); - - //determine method for calculating origin - if(pev->origin != g_vecZero) pev->impulse = 1; - - if (pev->speed == 0) pev->speed = 100; - m_iState = STATE_OFF; -} - -void CFuncTrain :: PostSpawn( void ) -{ - if (!FindPath()) return; - - if (pev->impulse) - { - m_vecSpawnOffset = m_vecSpawnOffset + pCurPath->pev->origin - pev->origin; - if (m_pParent) UTIL_AssignOrigin (this, pCurPath->pev->origin - m_pParent->pev->origin ); - else UTIL_AssignOrigin (this, pCurPath->pev->origin ); - } - else - { - m_vecSpawnOffset = m_vecSpawnOffset + (pCurPath->pev->origin - TrainOrg()) - pev->origin; - if (m_pParent) UTIL_AssignOrigin (this, pCurPath->pev->origin - TrainOrg() - m_pParent->pev->origin ); - else UTIL_AssignOrigin (this, pCurPath->pev->origin - TrainOrg()); - } - pev->target = pCurPath->pev->target; -} - -void CFuncTrain :: PostActivate( void ) -{ - if(m_iState == STATE_ON)//platform "in-moving" ? restore sound! - { - EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - } - if ( pev->spawnflags & SF_START_ON ) - { - m_iState = STATE_OFF; //restore sound on a next level - SetThink( Next ); //evil stuff... - SetNextThink( 0.1 ); - ClearBits( pev->spawnflags, SF_START_ON );//fire once - } -} - -void CFuncTrain::ClearPointers( void ) -{ - CBaseEntity::ClearPointers(); - pCurPath = NULL; - pNextPath = NULL; -} - -void CFuncTrain::OverrideReset( void ) -{ - // Are we moving? - if ( m_iState == STATE_ON ) - { - pev->target = pev->message; - Msg("Override target %s\n", STRING( pev->target )); - if (FindPath()) SetBits( pev->spawnflags, SF_START_ON );//PostActivate member - else Stop(); - } -} - -CBaseEntity *CFuncTrain::FindPath( void ) -{ - //find start track - Msg("Find corner %s\n", STRING( pev->target )); - pCurPath = UTIL_FindEntityByTargetname (NULL, STRING(pev->target)); - if(pCurPath && pCurPath->edict()) - { - return pCurPath; - } - return NULL; -} - -CBaseEntity *CFuncTrain::FindNextPath( void ) -{ - //safe way to check patch - if(!pCurPath) return FALSE; - - // get pointer to next target - if(pev->speed > 0)pNextPath = ((CPathCorner *)pCurPath)->GetNext(); - if(pev->speed < 0)pNextPath = ((CPathCorner *)pCurPath)->GetPrev(); - - if(pNextPath && pNextPath->edict()) //validate path - { - //record new value (this will be used after changelevel) - //pev->target = pNextPath->pev->targetname; - - //pCurPath = pNextPath; - Msg("CFuncTrain::FindNextPath: pCurPath %s pNextPath %s\n", STRING( pCurPath->pev->targetname ), STRING( pNextPath->pev->targetname )); - return pNextPath; //path found - } - - Stop();//stopping platform - return NULL; -} - -void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) Next(); - else if ( useType == USE_OFF ) Stop(); - else if (useType == USE_SET) Reverse();//reverse train - else if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - ALERT(at_console, "State: %s, speed %g\n", GetStringForState( GetState()), pev->speed ); - if(GetPrev() && GetPrev()->edict()) Msg("Prev path %s", STRING(GetPrev()->pev->targetname) ); - if(GetNext() && GetNext()->edict()) Msg("Next path %s", STRING(GetNext()->pev->targetname) ); - SHIFT; - } -} - -void CFuncTrain :: Next( void ) -{ - CBaseEntity *pTarg = FindPath(); - - if(!pTarg) return; - - //linear move to next corner. - if(m_iState == STATE_OFF)//enable train sound - { - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise) ); - EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM); - } - - ClearBits(pev->effects, EF_NOINTERP); //enable interpolation - m_iState = STATE_ON; - //pev->message = ((CPathCorner *)pCurPath)->GetNext()->pev->targetname; - pev->message = pev->target; - pev->target = pTarg->pev->target; - - /*if( pev->speed < 0 && FBitSet(pNextPath->pev->spawnflags, SF_CORNER_TELEPORT)) - { - SetBits(pev->effects, EF_NOINTERP); - if (m_pParent) UTIL_AssignOrigin(this, pNextPath->pev->origin - m_pParent->pev->origin ); - else UTIL_AssignOrigin(this, pNextPath->pev->origin ); - Wait(); // Get on with doing the next path corner. - return; - }*/ - - if (m_pParent) - { - if (pev->impulse) LinearMove( pTarg->pev->origin - m_pParent->pev->origin, fabs( pev->speed)); - else LinearMove (pTarg->pev->origin - TrainOrg() - m_pParent->pev->origin, fabs(pev->speed)); - } - else - { - if (pev->impulse) LinearMove( pTarg->pev->origin, fabs(pev->speed) ); - else LinearMove (pTarg->pev->origin - TrainOrg(), fabs(pev->speed) ); - } - pCurPath = pTarg; - SetMoveDone( Wait ); -} - -void CFuncTrain :: Wait( void ) -{ - UTIL_FireTargets(pev->netname, this, this, USE_TOGGLE ); - ((CPathCorner *)pCurPath)->UpdateTargets(); - ((CPathCorner *)pCurPath)->GetSpeed( &pev->speed ); - if(!Stop(((CPathCorner *)pCurPath)->GetDelay())) Next();// go to next corner -} - -BOOL CFuncTrain :: Teleport( void ) -{ - if( FBitSet(pNextPath->pev->spawnflags, SF_CORNER_TELEPORT)) - { - SetBits(pev->effects, EF_NOINTERP); - - //determine teleportation point - if(pev->speed > 0) - { - pNextPath = pNextPath->GetNext(); - ((CPathCorner *)pCurPath)->UpdateTargets(); - UTIL_FireTargets(pev->netname, this, this, USE_TOGGLE ); - } - if (m_pParent) UTIL_AssignOrigin(this, pNextPath->pev->origin - m_pParent->pev->origin ); - else UTIL_AssignOrigin(this, pNextPath->pev->origin ); - - pCurPath = pNextPath; - Next(); // Get on with doing the next path corner. - return TRUE; - } - return FALSE; -} - -BOOL CFuncTrain :: Stop( float flWait ) -{ - if( flWait == 0 ) return FALSE; - m_iState = STATE_OFF; - - // clear the sound channel. - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise) ); - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise1), m_flVolume, ATTN_NORM); - - UTIL_SetVelocity(this, g_vecZero); - UTIL_SetAvelocity(this, g_vecZero); - if( flWait > 0) - { - SetNextThink( flWait ); - SetThink( Next ); - } - - //wait for retrigger - if(flWait == -1) DontThink(); - return TRUE; -} - -void CFuncTrain::Reverse( void ) -{ - //update path if dir changed - if(pev->speed != 0 && pNextPath && pNextPath->edict()) pCurPath = pNextPath; - pev->speed = -pev->speed; - if(m_iState == STATE_ON) Next(); //reverse now! -} - -void CFuncTrain :: Blocked( CBaseEntity *pOther ) -{ - // Keep "movewith" entities in line - UTIL_AssignOrigin(this, pev->origin); - - if ( gpGlobals->time < m_flBlockedTime) return; - m_flBlockedTime = gpGlobals->time + 0.5; - - if(m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE) m_pParent->Blocked( pOther); - pOther->TakeDamage( pev, pev, 1, DMG_CRUSH ); - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - ASSERT(m_iState == STATE_ON); - - Stop( 0.5 ); -} -LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ); - -//======================================================================= -// func_tracktrain (controllable train) -//======================================================================= -void CFuncTrackTrain :: Precache( void ) -{ - CBaseBrush::Precache(); // precache damage sound - - int m_sounds = UTIL_LoadSoundPreset( m_iMoveSound ); - switch( m_sounds ) - { - case 1: pev->noise = UTIL_PrecacheSound( "plats/ttrain1.wav" ); break; - case 2: pev->noise = UTIL_PrecacheSound( "plats/ttrain2.wav" ); break; - case 3: pev->noise = UTIL_PrecacheSound( "plats/ttrain3.wav" ); break; - case 4: pev->noise = UTIL_PrecacheSound( "plats/ttrain4.wav" ); break; - case 5: pev->noise = UTIL_PrecacheSound( "plats/ttrain6.wav" ); break; - case 6: pev->noise = UTIL_PrecacheSound( "plats/ttrain7.wav" ); break; - default: pev->noise = UTIL_PrecacheSound( m_sounds ); break; // custom sound or sentence - } - - // always constant - pev->noise1 = UTIL_PrecacheSound( "plats/ttrain_brake1.wav" ); - pev->noise2 = UTIL_PrecacheSound( "plats/ttrain_start1.wav" ); -} - -void CFuncTrackTrain :: Spawn( void ) -{ - if ( pev->speed == 0 ) m_speed = 100; - else m_speed = pev->speed; - pev->speed = 0; - pev->velocity = g_vecZero; - m_vecBaseAvel = pev->avelocity; //LRC - save it for later - pev->avelocity = g_vecZero; - pev->impulse = m_speed; - m_dir = 1; - - if ( FStringNull(pev->target) ) Msg("Warning: %s with no target!\n", STRING(pev->classname)); - - //if ( pev->spawnflags & SF_NOTSOLID ) pev->solid = SOLID_NOT; - if ( pev->spawnflags & 8 ) pev->solid = SOLID_NOT; //temp solution - else pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - SetBits (pFlags, PF_ANGULAR); - UTIL_SetModel( ENT(pev), pev->model ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( this, pev->origin ); - pev->oldorigin = pev->origin; // Cache off placed origin for train controls - - m_controlMins = pev->mins; - m_controlMaxs = pev->maxs; - m_controlMaxs.z += 72; - - NextThink( 0.1, FALSE ); - SetThink( Find ); - Precache(); -} - -void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) -{ - if ( alwaysThink ) pev->flags |= FL_ALWAYSTHINK; - else pev->flags &= ~FL_ALWAYSTHINK; - SetNextThink( thinkTime, TRUE ); -} - -void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) -{ - // Blocker is on-ground on the train - if ( FBitSet( pOther->pev->flags, FL_ONGROUND ) && VARS(pOther->pev->groundentity) == pev ) - { - float deltaSpeed = fabs(pev->speed); - if ( deltaSpeed > 50 ) deltaSpeed = 50; - if ( !pOther->pev->velocity.z ) pOther->pev->velocity.z += deltaSpeed; - return; - } - else pOther->pev->velocity = (pOther->pev->origin - pev->origin ).Normalize() * pev->dmg; - if ( pev->dmg <= 0 ) return;// we can't hurt this thing, so we're not concerned with it - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); -} - -void CFuncTrackTrain::OverrideReset( void ) -{ - NextThink( 0.1, FALSE ); - SetThink( NearestPath ); -} - -void CFuncTrackTrain :: Find( void ) -{ - pPath = (CPathTrack*)UTIL_FindEntityByTargetname( NULL, STRING(pev->target) ); - if ( !pPath ) return; - - entvars_t *pevTarget = pPath->pev; - if ( !FClassnameIs( pevTarget, "path_track" ) ) - { - ALERT( at_error, "func_track_train must be on a path of path_track\n" ); - pPath = NULL; - return; - } - - Vector nextPos = pevTarget->origin; - nextPos.z += m_height; - - Vector look = nextPos; - look.z -= m_height; - ((CPathTrack *)pPath)->LookAhead( &look, m_length, 0 ); - look.z += m_height; - - Vector vTemp = UTIL_VecToAngles( look - nextPos ); - vTemp.y += 180; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) - { - vTemp.x = 0; - //pev->angles.x = 0; - } - - UTIL_AssignAngles(this, vTemp); - UTIL_AssignOrigin ( this, nextPos ); - - NextThink( 0.1, FALSE ); - SetThink( PostponeNext ); - pev->speed = m_startSpeed; - - UpdateSound(); -} - -TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrackTrain, pPath, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTrackTrain, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_speed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_dir, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_startSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMins, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMaxs, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_flBank, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_oldSpeed, FIELD_FLOAT ), -}; -IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseMover ); - - -void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wheels")) - { - m_length = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_height = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "startspeed")) - { - m_startSpeed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_iMoveSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bank")) - { - m_flBank = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseMover::KeyValue( pkvd ); -} - - - - - -void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ -// ALERT( at_console, "TRAIN: use\n" ); - - m_hActivator = pActivator; //AJH - - if (useType == USE_TOGGLE) - { - if(pev->speed != 0) useType = USE_OFF;//temp solution - else useType = USE_ON; - } - if (useType == USE_ON) - { - pev->speed = m_speed * m_dir; - PostponeNext(); - } - else if ( useType == USE_OFF ) - { - pev->speed = 0; - UTIL_SetVelocity(this, g_vecZero); //LRC - UTIL_SetAvelocity(this, g_vecZero); //LRC - StopSound(); - SetThink( NULL ); - } - else if ( useType == USE_SET ) - { - float delta = value; - - delta = ((int)(pev->speed * 4) / (int)m_speed)*0.25 + 0.25 * delta; - if ( delta > 1 ) - delta = 1; - else if ( delta < -1 ) - delta = -1; - if ( pev->spawnflags & SF_TRACKTRAIN_FORWARDONLY ) - { - if ( delta < 0 )delta = 0; - } - pev->speed = m_speed * delta; - - if(pev->speed == 0) - { - UTIL_SetVelocity(this, g_vecZero); - UTIL_SetAvelocity(this, g_vecZero); - StopSound(); - SetThink( NULL ); - } - if(pPath == NULL) - { - delta = 0; //G-Cont. Set speed to 0, and don't controls, if tracktrain on trackchange - return; - } - PostponeNext(); - ALERT( at_aiconsole, "TRAIN(%s), speed to %.2f\n", STRING(pev->targetname), pev->speed ); - } -} - -#define TRAIN_STARTPITCH 60 -#define TRAIN_MAXPITCH 200 -#define TRAIN_MAXSPEED 1000 // approx max speed for sound pitch calculation - -void CFuncTrackTrain :: StopSound( void ) -{ - // if sound playing, stop it - if( m_soundPlaying && pev->noise ) - { - STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise )); - EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100 ); - } - m_soundPlaying = 0; -} - -void CFuncTrackTrain :: UpdateSound( void ) -{ - float flpitch; - - if( !pev->noise ) return; - - flpitch = TRAIN_STARTPITCH + (abs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); - - if( !m_soundPlaying ) - { - // play startup sound for train - EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100 ); - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM, 0, (int)flpitch ); - m_soundPlaying = 1; - } - else - { - // update pitch - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int)flpitch ); - } -} - -void CFuncTrackTrain::ClearPointers( void ) -{ - CBaseEntity::ClearPointers(); - pPath = NULL; -} - -void CFuncTrackTrain :: PostActivate( void ) -{ -} - -void CFuncTrackTrain :: PostponeNext( void ) -{ - DesiredAction();//temp fix - //UTIL_SetAction( this ); -} - -void CFuncTrackTrain :: DesiredAction( void ) // Next( void ) -{ - float time = 0.5; - - if ( !pev->speed ) - { - UTIL_SetVelocity(this, g_vecZero); - DontThink(); - ALERT( at_aiconsole, "TRAIN(%s): Speed is 0\n", STRING(pev->targetname) ); - StopSound(); - return; - } - - if ( !pPath ) - { - UTIL_SetVelocity(this, g_vecZero); - DontThink(); - ALERT( at_aiconsole, "TRAIN(%s): Lost path\n", STRING(pev->targetname) ); - StopSound(); - return; - } - - UpdateSound(); - - Vector nextPos = pev->origin; - - nextPos.z -= m_height; - CBaseEntity *pnext = ((CPathTrack *)pPath)->LookAhead( &nextPos, pev->speed * 0.1, 1 ); - nextPos.z += m_height; - - UTIL_SetVelocity( this, (nextPos - pev->origin) * 10 ); //LRC - Vector nextFront = pev->origin; - - nextFront.z -= m_height; - if ( m_length > 0 ) - ((CPathTrack *)pPath)->LookAhead( &nextFront, m_length, 0 ); - else - ((CPathTrack *)pPath)->LookAhead( &nextFront, 100, 0 ); - nextFront.z += m_height; - - Vector delta = nextFront - pev->origin; - - Vector angles = UTIL_VecToAngles( delta ); - // The train actually points west - angles.y += 180; //LRC, FIXME: add a 'built facing' field. - - angles.fixangle(); - pev->angles.fixangle(); - - if ( !pnext || (delta.x == 0 && delta.y == 0) ) angles = pev->angles; - - float vy, vx, vz; - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOPITCH) ) vx = 10*UTIL_AngleDistance( angles.x, pev->angles.x ); - else vx = m_vecBaseAvel.x; - - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOYAW) ) vy = 10*UTIL_AngleDistance( angles.y, pev->angles.y ); - else vy = m_vecBaseAvel.y; - - if ( m_flBank != 0 ) - { - if ( pev->avelocity.y < -5 ) vz = UTIL_AngleDistance( UTIL_ApproachAngle( -m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else if ( pev->avelocity.y > 5 ) vz = UTIL_AngleDistance( UTIL_ApproachAngle( m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else vz = UTIL_AngleDistance( UTIL_ApproachAngle( 0, pev->angles.z, m_flBank*4 ), pev->angles.z) * 4; - } - else vz = m_vecBaseAvel.z; - UTIL_SetAvelocity(this, Vector(vx, vy, vz)); - - if ( pnext ) - { - if ( pnext != pPath ) - { - CBaseEntity *pFire; - if ( pev->speed >= 0 ) // check whether we're going forwards or backwards - pFire = pnext; - else - pFire = pPath; - - pPath = pnext; - // Fire the pass target if there is one - if ( pFire->pev->message ) - { - UTIL_FireTargets( pFire->pev->message, this, this, USE_TOGGLE ); - if ( FBitSet( pFire->pev->spawnflags, SF_PATH_FIREONCE ) ) - pFire->pev->message = 0; - } - - if ( pFire->pev->spawnflags & SF_PATH_DISABLE_TRAIN ) - pev->spawnflags |= SF_TRACKTRAIN_NOCONTROL; - - float setting = ((int)(pev->speed*4) / (int)m_speed) / 4.0; //LRC - one of { 1, 0.75, 0.5, 0.25, 0, ... -1 } - - CBaseEntity* pDest; //LRC - the path_track we're heading for, after pFire. - if (pev->speed > 0) - pDest = pFire->GetNext(); - else - pDest = pFire->GetPrev(); - - if ( pFire->pev->speed != 0) - { - //ALERT( at_console, "TrackTrain setting is %d / %d = %.2f\n", (int)(pev->speed*4), (int)m_speed, setting ); - - switch ( (int)(pFire->pev->armortype) ) - { - case PATHSPEED_SET: - // Don't override speed if under user control - if (pev->spawnflags & SF_TRACKTRAIN_NOCONTROL) - pev->speed = pFire->pev->speed; - ALERT( at_aiconsole, "TrackTrain %s speed set to %4.2f\n", STRING(pev->targetname), pev->speed ); - break; - case PATHSPEED_SET_MASTER: - m_speed = pFire->pev->speed; - pev->impulse = m_speed; - pev->speed = setting * m_speed; - ALERT( at_aiconsole, "TrackTrain %s master speed set to %4.2f\n", STRING(pev->targetname), pev->speed ); - break; - case PATHSPEED_ACCEL: - m_speed += pFire->pev->speed; - pev->impulse = m_speed; - pev->speed = setting * m_speed; - ALERT( at_aiconsole, "TrackTrain %s speed accel to %4.2f\n", STRING(pev->targetname), pev->speed ); - break; - case PATHSPEED_TIME: - float distance = (pev->origin - pDest->pev->origin).Length(); - // ALERT( at_console, "pFire=%s, distance=%.2f, ospeed=%.2f, nspeed=%.2f\n", STRING(pFire->pev->targetname), distance, pev->speed, distance / pFire->pev->speed); - m_speed = distance / pFire->pev->speed; - pev->impulse = m_speed; - pev->speed = setting * m_speed; - ALERT( at_aiconsole, "TrackTrain %s speed to %4.2f (timed)\n", STRING(pev->targetname), pev->speed ); - break; - } - } - //LRC- FIXME: add support, here, for a Teleport flag. - } - SetThink( PostponeNext ); - NextThink( time, TRUE ); - } - else // end of path, stop - { - Vector vecTemp; //LRC - StopSound(); - vecTemp = (nextPos - pev->origin); //LRC - - UTIL_SetAvelocity(this, g_vecZero); - float distance = vecTemp.Length(); //LRC - m_oldSpeed = pev->speed; - - - pev->speed = 0; - - // Move to the dead end - - // Are we there yet? - if ( distance > 0 ) - { - // no, how long to get there? - time = distance / m_oldSpeed; - UTIL_SetVelocity( this, vecTemp * (m_oldSpeed / distance) ); - SetThink( DeadEnd ); - NextThink( time, FALSE ); - } - else - { - UTIL_SetVelocity( this, vecTemp ); - DeadEnd(); - } - } -} - - -void CFuncTrackTrain::DeadEnd( void ) -{ - // Fire the dead-end target if there is one - CBaseEntity *pTrack, *pNext; - - pTrack = pPath; - - ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING(pev->targetname) ); - // Find the dead end path node - // HACKHACK -- This is bugly, but the train can actually stop moving at a different node depending on it's speed - // so we have to traverse the list to it's end. - if ( pTrack ) - { - if ( m_oldSpeed < 0 ) - { - do - { - pNext = ((CPathTrack *)pTrack)->ValidPath( pTrack->GetPrev(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - else - { - do - { - pNext = ((CPathTrack *)pTrack)->ValidPath( pTrack->GetNext(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - } - - UTIL_SetVelocity( this, g_vecZero ); - UTIL_SetAvelocity(this, g_vecZero ); - - if ( pTrack ) - { - ALERT( at_aiconsole, "at %s\n", STRING(pTrack->pev->targetname) ); - if ( pTrack->pev->netname ) - UTIL_FireTargets( pTrack->pev->netname, this, this, USE_TOGGLE ); - } -} - - -void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) -{ - Vector offset = pevControls->origin - pev->oldorigin; - - m_controlMins = pevControls->mins + offset; - m_controlMaxs = pevControls->maxs + offset; -} - - -BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) -{ - Vector offset = pevTest->origin - pev->origin; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - return FALSE; - - // Transform offset into local coordinates - UTIL_MakeVectors( pev->angles ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = -DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - if ( local.x >= m_controlMins.x && local.y >= m_controlMins.y && local.z >= m_controlMins.z && - local.x <= m_controlMaxs.x && local.y <= m_controlMaxs.y && local.z <= m_controlMaxs.z ) - return TRUE; - - return FALSE; -} - -void CFuncTrackTrain :: NearestPath( void ) -{ - CBaseEntity *pTrack = NULL; - CBaseEntity *pNearest = NULL; - float dist, closest; - - closest = 1024; - - while ((pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL) - { - // filter out non-tracks - if ( !(pTrack->pev->flags & (FL_CLIENT|FL_MONSTER)) && FClassnameIs( pTrack->pev, "path_track" ) ) - { - dist = (pev->origin - pTrack->pev->origin).Length(); - if ( dist < closest ) - { - closest = dist; - pNearest = pTrack; - } - } - } - - if( !pNearest ) - { - ALERT( at_console, "Can't find a nearby track !!!\n" ); - SetThink( NULL ); - return; - } - - ALERT( at_aiconsole, "TRAIN: %s, Nearest track is %s\n", STRING(pev->targetname), STRING(pNearest->pev->targetname) ); - // If I'm closer to the next path_track on this path, then it's my real path - pTrack = ((CPathTrack *)pNearest)->GetNext(); - if ( pTrack ) - { - if ( (pev->origin - pTrack->pev->origin).Length() < (pev->origin - pNearest->pev->origin).Length() ) - pNearest = pTrack; - } - - pPath = (CPathTrack *)pNearest; - - if ( pev->speed != 0 ) - { - NextThink( 0.1, FALSE ); - SetThink( PostponeNext ); - } -} -LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ); \ No newline at end of file diff --git a/server/ents/basemover.h b/server/ents/basemover.h deleted file mode 100644 index d58b5460..00000000 --- a/server/ents/basemover.h +++ /dev/null @@ -1,158 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= -#ifndef BASEMOVER_H -#define BASEMOVER_H - -class CBaseMover : public CBaseBrush -{ -public: - void KeyValue( KeyValueData *pkvd ); - virtual void AxisDir( void ); - void (CBaseMover::*m_pfnCallWhenMoveDone)(void); // custom movedone function - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int IsWater( void ){ return pev->skin != 0; }; - static TYPEDESCRIPTION m_SaveData[]; - float m_flMoveDistance; // rotating distance - float m_flBlockedTime; // set blocked refresh time - int m_iMode; // style of working - float m_flValue; // value to send - float m_flHeight; - float m_flWait; - float m_flLip; - - Vector m_vecPosition1; // startpos - Vector m_vecPosition2; // endpos - Vector m_vecAngle1; // startangle - Vector m_vecAngle2; // endangle - Vector m_vecFinalDest; // basemover finalpos - Vector m_vecFinalAngle; // basemover finalangle - Vector m_vecFloor; // basemover dest floor - float m_flLinearMoveSpeed; // member linear speed - float m_flAngularMoveSpeed; // member angular speed - - // common member functions - void LinearMove ( Vector vecInput, float flSpeed ); - void AngularMove( Vector vecDestAngle, float flSpeed ); - void ComplexMove( Vector vecInput, Vector vecDestAngle, float flSpeed ); - void EXPORT LinearMoveNow( void ); - void EXPORT AngularMoveNow( void ); - void EXPORT ComplexMoveNow( void ); - void EXPORT LinearMoveDone( void ); - void EXPORT AngularMoveDone( void ); - void EXPORT ComplexMoveDone( void ); - void EXPORT LinearMoveDoneNow( void ); - void EXPORT AngularMoveDoneNow( void ); - void EXPORT ComplexMoveDoneNow( void ); -}; - -class CBaseDoor : public CBaseMover -{ -public: - void Spawn( void ); - void Precache( void ); - virtual void PostSpawn( void ); - void EXPORT DoorUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ShowInfo( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT DoorTouch( CBaseEntity *pOther ); - virtual void Blocked( CBaseEntity *pOther ); - virtual void SetToggleState( int state ); - virtual int ObjectCaps( void ) - { - if ( FStringNull( pev->targetname ) && m_iMode != 1 ) // door without name player can direct using - return (CBaseMover::ObjectCaps() & ~FCAP_ACROSS_TRANSITION | FCAP_IMPULSE_USE | FCAP_ONLYDIRECT_USE); - return (CBaseMover::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); - }; - - // local functions - void EXPORT DoorGoUp( void ); - void EXPORT DoorGoDown( void ); - void EXPORT DoorHitTop( void ); - void EXPORT DoorHitBottom( void ); - virtual BOOL IsRotatingDoor( void ){ return FALSE; }; -}; - -class CRotDoor : public CBaseDoor -{ -public: - void Spawn( void ); - virtual void PostSpawn( void ) {} - virtual void SetToggleState( int state ); - virtual BOOL IsRotatingDoor( void ){ return TRUE; }; -}; - -class CMomentaryDoor : public CBaseMover -{ -public: - void Spawn( void ); - void Precache( void ); - void PostSpawn( void ); - void EXPORT MomentaryMoveDone( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return CBaseMover :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - -class CBasePlatform : public CBaseMover -{ -public: - void Precache( void ); - void Spawn( void ); - void PostSpawn( void ); - void Setup( void ); - void PostActivate( void ); - - virtual void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - float CalcFloor( void ) - { - float curfloor = ((pev->origin.z - m_vecPosition1.z) / step()) + 1; - if (curfloor - floor(curfloor) > 0.5) return ceil(curfloor); - else return floor(curfloor); - } - float step( void ) { return pev->size.z + m_flHeight - 2; } - float ftime( void ) { return step() / pev->speed; } //time to moving between floors - - void EXPORT GoUp( void ); - void EXPORT GoDown( void ); - void GoToFloor( float floor ); - void EXPORT HitTop( void ); - void EXPORT HitBottom( void ); - void EXPORT HitFloor( void ); - virtual BOOL IsMovingPlatform( void ) { return m_flHeight != 0 && m_flMoveDistance == 0; } - virtual BOOL IsRotatingPlatform( void ){ return m_flHeight == 0 && m_flMoveDistance != 0; } - virtual BOOL IsComplexPlatform( void ) { return m_flHeight != 0 && m_flMoveDistance != 0; } -}; - -class CFuncTrain : public CBasePlatform -{ -public: - void Spawn( void ); - void PostSpawn( void ); - void OverrideReset( void ); - void PostActivate( void ); - void ClearPointers( void ); - - BOOL Stop( float flWait = -1 ); - BOOL Teleport( void ); - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - Vector TrainOrg( void ) { return (pev->mins + pev->maxs) * 0.5; } - - void EXPORT Wait( void ); - void EXPORT Next( void ); - - //path operations - BOOL FindPath( void ); - BOOL FindNextPath( void ); - void UpdateTargets( void ); - void UpdateSpeed( float value = 0 ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CBaseEntity *pPath, *pNextPath; -}; -#endif //BASEMOVER_H \ No newline at end of file diff --git a/server/ents/baseother.cpp b/server/ents/baseother.cpp deleted file mode 100644 index 973bf27c..00000000 --- a/server/ents/baseother.cpp +++ /dev/null @@ -1,286 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2007 -// misc temporary entities -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "player.h" -#include "client.h" - -//======================================================================= -// sparkleent - explode post sparks -//======================================================================= -class CEnvShower : public CBaseEntity -{ - void Spawn( void ); - void Think( void ); - void Touch( CBaseEntity *pOther ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; -LINK_ENTITY_TO_CLASS( sparkleent, CEnvShower ); - -void CEnvShower::Spawn( void ) -{ - pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles; - pev->velocity.x += RANDOM_FLOAT( -100.0f, 100.0f ); - pev->velocity.y += RANDOM_FLOAT( -100.0f, 100.0f ); - if ( pev->velocity.z >= 0 ) pev->velocity.z += 200; - else pev->velocity.z -= 200; - pev->movetype = MOVETYPE_BOUNCE; - pev->gravity = 0.5; - SetNextThink( 0.1 ); - pev->solid = SOLID_NOT; - UTIL_SetModel( edict(), "models/common/null.mdl"); - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->speed = RANDOM_FLOAT( 0.5f, 1.5f ); - pev->angles = g_vecZero; -} - -void CEnvShower::Think( void ) -{ - UTIL_Sparks( pev->origin ); - - pev->speed -= 0.1; - if ( pev->speed > 0 ) - SetNextThink( 0.1 ); - else UTIL_Remove( this ); - pev->flags &= ~FL_ONGROUND; -} - -void CEnvShower::Touch( CBaseEntity *pOther ) -{ - if( pev->flags & FL_ONGROUND ) - pev->velocity = pev->velocity * 0.1f; - else pev->velocity = pev->velocity * 0.6f; - - if(( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y ) < 10.0f ) - pev->speed = 0; -} - -//==================================================================== -// ChangeLevelFire -//==================================================================== -class ChangeLevelFire : public CBaseLogic -{ -public: - void PostActivate( void ) { UTIL_FireTargets( pev->target, this, this, USE_TOGGLE ); UTIL_Remove( this ); } - int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() | FCAP_FORCE_TRANSITION; } -}; -LINK_ENTITY_TO_CLASS( fireent, ChangeLevelFire ); - -//======================================================================= -// faderent - rendering time effects -//======================================================================= -class CRenderFxFader : public CBaseLogic -{ -public: - void Spawn ( void ) { m_hTarget = CBaseEntity::Instance( pev->owner ); } - void Think ( void ) - { - if (((CBaseEntity*)m_hTarget) == NULL) - { - UTIL_Remove( this ); - return; - } - - float flDegree = (gpGlobals->time - pev->dmgtime)/pev->speed; - - if (flDegree >= 1) - { - m_hTarget->pev->renderamt = pev->renderamt + pev->health; - m_hTarget->pev->rendercolor = pev->rendercolor + pev->movedir; - m_hTarget->pev->scale = pev->scale + pev->frags; - m_hTarget->pev->framerate = pev->framerate + pev->max_health; - UTIL_FireTargets( pev->target, m_hTarget, this, USE_TOGGLE ); - m_hTarget = NULL; - - SetNextThink( 0.1 ); - SetThink(Remove); - } - else - { - m_hTarget->pev->renderamt = pev->renderamt + pev->health * flDegree; - m_hTarget->pev->rendercolor.x = pev->rendercolor.x + pev->movedir.x * flDegree; - m_hTarget->pev->rendercolor.y = pev->rendercolor.y + pev->movedir.y * flDegree; - m_hTarget->pev->rendercolor.z = pev->rendercolor.z + pev->movedir.z * flDegree; - m_hTarget->pev->scale = pev->scale + pev->frags * flDegree; - m_hTarget->pev->framerate = pev->framerate + pev->max_health * flDegree; - SetNextThink( 0.01 );//fader step - } - } -}; -LINK_ENTITY_TO_CLASS( faderent, CRenderFxFader ); - -//======================================================================= -// smokeent - temporary smoke -//======================================================================= -class CSmokeEnt : public CBaseAnimating -{ - void Spawn( void ); - void Think( void ); -}; -LINK_ENTITY_TO_CLASS( smokeent, CSmokeEnt ); - -void CSmokeEnt::Spawn( void ) -{ - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_NONE; - pev->armorvalue = gpGlobals->time; - - if( !pev->team ) pev->team = 50; - if( pev->team > 250 ) pev->team = 250; // normalize and remember about random value 0 - 5 -} - -void CSmokeEnt::Think( void ) -{ - if( pev->dmgtime ) - { - if( pev->dmgtime < gpGlobals->time ) - { - UTIL_Remove( this ); - return; - } - else if( RANDOM_FLOAT( 0, pev->dmgtime - pev->armorvalue ) > pev->dmgtime - gpGlobals->time ) - { - SetNextThink( 0.2 ); - return; - } - } - - Vector VecSrc = UTIL_RandomVector( pev->absmin, pev->absmax ); - - MESSAGE_BEGIN( MSG_PVS, gmsg.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, 5 ) + pev->impulse ); // scale * 10 - WRITE_BYTE( RANDOM_LONG( 0, 3 ) + 8 ); // framerate - MESSAGE_END(); - - StudioFrameAdvance( );//animate model if present - SetNextThink( 0.2 ); -} - -//========================================================= -// func_platform floor indicator -//========================================================= -class CFloorEnt:public CPointEntity -{ - void Think( void ); - void PostActivate( void ); - CBasePlatform *pElevator; // no need to save - PostActivate will be restore this -}; - -void CFloorEnt::PostActivate( void ) -{ - pElevator = (CBasePlatform*)CBasePlatform::Instance( pev->owner ); - SetNextThink( 0 ); -} - -void CFloorEnt::Think ( void ) -{ - if(pElevator && (pElevator->GetState() == STATE_TURN_ON || pElevator->GetState() == STATE_TURN_OFF) ) - { - UTIL_FireTargets( pev->target, pElevator, this, USE_SET, pElevator->CalcFloor()); - SetNextThink( 0.01 ); - } - else UTIL_Remove( this ); -} -LINK_ENTITY_TO_CLASS( floorent, CFloorEnt ); - - -//==================================================================== -// Laser pointer target -//==================================================================== -CLaserSpot *CLaserSpot::CreateSpot( entvars_t *pevOwner ) -{ - CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL ); - pSpot->Spawn(); - pSpot->pev->classname = MAKE_STRING( "misc_laserdot" ); - - if( pevOwner ) - { - // predictable laserspot (cl_lw must be set to 1) - pSpot->pev->flags |= FL_SKIPLOCALHOST; - pSpot->pev->owner = ENT( pevOwner ); - pevOwner->effects |= EF_LASERSPOT; - } - return pSpot; -} - -void CLaserSpot::Precache( void ) -{ - UTIL_PrecacheModel( "sprites/laserdot.spr" ); - UTIL_PrecacheSound( "weapons/spot_on.wav" ); - UTIL_PrecacheSound( "weapons/spot_off.wav" ); -} - -void CLaserSpot::Spawn( void ) -{ - Precache( ); - - // laser dot settings - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; - - pev->rendermode = kRenderGlow; - pev->renderfx = kRenderFxNoDissipation; - pev->renderamt = 255; - pev->rendercolor = Vector( 200, 12, 12 ); - - UTIL_SetModel( ENT( pev ), "sprites/laserdot.spr" ); - UTIL_SetOrigin( this, pev->origin ); -} - -void CLaserSpot::Suspend( float flSuspendTime ) -{ - pev->effects |= EF_NODRAW; - - if( !FNullEnt( pev->owner )) - pev->owner->v.effects &= ~EF_LASERSPOT; - - // -1 means suspend indefinitely - if( flSuspendTime == -1 ) SetThink( NULL ); - else - { - SetThink( Revive ); - SetNextThink( flSuspendTime ); - } -} - -void CLaserSpot::Revive( void ) -{ - if( !FNullEnt( pev->owner )) - pev->owner->v.effects |= EF_LASERSPOT; - - pev->effects &= ~EF_NODRAW; - SetThink( NULL ); -} - -void CLaserSpot::UpdateOnRemove( void ) -{ - // tell the owner about laserspot - if( !FNullEnt( pev->owner )) - pev->owner->v.effects &= ~EF_LASERSPOT; - - CBaseEntity :: UpdateOnRemove (); -} - -void CLaserSpot::Update( CBasePlayer *m_pPlayer ) -{ - TraceResult tr; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - UTIL_TraceLine( m_pPlayer->GetGunPosition(), m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 8192, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr ); - UTIL_SetOrigin( this, tr.vecEndPos ); - - if( UTIL_PointContents( tr.vecEndPos ) == CONTENTS_SKY && VARS( tr.pHit )->solid == SOLID_BSP ) - pev->effects |= EF_NODRAW; - else pev->effects &= ~EF_NODRAW; -} -LINK_ENTITY_TO_CLASS( misc_laserdot, CLaserSpot ); \ No newline at end of file diff --git a/server/ents/basephys.cpp b/server/ents/basephys.cpp deleted file mode 100644 index a5e01c90..00000000 --- a/server/ents/basephys.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2008 -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" - -class CPhysEntity : public CBaseEntity -{ -public: - void Precache( void ) - { - UTIL_PrecacheModel( pev->model, Model() ); - } - void Spawn( void ) - { - Precache(); - - pev->movetype = MOVETYPE_PHYSIC; - pev->solid = SolidType(); - pev->owner = ENT( pev ); // g-cont. i'm forget why needs this stuff :) - - UTIL_SetOrigin( this, pev->origin ); - UTIL_SetModel( ENT( pev ), pev->model, (char *)Model() ); - - SetObjectClass( ED_RIGIDBODY ); - } - virtual const char *Model( void ){ return NULL; } - virtual int SolidType( void ){ return SOLID_MESH; } // generic but slow - void PostActivate( void ) { } // stub -}; -LINK_ENTITY_TO_CLASS( func_physbox, CPhysEntity ); diff --git a/server/ents/baserockets.cpp b/server/ents/baserockets.cpp deleted file mode 100644 index 3e8a8bad..00000000 --- a/server/ents/baserockets.cpp +++ /dev/null @@ -1,982 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2006 -// rockets.cpp - projectiles code -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "baseweapon.h" -#include "nodes.h" -#include "client.h" -#include "soundent.h" -#include "decals.h" -#include "defaults.h" - - -//=========================== -// -// Grenade code -// -//=========================== -void CGrenade::Explode( Vector vecPos, int bitsDamageType, int contents ) -{ - float flRndSound;// sound randomizer - - pev->model = iStringNull;//invisible - pev->solid = SOLID_NOT;// intangible - pev->takedamage = DAMAGE_NO; - - if( contents != CONTENTS_SKY ) - { - // silent remove in sky - UTIL_Explode( vecPos, pev->owner, pev->impulse, pev->classname ); - - flRndSound = RANDOM_FLOAT( 0 , 1 ); - switch ( RANDOM_LONG( 0, 2 )) - { - case 0: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM ); break; - case 2: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM ); break; - } - } - - pev->effects |= EF_NODRAW; - SetThink( Remove ); - pev->velocity = g_vecZero; - SetNextThink( 0.3 ); -} - -void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) -{ - Detonate( ); -} - -// Timed grenade, this think is called when time runs out. -void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( Detonate ); - SetNextThink( 0 ); -} - -void CGrenade::PreDetonate( void ) -{ - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); - - SetThink( Detonate ); - SetNextThink( 1 ); -} - -void CGrenade::Detonate( void ) -{ - Vector vecPos = pev->origin - pev->velocity.Normalize() * 32; // set expolsion pos - int contents = UTIL_PointContents( pev->origin + pev->velocity.Normalize() * 8 ); - - Explode( vecPos, DMG_BLAST, contents ); -} - -void CGrenade::ExplodeTouch( CBaseEntity *pOther ) -{ - pev->enemy = pOther->edict(); - - Vector vecPos = pev->origin - pev->velocity.Normalize() * 32; // set expolsion pos - int contents = UTIL_PointContents( pev->origin + pev->velocity.Normalize() * 8 ); - - Explode( vecPos, DMG_BLAST, contents ); -} - -void CGrenade::DangerSoundThink( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length( ), 0.2 ); - SetNextThink( 0.2 ); - - if( pev->waterlevel != 0 && pev->watertype > CONTENTS_FLYFIELD ) - { - pev->velocity = pev->velocity * 0.5; - } -} - -void CGrenade::BounceTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // only do damage if we're moving fairly fast - if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100) - { - entvars_t *pevOwner = VARS( pev->owner ); - if( pevOwner ) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB ); - ApplyMultiDamage( pev, pevOwner); - } - m_flNextAttack = gpGlobals->time + 1.0; // debounce - } - - Vector vecTestVelocity; - // pev->avelocity = Vector (300, 300, 300); - - // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical - // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. - // trimming the Z velocity a bit seems to help quite a bit. - vecTestVelocity = pev->velocity; - vecTestVelocity.z *= 0.45; - - if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 ) - { - //ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() ); - - // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. - // go ahead and emit the danger sound. - - // register a radius louder than the explosion, so we make sure everyone gets out of the way - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, pev->dmg / 0.4, 0.3 ); - m_fRegisteredSound = TRUE; - } - - if ( pev->flags & FL_ONGROUND ) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.8; - pev->sequence = 1; - } - else - { - // play bounce sound - BounceSound(); - } - pev->framerate = pev->velocity.Length() / 200.0; - if( pev->framerate > 1.0 ) pev->framerate = 1; - else if( pev->framerate < 0.5 ) pev->framerate = 0; - -} - -void CGrenade::SlideTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // pev->avelocity = Vector (300, 300, 300); - - if (pev->flags & FL_ONGROUND) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.95; - - if( pev->velocity.x != 0 || pev->velocity.y != 0 ) - { - // maintain sliding sound - } - } - else BounceSound(); -} - -void CGrenade :: BounceSound( void ) -{ - switch( RANDOM_LONG( 0, 2 )) - { - case 0: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/grenade/hit1.wav", 0.25, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/grenade/hit2.wav", 0.25, ATTN_NORM ); break; - case 2: EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/grenade/hit3.wav", 0.25, ATTN_NORM ); break; - } -} - -void CGrenade :: TumbleThink( void ) -{ - if( !IsInWorld( )) - { - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance( ); - SetNextThink( 0.1 ); - - if ( pev->dmgtime - 1 < gpGlobals->time ) - { - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 ); - } - - if (pev->dmgtime <= gpGlobals->time) - { - SetThink( Detonate ); - } - if( pev->waterlevel != 0 && pev->watertype > CONTENTS_FLYFIELD ) - { - pev->velocity = pev->velocity * 0.5; - pev->framerate = 0.2; - } -} - - -void CGrenade:: Spawn( void ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->classname = MAKE_STRING( "grenade" ); - - pev->solid = SOLID_BBOX; - - SetObjectClass( ED_NORMAL ); - UTIL_SetModel( ENT( pev ), "models/props/hgrenade.mdl"); - - pev->dmg = 100; - m_fRegisteredSound = FALSE; -} - - -CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->Spawn(); - // contact grenades arc lower - pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it. - UTIL_SetOrigin( pGrenade, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity); - pGrenade->pev->owner = ENT(pevOwner); - pGrenade->pev->flags |= FL_PROJECTILE; - - // make monsters afaid of it while in the air - pGrenade->SetThink( DangerSoundThink ); - pGrenade->SetNextThink( 0 ); - - // Tumble in air - pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 ); - - // Explode on contact - pGrenade->SetTouch( ExplodeTouch ); - - UTIL_SetModel( ENT( pGrenade->pev ), "models/props/grenade.mdl"); - UTIL_SetSize( pGrenade->pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 )); - pGrenade->pev->dmg = M203_DMG; - - return pGrenade; -} - - -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - - pGrenade->pev->sequence = RANDOM_LONG( 3, 6 ); - pGrenade->pev->origin = vecStart; - pGrenade->Spawn(); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles( pGrenade->pev->velocity ); - pGrenade->pev->owner = ENT(pevOwner); - - pGrenade->SetTouch( BounceTouch ); // Bounce if touched - - // Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate - // will insert a DANGER sound into the world sound list and delay detonation for one second so that - // the grenade explodes after the exact amount of time specified in the call to ShootTimed(). - - pGrenade->pev->dmgtime = gpGlobals->time + time; - pGrenade->SetThink( TumbleThink ); - pGrenade->SetNextThink( 0.1 ); - - if( time < 0.1f ) - { - pGrenade->SetNextThink( 0 ); - pGrenade->pev->velocity = Vector( 0, 0, 0 ); - } - - pGrenade->pev->framerate = 1.0; - pGrenade->pev->flags |= FL_PROJECTILE; - - // Tumble through the air - pGrenade->pev->avelocity.x = -400; - - pGrenade->pev->gravity = 0.5; - pGrenade->pev->friction = 0.8; - pGrenade->pev->scale = 0.5; // original Valve model is too big :) - - UTIL_SetModel( ENT( pGrenade->pev ), "models/props/hgrenade.mdl" ); - UTIL_SetSize( pGrenade->pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 )); - pGrenade->pev->dmg = 100; - - return pGrenade; -} - -LINK_ENTITY_TO_CLASS( grenade, CGrenade ); - -//=========================== -// -// Rocket code -// -//=========================== -CRpgRocket *CRpgRocket::Create ( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CBasePlayerWeapon *pLauncher ) -{ - CRpgRocket *pRocket = GetClassPtr( (CRpgRocket *)NULL ); - - pRocket->pev->origin = vecOrigin; - pRocket->pev->angles = vecAngles; - pRocket->Spawn(); - pRocket->SetTouch( RocketTouch ); - pRocket->m_pLauncher = pLauncher;// remember what RPG fired me. - pRocket->m_pLauncher->m_cActiveRocket++;// register this missile as active for the launcher - pRocket->pev->owner = pOwner->edict(); - pRocket->pev->flags |= FL_PROJECTILE; - - return pRocket; -} - -TYPEDESCRIPTION CRpgRocket::m_SaveData[] = -{ - DEFINE_FIELD( CRpgRocket, m_flIgniteTime, FIELD_TIME ), - DEFINE_FIELD( CRpgRocket, m_pLauncher, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ); - -void CRpgRocket :: Spawn( void ) -{ - Precache( ); - - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - UTIL_SetModel(ENT(pev), "models/props/rocket.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( this, pev->origin ); - - pev->classname = MAKE_STRING( "rpg_rocket" ); - - SetThink( IgniteThink ); - SetTouch( RocketTouch ); - - pev->angles.x -= 30; - UTIL_MakeVectors( pev->angles ); - pev->angles.x = -(pev->angles.x + 30); - pev->velocity = gpGlobals->v_forward * 250; - pev->gravity = 0.5; - - SetNextThink( 0.4 ); - pev->dmg = RPG_ROCKET_DMG; -} - -void CRpgRocket :: RocketTouch ( CBaseEntity *pOther ) -{ - CBaseEntity *pPlayer = CBaseEntity::Instance(pev->owner); - if ( m_pLauncher ) m_pLauncher->m_cActiveRocket--; - STOP_SOUND( edict(), CHAN_VOICE, "weapons/rpg/rocket1.wav" ); - - ExplodeTouch( pOther ); -} - -void CRpgRocket::Detonate( void ) -{ - CBaseEntity *pPlayer = CBaseEntity::Instance(pev->owner); - if ( m_pLauncher ) m_pLauncher->m_cActiveRocket--; - STOP_SOUND( edict(), CHAN_VOICE, "weapons/rpg/rocket1.wav" ); - - CGrenade :: Detonate(); -} - -void CRpgRocket :: Precache( void ) -{ - UTIL_PrecacheModel( "models/props/rocket.mdl" ); - UTIL_PrecacheSound( "weapons/rpg/rocket1.wav" ); - UTIL_PrecacheSound( "weapons/rpg/beep.wav" ); - UTIL_PrecacheSound( "weapons/rpg/beep2.wav" ); - m_iTrail = UTIL_PrecacheModel( "sprites/smoke.spr" ); -} - -void CRpgRocket :: IgniteThink( void ) -{ - pev->movetype = MOVETYPE_FLY; - pev->effects |= EF_LIGHT; - - CreateTrail(); - m_flIgniteTime = gpGlobals->time; - - // set to follow laser spot - SetThink( FollowThink ); - SetNextThink( 0.1 ); -} - -void CRpgRocket :: CreateTrail( void ) -{ - if( b_setup ) return; - - // make rocket sound after save\load - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rpg/rocket1.wav", 1, 0.5 ); - - // restore rocket trail - SFX_Trail( entindex(), m_iTrail ); - b_setup = TRUE; -} - -void CRpgRocket :: FollowThink( void ) -{ - CBaseEntity *pOther = NULL; - Vector vecTarget; - Vector vecDir; - float flDist, flMax, flDot; - TraceResult tr; - UTIL_MakeAimVectors( pev->angles ); - - CreateTrail(); - - vecTarget = gpGlobals->v_forward; - flMax = 4096; - // Examine all entities within a reasonable radius - while ((pOther = UTIL_FindEntityByClassname( pOther, "misc_laserdot" )) != NULL) - { - UTIL_TraceLine ( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT(pev), &tr ); - // Msg( "%f\n", tr.flFraction ); - if (tr.flFraction >= 0.90) - { - vecDir = pOther->pev->origin - pev->origin; - flDist = vecDir.Length( ); - vecDir = vecDir.Normalize( ); - flDot = DotProduct( gpGlobals->v_forward, vecDir ); - if ((flDot > 0) && (flDist * (1 - flDot) < flMax)) - { - flMax = flDist * (1 - flDot); - vecTarget = vecDir; - } - } - } - - pev->angles = UTIL_VecToAngles( vecTarget ); - - // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it. - float flSpeed = pev->velocity.Length(); - if (gpGlobals->time - m_flIgniteTime < 1.0) - { - pev->velocity = pev->velocity * 0.2 + vecTarget * (flSpeed * 0.8 + 400); - if ( pev->waterlevel == 3 && pev->watertype > CONTENTS_FLYFIELD ) - { - // go slow underwater - if (pev->velocity.Length() > 300) - { - pev->velocity = pev->velocity.Normalize() * 300; - } - UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 4 ); - } - else - { - if (pev->velocity.Length() > 2000) - { - pev->velocity = pev->velocity.Normalize() * 2000; - } - } - } - else - { - if (pev->effects & EF_LIGHT) - { - pev->effects = 0; - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/rpg/rocket1.wav" ); - } - pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; - if ((pev->waterlevel == 0 || pev->watertype == CONTENTS_FOG) && pev->velocity.Length() < 1500) - { - Detonate( ); - } - } - //Msg( "%.0f\n", flSpeed ); - - SetNextThink( 0.05 ); -} -LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); - -//=========================== -// apache HVR rocket -//=========================== -void CApacheHVR :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - UTIL_SetModel(ENT(pev), "models/HVR.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( this, pev->origin ); - - SetThink( IgniteThink ); - SetTouch( ExplodeTouch ); - - UTIL_MakeAimVectors( pev->angles ); - pev->movedir = gpGlobals->v_forward; - pev->gravity = 0.5; - - SetNextThink( 0.1 ); - - pev->dmg = 150; -} - -void CApacheHVR :: Precache( void ) -{ - UTIL_PrecacheModel("models/HVR.mdl"); - m_iTrail = UTIL_PrecacheModel("sprites/smoke.spr"); - UTIL_PrecacheSound("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, gmsg.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 ); - SetNextThink( 0.1 ); -} - - -void CApacheHVR :: AccelerateThink( void ) -{ - // check world boundaries - if(!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - // accelerate - float flSpeed = pev->velocity.Length(); - if (flSpeed < 1800) - { - pev->velocity = pev->velocity + pev->movedir * 200; - } - - // re-aim - pev->angles = UTIL_VecToAngles( pev->velocity ); - - SetNextThink( 0.1 ); -} -LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ); - -//=========================== -// Nuclear explode code -//=========================== - -#define REDEEMER_ROCKET_DMG 500 - -CNukeExplode *CNukeExplode::Create ( Vector vecOrigin, CBaseEntity *pOwner ) -{ - CNukeExplode *pNuke = GetClassPtr( (CNukeExplode *)NULL ); - pNuke->pev->origin = vecOrigin; - pNuke->Spawn(); - pNuke->pev->classname = MAKE_STRING( "nuclear_explode" ); - pNuke->pevOwner = pOwner->pev; - - return pNuke; -} - -void CNukeExplode :: Spawn( void ) -{ - Precache(); - UTIL_SetModel( ENT( pev ), "models/props/nexplode.mdl" ); - TraceResult tr; - UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), &tr); - UTIL_ScreenShake( pev->origin, 16, 1, 2, 1700 ); - pev->oldorigin = tr.vecEndPos + (tr.vecPlaneNormal * 30); // save normalized position - - // create first explode sprite - SFX_Explode( m_usExplodeSprite, pev->origin, 70, TE_EXPLFLAG_NOPARTICLES|TE_EXPLFLAG_NOSOUND|TE_EXPLFLAG_NODLIGHTS ); - EMIT_SOUND( edict(), CHAN_VOICE, "weapons/warhead/whexplode.wav", 1, ATTN_NONE ); - - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; - pev->rendermode = kRenderTransAdd; - pev->renderamt = 190; - pev->scale = 0.5; - UTIL_SetOrigin( this, pev->origin ); - - SetThink( ExplodeThink ); - - pev->dmg = REDEEMER_ROCKET_DMG; - SetNextThink( 0 ); -} - -void CNukeExplode :: Precache( void ) -{ - m_usExplodeSprite = UTIL_PrecacheModel( "sprites/war_explo01.spr" ); - m_usExplodeSprite2 = UTIL_PrecacheModel( "sprites/war_explo02.spr" ); - UTIL_PrecacheModel( "models/props/nexplode.mdl" ); - UTIL_PrecacheSound( "weapons/warhead/whexplode.wav" ); -} - -void CNukeExplode :: ExplodeThink( void ) -{ - pev->renderamt = UTIL_Approach( 0, pev->renderamt, 200 * gpGlobals->frametime ); - pev->scale = UTIL_Approach( 30, pev->scale, 30 * gpGlobals->frametime ); - - if( pev->scale > 8.0f && m_usExplodeSprite2 ) // create second explode sprite - { - SFX_Explode( m_usExplodeSprite2, pev->origin, 70, TE_EXPLFLAG_NOPARTICLES|TE_EXPLFLAG_NOSOUND|TE_EXPLFLAG_NODLIGHTS ); - m_usExplodeSprite2 = 0; // fire once - } - pev->owner = NULL; // can't traceline attack owner if this is set - - ::RadiusDamage( pev->origin, pev, pevOwner, pev->renderamt/2, pev->scale * 30, CLASS_NONE, DMG_BLAST|DMG_NUCLEAR ); - if( pev->scale == 30 ) UTIL_Remove( this ); - - SetNextThink( 0.01 ); -} -LINK_ENTITY_TO_CLASS( nuclear_explode, CNukeExplode ); - -//=========================== -// Nuke rocket code -//=========================== - -// redeemder settings (weapon_redeemer) -#define WARHEAD_SPEED 500 -#define WARHEAD_SPEED_UNDERWATER 300 -#define WARHEAD_MAX_SPEED 1200 - -CWHRocket *CWHRocket::Create( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CBasePlayerWeapon *pLauncher, BOOL Controllable ) -{ - CWHRocket *pRocket = GetClassPtr( (CWHRocket *)NULL ); - - pRocket->pev->origin = vecOrigin; - pRocket->pev->angles = vecAngles; - pRocket->m_pLauncher = pLauncher; // remember what RPG fired me. - pRocket->pev->owner = pOwner->edict(); - pRocket->pev->button = Controllable; // memeber rocket type - pRocket->pev->classname = MAKE_STRING( "nuke_rocket" ); - pRocket->m_pLauncher->m_cActiveRocket++;// register rocket - pRocket->Spawn(); - pRocket->pev->flags |= FL_PROJECTILE; - - return pRocket; -} - -TYPEDESCRIPTION CWHRocket::m_SaveData[] = -{ - DEFINE_FIELD( CWHRocket, m_pLauncher, FIELD_CLASSPTR ), - DEFINE_FIELD( CWHRocket, m_pPlayer, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CWHRocket, CBaseAnimating ); - - -void CWHRocket :: Spawn( void ) -{ - Precache( ); - - m_pPlayer = (CBasePlayer*)CBasePlayer::Instance( pev->owner ); - if( !m_pPlayer ) // leveldesigner may put rocket on a map - { - if( !IsMultiplayer()) - { - ALERT( at_warning, "player pointer is not valid\n" ); - m_pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( 1 ); - } - else - { - UTIL_Remove( this ); - return; - } - } - - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_SLIDEBOX; - pev->takedamage = DAMAGE_YES; - pev->health = 10; - pev->speed = WARHEAD_SPEED; // set initial speed - - UTIL_SetModel( ENT( pev ), "models/props/whrocket.mdl" ); - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/warhead/launch.wav", 1, 0.5 ); - UTIL_SetOrigin( this, pev->origin ); - - SetThink( FollowThink ); - SetTouch( NukeTouch ); - - UTIL_MakeVectors( pev->angles ); - pev->angles.x = -(pev->angles.x); - pev->velocity = gpGlobals->v_forward * pev->speed; - m_Center = pev->angles; - - if( pev->button ) - { - UTIL_SetView( m_pPlayer, this, CAMERA_ON|INVERSE_X ); - m_pLauncher->m_iOnControl = 1; // start controlling - m_pPlayer->m_iWarHUD = 1; // enable warhead HUD - } - SetNextThink( 0.1 ); -} - -void CWHRocket :: Precache( void ) -{ - UTIL_PrecacheModel("models/props/whrocket.mdl"); - UTIL_PrecacheSound("weapons/warhead/launch.wav"); - UTIL_PrecacheSound("weapons/warhead/whfly.wav"); - UTIL_PrecacheEntity( "nuclear_explode" );//explode - m_iTrail = UTIL_PrecacheAurora("whtrail"); - m_iBurst = UTIL_PrecacheAurora("whburst"); - b_setup = FALSE; -} - -void CWHRocket :: CreateTrail( void ) -{ - if( b_setup ) return; // restore function - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/warhead/whfly.wav", 1, 0.5 ); - UTIL_SetAurora( this, m_iTrail ); - UTIL_SetAurora( this, m_iBurst ); - pev->renderfx = kRenderFxAurora; - b_setup = TRUE; -} - -void CWHRocket :: FollowThink( void ) -{ - Vector angles, velocity;//private angles & velocity to transform - CreateTrail(); - - if( pev->button ) // controllable rocket - { - UTIL_MakeVectorsPrivate( m_pPlayer->pev->v_angle, forward, NULL, NULL ); - - angles = m_pPlayer->pev->v_angle; - angles.x = -angles.x; - float steer = WARHEAD_MAX_SPEED / pev->speed; // steer factor - - angles.x = m_Center.x + UTIL_AngleDistance( angles.x, m_Center.x ); - angles.y = m_Center.y + UTIL_AngleDistance( angles.y, m_Center.y ); - angles.z = m_Center.z + UTIL_AngleDistance( angles.z, m_Center.z ); - - float distX = UTIL_AngleDistance( angles.x, pev->angles.x ); - pev->avelocity.x = distX * steer; - - float distY = UTIL_AngleDistance( angles.y, pev->angles.y ); - pev->avelocity.y = distY * steer; - - float distZ = UTIL_AngleDistance( angles.z, pev->angles.z ); - pev->avelocity.z = distY * -steer + distZ * steer; - - pev->velocity = forward * pev->speed + pev->avelocity; - if( m_pLauncher && m_pLauncher->m_iOnControl == 2 ) - { - Detonate(); // check for himself destroy - return; - } - } - CalculateVelocity(); - - //Msg("Speed %.f\n", pev->velocity.Length()); - SetNextThink( 0.1 ); -} - -void CWHRocket::CalculateVelocity ( void ) -{ - if(pev->waterlevel == 3)//go slow underwater - { - if (pev->speed > WARHEAD_SPEED_UNDERWATER) pev->speed -= 30; - GetAttachment( 0, pev->oldorigin, pev->movedir ); - UTIL_BubbleTrail( pev->oldorigin - pev->velocity * 0.1, pev->oldorigin, 4 ); - if( pev->button ) m_pPlayer->m_iWarHUD = 2; - } - else - { - pev->speed += 5; // accelerate rocket - if( pev->button ) m_pPlayer->m_iWarHUD = 1; - } - if( pev->speed > WARHEAD_SPEED ) - pev->velocity = pev->velocity.Normalize() * WARHEAD_SPEED; -} - -int CWHRocket::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - pev->health -= flDamage;//calculate health - if (pev->health <= 0) Detonate(); - return 1; -} - -void CWHRocket :: NukeTouch ( CBaseEntity *pOther ) -{ - pev->enemy = pOther->edict(); //save enemy - - Vector vecAngles( pev->angles ); - vecAngles.x = -vecAngles.x; - - UTIL_MakeVectors( vecAngles ); - - // check for sky - if( UTIL_PointContents( pev->origin + gpGlobals->v_forward * 32 ) == CONTENTS_SKY ) - Detonate( FALSE ); // silent remove in sky - else Detonate(); - - SetNextThink( 0.7f ); -} - -void CWHRocket :: Detonate ( bool explode ) -{ - // NOTE: Player can controlled one rocket at moment - // but non controlled rocket don't reset this indicator - if( pev->button ) m_pPlayer->m_iWarHUD = 3; // make static noise - - // launcher callback - if( m_pLauncher ) m_pLauncher->m_cActiveRocket--; - - pev->takedamage = DAMAGE_NO; - pev->renderfx = kRenderFxNone; // disable trail - pev->velocity = g_vecZero; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NODRAW; - pev->model = iStringNull; // invisible - - STOP_SOUND( edict(), CHAN_VOICE, "weapons/warhead/whfly.wav" );//stop flying sound - - if( explode ) - { - // make nuclear explosion if needed - CNukeExplode::Create( pev->origin, m_pPlayer ); - SetThink( RemoveRocket ); - SetNextThink( 2.5 ); // let the smoke continue moving - } - else - { - SetThink( RemoveRocket ); - SetNextThink( 2.5 ); - } -} -void CWHRocket :: RemoveRocket ( void ) -{ - if( m_pLauncher ) - m_pLauncher->m_iOnControl = 0; //stop controlling - if( pev->button ) - { - m_pPlayer->m_iWarHUD = 0;//reset HUD - UTIL_SetView( m_pPlayer, iStringNull, 0 );//reset view - } - - SetThink( Remove ); - SetNextThink( 0.1 ); -} -LINK_ENTITY_TO_CLASS( nuke_rocket, CWHRocket ); - - -//=========================== -// crossbow bolt -//=========================== -CBolt *CBolt::Create( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner ) -{ - // Create a new entity with CBolt private data - CBolt *pBolt = GetClassPtr( (CBolt *)NULL ); - pBolt->pev->classname = MAKE_STRING("bolt"); - pBolt->Spawn(); - pBolt->pev->origin = vecOrigin; - pBolt->pev->angles = vecAngles; - pBolt->pev->owner = pOwner->edict(); - pBolt->pev->avelocity.z = 10; - - return pBolt; -} - -void CBolt::Spawn( ) -{ - Precache( ); - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->gravity = 0.5; - UTIL_SetModel(ENT(pev), "models/crossbow_bolt.mdl"); - - UTIL_SetOrigin( this, pev->origin ); - UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - - EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_fire1.wav", 1, ATTN_NORM); - - SetThink( BubbleThink ); - SetNextThink( 0.2 ); -} - -void CBolt::Precache( ) -{ - UTIL_PrecacheModel("models/crossbow_bolt.mdl"); - UTIL_PrecacheSound("weapons/xbow_hitbod1.wav"); - UTIL_PrecacheSound("weapons/xbow_hitbod2.wav"); - UTIL_PrecacheSound("weapons/xbow_hit1.wav"); - UTIL_PrecacheSound("weapons/xbow_fire1.wav"); -} - -void CBolt::Touch( CBaseEntity *pOther ) -{ - SetTouch( NULL ); - - if (pOther->IsMonster() || pOther->IsPlayer()) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - entvars_t *pevOwner; - - pevOwner = VARS( pev->owner ); - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, BOLT_DMG, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); - ApplyMultiDamage( pev, pevOwner ); - - pev->velocity = Vector( 0, 0, 0 ); - - // play body "thwack" sound - switch( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break; - } - - Killed( pev, GIB_NEVER ); - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7)); - - SetNextThink( 0 ); - - Vector vecDir = pev->velocity.Normalize( ); - UTIL_SetOrigin( this, pev->origin - vecDir * 12 ); - pev->angles = UTIL_VecToAngles( vecDir ); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_FLY; - pev->velocity = Vector( 0, 0, 0 ); - pev->avelocity.z = 0; - pev->angles.z = RANDOM_LONG(0, 360); - - if ( pOther == g_pWorld ) SetThink( PVSRemove ); - else if( pOther->IsBSPModel()) - { - SetParent( pOther );//glue bolt with parent system - SetThink( PVSRemove ); - } - else SetThink( Remove ); - if( UTIL_PointContents( pev->origin ) != CONTENTS_WATER ) - UTIL_Sparks( pev->origin ); - } -} - -void CBolt::BubbleThink( void ) -{ - if (pev->waterlevel == 3) UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 ); - SetNextThink( 0.1 ); -} - -LINK_ENTITY_TO_CLASS( bolt, CBolt ); \ No newline at end of file diff --git a/server/ents/baserockets.h b/server/ents/baserockets.h deleted file mode 100644 index 43414e97..00000000 --- a/server/ents/baserockets.h +++ /dev/null @@ -1,111 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2006 -// rockets.h - projectiles code -//======================================================================= -#include "baseweapon.h" - -class CGrenade : public CBaseMonster -{ -public: - void Spawn( void ); - - static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ); - static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - - void Explode( Vector vecPos, int bitsDamageType, int contents ); - - void EXPORT BounceTouch( CBaseEntity *pOther ); - void EXPORT SlideTouch( CBaseEntity *pOther ); - void EXPORT ExplodeTouch( CBaseEntity *pOther ); - void EXPORT DangerSoundThink( void ); - void EXPORT PreDetonate( void ); - void EXPORT Detonate( void ); - void EXPORT DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT TumbleThink( void ); - - virtual void BounceSound( void ); - virtual int BloodColor( void ) { return DONT_BLEED; } - virtual void Killed( entvars_t *pevAttacker, int iGib ); - - BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet. -}; - -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 ); - void Detonate( void ); - void CreateTrail( void ); - static CRpgRocket *Create ( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CBasePlayerWeapon *pLauncher ); - - int m_iTrail; - float m_flIgniteTime; - CBasePlayerWeapon *m_pLauncher;// pointer back to the launcher that fired me. - BOOL b_setup; -}; - -class CApacheHVR : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void EXPORT IgniteThink( void ); - void EXPORT AccelerateThink( void ); - - int m_iTrail; -}; - -class CNukeExplode : public CBaseLogic -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT ExplodeThink( void ); - static CNukeExplode *Create ( Vector vecOrigin, CBaseEntity *pOwner ); - short m_usExplodeSprite; - short m_usExplodeSprite2; - entvars_t *pevOwner; // keep pointer to rocket owner -}; - -class CWHRocket : public CBaseAnimating -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - void Spawn( void ); - void Precache( void ); - void CreateTrail( void ); - void EXPORT FollowThink( void ); - void EXPORT NukeTouch( CBaseEntity *pOther ); - void EXPORT RemoveRocket ( void ); - void CalculateVelocity ( void ); - void Detonate ( bool explode = 1 ); - static CWHRocket *Create ( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CBasePlayerWeapon *pLauncher, BOOL Control ); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - - int m_iTrail, m_iBurst;// rocket trail - CBasePlayerWeapon *m_pLauncher;// pointer back to the launcher that fired me. - CBasePlayer *m_pPlayer; - Vector m_Center, forward; - BOOL b_setup; -}; - -class CBolt : public CBaseAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - void EXPORT BubbleThink( void ); - void Touch( CBaseEntity *pOther ); - static CBolt *Create( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner ); - - int m_iTrail; -}; \ No newline at end of file diff --git a/server/ents/basesprite.h b/server/ents/basesprite.h deleted file mode 100644 index 60a4a0fa..00000000 --- a/server/ents/basesprite.h +++ /dev/null @@ -1,150 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef BASESPRITE_H -#define BASESPRITE_H - -#define SF_TEMPSPRITE 0x8000 //play sequence and die -#include "baseworld.h" - -class CSprite : public CBaseLogic -{ -public: - void Spawn( void ); - void Precache( void ) { UTIL_PrecacheModel( pev->model ); } - void PostActivate( void ) - { - // env_glow always enabled - if( FClassnameIs( pev, "env_glow" ) || FStringNull( pev->targetname ) || pev->spawnflags & SF_START_ON ) - { - TurnOn(); - ClearBits( pev->spawnflags, SF_START_ON ); - } - else TurnOff(); - } - - void Think( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void Move( void ); - void PostSpawn( void ); - void Animate( float frames ) - { - if( Frames() > 1 ) - { - pev->frame += frames; - if( pev->frame > Frames() ) - { - if( pev->spawnflags & SF_FIREONCE ) TurnOff(); - else if( Frames() > 0 ) pev->frame = fmod( pev->frame, Frames() ); - } - } - } - void TurnOff( void ); - void TurnOn( void ); - float Frames( void ) { return MODEL_FRAMES( pev->modelindex ) - 1; } - inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx ) - { - pev->rendermode = rendermode; - pev->rendercolor.x = r; - pev->rendercolor.y = g; - pev->rendercolor.z = b; - pev->renderamt = a; - pev->renderfx = fx; - } - inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } - inline void SetScale( float scale ) { pev->scale = scale; } - inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } - - inline void AnimateAndDie( float framerate ) - { - SetBits( pev->spawnflags, SF_TEMPSPRITE ); - pev->framerate = framerate; - pev->dmg_take = gpGlobals->time + (Frames() / framerate); - SetNextThink( 0 ); - } - static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) - { - CSprite *pSprite = GetClassPtr( (CSprite *)NULL ); - pSprite->pev->classname = MAKE_STRING("env_sprite"); - pSprite->pev->model = MAKE_STRING(pSpriteName); - pSprite->pev->origin = origin; - pSprite->Spawn(); - if ( animate ) pSprite->TurnOn(); - else ClearBits( pSprite->pev->effects, EF_NODRAW ); - - return pSprite; - } -}; - -class CShot : public CSprite -{ -public: - void Touch ( CBaseEntity *pOther ) - { - if (pev->teleport_time > gpGlobals->time) return; - pev->teleport_time = gpGlobals->time + 0.1; - if ( pOther != g_pWorld) UTIL_FireTargets( pev->target, pOther, this, USE_ON ); - else UTIL_FireTargets( pev->target, pOther, this, USE_SET ); //world touch - } - static CShot *CreateShot ( const char *szGibModel, Vector size ) - { - CShot *pShot = GetClassPtr( (CShot*)NULL ); - pShot->pev->classname = MAKE_STRING("shot"); - pShot->pev->solid = SOLID_SLIDEBOX; - UTIL_SetModel(ENT(pShot->pev), szGibModel ); - UTIL_SetSize(pShot->pev, -size, size ); - return pShot; - } -}; - -class CGib : public CBaseEntity -{ -public: - void Spawn( const char *szGibModel ); - void EXPORT BounceGibTouch ( CBaseEntity *pOther ); - void EXPORT StickyGibTouch ( CBaseEntity *pOther ); - void EXPORT WaitTillLand( void ); - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } - static CGib *CreateGib ( CBaseEntity *pVictim, const char *szGibModel, int gibtype ); - - //spawn gibs - static void SpawnHeadGib( CBaseEntity *pVictim, string_t m_iGibModel = NULL ) - { - if( FStringNull( m_iGibModel )) - CreateGib( pVictim, "models/gibs/hgibs.mdl", 1 ); - else CreateGib( pVictim, STRING( m_iGibModel ), 1 ); - } - - static void SpawnRandomGibs( CBaseEntity *pVictim, int cGibs, int human, string_t m_iGibModel = NULL ) - { - const char *model; - if( FStringNull( m_iGibModel )) - { - if( human ) model = "models/gibs/hgibs.mdl"; - else model = "models/gibs/agibs.mdl"; - } - else model = (char *)STRING( m_iGibModel ); - - for( int i = 0; i < cGibs; i++ ) - CreateGib( pVictim, model, 0 ); - } - - static void SpawnStickyGibs( CBaseEntity *pVictim, int cGibs, string_t m_iGibModel = NULL ) - { - if( !FStringNull( m_iGibModel )) - for( int i = 0; i < cGibs; i++ ) - CreateGib( pVictim, STRING( m_iGibModel ), 2 ); - else for( int i = 0; i < cGibs; i++ ) - CreateGib( pVictim, "models/gibs/stickygib.mdl", 2 ); - } - - int m_bloodColor; - int m_cBloodDecals; - int m_material; - float m_lifeTime; -}; - -#endif //BASESPRITE_H \ No newline at end of file diff --git a/server/ents/basetank.cpp b/server/ents/basetank.cpp deleted file mode 100644 index f9b4944c..00000000 --- a/server/ents/basetank.cpp +++ /dev/null @@ -1,1154 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "sfx.h" -#include "cbase.h" -#include "basebeams.h" -#include "baseweapon.h" -#include "basetank.h" -#include "monsters.h" - -TYPEDESCRIPTION CFuncTank::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTank, m_yawCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_fireLast, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_fireRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_lastSightTime, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_persist, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_Range, FIELD_RANGE ), - DEFINE_FIELD( CFuncTank, m_barrelPos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spriteScale, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_iszSpriteSmoke, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_iszSpriteFlash, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_bulletType, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_sightOrigin, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spread, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_pControls, FIELD_CLASSPTR ), //LRC - DEFINE_FIELD( CFuncTank, m_pSpot, FIELD_CLASSPTR ), //LRC - DEFINE_FIELD( CFuncTank, m_flNextAttack, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_iBulletDamage, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_iszMaster, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_iszFireMaster, FIELD_STRING ), //LRC -}; -IMPLEMENT_SAVERESTORE( CFuncTank, CBaseEntity ); - -void CFuncTank :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "yawrate")) - { - m_yawRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawrange")) - { - m_yawRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawtolerance")) - { - m_yawTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrange")) - { - m_pitchRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrate")) - { - m_pitchRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchtolerance")) - { - m_pitchTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firerate")) - { - m_fireRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrelend")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritescale")) - { - m_spriteScale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritesmoke")) - { - m_iszSpriteSmoke = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spriteflash")) - { - m_iszSpriteFlash = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "rotatesound")) - { - pev->noise = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "persistence")) - { - m_persist = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bullet")) - { - m_bulletType = (TANKBULLET)atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "bullet_damage" )) - { - m_iBulletDamage = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firespread")) - { - m_spread = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "Range")) - { - m_Range = RandomRange(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "master")) - { - m_iszMaster = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firemaster")) - { - m_iszFireMaster = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iClass")) - { - m_iTankClass = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CFuncTank :: Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything - pev->solid = SOLID_BSP; - UTIL_SetModel( ENT(pev), pev->model ); - SetBits (pFlags, PF_ANGULAR); - - if ( IsActive() ) - { - SetNextThink(1.0); - } - - if (!m_iTankClass) - { - m_iTankClass = 0; - } - - if(m_Range.m_flMax == 0) m_Range.m_flMax = 4096; - - if ( m_fireRate <= 0 ) m_fireRate = 1; - if ( m_spread > MAX_FIRING_SPREADS ) m_spread = 0; - - pev->oldorigin = pev->origin; -} - -void CFuncTank::PostSpawn( void ) -{ - if (m_pParent) - { - m_yawCenter = pev->angles.y - m_pParent->pev->angles.y; - m_pitchCenter = pev->angles.x - m_pParent->pev->angles.x; - } - else - { - m_yawCenter = pev->angles.y; - m_pitchCenter = pev->angles.x; - } - - CBaseEntity *pTarget = UTIL_FindEntityByTargetname(NULL, STRING(pev->netname), NULL ); - if(pTarget) - { - m_barrelPos = pTarget->pev->origin - pev->origin; //write offset - UTIL_Remove( pTarget ); - } - else if(!IsLaserTank()) //get "laserentity" position for tanklaser - { - Msg("Error! %s: %s haven't barrel end entity! Use default values.\n", STRING(pev->classname), STRING(pev->targetname)); - m_barrelPos = Vector( fabs(pev->absmax.x), 0, 0 ); - } - m_sightOrigin = BarrelPosition(); // Point at the end of the barrel -} - -void CFuncTank :: Precache( void ) -{ - if ( m_iszSpriteSmoke ) - UTIL_PrecacheModel( m_iszSpriteSmoke ); - if ( m_iszSpriteFlash ) - UTIL_PrecacheModel( m_iszSpriteFlash ); - if ( pev->noise ) - UTIL_PrecacheSound( pev->noise ); -} - -BOOL CFuncTank :: StartControl( CBasePlayer* pController, CFuncTankControls *pControls ) -{ - // we're already being controlled or playing a sequence - if ( m_pControls != NULL ) - return FALSE; - - // Team only or disabled? - if ( m_iszMaster ) - { - if ( !UTIL_IsMasterTriggered( m_iszMaster, pController ) ) - return FALSE; - } - - m_iState = STATE_ON; - m_pControls = pControls; - - if (m_pSpot) m_pSpot->Revive(); - - SetNextThink(0.3); - return TRUE; -} - -void CFuncTank :: StopControl( CFuncTankControls* pControls) -{ - if ( !m_pControls || m_pControls != pControls) - { - return; - } - m_iState = STATE_OFF; - - if (m_pSpot) m_pSpot->Suspend(-1); - StopRotSound(); //LRC - - DontThink(); - UTIL_SetAvelocity(this, g_vecZero); - m_pControls = NULL; - - if ( IsActive() ) - { - SetNextThink(1.0); - } -} - -void CFuncTank::UpdateSpot( void ) -{ - if ( pev->spawnflags & SF_TANK_LASERSPOT ) - { - - if (!m_pSpot) m_pSpot = CLaserSpot::CreateSpot(); - - Vector vecAiming; - UTIL_MakeVectorsPrivate( pev->angles, vecAiming, NULL, NULL ); - Vector vecSrc = BarrelPosition( ); - - TraceResult tr; - UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, ENT(pev), &tr ); - UTIL_SetOrigin( m_pSpot, tr.vecEndPos ); - } -} - -void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_TANK_CANCONTROL ) - { - if ( pActivator->Classify() != CLASS_PLAYER ) return; - } - else - { - if (useType == USE_TOGGLE) - { - if(IsActive()) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - TankActivate(); - if (m_pSpot) m_pSpot->Revive(); - } - else if (useType == USE_OFF) - { - TankDeactivate(); - if (m_pSpot) m_pSpot->Suspend(-1); - } - } -} - -CBaseEntity *CFuncTank:: BestVisibleEnemy ( void ) -{ - CBaseEntity *pReturn; - int iNearest; - int iDist; - int iBestRelationship; - int iLookDist = m_Range.m_flMax ? m_Range.m_flMax : 512; //thanks to Waldo for this. - - iNearest = 8192;// so first visible entity will become the closest. - pReturn = NULL; - iBestRelationship = R_DL; - - CBaseEntity *pList[100]; - - Vector delta = Vector( iLookDist, iLookDist, iLookDist ); - - // 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 ); - int i; - - for (i = 0; i < count; i++ ) - { - if ( pList[i]->IsAlive() ) - { - if ( IRelationship( pList[i] ) > 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 ( pList[i] ); - iNearest = ( pList[i]->pev->origin - pev->origin ).Length(); - pReturn = pList[i]; - } - else if ( IRelationship( pList[i] ) == 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 = ( pList[i]->pev->origin - pev->origin ).Length(); - - if ( iDist <= iNearest ) - { - iNearest = iDist; - //these are guaranteed to be the same! iBestRelationship = IRelationship ( pList[i] ); - pReturn = pList[i]; - } - } - } - } - return pReturn; -} - - -int CFuncTank::IRelationship( CBaseEntity* pTarget ) -{ - int iOtherClass = pTarget->Classify(); - if (iOtherClass == CLASS_NONE) return R_NO; - - if (!m_iTankClass) - { - if (iOtherClass == CLASS_PLAYER) - return R_HT; - else - return R_NO; - } - else if (m_iTankClass == CLASS_PLAYER_ALLY) - { - switch (iOtherClass) - { - case CLASS_HUMAN_MILITARY: - case CLASS_MACHINE: - case CLASS_ALIEN_MILITARY: - case CLASS_ALIEN_MONSTER: - case CLASS_ALIEN_PREDATOR: - case CLASS_ALIEN_PREY: - return R_HT; - default: - return R_NO; - } - } - else if (m_iTankClass == CLASS_HUMAN_MILITARY) - { - switch (iOtherClass) - { - case CLASS_PLAYER: - case CLASS_PLAYER_ALLY: - case CLASS_ALIEN_MILITARY: - case CLASS_ALIEN_MONSTER: - case CLASS_ALIEN_PREDATOR: - case CLASS_ALIEN_PREY: - return R_HT; - case CLASS_HUMAN_PASSIVE: - return R_DL; - default: - return R_NO; - } - } - else if (m_iTankClass == CLASS_ALIEN_MILITARY) - { - switch (iOtherClass) - { - case CLASS_PLAYER: - case CLASS_PLAYER_ALLY: - case CLASS_HUMAN_MILITARY: - return R_HT; - case CLASS_HUMAN_PASSIVE: - return R_DL; - default: - return R_NO; - } - } - else return R_NO; -} - -BOOL CFuncTank :: InRange( float range ) -{ - if ( range < m_Range.m_flMin ) - return FALSE; - if ( m_Range.m_flMax > 0 && range > m_Range.m_flMax ) - return FALSE; - - return TRUE; -} - -void CFuncTank :: Think( void ) -{ - TrackTarget(); - - if ( fabs(pev->avelocity.x) > 1 || fabs(pev->avelocity.y) > 1 ) - StartRotSound(); - else StopRotSound(); -} - -void CFuncTank::TrackTarget( void ) -{ - TraceResult tr; - BOOL updateTime = FALSE, lineOfSight; - Vector angles, direction, targetPosition, barrelEnd; - Vector v_right, v_up; - CBaseEntity *pTarget; - CBasePlayer* pController = NULL; - - if (m_pControls && m_pControls->m_pController) - { - UpdateSpot(); - pController = m_pControls->m_pController; - pController->pev->viewmodel = 0; - SetNextThink(0.05); - - if( pev->spawnflags & SF_TANK_MATCHTARGET ) - { - // "Match target" mode: - // first, get the player's angles - angles = pController->pev->v_angle; - - // work out what point the player is looking at - UTIL_MakeVectorsPrivate( angles, direction, NULL, NULL ); - - targetPosition = pController->EyePosition() + direction * 1000; - - edict_t *ownerTemp = pev->owner; //LRC store the owner, so we can put it back after the check - pev->owner = pController->edict(); //LRC when doing the matchtarget check, don't hit the player or the tank. - - UTIL_TraceLine( - pController->EyePosition(), - targetPosition, - missile, //the opposite of ignore_monsters: target them if we go anywhere near! - ignore_glass, - edict(), &tr - ); - - pev->owner = ownerTemp; //LRC put the owner back - - // Work out what angle we need to face to look at that point - direction = tr.vecEndPos - pev->origin; - angles = UTIL_VecToAngles( direction ); - targetPosition = tr.vecEndPos; - - // Calculate the additional rotation to point the end of the barrel at the target - // (instead of the gun's center) - AdjustAnglesForBarrel( angles, direction.Length() ); - } - else - { - // "Match angles" mode - // just get the player's angles - angles = pController->pev->v_angle; - angles[0] = 0 - angles[0]; - - UpdateSpot(); - SetNextThink( 0.05 ); // g-cont. for more smoothing motion a laser spot - } - } - else - { - if ( IsActive() ) - { - SetNextThink(0.1); - } - else - { - DontThink(); - UTIL_SetAvelocity(this, g_vecZero); - return; - } - - UpdateSpot(); - - // if we can't see any players - pTarget = BestVisibleEnemy(); - if ( FNullEnt( pTarget ) ) - { - if ( IsActive() ) SetNextThink(2); // No enemies visible, wait 2 secs - return; - } - - // Calculate angle needed to aim at target - barrelEnd = BarrelPosition(); - targetPosition = pTarget->pev->origin + pTarget->pev->view_ofs; - float range = (targetPosition - barrelEnd).Length(); - - if ( !InRange( range ) ) - return; - - UTIL_TraceLine( barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr ); - - if ( tr.flFraction == 1.0 || tr.pHit == ENT(pTarget->pev) ) - { - lineOfSight = TRUE; - - if ( InRange( range ) && pTarget->IsAlive() ) - { - updateTime = TRUE; // I think I saw him, pa! - m_sightOrigin = UpdateTargetPosition( pTarget ); - } - } - else - { - // No line of sight, don't track - lineOfSight = FALSE; - } - - direction = m_sightOrigin - pev->origin; - angles = UTIL_VecToAngles( direction ); - AdjustAnglesForBarrel( angles, direction.Length() ); - } - - angles.x = -angles.x; - - float currentYawCenter, currentPitchCenter; - - // Force the angles to be relative to the center position - if (m_pParent) - { - currentYawCenter = m_yawCenter + m_pParent->pev->angles.y; - currentPitchCenter = m_pitchCenter + m_pParent->pev->angles.x; - } - else - { - currentYawCenter = m_yawCenter; - currentPitchCenter = m_pitchCenter; - } - - angles.y = currentYawCenter + UTIL_AngleDistance( angles.y, currentYawCenter ); - angles.x = currentPitchCenter + UTIL_AngleDistance( angles.x, currentPitchCenter ); - - // Limit against range in y - if (m_yawRange < 360) - { - if ( angles.y > currentYawCenter + m_yawRange ) - { - angles.y = currentYawCenter + m_yawRange; - updateTime = FALSE; // If player is outside fire arc, we didn't really see him - } - else if ( angles.y < (currentYawCenter - m_yawRange) ) - { - angles.y = (currentYawCenter - m_yawRange); - updateTime = FALSE; // If player is outside fire arc, we didn't really see him - } - } - // we can always 'see' the whole vertical arc, so it's just the yaw we needed to check. - - if ( updateTime ) - m_lastSightTime = gpGlobals->time; - - // Move toward target at rate or less - float distY = UTIL_AngleDistance( angles.y, pev->angles.y ); - Vector setAVel = g_vecZero; - - setAVel.y = distY * 10; - if ( setAVel.y > m_yawRate ) setAVel.y = m_yawRate; - else if ( setAVel.y < -m_yawRate ) setAVel.y = -m_yawRate; - - // Limit against range in x - if ( angles.x > currentPitchCenter + m_pitchRange ) angles.x = currentPitchCenter + m_pitchRange; - else if ( angles.x < currentPitchCenter - m_pitchRange ) angles.x = currentPitchCenter - m_pitchRange; - - // Move toward target at rate or less - float distX = UTIL_AngleDistance( angles.x, pev->angles.x ); - setAVel.x = distX * 10; - - if ( setAVel.x > m_pitchRate ) setAVel.x = m_pitchRate; - else if ( setAVel.x < -m_pitchRate ) setAVel.x = -m_pitchRate; - - UTIL_SetAvelocity(this, setAVel); - - // notify the TankSequence if we're (pretty close to) facing the target - - // firing with player-controlled tanks: - if ( pController ) - { - if ( gpGlobals->time < m_flNextAttack ) - return; - - if ( pController->pev->button & IN_ATTACK ) - { - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - - // to make sure the gun doesn't fire too many bullets - m_fireLast = gpGlobals->time - (1/m_fireRate) - 0.01; - - TryFire( BarrelPosition(), forward, pController->pev ); - - if ( pController && pController->IsPlayer() ) - ((CBasePlayer *)pController)->m_iWeaponVolume = LOUD_GUN_VOLUME; - - m_flNextAttack = gpGlobals->time + (1/m_fireRate); - } - else m_iState = STATE_ON; - } - // firing with automatic guns: - else if ( CanFire() && ( (fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (pev->spawnflags & SF_TANK_LINEOFSIGHT) ) ) - { - BOOL fire = FALSE; - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - - if ( pev->spawnflags & SF_TANK_LINEOFSIGHT ) - { - float length = direction.Length(); - UTIL_TraceLine( barrelEnd, barrelEnd + forward * length, dont_ignore_monsters, edict(), &tr ); - if ( tr.pHit == ENT(pTarget->pev) ) - fire = TRUE; - } - else fire = TRUE; - - if ( fire ) - { - TryFire( BarrelPosition(), forward, pev ); - } - else - { - m_fireLast = 0; - } - } - else m_fireLast = 0; -} - -void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) -{ - float r2, d2; - - - if ( m_barrelPos.y != 0 || m_barrelPos.z != 0 ) - { - distance -= m_barrelPos.z; - d2 = distance * distance; - if ( m_barrelPos.y ) - { - r2 = m_barrelPos.y * m_barrelPos.y; - angles.y += (180.0 / M_PI) * atan2( m_barrelPos.y, sqrt( d2 - r2 ) ); - } - if ( m_barrelPos.z ) - { - r2 = m_barrelPos.z * m_barrelPos.z; - angles.x += (180.0 / M_PI) * atan2( -m_barrelPos.z, sqrt( d2 - r2 ) ); - } - } -} - -// Check the FireMaster before actually firing -void CFuncTank::TryFire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - m_iState = STATE_IN_USE; - if (UTIL_IsMasterTriggered(m_iszFireMaster, NULL)) - { - Fire( barrelEnd, forward, pevAttacker ); - } -} - -// Fire targets and spawn sprites -void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - if ( m_iszSpriteSmoke ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteSmoke), barrelEnd, TRUE ); - pSprite->AnimateAndDie( RANDOM_FLOAT( 15.0, 20.0 ) ); - pSprite->SetTransparency( kRenderTransAlpha, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, 255, kRenderFxNone ); - pSprite->pev->velocity.z = RANDOM_FLOAT(40, 80); - pSprite->SetScale( m_spriteScale ); - } - if ( m_iszSpriteFlash ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteFlash), barrelEnd, TRUE ); - pSprite->AnimateAndDie( 60 ); - pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); - pSprite->SetScale( m_spriteScale ); - } - UTIL_FireTargets( pev->target, this, this, USE_TOGGLE ); - } - m_fireLast = gpGlobals->time; -} - -void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ) -{ - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - Vector vecDir = vecForward + - x * vecSpread.x * gpGlobals->v_right + - y * vecSpread.y * gpGlobals->v_up; - Vector vecEnd; - - vecEnd = vecStart + vecDir * 4096; - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &tr ); -} - - -void CFuncTank::StartRotSound( void ) -{ - if ( !pev->noise || (pev->spawnflags & SF_TANK_SOUNDON) ) - return; - pev->spawnflags |= SF_TANK_SOUNDON; - EMIT_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise), 0.85, ATTN_NORM); -} - - -void CFuncTank::StopRotSound( void ) -{ - if ( pev->spawnflags & SF_TANK_SOUNDON ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise) ); - pev->spawnflags &= ~SF_TANK_SOUNDON; -} - -//============================================================================ -// FUNC TANK -//============================================================================ -class CFuncTankGun : public CFuncTank -{ -public: - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tank, CFuncTankGun ); - -void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - // FireBullets needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - switch( m_bulletType ) - { - case TANK_BULLET_9MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_9MM, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_MP5: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MP5, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_12MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_12MM, 1, m_iBulletDamage, pevAttacker ); - break; - - default: - case TANK_BULLET_NONE: - break; - } - } - CFuncTank::Fire( barrelEnd, forward, pevAttacker ); - } - } - else CFuncTank::Fire( barrelEnd, forward, pevAttacker ); -} - - -//============================================================================ -// FUNC TANK LASER -//============================================================================ -class CFuncTankLaser : public CFuncTank -{ -public: - void Activate( void ); - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - BOOL IsLaserTank( void ) { return TRUE; } - void Think( void ); - void PostActivate( void ); - void PostSpawn( void ); - CLaser *GetLaser( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - CLaser *m_pLaser; - float m_laserTime; -}; -LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ); - -TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankLaser, m_pLaser, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTankLaser, m_laserTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ); - -void CFuncTankLaser::Activate( void ) -{ - if ( !GetLaser() ) - { - UTIL_Remove(this); - Msg( "Error: Laser tank with no env_laser!\n" ); - } - else - { - m_pLaser->TurnOff(); - } - CFuncTank::Activate(); -} - -void CFuncTankLaser::PostSpawn( void ) -{ - CFuncTank::PostSpawn(); - - if(m_barrelPos == g_vecZero) //check for custom barrelend - { - if(GetLaser()) m_barrelPos = m_pLaser->pev->origin - pev->origin; //write offset - else m_barrelPos = Vector( fabs(pev->absmax.x), 0, 0 ); //write default - m_sightOrigin = BarrelPosition(); // Point at the end of the barrel - } -} - -void CFuncTankLaser::PostActivate( void ) -{ - //set laser parent once only - if(m_pLaser && m_pLaser->m_pParent != this) - { - m_pLaser->SetParent( this ); - } -} - -void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "laserentity")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CFuncTank::KeyValue( pkvd ); -} - - -CLaser *CFuncTankLaser::GetLaser( void ) -{ - if ( m_pLaser ) return m_pLaser; - - CBaseEntity *pEntity; - - pEntity = UTIL_FindEntityByTargetname( NULL, STRING(pev->message) ); - while ( pEntity ) - { - // Found the laser - if ( FClassnameIs( pEntity->pev, "env_laser" ) ) - { - m_pLaser = (CLaser *)pEntity; - m_pLaser->pev->angles = pev->angles; //copy tank angles - break; - } - else pEntity = UTIL_FindEntityByTargetname( pEntity, STRING(pev->message) ); - } - - return m_pLaser; -} - - -void CFuncTankLaser::Think( void ) -{ - if ( m_pLaser && m_pLaser->GetState() == STATE_ON && (gpGlobals->time > m_laserTime)) - m_pLaser->TurnOff(); - CFuncTank::Think(); -} - -void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - TraceResult tr; - - if ( m_fireLast != 0 && GetLaser() ) - { - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount ) - { - for ( i = 0; i < bulletCount; i++ ) - { - m_pLaser->pev->origin = barrelEnd; - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - m_laserTime = gpGlobals->time + 0.1; - m_pLaser->TurnOn(); - m_pLaser->pev->dmgtime = gpGlobals->time - 1.0; - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else CFuncTank::Fire( barrelEnd, forward, pev ); - -} - -//============================================================================ -// FUNC TANK ROCKET -//============================================================================ -class CFuncTankRocket : public CFuncTank -{ -public: - void Precache( void ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - BOOL IsRocketTank( void ) { return TRUE; } -}; -LINK_ENTITY_TO_CLASS( func_tankrocket, CFuncTankRocket ); - -void CFuncTankRocket::Precache( void ) -{ - UTIL_PrecacheEntity( "rpg_rocket" ); - CFuncTank::Precache(); -} - -void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - CBaseEntity *pRocket = CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else CFuncTank::Fire( barrelEnd, forward, pev ); -} - -//============================================================================ -// FUNC TANK MORTAR -//============================================================================ -class CFuncTankMortar : public CFuncTank -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ); - - -void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iMagnitude")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CFuncTank::KeyValue( pkvd ); -} - - -void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - // Only create 1 explosion - if ( bulletCount > 0 ) - { - TraceResult tr; - - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - UTIL_Explode( tr.vecEndPos, edict(), pev->impulse ); - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else CFuncTank::Fire( barrelEnd, forward, pev ); -} - - -//============================================================================ -// FUNC TANK CONTROLS -//============================================================================ -void CFuncTankControls::Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NODRAW; - UTIL_SetModel( ENT(pev), pev->model ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( this, pev->origin ); -} - -void CFuncTankControls :: KeyValue( KeyValueData *pkvd ) -{ - if ( m_cTanks < MAX_MULTI_TARGETS ) - { - // add this field to the target list - // this assumes that additional fields are targetnames and their values are delay values. - - char tmp[128]; - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iTankName[ m_cTanks ] = ALLOC_STRING( tmp ); - m_cTanks++; - pkvd->fHandled = TRUE; - } -} - -TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankControls, m_pController, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTankControls, m_vecControllerUsePos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTankControls, m_cTanks, FIELD_INTEGER ), - DEFINE_ARRAY( CFuncTankControls, m_iTankName, FIELD_STRING, MAX_MULTI_TARGETS ), -}; -IMPLEMENT_SAVERESTORE( CFuncTankControls, CBaseEntity ); - -BOOL CFuncTankControls :: OnControls( entvars_t *pevTest ) -{ - Vector offset = pevTest->origin - pev->origin; - - if (m_pParent) - { - if ( ((m_vecControllerUsePos + m_pParent->pev->origin) - pevTest->origin).Length() <= 30 ) - return TRUE; - } - else if ( (m_vecControllerUsePos - pevTest->origin).Length() <= 30 ) return TRUE; - return FALSE; -} - -void CFuncTankControls :: HandleTank ( CBaseEntity *pActivator, CBaseEntity *pTank, BOOL activate ) -{ - if( !strncmp( STRING( pTank->pev->classname ), "func_tank", 9 )) - { - if( activate ) - { - if( (( CFuncTank *)pTank)->StartControl(( CBasePlayer *)pActivator, this )) - { - m_iState = STATE_ON; //we have active tank! - } - } - else (( CFuncTank *)pTank)->StopControl( this ); - } -} - -void CFuncTankControls :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *tryTank = NULL; - if ( useType == USE_SHOWINFO) - { - DEBUGHEAD; - return; - } - - if ( !m_pController && useType != USE_OFF ) - { - if (!pActivator || !(pActivator->IsPlayer())) return; - if (m_iState != STATE_OFF || ((CBasePlayer*)pActivator)->m_pTank != NULL) return; - - //find all specified tanks - for(int i = 0; i < m_cTanks; i++) - { - //find all tanks with current name - while( tryTank = UTIL_FindEntityByTargetname(tryTank, STRING(m_iTankName[i]))) - { - HandleTank( pActivator, tryTank, TRUE ); - } - } - if (m_iState == STATE_ON) - { - // we found at least one tank to use, so holster player's weapon - m_pController = (CBasePlayer*)pActivator; - m_pController->m_pTank = this; - if ( m_pController->m_pActiveItem ) - { - m_pController->m_pActiveItem->Holster(); - m_pController->pev->weaponmodel = 0; - //viewmodel reset in tank - } - m_pController->m_iHideHUD |= HIDEHUD_WEAPONS; - - if (m_pParent) - m_vecControllerUsePos = m_pController->pev->origin - m_pParent->pev->origin; - else m_vecControllerUsePos = m_pController->pev->origin; - } - } - else if (m_pController && useType != USE_ON) - { - //find all specified tanks - for(int i = 0; i < m_cTanks; i++) - { - //find all tanks with current name - while( tryTank = UTIL_FindEntityByTargetname(tryTank, STRING(m_iTankName[i]))) - { - HandleTank( pActivator, tryTank, FALSE ); - } - } - - // bring back player's weapons - if ( m_pController->m_pActiveItem ) m_pController->m_pActiveItem->Deploy(); - - m_pController->m_iHideHUD &= ~HIDEHUD_WEAPONS; - m_pController->m_pTank = NULL; - - m_pController = NULL; - m_iState = STATE_OFF; - } - -} - -LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ); \ No newline at end of file diff --git a/server/ents/basetank.h b/server/ents/basetank.h deleted file mode 100644 index 828dd6a2..00000000 --- a/server/ents/basetank.h +++ /dev/null @@ -1,143 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#define SF_TANK_ACTIVE 0x0001 -#define SF_TANK_LINEOFSIGHT 0x0010 -#define SF_TANK_CANCONTROL 0x0020 -#define SF_TANK_LASERSPOT 0x0040 //LRC -#define SF_TANK_MATCHTARGET 0x0080 //LRC -#define SF_TANK_SOUNDON 0x8000 -#define SF_TANK_SEQFIRE 0x10000 //LRC - a TankSequence is telling me to fire - -static Vector gTankSpread[] = -{ - Vector( 0, 0, 0 ), // perfect - Vector( 0.025, 0.025, 0.025 ), // small cone - Vector( 0.05, 0.05, 0.05 ), // medium cone - Vector( 0.1, 0.1, 0.1 ), // large cone - Vector( 0.25, 0.25, 0.25 ), // extra-large cone -}; -#define MAX_FIRING_SPREADS ARRAYSIZE(gTankSpread) - -enum TANKBULLET -{ - TANK_BULLET_NONE = 0, - TANK_BULLET_9MM = 1, - TANK_BULLET_MP5 = 2, - TANK_BULLET_12MM = 3, -}; - -class CFuncTankControls; -class CFuncTank : public CBaseBrush -{ -public: - void Spawn( void ); - void PostSpawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void TrackTarget( void ); - int IRelationship( CBaseEntity* pTarget ); - int Classify( void ) { return m_iTankClass; } - - void TryFire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - virtual void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - virtual Vector UpdateTargetPosition( CBaseEntity *pTarget ) - { - return pTarget->BodyTarget( pev->origin ); - } - - void StartRotSound( void ); - void StopRotSound( void ); - - inline BOOL IsActive( void ) { return (pev->spawnflags & SF_TANK_ACTIVE)?TRUE:FALSE; } - inline void TankActivate( void ) { pev->spawnflags |= SF_TANK_ACTIVE; SetNextThink(0.1); m_fireLast = 0; } - inline void TankDeactivate( void ) { pev->spawnflags &= ~SF_TANK_ACTIVE; m_fireLast = 0; StopRotSound(); } - inline BOOL CanFire( void ) { return (gpGlobals->time - m_lastSightTime) < m_persist; } - BOOL InRange( float range ); - void TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ); - - Vector BarrelPosition( void ) - { - Vector forward, right, up; - UTIL_MakeVectorsPrivate( pev->angles, forward, right, up ); - return pev->origin + (forward * m_barrelPos.x) + (right * m_barrelPos.y) + (up * m_barrelPos.z); - } - - void AdjustAnglesForBarrel( Vector &angles, float distance ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void UpdateSpot( void ); - BOOL StartControl( CBasePlayer* pController, CFuncTankControls* pControls ); - void StopControl( CFuncTankControls* pControls ); - - CBaseEntity* BestVisibleEnemy( void ); - CFuncTankControls* m_pControls; // tankcontrols is used as a go-between. - CLaserSpot* m_pSpot; // Laser spot entity - - virtual BOOL IsRocketTank( void ) { return FALSE; } - virtual BOOL IsLaserTank( void ) { return FALSE; } - -protected: - float m_flNextAttack; - - float m_yawCenter; // "Center" yaw - float m_yawRate; // Max turn rate to track targets - float m_yawRange; // Range of turning motion (one-sided: 30 is +/- 30 degress from center) - // Zero is full rotation - float m_yawTolerance; // Tolerance angle - - float m_pitchCenter; // "Center" pitch - float m_pitchRate; // Max turn rate on pitch - float m_pitchRange; // Range of pitch motion as above - float m_pitchTolerance; // Tolerance angle - - float m_lastSightTime;// Last time I saw target - float m_persist; // Persistence of firing (how long do I shoot when I can't see) - RandomRange m_Range; - float m_minRange; // Minimum range to aim/track - float m_maxRange; // Max range to aim/track - float m_fireLast; // Last time I fired - float m_fireRate; // How many rounds/second - - Vector m_barrelPos; // Length of the freakin barrel - float m_spriteScale; // Scale of any sprites we shoot - int m_iszSpriteSmoke; - int m_iszSpriteFlash; - TANKBULLET m_bulletType; // Bullet type - int m_iBulletDamage; // 0 means use Bullet type's default damage - - Vector m_sightOrigin; // Last sight of target - int m_spread; // firing spread - int m_iszMaster; // Master entity - int m_iszFireMaster;//LRC - Fire-Master entity (prevents firing when inactive) - - int m_iTankClass; // Behave As -}; - -class CFuncTankControls : public CBaseLogic -{ -public: - virtual int ObjectCaps( void ) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; } - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - void HandleTank ( CBaseEntity *pActivator, CBaseEntity *m_pTank, BOOL activate ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - BOOL OnControls( entvars_t *pevTest ); - - Vector m_vecControllerUsePos; // where was the player standing when he used me? - - CBasePlayer* m_pController; - //max 32 tanks allowed to control - int m_iTankName [ MAX_MULTI_TARGETS ];// list if indexes into global string array - int m_cTanks;// the total number of targets in this manager's fire list. - EHANDLE m_hPlayer; -}; \ No newline at end of file diff --git a/server/ents/basetrain.cpp b/server/ents/basetrain.cpp deleted file mode 100644 index 94b1a4ba..00000000 --- a/server/ents/basetrain.cpp +++ /dev/null @@ -1,1074 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "sfx.h" -#include "cbase.h" -#include "basebeams.h" -#include "baseweapon.h" -#include "monsters.h" -#include "defaults.h" -#include "player.h" - -// Tracktrain spawn flags -#define SF_TRACKTRAIN_NOPITCH 0x0001 -#define SF_TRACKTRAIN_NOCONTROL 0x0002 -#define SF_TRACKTRAIN_FORWARDONLY 0x0004 -#define SF_TRACKTRAIN_PASSABLE 0x0008 -#define SF_TRACKTRAIN_NOYAW 0x0010 //LRC -#define SF_TRACKTRAIN_AVELOCITY 0x800000 //LRC - avelocity has been set manually, don't turn. -#define SF_TRACKTRAIN_AVEL_GEARS 0x400000 //LRC - avelocity should be scaled up/down when the train changes gear. - -// Spawnflag for CPathTrack -#define SF_PATH_DISABLED 0x00000001 -#define SF_PATH_FIREONCE 0x00000002 -#define SF_PATH_ALTREVERSE 0x00000004 -#define SF_PATH_DISABLE_TRAIN 0x00000008 -#define SF_PATH_ALTERNATE 0x00008000 -#define SF_PATH_AVELOCITY 0x00080000 //LRC - -//LRC - values in 'armortype' -#define PATHSPEED_SET 0 -#define PATHSPEED_ACCEL 1 -#define PATHSPEED_TIME 2 -#define PATHSPEED_SET_MASTER 3 - - -//#define PATH_SPARKLE_DEBUG 1 // This makes a particle effect around path_track entities for debugging -class CPathTrack : public CPointEntity -{ -public: - void Spawn( void ); - void Activate( void ); - void KeyValue( KeyValueData* pkvd); - - void SetPrevious( CPathTrack *pprevious ); - void Link( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - CBaseEntity *ValidPath( CBaseEntity *ppath, int testFlag ); // Returns ppath if enabled, NULL otherwise - void Project( CBaseEntity *pstart, CBaseEntity *pend, Vector *origin, float dist ); - - static CPathTrack *Instance( edict_t *pent ); - - CBaseEntity *LookAhead( Vector *origin, float dist, int move ); - CBaseEntity *Nearest( Vector origin ); //notused - - CBaseEntity *GetNext( void ); - CBaseEntity *GetPrev( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; -#if PATH_SPARKLE_DEBUG - void EXPORT Sparkle(void); -#endif - - float m_length; - string_t m_altName; - CPathTrack *m_pnext; - CPathTrack *m_pprevious; - CPathTrack *m_paltpath; -}; - -class CFuncTrackTrain : public CBaseMover -{ -public: - void Spawn( void ); - void Precache( void ); - - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData* pkvd ); - - void EXPORT DesiredAction( void ); //LRC - used to be called Next! - void PostActivate( void ); - void ClearPointers( void ); - -// void EXPORT Next( void ); - void EXPORT PostponeNext( void ); - void EXPORT Find( void ); - void EXPORT NearestPath( void ); - void EXPORT DeadEnd( void ); - - void NextThink( float thinkTime, BOOL alwaysThink ); - - void SetTrack( CBaseEntity *track ) { pPath = ((CPathTrack *)track)->Nearest(pev->origin); } - void SetControls( entvars_t *pevControls ); - BOOL OnControls( entvars_t *pev ); - - void StopSound ( void ); - void UpdateSound ( void ); - - static CFuncTrackTrain *Instance( edict_t *pent ) - { - if ( FClassnameIs( pent, "func_tracktrain" ) ) - return (CFuncTrackTrain *)GET_PRIVATE(pent); - return NULL; - } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return CBaseMover :: ObjectCaps() | FCAP_DIRECTIONAL_USE; } - - virtual void OverrideReset( void ); - - CBaseEntity *pPath; - float m_length; - float m_height; - // I get it... this records the train's max speed (as set by the level designer), whereas - // pev->speed records the current speed (as set by the player). --LRC - // m_speed is also stored, as an int, in pev->impulse. - float m_speed; - float m_dir; - float m_startSpeed; - Vector m_controlMins; - Vector m_controlMaxs; - int m_soundPlaying; - float m_flBank; - float m_oldSpeed; - Vector m_vecBaseAvel; // LRC - the underlying avelocity, superceded by normal turning behaviour where applicable -}; - -TYPEDESCRIPTION CPathTrack::m_SaveData[] = -{ - DEFINE_FIELD( CPathTrack, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CPathTrack, m_pnext, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_paltpath, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_pprevious, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_altName, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CPathTrack, CBaseEntity ); -LINK_ENTITY_TO_CLASS( path_track, CPathTrack ); - -// -// Cache user-entity-field values until spawn is called. -// -void CPathTrack :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "altpath")) - { - m_altName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "turnspeed")) //LRC - { - if (pkvd->szValue[0]) // if the field is blank, don't set the spawnflag. - { - pev->spawnflags |= SF_PATH_AVELOCITY; - UTIL_StringToVector( (float*)pev->avelocity, pkvd->szValue); - } - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int on; - - // Use toggles between two paths - if ( m_paltpath ) - { - on = !FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ); - if (useType == USE_TOGGLE) - { - if(on) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON)ClearBits( pev->spawnflags, SF_PATH_ALTERNATE ); - else if(useType == USE_OFF)SetBits( pev->spawnflags, SF_PATH_ALTERNATE ); - } - else // Use toggles between enabled/disabled - { - on = !FBitSet( pev->spawnflags, SF_PATH_DISABLED ); - if (useType == USE_TOGGLE) - { - if(on) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON)ClearBits( pev->spawnflags, SF_PATH_DISABLED ); - else if(useType == USE_OFF)SetBits( pev->spawnflags, SF_PATH_DISABLED ); - } -} - - -void CPathTrack :: Link( void ) -{ - CBaseEntity *pTarget; - - if ( !FStringNull(pev->target) ) - { - pTarget = UTIL_FindEntityByTargetname( NULL, STRING(pev->target) ); - if ( pTarget ) - { - m_pnext = (CPathTrack*)pTarget; - m_pnext->SetPrevious( this ); - } - else - ALERT( at_console, "Dead end link %s\n", STRING(pev->target) ); - } - - // Find "alternate" path - if ( m_altName ) - { - pTarget = UTIL_FindEntityByTargetname( NULL, STRING(m_altName) ); - if ( pTarget ) // If no next pointer, this is the end of a path - { - m_paltpath = (CPathTrack*)pTarget; - m_paltpath->SetPrevious( this ); - } - } -} - - -void CPathTrack :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - - m_pnext = NULL; - m_pprevious = NULL; -// DEBUGGING CODE -#if PATH_SPARKLE_DEBUG - SetThink( Sparkle ); - SetNextThink( 0.5 ); -#endif -} - - -void CPathTrack::Activate( void ) -{ - if ( !FStringNull( pev->targetname ) ) // Link to next, and back-link - Link(); - - CPointEntity::Activate(); -} - -CBaseEntity *CPathTrack :: ValidPath( CBaseEntity *ppath, int testFlag ) -{ - if ( !ppath ) - return NULL; - - if ( testFlag && FBitSet( ppath->pev->spawnflags, SF_PATH_DISABLED ) ) - return NULL; - - return ppath; -} - - -void CPathTrack :: Project( CBaseEntity *pstart, CBaseEntity *pend, Vector *origin, float dist ) -{ - if ( pstart && pend ) - { - Vector dir = (pend->pev->origin - pstart->pev->origin); - dir = dir.Normalize(); - *origin = pend->pev->origin + dir * dist; - } -} - -CBaseEntity *CPathTrack::GetNext( void ) -{ - if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) - return m_paltpath; - - return m_pnext; -} - - - -CBaseEntity *CPathTrack::GetPrev( void ) -{ - if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) - return m_paltpath; - - return m_pprevious; -} - - - -void CPathTrack::SetPrevious( CPathTrack *pprev ) -{ - // Only set previous if this isn't my alternate path - if ( pprev && !FStrEq( STRING(pprev->pev->targetname), STRING(m_altName) ) ) - m_pprevious = pprev; -} - - -// Assumes this is ALWAYS enabled -CBaseEntity *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) -{ - CBaseEntity *pcurrent; - float originalDist = dist; - - pcurrent = this; - Vector currentPos = *origin; - - if ( dist < 0 ) // Travelling backwards through path - { - dist = -dist; - while ( dist > 0 ) - { - Vector dir = pcurrent->pev->origin - currentPos; - float length = dir.Length(); - if ( !length ) - { - if ( !ValidPath(pcurrent->GetPrev(), move) ) // If there is no previous node, or it's disabled, return now. - { - if ( !move ) - Project( pcurrent->GetNext(), pcurrent, origin, dist ); - return NULL; - } - pcurrent = pcurrent->GetPrev(); - } - else if ( length > dist ) // enough left in this path to move - { - *origin = currentPos + (dir * (dist / length)); - return pcurrent; - } - else - { - dist -= length; - currentPos = pcurrent->pev->origin; - *origin = currentPos; - if ( !ValidPath(pcurrent->GetPrev(), move) ) // If there is no previous node, or it's disabled, return now. - return NULL; - - pcurrent = pcurrent->GetPrev(); - } - } - *origin = currentPos; - return pcurrent; - } - else - { - while ( dist > 0 ) - { - if ( !ValidPath(pcurrent->GetNext(), move) ) // If there is no next node, or it's disabled, return now. - { - if ( !move ) - Project( pcurrent->GetPrev(), pcurrent, origin, dist ); - return NULL; - } - Vector dir = pcurrent->GetNext()->pev->origin - currentPos; - float length = dir.Length(); - if ( !length && !ValidPath( pcurrent->GetNext()->GetNext(), move ) ) - { - if ( dist == originalDist ) // HACK -- up against a dead end - return NULL; - return pcurrent; - } - if ( length > dist ) // enough left in this path to move - { - *origin = currentPos + (dir * (dist / length)); - return pcurrent; - } - else - { - dist -= length; - currentPos = pcurrent->GetNext()->pev->origin; - pcurrent = pcurrent->GetNext(); - *origin = currentPos; - } - } - *origin = currentPos; - } - - return pcurrent; -} - - -// Assumes this is ALWAYS enabled -CBaseEntity *CPathTrack :: Nearest( Vector origin ) -{ - int deadCount; - float minDist, dist; - Vector delta; - CBaseEntity *ppath, *pnearest; - - - delta = origin - pev->origin; - delta.z = 0; - minDist = delta.Length(); - pnearest = this; - ppath = GetNext(); - - // Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :) - deadCount = 0; - while ( ppath && ppath != this ) - { - deadCount++; - if ( deadCount > 9999 ) - { - ALERT( at_error, "Bad sequence of path_tracks from %s", STRING(pev->targetname) ); - return NULL; - } - delta = origin - ppath->pev->origin; - delta.z = 0; - dist = delta.Length(); - if ( dist < minDist ) - { - minDist = dist; - pnearest = ppath; - } - ppath = ppath->GetNext(); - } - return pnearest; -} - - -CPathTrack *CPathTrack::Instance( edict_t *pent ) -{ - if ( FClassnameIs( pent, "path_track" ) ) - return (CPathTrack *)GET_PRIVATE(pent); - return NULL; -} - - - // DEBUGGING CODE -#if PATH_SPARKLE_DEBUG -void CPathTrack :: Sparkle( void ) -{ - - SetNextThink( 0.2 ); - if ( FBitSet( pev->spawnflags, SF_PATH_DISABLED ) ) - UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 210, 10); - else - UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 84, 10); -} -#endif - -//======================================================================= -// func_tracktrain (controllable train) -//======================================================================= -void CFuncTrackTrain :: Precache( void ) -{ - CBaseBrush::Precache();//precache damage sound - - int m_sounds = UTIL_LoadSoundPreset(m_iMoveSound); - switch (m_sounds) - { - case 1: pev->noise = UTIL_PrecacheSound("plats/ttrain1.wav");break; - case 2: pev->noise = UTIL_PrecacheSound("plats/ttrain2.wav");break; - case 3: pev->noise = UTIL_PrecacheSound("plats/ttrain3.wav");break; - case 4: pev->noise = UTIL_PrecacheSound("plats/ttrain4.wav");break; - case 5: pev->noise = UTIL_PrecacheSound("plats/ttrain6.wav");break; - case 6: pev->noise = UTIL_PrecacheSound("plats/ttrain7.wav");break; - default: pev->noise = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStopSound); - switch (m_sounds) - { - case 1: pev->noise1 = UTIL_PrecacheSound("plats/ttrain_brake1.wav");break; - default: pev->noise1 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } - - m_sounds = UTIL_LoadSoundPreset(m_iStartSound); - switch (m_sounds) - { - case 1: pev->noise2 = UTIL_PrecacheSound("plats/ttrain_start1.wav");break; - default: pev->noise2 = UTIL_PrecacheSound(m_sounds); break;//custom sound or sentence - } -} - -void CFuncTrackTrain :: Spawn( void ) -{ - if ( pev->speed == 0 ) m_speed = 100; - else m_speed = pev->speed; - pev->speed = 0; - pev->velocity = g_vecZero; - m_vecBaseAvel = pev->avelocity; //LRC - save it for later - pev->avelocity = g_vecZero; - pev->impulse = m_speed; - m_dir = 1; - - if ( FStringNull(pev->target) ) Msg("Warning: %s with no target!\n", STRING(pev->classname)); - - //if ( pev->spawnflags & SF_NOTSOLID ) pev->solid = SOLID_NOT; - if ( pev->spawnflags & 8 ) pev->solid = SOLID_NOT; //temp solution - else pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - SetBits (pFlags, PF_ANGULAR); - UTIL_SetModel( ENT(pev), pev->model ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( this, pev->origin ); - pev->oldorigin = pev->origin; // Cache off placed origin for train controls - - m_controlMins = pev->mins; - m_controlMaxs = pev->maxs; - m_controlMaxs.z += 72; - - NextThink( 0.1, FALSE ); - SetThink( Find ); - Precache(); -} - -void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) -{ - if ( alwaysThink ) pev->flags |= FL_ALWAYSTHINK; - else pev->flags &= ~FL_ALWAYSTHINK; - SetNextThink( thinkTime, TRUE ); -} - -void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) -{ - // Blocker is on-ground on the train - if ( FBitSet( pOther->pev->flags, FL_ONGROUND ) && VARS(pOther->pev->groundentity) == pev ) - { - float deltaSpeed = fabs(pev->speed); - if ( deltaSpeed > 50 ) deltaSpeed = 50; - if ( !pOther->pev->velocity.z ) pOther->pev->velocity.z += deltaSpeed; - return; - } - else pOther->pev->velocity = (pOther->pev->origin - pev->origin ).Normalize() * pev->dmg; - if ( pev->dmg <= 0 ) return;// we can't hurt this thing, so we're not concerned with it - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); -} - -void CFuncTrackTrain::OverrideReset( void ) -{ - NextThink( 0.1, FALSE ); - SetThink( NearestPath ); -} - -void CFuncTrackTrain :: Find( void ) -{ - pPath = (CPathTrack*)UTIL_FindEntityByTargetname( NULL, STRING(pev->target) ); - if ( !pPath ) return; - - entvars_t *pevTarget = pPath->pev; - if ( !FClassnameIs( pevTarget, "path_track" ) ) - { - ALERT( at_error, "func_track_train must be on a path of path_track\n" ); - pPath = NULL; - return; - } - - Vector nextPos = pevTarget->origin; - nextPos.z += m_height; - - Vector look = nextPos; - look.z -= m_height; - ((CPathTrack *)pPath)->LookAhead( &look, m_length, 0 ); - look.z += m_height; - - Vector vTemp = UTIL_VecToAngles( look - nextPos ); - vTemp.y += 180; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) - { - vTemp.x = 0; - //pev->angles.x = 0; - } - - UTIL_AssignAngles(this, vTemp); - UTIL_AssignOrigin ( this, nextPos ); - - NextThink( 0.1, FALSE ); - SetThink( PostponeNext ); - pev->speed = m_startSpeed; - - UpdateSound(); -} - -TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrackTrain, pPath, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTrackTrain, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_speed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_dir, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_startSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMins, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMaxs, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_flBank, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_oldSpeed, FIELD_FLOAT ), -}; -IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseMover ); - - -void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wheels")) - { - m_length = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_height = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "startspeed")) - { - m_startSpeed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_iMoveSound = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bank")) - { - m_flBank = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseMover::KeyValue( pkvd ); -} - - - - - -void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ -// ALERT(at_console, "TRAIN: use\n"); - - m_hActivator = pActivator; //AJH - - if (useType == USE_TOGGLE) - { - if(pev->speed != 0) useType = USE_OFF;//temp solution - else useType = USE_ON; - } - if (useType == USE_ON) - { - pev->speed = m_speed * m_dir; - PostponeNext(); - } - else if ( useType == USE_OFF ) - { - pev->speed = 0; - UTIL_SetVelocity(this, g_vecZero); //LRC - UTIL_SetAvelocity(this, g_vecZero); //LRC - StopSound(); - SetThink( NULL ); - } - else if ( useType == USE_SET ) - { - float delta = value; - - delta = ((int)(pev->speed * 4) / (int)m_speed)*0.25 + 0.25 * delta; - if ( delta > 1 ) - delta = 1; - else if ( delta < -1 ) - delta = -1; - if ( pev->spawnflags & SF_TRACKTRAIN_FORWARDONLY ) - { - if ( delta < 0 )delta = 0; - } - pev->speed = m_speed * delta; - - if(pev->speed == 0) - { - UTIL_SetVelocity(this, g_vecZero); - UTIL_SetAvelocity(this, g_vecZero); - StopSound(); - SetThink( NULL ); - } - if(pPath == NULL) - { - delta = 0; //G-Cont. Set speed to 0, and don't controls, if tracktrain on trackchange - return; - } - PostponeNext(); - ALERT( at_aiconsole, "TRAIN(%s), speed to %.2f\n", STRING(pev->targetname), pev->speed ); - } -} - -#define TRAIN_STARTPITCH 60 -#define TRAIN_MAXPITCH 200 -#define TRAIN_MAXSPEED 1000 // approx max speed for sound pitch calculation - -void CFuncTrackTrain :: StopSound( void ) -{ - // if sound playing, stop it - if (m_soundPlaying && pev->noise) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100); - } - - m_soundPlaying = 0; -} - -void CFuncTrackTrain :: UpdateSound( void ) -{ - float flpitch; - - if (!pev->noise) - return; - - flpitch = TRAIN_STARTPITCH + (abs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); - - if (!m_soundPlaying) - { - // play startup sound for train - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100); - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, (int) flpitch); - m_soundPlaying = 1; - } - else - { - // update pitch - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int) flpitch); - } -} - -void CFuncTrackTrain::ClearPointers( void ) -{ - CBaseEntity::ClearPointers(); - pPath = NULL; -} - -void CFuncTrackTrain :: PostActivate( void ) -{ -} -void CFuncTrackTrain :: PostponeNext( void ) -{ - UTIL_SetAction( this ); -} - -void CFuncTrackTrain :: DesiredAction( void ) // Next( void ) -{ - float time = 0.5; - - if ( !pev->speed ) - { - UTIL_SetVelocity(this, g_vecZero); - DontThink(); - ALERT( at_aiconsole, "TRAIN(%s): Speed is 0\n", STRING(pev->targetname) ); - StopSound(); - return; - } - - if ( !pPath ) - { - UTIL_SetVelocity(this, g_vecZero); - DontThink(); - ALERT( at_aiconsole, "TRAIN(%s): Lost path\n", STRING(pev->targetname) ); - StopSound(); - return; - } - - UpdateSound(); - - Vector nextPos = pev->origin; - - nextPos.z -= m_height; - CBaseEntity *pnext = ((CPathTrack *)pPath)->LookAhead( &nextPos, pev->speed * 0.1, 1 ); - nextPos.z += m_height; - - UTIL_SetVelocity( this, (nextPos - pev->origin) * 10 ); //LRC - Vector nextFront = pev->origin; - - nextFront.z -= m_height; - if ( m_length > 0 ) - ((CPathTrack *)pPath)->LookAhead( &nextFront, m_length, 0 ); - else - ((CPathTrack *)pPath)->LookAhead( &nextFront, 100, 0 ); - nextFront.z += m_height; - - Vector delta = nextFront - pev->origin; - - Vector angles = UTIL_VecToAngles( delta ); - // The train actually points west - angles.y += 180; //LRC, FIXME: add a 'built facing' field. - - angles.fixangle(); - pev->angles.fixangle(); - - if ( !pnext || (delta.x == 0 && delta.y == 0) ) angles = pev->angles; - - float vy, vx, vz; - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOPITCH) ) vx = 10*UTIL_AngleDistance( angles.x, pev->angles.x ); - else vx = m_vecBaseAvel.x; - - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOYAW) ) vy = 10*UTIL_AngleDistance( angles.y, pev->angles.y ); - else vy = m_vecBaseAvel.y; - - if ( m_flBank != 0 ) - { - if ( pev->avelocity.y < -5 ) vz = UTIL_AngleDistance( UTIL_ApproachAngle( -m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else if ( pev->avelocity.y > 5 ) vz = UTIL_AngleDistance( UTIL_ApproachAngle( m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else vz = UTIL_AngleDistance( UTIL_ApproachAngle( 0, pev->angles.z, m_flBank*4 ), pev->angles.z) * 4; - } - else vz = m_vecBaseAvel.z; - UTIL_SetAvelocity(this, Vector(vx, vy, vz)); - - if ( pnext ) - { - if ( pnext != pPath ) - { - CBaseEntity *pFire; - if ( pev->speed >= 0 ) // check whether we're going forwards or backwards - pFire = pnext; - else - pFire = pPath; - - pPath = pnext; - // Fire the pass target if there is one - if ( pFire->pev->message ) - { - UTIL_FireTargets( pFire->pev->message, this, this, USE_TOGGLE ); - if ( FBitSet( pFire->pev->spawnflags, SF_PATH_FIREONCE ) ) - pFire->pev->message = 0; - } - - if ( pFire->pev->spawnflags & SF_PATH_DISABLE_TRAIN ) - pev->spawnflags |= SF_TRACKTRAIN_NOCONTROL; - - float setting = ((int)(pev->speed*4) / (int)m_speed) / 4.0; //LRC - one of { 1, 0.75, 0.5, 0.25, 0, ... -1 } - - CBaseEntity* pDest; //LRC - the path_track we're heading for, after pFire. - if (pev->speed > 0) - pDest = pFire->GetNext(); - else - pDest = pFire->GetPrev(); - - if ( pFire->pev->speed != 0) - { - //ALERT( at_console, "TrackTrain setting is %d / %d = %.2f\n", (int)(pev->speed*4), (int)m_speed, setting ); - - switch ( (int)(pFire->pev->armortype) ) - { - case PATHSPEED_SET: - // Don't override speed if under user control - if (pev->spawnflags & SF_TRACKTRAIN_NOCONTROL) - pev->speed = pFire->pev->speed; - ALERT( at_aiconsole, "TrackTrain %s speed set to %4.2f\n", STRING(pev->targetname), pev->speed ); - break; - case PATHSPEED_SET_MASTER: - m_speed = pFire->pev->speed; - pev->impulse = m_speed; - pev->speed = setting * m_speed; - ALERT( at_aiconsole, "TrackTrain %s master speed set to %4.2f\n", STRING(pev->targetname), pev->speed ); - break; - case PATHSPEED_ACCEL: - m_speed += pFire->pev->speed; - pev->impulse = m_speed; - pev->speed = setting * m_speed; - ALERT( at_aiconsole, "TrackTrain %s speed accel to %4.2f\n", STRING(pev->targetname), pev->speed ); - break; - case PATHSPEED_TIME: - float distance = (pev->origin - pDest->pev->origin).Length(); - //ALERT(at_console, "pFire=%s, distance=%.2f, ospeed=%.2f, nspeed=%.2f\n", STRING(pFire->pev->targetname), distance, pev->speed, distance / pFire->pev->speed); - m_speed = distance / pFire->pev->speed; - pev->impulse = m_speed; - pev->speed = setting * m_speed; - ALERT( at_aiconsole, "TrackTrain %s speed to %4.2f (timed)\n", STRING(pev->targetname), pev->speed ); - break; - } - } - //LRC- FIXME: add support, here, for a Teleport flag. - } - SetThink( PostponeNext ); - NextThink( time, TRUE ); - } - else // end of path, stop - { - Vector vecTemp; //LRC - StopSound(); - vecTemp = (nextPos - pev->origin); //LRC - - UTIL_SetAvelocity(this, g_vecZero); - float distance = vecTemp.Length(); //LRC - m_oldSpeed = pev->speed; - - - pev->speed = 0; - - // Move to the dead end - - // Are we there yet? - if ( distance > 0 ) - { - // no, how long to get there? - time = distance / m_oldSpeed; - UTIL_SetVelocity( this, vecTemp * (m_oldSpeed / distance) ); - SetThink( DeadEnd ); - NextThink( time, FALSE ); - } - else - { - UTIL_SetVelocity( this, vecTemp ); - DeadEnd(); - } - } -} - - -void CFuncTrackTrain::DeadEnd( void ) -{ - // Fire the dead-end target if there is one - CBaseEntity *pTrack, *pNext; - - pTrack = pPath; - - ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING(pev->targetname) ); - // Find the dead end path node - // HACKHACK -- This is bugly, but the train can actually stop moving at a different node depending on it's speed - // so we have to traverse the list to it's end. - if ( pTrack ) - { - if ( m_oldSpeed < 0 ) - { - do - { - pNext = ((CPathTrack *)pTrack)->ValidPath( pTrack->GetPrev(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - else - { - do - { - pNext = ((CPathTrack *)pTrack)->ValidPath( pTrack->GetNext(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - } - - UTIL_SetVelocity( this, g_vecZero ); - UTIL_SetAvelocity(this, g_vecZero ); - - if ( pTrack ) - { - ALERT( at_aiconsole, "at %s\n", STRING(pTrack->pev->targetname) ); - if ( pTrack->pev->netname ) - UTIL_FireTargets( pTrack->pev->netname, this, this, USE_TOGGLE ); - } -} - - -void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) -{ - Vector offset = pevControls->origin - pev->oldorigin; - - m_controlMins = pevControls->mins + offset; - m_controlMaxs = pevControls->maxs + offset; -} - - -BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) -{ - Vector offset = pevTest->origin - pev->origin; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - return FALSE; - - // Transform offset into local coordinates - UTIL_MakeVectors( pev->angles ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = -DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - if ( local.x >= m_controlMins.x && local.y >= m_controlMins.y && local.z >= m_controlMins.z && - local.x <= m_controlMaxs.x && local.y <= m_controlMaxs.y && local.z <= m_controlMaxs.z ) - return TRUE; - - return FALSE; -} - -void CFuncTrackTrain :: NearestPath( void ) -{ - CBaseEntity *pTrack = NULL; - CBaseEntity *pNearest = NULL; - float dist, closest; - - closest = 1024; - - while ((pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL) - { - // filter out non-tracks - if ( !(pTrack->pev->flags & (FL_CLIENT|FL_MONSTER)) && FClassnameIs( pTrack->pev, "path_track" ) ) - { - dist = (pev->origin - pTrack->pev->origin).Length(); - if ( dist < closest ) - { - closest = dist; - pNearest = pTrack; - } - } - } - - if ( !pNearest ) - { - ALERT( at_console, "Can't find a nearby track !!!\n" ); - SetThink(NULL); - return; - } - - ALERT( at_aiconsole, "TRAIN: %s, Nearest track is %s\n", STRING(pev->targetname), STRING(pNearest->pev->targetname) ); - // If I'm closer to the next path_track on this path, then it's my real path - pTrack = ((CPathTrack *)pNearest)->GetNext(); - if ( pTrack ) - { - if ( (pev->origin - pTrack->pev->origin).Length() < (pev->origin - pNearest->pev->origin).Length() ) - pNearest = pTrack; - } - - pPath = (CPathTrack *)pNearest; - - if ( pev->speed != 0 ) - { - NextThink( 0.1, FALSE ); - SetThink( PostponeNext ); - } -} -LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ); - -//======================================================================= -// volume of space that the player must stand in to control the train -//======================================================================= -class CFuncTrainControls : public CPointEntity -{ -public: - void Spawn( void ); - void PostSpawn( void ); -}; -LINK_ENTITY_TO_CLASS( func_traincontrols, CFuncTrainControls ); - -void CFuncTrainControls :: PostSpawn( void ) -{ - CBaseEntity *pTarget = NULL; - - do - { - pTarget = UTIL_FindEntityByTargetname( pTarget, STRING(pev->target) ); - } while ( pTarget && !FClassnameIs(pTarget->pev, "func_tracktrain") ); - - if ( !pTarget ) - { - ALERT( at_console, "TrackTrainControls: No train %s\n", STRING(pev->target) ); - return; - } - - CFuncTrackTrain *ptrain = (CFuncTrackTrain*)pTarget; - ptrain->SetControls( pev ); - UTIL_Remove( this ); -} - -void CFuncTrainControls :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - UTIL_SetModel( ENT(pev), pev->model ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( this, pev->origin ); -} \ No newline at end of file diff --git a/server/ents/basetrigger.cpp b/server/ents/basetrigger.cpp deleted file mode 100644 index 4ec8458a..00000000 --- a/server/ents/basetrigger.cpp +++ /dev/null @@ -1,938 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "player.h" -#include "baseweapon.h" - -//======================================================================= -// func_trigger - volume, that fire target when player in or out -//======================================================================= -#define SF_TRIGGER_ALLOWMONSTERS 1 // monsters allowed to fire this trigger -#define SF_TRIGGER_NOCLIENTS 2 // players not allowed to fire this trigger -#define SF_TRIGGER_PUSHABLES 4 // only pushables can fire this trigger - -class CBaseTrigger; -class CInOutRegister : public CPointEntity -{ -public: - BOOL IsRegistered ( CBaseEntity *pValue ); - CInOutRegister *Prune( void ); - CInOutRegister *Add( CBaseEntity *pValue ); - BOOL IsEmpty( void ) { return m_pNext ? FALSE:TRUE; }; - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CBaseTrigger *m_pField; - CInOutRegister *m_pNext; - EHANDLE m_hValue; -}; - -class CBaseTrigger : public CBaseLogic -{ -public: - void Spawn( void ); - void EXPORT Touch( CBaseEntity *pOther ); - void EXPORT Update( void ); - void EXPORT Remove( void ); //generic method for right delete trigger class - virtual void FireOnEntry( CBaseEntity *pOther ){} - virtual void FireOnLeave( CBaseEntity *pOther ){} - - BOOL CanTouch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - STATE GetState() { return m_pRegister->IsEmpty()? STATE_OFF : STATE_ON; } - CInOutRegister *m_pRegister; -}; -TYPEDESCRIPTION CBaseTrigger::m_SaveData[] = -{ DEFINE_FIELD( CBaseTrigger, m_pRegister, FIELD_CLASSPTR ), }; -IMPLEMENT_SAVERESTORE(CBaseTrigger, CBaseLogic); - -TYPEDESCRIPTION CInOutRegister::m_SaveData[] = -{ DEFINE_FIELD( CInOutRegister, m_pField, FIELD_CLASSPTR ), - DEFINE_FIELD( CInOutRegister, m_pNext, FIELD_CLASSPTR ), - DEFINE_FIELD( CInOutRegister, m_hValue, FIELD_EHANDLE ), -}; IMPLEMENT_SAVERESTORE(CInOutRegister,CPointEntity); -LINK_ENTITY_TO_CLASS( zoneent, CInOutRegister ); - -BOOL CInOutRegister::IsRegistered ( CBaseEntity *pValue ) -{ - if (m_hValue == pValue) return TRUE; - else if (m_pNext) return m_pNext->IsRegistered( pValue ); - else return FALSE; -} - -CInOutRegister *CInOutRegister::Add( CBaseEntity *pValue ) -{ - if (m_hValue == pValue) - { - // it's already in the list, don't need to do anything - return this; - } - else if (m_pNext) - { - // keep looking - m_pNext = m_pNext->Add( pValue ); - return this; - } - else - { - // reached the end of the list; add the new entry, and trigger - CInOutRegister *pResult = GetClassPtr( (CInOutRegister*)NULL ); - pResult->m_hValue = pValue; - pResult->m_pNext = this; - pResult->m_pField = m_pField; - pResult->pev->classname = MAKE_STRING("zoneent"); - m_pField->FireOnEntry( pValue ); - return pResult; - } -} - -CInOutRegister *CInOutRegister::Prune( void ) -{ - if ( m_hValue ) - { - ASSERTSZ(m_pNext != NULL, "invalid InOut registry terminator\n"); - if ( m_pField->Intersects(m_hValue) ) - { - // this entity is still inside the field, do nothing - m_pNext = m_pNext->Prune(); - return this; - } - else - { - // this entity has just left the field, trigger - m_pField->FireOnLeave( m_hValue ); - SetThink( Remove ); - SetNextThink( 0.1 ); - return m_pNext->Prune(); - } - } - else - { // this register has a missing or null value - if (m_pNext) - { - // this is an invalid list entry, remove it - SetThink( Remove ); - SetNextThink( 0.1 ); - return m_pNext->Prune(); - } - else - { - // this is the list terminator, leave it. - return this; - } - } -} - -void CBaseTrigger::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "offtarget")) - { - pev->netname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "modifier")) - { - pev->armorvalue = atof(pkvd->szValue) / 100.0; - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "roomtype" )) //for soundfx - { - pev->button = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "wait" )) // for trigger_push - { - m_flDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CBaseTrigger :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_NO; - UTIL_SetModel( ENT( pev ), pev->model ); // set size and link into world - SetObjectClass( ED_TRIGGER ); - - // create a null-terminator for the registry - m_pRegister = GetClassPtr(( CInOutRegister *)NULL ); - m_pRegister->m_hValue = NULL; - m_pRegister->m_pNext = NULL; - m_pRegister->m_pField = this; - m_pRegister->pev->classname = MAKE_STRING("zoneent"); - m_pRegister->SetObjectClass( ED_STATIC ); - - SetThink( Update ); -} - -BOOL CBaseTrigger :: CanTouch( CBaseEntity *pOther ) -{ - if ( gpGlobals->time < pev->dmgtime) return FALSE; - pev->dmgtime = gpGlobals->time + m_flWait; - - // Only touch clients, monsters, or pushables (depending on flags) - if (pOther->pev->flags & FL_CLIENT) return !(pev->spawnflags & SF_TRIGGER_NOCLIENTS); - else if (pOther->pev->flags & FL_MONSTER) return pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS; - else if (pOther->IsPushable()) return pev->spawnflags & SF_TRIGGER_PUSHABLES; - return FALSE; -} - -void CBaseTrigger :: Touch( CBaseEntity *pOther ) -{ - if (!CanTouch(pOther)) return; - m_hActivator = pOther; //save activator; - - m_pRegister = m_pRegister->Add(pOther); - if (m_fNextThink <= 0 && !m_pRegister->IsEmpty())SetNextThink( 0.1 ); -} - -void CBaseTrigger :: Update( void ) -{ - // Prune handles all Intersects tests and fires targets as appropriate - m_pRegister = m_pRegister->Prune(); - - if (m_pRegister->IsEmpty()) DontThink(); - else SetNextThink( 0.1 ); -} - -void CBaseTrigger :: Remove( void ) -{ - UTIL_Remove( m_pRegister ); - UTIL_Remove( this ); -} - -//======================================================================= -// trigger_mutiple - classic QUAKE trigger -//======================================================================= -class CTriggerMulti : public CBaseTrigger -{ - void FireOnEntry( CBaseEntity *pOther ) - { - if(!IsLockedByMaster(pOther)) - UTIL_FireTargets(pev->target, pOther, this, USE_TOGGLE ); - } - void FireOnLeave( CBaseEntity *pOther ) - { - if (!IsLockedByMaster(pOther)) - UTIL_FireTargets(pev->netname, pOther, this, USE_TOGGLE ); - } -}; -LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMulti ); - -//======================================================================= -// trigger_once - classic QUAKE trigger -//======================================================================= -class CTriggerOnce : public CBaseTrigger -{ - void FireOnEntry( CBaseEntity *pOther ) - { - if ( !IsLockedByMaster(pOther)) - { - UTIL_FireTargets( pev->target, pOther, this, USE_TOGGLE ); - SetThink( Remove ); - SetNextThink( 0 ); - } - } -}; -LINK_ENTITY_TO_CLASS( trigger_once, CTriggerOnce ); - -//======================================================================= -// trigger_autosave - game autosave -//======================================================================= -class CTriggerSave : public CBaseTrigger -{ - void FireOnEntry( CBaseEntity *pOther ) { SERVER_COMMAND( "autosave\n" ); } - void FireOnLeave( CBaseEntity *pOther ) - { - SetThink( Remove ); - SetNextThink( 0 ); - } -}; -LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ); - -//======================================================================= -// func_friction - game autosave -//======================================================================= -class CChangeFriction : public CBaseTrigger -{ - void Spawn( void ) - { - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - UTIL_SetModel(ENT(pev), pev->model ); - } - void Touch( CBaseEntity *pOther ) - { - if ( pOther->pev->movetype != 11 && pOther->pev->movetype != 10 ) - pOther->pev->friction = pev->armorvalue; - } -}; -LINK_ENTITY_TO_CLASS( func_friction, CChangeFriction ); - -#define SF_PUSH_ONCE 1 - -//======================================================================= -// trigger_push - triger that pushes player -//======================================================================= -class CTriggerPush : public CBaseTrigger -{ - void Spawn( void ) - { - if ( pev->angles == g_vecZero ) pev->angles.y = 360; - if (pev->speed == 0) pev->speed = 100; - UTIL_LinearVector( this ); - - if ( FBitSet (pev->spawnflags, 2) ) pev->solid = SOLID_NOT; - else pev->solid = SOLID_TRIGGER; - - pev->movetype = MOVETYPE_NONE; - UTIL_SetModel(ENT(pev), pev->model ); - SetBits( pev->effects, EF_NODRAW ); - UTIL_SetOrigin( this, pev->origin ); - } - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - if (pev->solid == SOLID_NOT) - { - pev->solid = SOLID_TRIGGER; - gpGlobals->force_retouch++; - } - else pev->solid = SOLID_NOT; - UTIL_SetOrigin( this, pev->origin ); - } - void Touch( CBaseEntity *pOther ) - { - switch( pOther->pev->movetype ) - { - case MOVETYPE_NONE: - case MOVETYPE_PUSH: - case MOVETYPE_NOCLIP: - case MOVETYPE_FOLLOW: - return; - } - - if ( pOther->pev->solid != SOLID_NOT && pOther->pev->solid != SOLID_BSP ) - { - // Instant trigger, just transfer velocity and remove - if (FBitSet(pev->spawnflags, 1)) - { - pOther->pev->velocity = pOther->pev->velocity + (pev->speed * pev->movedir); - if ( pOther->pev->velocity.z > 0 ) pOther->pev->flags &= ~FL_ONGROUND; - UTIL_Remove( this ); - } - else - { - Vector vecPush = (pev->speed * pev->movedir); - if ( pOther->pev->flags & FL_BASEVELOCITY ) - vecPush = vecPush + pOther->pev->basevelocity; - pOther->pev->basevelocity = vecPush; - pOther->pev->flags |= FL_BASEVELOCITY; - } - } - } -}; -LINK_ENTITY_TO_CLASS( trigger_push, CTriggerPush ); - -//======================================================================= -// trigger_gravity - classic HALF_LIFE gravity modifier -//======================================================================= -class CTriggerGravity : public CBaseTrigger -{ - void FireOnEntry( CBaseEntity *pOther ) { pOther->pev->gravity = pev->gravity; } - //void FireOnLeave( CBaseEntity *pOther ) { pOther->pev->gravity = EARTH_GRAVITY;} -}; -LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity); - -//======================================================================= -// trigger_sound - a DSP zone, brush prototype of env_sound -//======================================================================= -class CTriggerSound : public CBaseTrigger -{ - void FireOnEntry( CBaseEntity *pOther ) - { - if (!pOther->IsPlayer()) return; - pev->impulse = ((CBasePlayer *)pOther)->m_iSndRoomtype; //save old dsp sound - ((CBasePlayer *)pOther)->m_iSndRoomtype = pev->button; //set new dsp - ((CBasePlayer *)pOther)->hearNeedsUpdate = 1; - } - void FireOnLeave( CBaseEntity *pOther ) - { - if (!pOther->IsPlayer()) return; - ((CBasePlayer *)pOther)->m_iSndRoomtype = pev->impulse; //restore old dsp - ((CBasePlayer *)pOther)->hearNeedsUpdate = 1; - } -}; -LINK_ENTITY_TO_CLASS( trigger_sound, CTriggerSound ); -LINK_ENTITY_TO_CLASS( func_soundfx, CTriggerSound ); // Xash 0.4 compatibility - -//======================================================================= -// trigger_changelevel - classic HALF_LIFE changelevel -//======================================================================= -class CChangeLevel : public CBaseLogic -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) { return CBaseLogic :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void ChangeLevelNow( CBaseEntity *pActivator ); - void Touch( CBaseEntity *pOther ){ if (pOther->IsPlayer())Think(); } - void Think( void ) - { - FireAfter(); - //SERVER_COMMAND( "intermission\n" ); - UTIL_ChangeLevel( pev->netname, pev->message ); - } - void FireAfter( void ); -}; -LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ); - -void CChangeLevel :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "map")) - { - char m_szMapName[MAP_MAX_NAME]; - if (strlen(pkvd->szValue) >= MAP_MAX_NAME) - Msg("ERROR: Map name '%s' too long (%d chars)\n", pkvd->szValue, MAP_MAX_NAME ); - - strcpy(m_szMapName, pkvd->szValue); - for (int i = 0; m_szMapName[i]; i++) { m_szMapName[i] = tolower(m_szMapName[i]); } - pev->netname = ALLOC_STRING( m_szMapName ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "landmark")) - { - if (strlen(pkvd->szValue) >= MAP_MAX_NAME) - Msg("ERROR: Landmark name '%s' too long (%d chars)\n", pkvd->szValue, MAP_MAX_NAME ); - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "changetarget")) - { - pev->target = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CChangeLevel :: Spawn( void ) -{ - if( FStringNull( pev->netname )) - ALERT( at_error, "a % doesn't have a map\n", STRING( pev->classname )); - if( FStringNull( pev->message )) - ALERT( at_error, "trigger_changelevel to %s doesn't have a landmark\n", STRING( pev->netname )); - - // determine work style - if( FStringNull( pev->targetname )) SetUse( NULL ); - else SetTouch( NULL ); - - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - UTIL_SetModel(ENT(pev), pev->model); - SetBits( pev->effects, EF_NODRAW );//make invisible -} - -void CChangeLevel :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - Msg( "Mapname: %s, Landmark name %f\n", STRING(pev->netname), STRING(pev->message)); - SHIFT; - } - else SetNextThink( 0 ); -} - -void CChangeLevel :: FireAfter( void ) -{ - // Create an entity to fire the changetarget - if (!FStringNull( pev->target )) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 ); - CBaseEntity *pChlFire = CBaseEntity::Create( "fireent", pPlayer->pev->origin, g_vecZero, NULL ); - if ( pChlFire ) pChlFire->pev->target = pev->target; - } -} - -//========================================================= -// trigger_playerfreeze -//========================================================= -class CTriggerFreeze : public CBaseLogic -{ - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - m_hActivator = pActivator; - - if (pActivator && pActivator->pev->flags & FL_CLIENT); - else pActivator = UTIL_PlayerByIndex( 1 ); - - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - ((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(FALSE); - m_iState = STATE_ON; - if(m_flDelay) SetNextThink( m_flDelay ); - } - else if(useType == USE_OFF) - { - ((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(TRUE); - m_iState = STATE_OFF; - DontThink(); - } - else if(useType == USE_SHOWINFO) { DEBUGHEAD; } - } - void Think( void ) - { - ((CBasePlayer *)((CBaseEntity *)m_hActivator))->EnableControl(TRUE); - m_iState = STATE_OFF; - } - -}; -LINK_ENTITY_TO_CLASS( trigger_playerfreeze, CTriggerFreeze ); - -//======================================================================= -// trigger_hurt - classic QUAKE damage inflictor -//======================================================================= -class CTriggerHurt : public CBaseLogic -{ -public: - void Spawn( void ); - void Think( void ); - void Touch ( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ); - -void CTriggerHurt :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damagetype")) - { - pev->button |= atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CTriggerHurt :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - UTIL_SetModel(ENT(pev), pev->model); - UTIL_SetOrigin( this, pev->origin ); - SetBits( pev->effects, EF_NODRAW ); - m_iState = STATE_OFF; - - if (!FBitSet(pev->spawnflags, 2 )) Use( this, this, USE_ON, 0 ); -} - -void CTriggerHurt :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_TOGGLE) - { - if(m_iState) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - pev->solid = SOLID_TRIGGER; - gpGlobals->force_retouch++; - UTIL_SetOrigin( this, pev->origin ); - if (pev->button & DMG_RADIATION) SetNextThink( RANDOM_FLOAT(0.0, 0.5) ); - m_iState = STATE_ON; - } - else if (useType == USE_OFF) - { - pev->solid = SOLID_NOT; - UTIL_SetOrigin( this, pev->origin ); - if (pev->button & DMG_RADIATION) DontThink(); - m_iState = STATE_OFF; - } - else if (useType == USE_SET) - { - pev->dmg = value;//set dmg level - } - else if (useType == USE_RESET) - { - pev->dmg = 0;//reset dmg level - } - else if (useType == USE_SHOWINFO) - { - DEBUGHEAD; - ALERT( at_console, "State: %s, Dmg value %g\n", GetStringForState( GetState()), pev->dmg ); - PrintStringForDamage( pev->button ); - } - -} - -void CTriggerHurt :: Touch ( CBaseEntity *pOther ) -{ - float fldmg; - - if ( !pOther->pev->takedamage ) return; - if ( !FBitSet( pOther->pev->flags, FL_CLIENT|FL_MONSTER ) && !pOther->IsPushable() ) return; - - if ( IsMultiplayer() ) - { - if ( pev->dmgtime > gpGlobals->time ) - { - if ( gpGlobals->time != pev->pain_finished ) - { - // too early to hurt again, and not same frame with a different entity - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - if ( pev->impulse & playerMask ) return; - pev->impulse |= playerMask; - } - else return; - } - } - else - { - pev->impulse = 0; - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - pev->impulse |= playerMask; - } - } - } - else if( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished ) return; - - fldmg = pev->dmg * 0.5; // 0.5 seconds worth of damage, pev->dmg is damage/second - - if ( fldmg < 0 ) pOther->TakeHealth( -fldmg, pev->button ); - else pOther->TakeDamage( pev, pev, fldmg, pev->button ); - - pev->pain_finished = gpGlobals->time; - pev->dmgtime = gpGlobals->time + 0.5; -} - -void CTriggerHurt :: Think( void ) -{ - edict_t *pentPlayer; - CBasePlayer *pPlayer = NULL; - float flRange; - entvars_t *pevTarget; - Vector vecSpot1; - Vector vecSpot2; - Vector vecRange; - Vector origin; - Vector view_ofs; - - origin = pev->origin; - view_ofs = pev->view_ofs; - - pev->origin = (pev->absmin + pev->absmax) * 0.5; - pev->view_ofs = pev->view_ofs * 0.0; - pentPlayer = FIND_CLIENT_IN_PVS(edict()); - - pev->origin = origin; - pev->view_ofs = view_ofs; - - if (!FNullEnt(pentPlayer)) - { - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); - pevTarget = VARS(pentPlayer); - vecSpot1 = (pev->absmin + pev->absmax) * 0.5; - vecSpot2 = (pevTarget->absmin + pevTarget->absmax) * 0.5; - vecRange = vecSpot1 - vecSpot2; - flRange = vecRange.Length(); - if (pPlayer->m_flgeigerRange >= flRange) pPlayer->m_flgeigerRange = flRange; - } - SetNextThink( 0.25 ); -} - -//======================================================================= -// trigger_transition - area that moving all entities inside across level -//======================================================================= -class CTriggerTransition : public CPointEntity // Don't change this! -{ -public: - void Spawn( void ) - { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - UTIL_SetModel( ENT( pev ), pev->model ); - pev->model = pev->modelindex = 0; - } -}; -LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerTransition ); - -//======================================================================= -// trigger_camera - generic camera -//======================================================================= -class CTriggerCamera : public CBaseLogic -{ - void Spawn (void ); - void PostSpawn( void ); - void UpdatePlayerView( void ); - void Think( void ); - void PostActivate( void ); - void OverrideReset( void ); - void Move( void ); - void TurnOn( void ); - void TurnOff(void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData* ); - int ObjectCaps( void ) { return CBaseLogic::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - CBaseEntity* pTarget; -}; -LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ); - - -#define SF_CAMERA_PLAYER_POSITION 1 // start from player eyes -#define SF_CAMERA_PLAYER_TARGET 2 // player it's camera target -#define SF_CAMERA_PLAYER_TAKECONTROL 4 // freeze player - -void CTriggerCamera :: KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq( pkvd->szKeyName, "viewentity" )) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq( pkvd->szKeyName, "moveto" )) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseLogic::KeyValue( pkvd ); -} - -void CTriggerCamera :: Spawn (void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - m_iState = STATE_OFF; - - UTIL_SetModel( ENT( pev ), "models/common/null.mdl" ); - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - SetBits( pFlags, PF_POINTENTITY ); -} - -void CTriggerCamera::PostSpawn( void ) -{ - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->message )); - if ( m_pGoalEnt ) UTIL_SetOrigin( this, m_pGoalEnt->pev->origin ); -} - -void CTriggerCamera::OverrideReset( void ) -{ - // find path_corner on a next level - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->message )); - if( m_pGoalEnt ) UTIL_SetOrigin( this, m_pGoalEnt->pev->origin ); -} - -void CTriggerCamera::PostActivate( void ) -{ - if (FStrEq( STRING( pev->target ), "player" ) || ( pev->spawnflags & SF_CAMERA_PLAYER_TARGET )) - pTarget = UTIL_PlayerByIndex( 1 ); - else pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target )); -} - -void CTriggerCamera::Think( void ) -{ - SetNextThink( gpGlobals->frametime ); - - Move(); - pev->dmgtime = gpGlobals->time; - if ( pTarget ) UTIL_WatchTarget( this, pTarget ); - - if( m_flWait && pev->teleport_time < gpGlobals->time ) - { - TurnOff(); - } -} - -void CTriggerCamera :: UpdatePlayerView( void ) -{ - int flags = 0; - - if( m_hActivator == NULL || !m_hActivator->edict() || !( m_hActivator->pev->flags & FL_CLIENT )) - { - ALERT( at_error, "Camera: No Client!\n" ); - return; - } - - if( pev->spawnflags & SF_CAMERA_PLAYER_TAKECONTROL ) - { - int state; - - if( GetState() == STATE_ON ) - state = TRUE; - else state = FALSE; - - // freeze player - ((CBasePlayer *)((CBaseEntity *)m_hActivator))->EnableControl( state ); - } -#if 1 - if( GetState() == STATE_OFF ) - flags |= CAMERA_ON; - else flags = 0; - - CBaseEntity *pCamera = UTIL_FindEntityByTargetname( NULL, STRING( pev->netname )); - if( pCamera && !pCamera->IsBSPModel( )) - UTIL_SetView( m_hActivator, pCamera, flags ); - else UTIL_SetView( m_hActivator, this, flags ); -#else - // enchanced engine SET_VIEW (see code in client\global\view.cpp) - if( GetState() == STATE_OFF ) - SET_VIEW( m_hActivator->edict(), edict() ); - else SET_VIEW( m_hActivator->edict(), m_hActivator->edict() ); -#endif -} - -void CTriggerCamera :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( pActivator && pActivator->IsPlayer( )) - { - // only at player - m_hActivator = pActivator; - } - else if( !IsMultiplayer( )) - { - m_hActivator = UTIL_PlayerByIndex( 1 ); - } - else - { - ALERT( at_warning, "%s: %s activator not player. Ignored.\n", STRING( pev->classname ), STRING( pev->targetname )); - return; - } - - if ( useType == USE_TOGGLE ) - { - if ( m_iState == STATE_OFF ) - useType = USE_ON; - else useType = USE_OFF; - } - if ( useType == USE_ON ) - { - TurnOn(); - } - else if ( useType == USE_OFF ) - { - TurnOff(); - } - else if ( useType == USE_SHOWINFO ) - { - ALERT( at_console, "======/Xash Debug System/======\n"); - ALERT( at_console, "classname: %s\n", STRING( pev->classname )); - ALERT( at_console, "State: %s, Look at %s\n", GetStringForState( GetState()), pev->netname ? STRING( pev->netname ) : STRING( pev->targetname )); - ALERT( at_console, "Speed: %g Camera target: %s\n", pev->speed, pTarget ? STRING(pTarget->pev->targetname) : "None" ); - } -} - -void CTriggerCamera::Move( void ) -{ - // Not moving on a path, return - if (!m_pGoalEnt) return; - - // Subtract movement from the previous frame - pev->frags -= pev->speed * gpGlobals->frametime; - - // Have we moved enough to reach the target? - if ( pev->frags <= 0 ) - { - // Fire the passtarget if there is one - if ( m_pGoalEnt->pev->message ) - { - UTIL_FireTargets( m_pGoalEnt->pev->message, this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_FIREONCE ) ) - m_pGoalEnt->pev->message = 0; - } - - if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_TELEPORT ) ) - { - m_pGoalEnt = m_pGoalEnt->GetNext(); - if ( m_pGoalEnt ) UTIL_AssignOrigin( this, m_pGoalEnt->pev->origin ); - } - if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_WAITFORTRIG ) ) - { - //strange feature... - } - - // Time to go to the next target - m_pGoalEnt = m_pGoalEnt->GetNext(); - - // Set up next corner - if ( !m_pGoalEnt ) UTIL_SetVelocity( this, g_vecZero ); - else - { - pev->message = m_pGoalEnt->pev->targetname; //save last corner - pev->armorvalue = m_pGoalEnt->pev->speed; - - Vector delta = m_pGoalEnt->pev->origin - pev->origin; - pev->frags = delta.Length(); - pev->movedir = delta.Normalize(); - m_flDelay = gpGlobals->time + m_pGoalEnt->GetDelay(); - } - } - - if ( m_flDelay > gpGlobals->time ) - pev->speed = UTIL_Approach( 0, pev->speed, 500 * gpGlobals->frametime ); - else pev->speed = UTIL_Approach( pev->armorvalue, pev->speed, 500 * gpGlobals->frametime ); - - if( !pTarget ) UTIL_WatchTarget( this, m_pGoalEnt ); // watch for track - - float fraction = 2 * gpGlobals->frametime; - UTIL_SetVelocity( this, ((pev->movedir * pev->speed) * fraction) + (pev->velocity * ( 1 - fraction ))); -} - -void CTriggerCamera::TurnOff( void ) -{ - if( m_pGoalEnt ) m_pGoalEnt = m_pGoalEnt->GetPrev(); - UTIL_SetVelocity( this, g_vecZero ); - UTIL_SetAvelocity( this, g_vecZero ); - UpdatePlayerView(); - m_iState = STATE_OFF; - DontThink(); -} - -void CTriggerCamera::TurnOn( void ) -{ - pev->dmgtime = gpGlobals->time; - pev->armorvalue = pev->speed; - pev->frags = 0; - - // copy over player information - if ( pev->spawnflags & SF_CAMERA_PLAYER_POSITION ) - { - UTIL_SetOrigin( this, m_hActivator->pev->origin + m_hActivator->pev->view_ofs ); - pev->angles.x = -m_hActivator->pev->angles.x; - pev->angles.y = m_hActivator->pev->angles.y; - pev->angles.z = 0; - pev->velocity = m_hActivator->pev->velocity; - ClearBits( pev->spawnflags, SF_CAMERA_PLAYER_POSITION ); - } - - // time-based camera - if( m_flWait ) pev->teleport_time = gpGlobals->time + m_flWait; - - Move(); - UpdatePlayerView(); - m_iState = STATE_ON; - SetNextThink( gpGlobals->frametime ); -} \ No newline at end of file diff --git a/server/ents/baseweapon.cpp b/server/ents/baseweapon.cpp deleted file mode 100644 index 53d0cb8b..00000000 --- a/server/ents/baseweapon.cpp +++ /dev/null @@ -1,2084 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2006 -// baseweapon.cpp - player weapon baseclass -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "player.h" -#include "monsters.h" -#include "baseweapon.h" -#include "soundent.h" -#include "decals.h" -#include "gamerules.h" -#include "defaults.h" - -// base defines -extern int gEvilImpulse101; -ItemInfo CBasePlayerWeapon::ItemInfoArray[MAX_WEAPONS]; -AmmoInfo CBasePlayerWeapon::AmmoInfoArray[MAX_AMMO_SLOTS]; -char NameItems[32][MAX_WEAPONS]; -int ID[MAX_WEAPONS]; -int GlobalID = 0; -int g_iSwing; - -// replacement table for classic half-life weapons -// add animation names if we need -const char *NAME_VM_PUMP[] = { "pump", }; -const char *NAME_VM_IDLE1[] = { "idle", "idle1", }; -const char *NAME_VM_IDLE2[] = { "fidget", "fidget1", }; -const char *NAME_VM_IDLE3[] = { "idle3", }; -const char *NAME_VM_RELOAD[] = { "reload", }; -const char *NAME_VM_DEPLOY[] = { "draw", "draw1", "deploy" }; -const char *NAME_VM_HOLSTER[] = { "holster", "holster1" }; -const char *NAME_VM_TURNON[] = { "altfireon", }; -const char *NAME_VM_TURNOFF[] = { "altfireoff", }; -const char *NAME_VM_IDLE_EMPTY[] = { "idle2", }; -const char *NAME_VM_START_RELOAD[] = { "start_reload" }; -const char *NAME_VM_DEPLOY_EMPTY[] = { "draw2", }; -const char *NAME_VM_HOLSTER_EMPTY[] = { "holster2" }; -const char *NAME_VM_RANGE_ATTACK1[] = { "fire", "fire1", "shoot", }; -const char *NAME_VM_RANGE_ATTACK2[] = { "fire3", }; -const char *NAME_VM_RANGE_ATTACK3[] = { "fire4", }; -const char *NAME_VM_MELEE_ATTACK1[] = { "fire2", "shoot_big", "grenade" }; -const char *NAME_VM_MELEE_ATTACK2[] = { "fire3", }; -const char *NAME_VM_MELEE_ATTACK3[] = { "fire4", }; - - -//*********************************************************** -// main functions () -//*********************************************************** -TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlayerWeapon, m_pPlayer, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayerWeapon, m_pNext, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayerWeapon, m_iId, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flTimeUpdate, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_iPrimaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iSecondaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iClip, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iDefaultAmmo, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iDefaultAmmo2, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iZoom, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_cActiveRocket, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iOnControl, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iStepReload, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iBody, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iSkin, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iSpot, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBaseAnimating ); - -//generic weapon entity -LINK_ENTITY_TO_CLASS( weapon_generic, CBasePlayerWeapon ); - -//========================================================= -// AttemptToMaterialize - the item is trying to rematerialize, -// should it do so now or wait longer? -//========================================================= -void CBasePlayerWeapon::AttemptToMaterialize( void ) -{ - float time = g_pGameRules->FlWeaponTryRespawn( this ); - - if ( time == 0 ) - { - // materialize - SetThink( Materialize ); - SetNextThink( 0 ); - return; - } - SetNextThink( time ); -} - -void CBasePlayerWeapon::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - - SetObjectClass( ED_NORMAL ); - pev->effects &= ~EF_NODRAW; - pev->renderfx = kRenderFxGlowShell; - pev->renderamt = 40; - pev->frags = 0; - pev->rendercolor.x = RANDOM_LONG( 25, 255 ); - pev->rendercolor.y = RANDOM_LONG( 25, 255 ); - pev->rendercolor.z = RANDOM_LONG( 25, 255 ); - pev->scale = 0.01; - SetNextThink( 0.001 ); - } - - if( pev->scale > 1.2 ) - pev->frags = 1; - if ( pev->frags == 1 ) - { - // set effects for respawn item - if( pev->scale > 1.0 ) - pev->scale -= 0.05; - else - { - pev->renderfx = kRenderFxNone; - pev->frags = 0; - pev->solid = SOLID_TRIGGER; - UTIL_SetOrigin( this, pev->origin );// link into world. - SetTouch( DefaultTouch ); - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/respawn.wav", 1, ATTN_NORM, 0, 150 ); - SetThink( NULL ); - DontThink(); - } - } - else pev->scale += 0.05; - SetNextThink (0.001); -} - -//========================================================= -// CheckRespawn - a player is taking this weapon, should -// it respawn? -//========================================================= -void CBasePlayerWeapon :: CheckRespawn ( void ) -{ - switch ( g_pGameRules->WeaponShouldRespawn( this ) ) - { - case GR_WEAPON_RESPAWN_YES: - Respawn(); - break; - case GR_WEAPON_RESPAWN_NO: return; - } -} - -//========================================================= -// Respawn- this item is already in the world, but it is -// invisible and intangible. Make it visible and tangible. -//========================================================= -CBaseEntity* CBasePlayerWeapon::Respawn( void ) -{ - // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code - // will decide when to make the weapon visible and touchable. - CBaseEntity *pNewWeapon = NULL; - edict_t *pent; - - pent = CREATE_NAMED_ENTITY( pev->classname ); - if( FNullEnt( pent )) return NULL; - pNewWeapon = Instance( pent ); - - if( pNewWeapon ) - { - pNewWeapon->SetObjectClass( ED_NORMAL ); - pNewWeapon->pev->owner = pev->owner; - pNewWeapon->pev->origin = g_pGameRules->VecWeaponRespawnSpot( this ); - pNewWeapon->pev->angles = pev->angles; - pNewWeapon->pev->netname = pev->netname; //copy weapon_script name - DispatchSpawn( pNewWeapon->edict() ); - pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now - pNewWeapon->SetTouch( NULL );// no touch - pNewWeapon->SetThink( AttemptToMaterialize ); - - DROP_TO_FLOOR( pNewWeapon->edict( )); - - // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement, - // but when it should respawn is based on conditions belonging to the weapon that was taken. - pNewWeapon->AbsoluteNextThink( g_pGameRules->FlWeaponRespawnTime( this )); - } - else ALERT( at_error, "failed to respawn %s!\n", STRING( pev->classname )); - - return pNewWeapon; -} - -//========================================================= -// FallThink - Items that have just spawned run this think -// to catch them when they hit the ground. Once we're sure -// that the object is grounded, we change its solid type -// to trigger and set it in a large box that helps the -// player get it. -//========================================================= -void CBasePlayerWeapon::FallThink ( void ) -{ - SetNextThink( 0.1 ); - - if ( pev->flags & FL_ONGROUND ) - { - // clatter if we have an owner (i.e., dropped by someone) - // don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!) - if ( !FNullEnt( pev->owner ) ) - { - int pitch = 95 + RANDOM_LONG(0,29); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "items/weapondrop1.wav", 1, ATTN_NORM, 0, pitch); - } - - // lie flat - pev->angles.x = 0; - pev->angles.z = 0; - - pev->solid = SOLID_TRIGGER; - - UTIL_SetOrigin( this, pev->origin );// link into world. - SetTouch( DefaultTouch ); - SetThink (NULL); - } -} - -BOOL CBasePlayerWeapon :: CanDeploy( void ) -{ - BOOL bHasAmmo = 0; - if(iFlags() & ITEM_FLAG_SELECTONEMPTY) return TRUE; - - // this weapon doesn't use ammo, can always deploy. - if ( !FStriCmp( pszAmmo1(), "none" )) return TRUE; - - if ( pszAmmo1() ) bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); - if ( pszAmmo2() ) bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); - if (m_iClip > 0) bHasAmmo |= 1; - - if (!bHasAmmo) return FALSE; - return TRUE; -} - -//========================================================= -// Precache weapons and all resources -//========================================================= -void CBasePlayerWeapon :: Precache( void ) -{ - ItemInfo II; - - if( GetItemInfo( &II )) - { - ItemInfoArray[II.iId] = II; - - if( II.iszAmmo1 ) AddAmmoName( II.iszAmmo1 ); - if( II.iszAmmo2 ) AddAmmoName( II.iszAmmo2 ); - - memset( &II, 0, sizeof( II )); - - UTIL_PrecacheModel( iViewModel() ); - UTIL_PrecacheModel( iWorldModel() ); - } -} - -//========================================================= -// Get Weapon Info from Script File -//========================================================= -int CBasePlayerWeapon :: GetItemInfo( ItemInfo *p ) -{ - if( FStringNull( pev->netname )) - pev->netname = pev->classname; - - if( ParseWeaponFile( p, STRING( pev->netname ))) - { - // make unical weapon number - GenerateID(); - p->iId = m_iId; - return 1; - } - return 0; -} - -//========================================================= -// Base Spawn -//========================================================= -void CBasePlayerWeapon :: Spawn( void ) -{ - Precache(); - - // don't let killed entity continue spawning - if( pev->flags & FL_KILLME ) - return; - - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_BBOX; - pev->sequence = 1; // set world animation - - UTIL_SetOrigin( this, pev->origin ); - UTIL_SetModel( ENT( pev ), iWorldModel( )); - SetObjectClass( ED_NORMAL ); - - SetTouch( DefaultTouch ); - SetThink( FallThink ); - - // pointsize until it lands on the ground. - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 )); - - m_iSpot = 0; - pev->animtime = gpGlobals->time + 0.1; - b_restored = TRUE; // already restored - - SetNextThink( 0.1 ); -} - -//========================================================= -// Make unical ID number for each weapon -//========================================================= -void CBasePlayerWeapon :: GenerateID( void ) -{ - for( int i = 0; i < GlobalID; i++ ) - { - if( FStrEq( STRING( pev->netname ), NameItems[i] )) - { - m_iId = ID[i]; - return; - } - } - - GlobalID++; - m_iId = GlobalID; - strcpy( NameItems[GlobalID-1], STRING( pev->netname )); - ID[GlobalID-1] = m_iId; -} - -//========================================================= -// Default Touch -//========================================================= -void CBasePlayerWeapon::DefaultTouch( CBaseEntity *pOther ) -{ - // if it's not a player, ignore - if ( !pOther->IsPlayer() ) return; - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - - // can I have this? - if ( !g_pGameRules->CanHavePlayerItem( pPlayer, this ) ) - { - if ( gEvilImpulse101 ) UTIL_Remove( this ); - return; - } - - if( pOther->AddPlayerItem( this )) - { - AttachToPlayer( pPlayer ); - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM); - } -} - -//========================================================= -// Reset ItemInfo as default -//========================================================= -void CBasePlayerWeapon :: ResetParse( ItemInfo *II ) -{ - m_iId = MAX_WEAPONS; //Will be owerwrite with GenerateID() - II->iSlot = 0; - II->iPosition = 0; - II->iViewModel = iStringNull; - II->iWorldModel = iStringNull; - strcpy( II->szAnimExt, "onehanded"); - II->iszAmmo1 = MAKE_STRING( "none" ); - II->iMaxAmmo1 = WEAPON_NOAMMO; - II->iszAmmo2 = MAKE_STRING( "none" ); - II->iMaxAmmo2 = WEAPON_NOAMMO; - II->iMaxClip = -1; - II->iFlags = 0; - II->iWeight = 0; - II->attack1 = NONE; - II->attack2 = NONE; - II->fNextAttack = 0.5; - II->fNextAttack2 = 0.5; - memset( II->firesound, 0, sizeof( MAX_SHOOTSOUNDS )); - memset( II->sfxsound, 0, sizeof( MAX_SHOOTSOUNDS )); - II->sndcount = 0; - II->sfxcount = 0; - II->emptysnd = iStringNull; - II->punchangle1 = RandomRange(0.0); - II->punchangle2 = RandomRange(0.0); - II->recoil1 = RandomRange(0.0); - II->recoil2 = RandomRange(0.0); - m_iDefaultAmmo = 0; - m_iDefaultAmmo2 = 0; -} - -//========================================================= -// Parse Script File -//========================================================= -int CBasePlayerWeapon :: ParseWeaponFile( ItemInfo *II, const char *filename ) -{ - char path[256]; - int iResult = 0; - - sprintf( path, "scripts/items/%s.txt", filename ); - char *afile = (char *)LOAD_FILE( path, NULL ); - const char *pfile = afile; - - ResetParse( II ); - - if( !pfile ) - { - ALERT( at_warning, "Weapon info file for %s not found!\n", STRING( pev->netname )); - UTIL_Remove( this ); - return 0; - } - else - { - - II->iszName = pev->netname; - ALERT( at_aiconsole, "\nparse %s.txt\n", STRING( II->iszName )); - // parses the type, moves the file pointer - iResult = ParseWeaponData( II, pfile ); - ALERT( at_aiconsole, "Parsing: WeaponData{} %s\n", iResult ? "^3OK" : "^1ERROR" ); - iResult = ParsePrimaryAttack( II, pfile ); - ALERT( at_aiconsole, "Parsing: PrimaryAttack{} %s\n", iResult ? "^3OK" : "^1ERROR" ); - iResult = ParseSecondaryAttack( II, pfile ); - ALERT( at_aiconsole, "Parsing: SecondaryAttack{} %s\n", iResult ? "^3OK" : "^1ERROR" ); - iResult = ParseSoundData( II, pfile ); - ALERT( at_aiconsole, "Parsing: SoundData{} %s\n", iResult ? "^3OK" : "^1ERROR" ); - COM_FreeFile( afile ); - return 1; - } -} - -//========================================================= -// Parse SoundData {} section -//========================================================= -int CBasePlayerWeapon :: ParseSoundData( ItemInfo *II, const char *pfile ) -{ - char *token = NULL; - - while ( FStriCmp( token, "SoundData") ) // search SoundData header - { - if( !pfile ) return 0; - token = COM_ParseToken( &pfile ); - } - while ( FStriCmp( token, "{") ) // search { - { - if( !pfile ) return 0; - token = COM_ParseToken( &pfile ); - } - - token = COM_ParseToken( &pfile ); - while ( FStriCmp( token, "}" ) ) - { - if ( !token ) break; - - if ( !FStriCmp( token, "firesound" )) - { - token = COM_ParseToken( &pfile ); - if( II->sndcount < MAX_SHOOTSOUNDS ) - { - II->firesound[II->sndcount] = UTIL_PrecacheSound( token ); // precache sound - II->sndcount++; - } - else - { - ALERT( at_warning, "Too many shoot sounds for %s\n", STRING( pev->netname )); - break; // syntax error, stop parsing - } - } - else if ( !FStriCmp( token, "sfxsound" )) - { - token = COM_ParseToken( &pfile ); - if( II->sfxcount < MAX_SHOOTSOUNDS ) - { - II->sfxsound[II->sfxcount] = UTIL_PrecacheSound( token ); // precache sound - II->sfxcount++; - } - else - { - ALERT( at_warning, "Too many sfx sounds for %s\n", STRING( pev->netname )); - break; // syntax error, stop parsing - } - } - else if ( !FStriCmp( token, "emptysound" )) - { - token = COM_ParseToken( &pfile ); - II->emptysnd = UTIL_PrecacheSound( token );//precache sound - } - token = COM_ParseToken( &pfile ); - } - return 1; -} - -//========================================================= -// Parse SecondaryAttack {} section -//========================================================= -int CBasePlayerWeapon :: ParseSecondaryAttack( ItemInfo *II, const char *pfile ) -{ - char *token = NULL; - - while ( FStriCmp( token, "SecondaryAttack") ) //search SecondaryAttack header - { - if( !pfile ) return 0; - token = COM_ParseToken( &pfile ); - } - while ( FStriCmp( token, "{") ) //search { - { - if( !pfile ) return 0; - token = COM_ParseToken( &pfile ); - } - - token = COM_ParseToken( &pfile ); - while ( FStriCmp( token, "}" ) ) - { - if ( !token ) break; - - if ( !FStriCmp( token, "action" )) - { - token = COM_ParseToken( &pfile ); - if ( !FStriCmp( token, "none" )) II->attack2 = NONE; - else if ( !FStriCmp( token, "ammo1" )) II->attack2 = AMMO1; - else if ( !FStriCmp( token, "ammo1." )) - { - II->attack2 = AMMO1; - SetBits(pev->impulse, SATTACK_FIREMODE1); - } - else if ( !FStriCmp( token, "ammo2" )) II->attack2 = AMMO2; - else if ( !FStriCmp( token, "ammo2." )) - { - II->attack2 = AMMO2; - SetBits(pev->impulse, SATTACK_FIREMODE1); - } - else if ( !FStriCmp( token, "laserdot" )) II->attack2 = LASER_DOT; - else if ( !FStriCmp( token, "zoom" )) II->attack2 = ZOOM; - else if ( !FStriCmp( token, "flashlight" )) II->attack2 = FLASHLIGHT; - else if ( !FStriCmp( token, "switchmode" )) II->attack2 = SWITCHMODE; - else if ( !FStriCmp( token, "swing" )) II->attack2 = SWING; - else II->attack2 = ALLOC_STRING( token ); //client command - } - else if ( !FStriCmp( token, "punchangle" )) - { - token = COM_ParseToken( &pfile ); - II->punchangle2 = RandomRange((char *)STRING(ALLOC_STRING(token))); - } - else if ( !FStriCmp( token, "recoil" )) - { - token = COM_ParseToken( &pfile ); - II->recoil2 = RandomRange((char *)STRING(ALLOC_STRING(token))); - } - else if ( !FStriCmp( token, "nextattack" )) - { - token = COM_ParseToken( &pfile ); - II->fNextAttack2 = atof(token); - } - token = COM_ParseToken( &pfile ); - } - return 1; -} - -//========================================================= -// Parse PrimaryAttack {} section -//========================================================= -int CBasePlayerWeapon :: ParsePrimaryAttack( ItemInfo *II, const char *pfile ) -{ - char *token = NULL; - - while ( FStriCmp( token, "PrimaryAttack") ) //search PrimaryAttack header - { - if(!pfile) return 0; - token = COM_ParseToken( &pfile ); - } - while ( FStriCmp( token, "{") ) //search { - { - if(!pfile) return 0; - token = COM_ParseToken( &pfile ); - } - - token = COM_ParseToken( &pfile ); - while ( FStriCmp( token, "}" ) ) - { - if ( !token ) break; - - if ( !FStriCmp( token, "action" )) - { - token = COM_ParseToken( &pfile ); - if ( !FStriCmp( token, "none" )) II->attack1 = NONE; - else if ( !FStriCmp( token, "ammo1" )) II->attack1 = AMMO1; - else if ( !FStriCmp( token, "ammo1." )) - { - II->attack1 = AMMO1; - SetBits(pev->impulse, PATTACK_FIREMODE1); - } - else if ( !FStriCmp( token, "ammo2" )) II->attack1 = AMMO2; - else if ( !FStriCmp( token, "ammo2." )) - { - II->attack1 = AMMO2; - SetBits(pev->impulse, PATTACK_FIREMODE1); - } - else if ( !FStriCmp( token, "laserdot" )) II->attack1 = LASER_DOT; - else if ( !FStriCmp( token, "zoom" )) II->attack1 = ZOOM; - else if ( !FStriCmp( token, "flashlight" )) II->attack1 = FLASHLIGHT; - else if ( !FStriCmp( token, "switchmode" )) II->attack1 = SWITCHMODE; - else if ( !FStriCmp( token, "swing" )) II->attack1 = SWING; - else II->attack1 = ALLOC_STRING( token ); //client command - } - else if ( !FStriCmp( token, "punchangle" )) - { - token = COM_ParseToken( &pfile ); - II->punchangle1 = RandomRange((char *)STRING(ALLOC_STRING(token))); - } - else if ( !FStriCmp( token, "recoil" )) - { - token = COM_ParseToken( &pfile ); - II->recoil1 = RandomRange((char *)STRING(ALLOC_STRING(token))); - } - else if ( !FStriCmp( token, "nextattack" )) - { - token = COM_ParseToken( &pfile ); - II->fNextAttack = atof(token); - } - token = COM_ParseToken( &pfile ); - } - return 1; -} - -//========================================================= -// Parse WeaponData {} section -//========================================================= -int CBasePlayerWeapon :: ParseWeaponData( ItemInfo *II, const char *pfile ) -{ - char *token = NULL; - - while ( FStriCmp( token, "WeaponData") ) - { - if ( !pfile ) return 0; - token = COM_ParseToken( &pfile ); - } - while ( FStriCmp( token, "{") ) // search { - { - if ( !pfile ) return 0; - token = COM_ParseToken( &pfile ); - } - - token = COM_ParseToken( &pfile ); - while ( FStriCmp( token, "}" )) - { - if ( !token ) break; - - if ( !FStriCmp( token, "viewmodel" )) - { - token = COM_ParseToken( &pfile ); - II->iViewModel = ALLOC_STRING(token); - } - else if( !FStriCmp( token, "playermodel" )) - { - token = COM_ParseToken( &pfile ); - II->iWorldModel = ALLOC_STRING(token); - } - else if( !FStriCmp( token, "anim_prefix" )) - { - token = COM_ParseToken( &pfile ); - strncpy( II->szAnimExt, token, sizeof( II->szAnimExt )); - } - else if( !FStriCmp( token, "bucket" )) - { - token = COM_ParseToken( &pfile ); - II->iSlot = atoi( token ); - } - else if( !FStriCmp( token, "bucket_position" )) - { - token = COM_ParseToken( &pfile ); - II->iPosition = atoi( token ); - } - else if( !FStriCmp( token, "clip_size" )) - { - token = COM_ParseToken( &pfile ); - if( !FStriCmp( token, "noclip" )) - II->iMaxClip = -1; - else II->iMaxClip = atoi( token ); - } - else if( !FStriCmp( token, "primary_ammo" )) - { - token = COM_ParseToken( &pfile ); - - if ( !FStriCmp( token, "none" )) II->iMaxAmmo1 = WEAPON_NOAMMO; - else if ( !FStriCmp( token, "357" )) II->iMaxAmmo1 = DESERT_MAX_CARRY; - else if ( !FStriCmp( token, "9mm" )) II->iMaxAmmo1 = GLOCK_MAX_CARRY; - else if ( !FStriCmp( token, "12mm" )) II->iMaxAmmo1 = GLOCK_MAX_CARRY; - else if ( !FStriCmp( token, "762" )) II->iMaxAmmo1 = M40A1_MAX_CARRY; - else if ( !FStriCmp( token, "m203" )) II->iMaxAmmo1 = M203_GRENADE_MAX_CARRY; - else if ( !FStriCmp( token, "nuke" )) II->iMaxAmmo1 = ROCKET_MAX_CARRY; - else if ( !FStriCmp( token, "rockets" )) II->iMaxAmmo1 = ROCKET_MAX_CARRY; - else if ( !FStriCmp( token, "556" )) II->iMaxAmmo1 = GLOCK_MAX_CARRY; - else if ( !FStriCmp( token, "buckshot" )) II->iMaxAmmo1 = BUCKSHOT_MAX_CARRY; - else if ( !FStriCmp( token, "grenade" )) II->iMaxAmmo1 = M203_GRENADE_MAX_CARRY; - else if ( !FStriCmp( token, "bolts" )) II->iMaxAmmo1 = BOLT_MAX_CARRY; - - II->iszAmmo1 = ALLOC_STRING( token ); - } - else if ( !FStriCmp( token, "secondary_ammo" )) - { - token = COM_ParseToken( &pfile ); - - if ( !FStriCmp( token, "none" )) II->iMaxAmmo2 = WEAPON_NOAMMO; - else if ( !FStriCmp( token, "357" )) II->iMaxAmmo2 = DESERT_MAX_CARRY; - else if ( !FStriCmp( token, "9mm" )) II->iMaxAmmo2 = GLOCK_MAX_CARRY; - else if ( !FStriCmp( token, "12mm" )) II->iMaxAmmo2 = GLOCK_MAX_CARRY; - else if ( !FStriCmp( token, "762" )) II->iMaxAmmo2 = M40A1_MAX_CARRY; - else if ( !FStriCmp( token, "m203" )) II->iMaxAmmo2 = M203_GRENADE_MAX_CARRY; - else if ( !FStriCmp( token, "nuke" )) II->iMaxAmmo2 = ROCKET_MAX_CARRY; - else if ( !FStriCmp( token, "rockets" )) II->iMaxAmmo2 = ROCKET_MAX_CARRY; - else if ( !FStriCmp( token, "556" )) II->iMaxAmmo2 = GLOCK_MAX_CARRY; - else if ( !FStriCmp( token, "buckshot" )) II->iMaxAmmo2 = BUCKSHOT_MAX_CARRY; - else if ( !FStriCmp( token, "grenade" )) II->iMaxAmmo1 = M203_GRENADE_MAX_CARRY;//don't change this! - else if ( !FStriCmp( token, "bolts" )) II->iMaxAmmo2 = BOLT_MAX_CARRY; - - II->iszAmmo2 = ALLOC_STRING( token ); - } - else if ( !FStriCmp( token, "defaultammo" )) - { - token = COM_ParseToken( &pfile ); - m_iDefaultAmmo = RandomRange( token ).Random(); - } - else if ( !FStriCmp( token, "defaultammo2" )) - { - token = COM_ParseToken( &pfile ); - m_iDefaultAmmo2 = RandomRange( token ).Random(); - } - else if ( !FStriCmp( token, "weight" )) - { - token = COM_ParseToken( &pfile ); - II->iWeight = atoi(token); - } - else if ( !FStriCmp( token, "item_flags" )) - { - token = COM_ParseToken( &pfile ); - II->iFlags = atoi(token); - } - token = COM_ParseToken( &pfile ); - } - return 1; -} - -//========================================================= -// Set Animation at ACT -//========================================================= -int CBasePlayerWeapon :: PlaySequence( Activity activity, float fps ) -{ - if(!m_pPlayer->pev->viewmodel) return -1; - UTIL_SetModel( ENT(pev), STRING( m_pPlayer->pev->viewmodel )); - int iSequence = LookupActivity( activity ); - if( iSequence != -1 ) SendWeaponAnim( iSequence, fps ); - else DevMsg("Warning: %s not found\n", activity_map[activity - 1].name); - - return iSequence; -} - -//========================================================= -// Set Animation at name -//========================================================= -int CBasePlayerWeapon :: SetAnimation( char *name, float fps ) -{ - if( !m_pPlayer->pev->viewmodel ) return -1; - UTIL_SetModel( ENT( pev ), STRING( m_pPlayer->pev->viewmodel )); - int iSequence = LookupSequence( name ); - if( iSequence != -1 ) SendWeaponAnim( iSequence, fps ); - else ALERT( at_warning, "sequence \"%s\" not found\n", name ); - - return iSequence; -} - -//========================================================= -// Found sequence at act or name (generic method) -//========================================================= -int CBasePlayerWeapon :: SetAnimation( Activity activity, float fps ) -{ - int iSequence, m_iAnimCount; - const char **pAnimsList = NULL; - - if(!m_pPlayer->pev->viewmodel) return -1; - UTIL_SetModel( ENT(pev), STRING( m_pPlayer->pev->viewmodel )); - - // try to playing ACT sequence - iSequence = LookupActivity( activity ); - if( iSequence != -1 ) - { - SendWeaponAnim( iSequence, fps ); // activity method - return iSequence; - } - - // ACT not found, translate name to ACT - switch ( activity ) - { - case ACT_VM_IDLE1: - pAnimsList = NAME_VM_IDLE1; - m_iAnimCount = ARRAYSIZE( NAME_VM_IDLE1 ); - break; - case ACT_VM_IDLE2: - pAnimsList = NAME_VM_IDLE2; - m_iAnimCount = ARRAYSIZE( NAME_VM_IDLE2 ); - break; - case ACT_VM_IDLE3: - pAnimsList = NAME_VM_IDLE3; - m_iAnimCount = ARRAYSIZE( NAME_VM_IDLE3 ); - break; - case ACT_VM_IDLE_EMPTY: - pAnimsList = NAME_VM_IDLE_EMPTY; - m_iAnimCount = ARRAYSIZE( NAME_VM_IDLE_EMPTY ); - break; - case ACT_VM_RANGE_ATTACK1: - pAnimsList = NAME_VM_RANGE_ATTACK1; - m_iAnimCount = ARRAYSIZE( NAME_VM_RANGE_ATTACK1 ); - break; - case ACT_VM_RANGE_ATTACK2: - pAnimsList = NAME_VM_RANGE_ATTACK2; - m_iAnimCount = ARRAYSIZE( NAME_VM_RANGE_ATTACK2 ); - break; - case ACT_VM_RANGE_ATTACK3: - pAnimsList = NAME_VM_RANGE_ATTACK3; - m_iAnimCount = ARRAYSIZE( NAME_VM_RANGE_ATTACK3 ); - break; - case ACT_VM_MELEE_ATTACK1: - pAnimsList = NAME_VM_MELEE_ATTACK1; - m_iAnimCount = ARRAYSIZE( NAME_VM_MELEE_ATTACK1 ); - break; - case ACT_VM_MELEE_ATTACK2: - pAnimsList = NAME_VM_MELEE_ATTACK2; - m_iAnimCount = ARRAYSIZE( NAME_VM_MELEE_ATTACK2 ); - break; - case ACT_VM_MELEE_ATTACK3: - pAnimsList = NAME_VM_MELEE_ATTACK3; - m_iAnimCount = ARRAYSIZE( NAME_VM_MELEE_ATTACK3 ); - break; - case ACT_VM_PUMP: - pAnimsList = NAME_VM_PUMP; - m_iAnimCount = ARRAYSIZE( NAME_VM_PUMP ); - break; - case ACT_VM_START_RELOAD: - pAnimsList = NAME_VM_START_RELOAD; - m_iAnimCount = ARRAYSIZE( NAME_VM_START_RELOAD ); - break; - case ACT_VM_RELOAD: - pAnimsList = NAME_VM_RELOAD; - m_iAnimCount = ARRAYSIZE( NAME_VM_RELOAD ); - break; - case ACT_VM_DEPLOY: - pAnimsList = NAME_VM_DEPLOY; - m_iAnimCount = ARRAYSIZE( NAME_VM_DEPLOY ); - break; - case ACT_VM_DEPLOY_EMPTY: - pAnimsList = NAME_VM_DEPLOY_EMPTY; - m_iAnimCount = ARRAYSIZE( NAME_VM_DEPLOY_EMPTY ); - break; - case ACT_VM_HOLSTER: - pAnimsList = NAME_VM_HOLSTER; - m_iAnimCount = ARRAYSIZE( NAME_VM_HOLSTER ); - break; - case ACT_VM_HOLSTER_EMPTY: - pAnimsList = NAME_VM_HOLSTER_EMPTY; - m_iAnimCount = ARRAYSIZE( NAME_VM_HOLSTER_EMPTY ); - break; - case ACT_VM_TURNON: - pAnimsList = NAME_VM_TURNON; - m_iAnimCount = ARRAYSIZE( NAME_VM_TURNON ); - break; - case ACT_VM_TURNOFF: - pAnimsList = NAME_VM_TURNOFF; - m_iAnimCount = ARRAYSIZE( NAME_VM_TURNOFF ); - break; - default: - m_iAnimCount = 0; - break; - } - - // lookup all names - for(int i = 0; i < m_iAnimCount; i++ ) - { - iSequence = LookupSequence( pAnimsList[i] ); - if( iSequence != -1 ) - { - SendWeaponAnim( iSequence, fps ); // names method - return iSequence; - } - } - - return -1; //no matches found -} - -float CBasePlayerWeapon :: SequenceFPS( int iSequence ) -{ - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)GET_MODEL_PTR( ENT( pev )); - - if( pstudiohdr ) - { - dstudioseqdesc_t *pseqdesc; - - if( iSequence == -1 ) iSequence = m_iSequence; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + iSequence; - return pseqdesc->fps; - } - return 0.0f; -} - -float CBasePlayerWeapon :: SequenceDuration( int iSequence, float fps ) -{ - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)GET_MODEL_PTR( ENT( pev )); - - if( pstudiohdr ) - { - dstudioseqdesc_t *pseqdesc; - - if( iSequence == -1 ) iSequence = m_iSequence; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + iSequence; - if( fps == 0.0f ) fps = pseqdesc->fps; - return (float)pseqdesc->numframes / fps; - } - return 0.0f; -} - -//========================================================= -// Set Weapon Anim -//========================================================= -void CBasePlayerWeapon :: SendWeaponAnim( int sequence, float fps ) -{ - float framerate = 1.0f; // fps multiplier - m_iSequence = sequence; // member current sequence - - if( fps ) - { - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)GET_MODEL_PTR( ENT( pev )); - if( pstudiohdr ) - { - dstudioseqdesc_t *pseqdesc; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + m_iSequence; - framerate = fps / pseqdesc->fps; - } - } - - m_pPlayer->pev->weaponanim = m_iSequence; - - // calculate additional body for special effects - pev->body = (pev->body % NUM_HANDS) + NUM_HANDS * m_iBody; - - MESSAGE_BEGIN( MSG_ONE, gmsg.WeaponAnim, NULL, m_pPlayer->pev ); - WRITE_BYTE( m_iSequence ); - WRITE_BYTE( pev->body ); - WRITE_BYTE( framerate * 16 ); - MESSAGE_END(); - - SetNextIdle( SequenceDuration( )); -} - -//========================================================= -// generic base functions -//========================================================= -BOOL CBasePlayerWeapon :: DefaultDeploy( Activity activity ) -{ - if( PLAYER_HAS_SUIT ) - pev->body |= GORDON_SUIT; - else pev->body &= ~GORDON_SUIT; - - m_iClientSkin = -1; // reset last skin info for new weapon - m_iClientBody = -1; // reset last body info for new weapon - m_iClientFov = -1; // reset last fov info for new weapon - - m_pPlayer->pev->viewmodel = iViewModel(); - m_pPlayer->pev->weaponmodel = iWorldModel(); - strcpy( m_pPlayer->m_szAnimExtention, szAnimExt()); - - m_iSequence = LookupActivity( activity ); - float fps = IsMultiplayer() ? SequenceFPS() * 2.0f : 0.0f; - if( SetAnimation( activity, fps ) != -1 ) - { - SetNextAttack( SequenceDuration( m_iSequence, fps )); // delay before idle playing - return TRUE; - } - - // animation not found - return FALSE; -} - -BOOL CBasePlayerWeapon :: DefaultHolster( Activity activity ) -{ - m_fInReload = FALSE; - int iResult = 0; - - m_iSequence = LookupActivity( activity ); - float fps = IsMultiplayer() ? SequenceFPS() * 2.0f : 0.0f; - - ZoomReset(); - - iResult = SetAnimation( activity, fps ); - if( iResult == -1 ) return 0; - - SetNextAttack( SequenceDuration( m_iSequence, fps )); // delay before switching - if( m_pSpot ) // disable laser dot - { - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/spot_off.wav", 1, ATTN_NORM ); - m_pSpot->Killed(); - m_pSpot = NULL; - } - m_iSkin = 0; // reset screen - - if( iAttack1() == FLASHLIGHT || iAttack2() == FLASHLIGHT ) - ClearBits( m_pPlayer->pev->effects, EF_DIMLIGHT ); - - if(( iFlags() & ITEM_FLAG_EXHAUSTIBLE ) && (m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] <= 0 )) - { - // no more ammo! - m_pPlayer->pev->weapons &= ~(1<pev->viewmodel = iStringNull; - m_pPlayer->pev->weaponmodel = iStringNull; - SetThink( DestroyItem ); - SetNextThink( 0.5 ); - } - - // animation not found - return 1; -} - -void CBasePlayerWeapon :: DefaultIdle( void ) -{ - // weapon have clip and ammo or just have ammo - if ((iMaxClip() && m_iClip) || m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 || iMaxAmmo1() == -1) - { - // play random idle animation - int iAnim; - float flRand = RANDOM_FLOAT(0, 1.2); - if (flRand < 0.2) iAnim = ACT_VM_IDLE1; - else if ( 0.4 > flRand && flRand > 0.2 ) iAnim = ACT_VM_IDLE2; - else if ( 0.8 > flRand && flRand > 0.5 ) iAnim = ACT_VM_IDLE3; - else - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_LONG(10, 15); - return;//don't execute SetAnimation - } - SetAnimation((Activity)iAnim); - } - else - { - SetAnimation( ACT_VM_IDLE_EMPTY ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_LONG(20, 45); - } -} - -BOOL CBasePlayerWeapon :: DefaultReload( Activity sequence ) -{ - if( m_cActiveRocket && m_iSpot ) - return FALSE; - if( m_flNextPrimaryAttack > UTIL_WeaponTimeBase()) - return FALSE; - if( m_flNextSecondaryAttack > UTIL_WeaponTimeBase()) - return FALSE; - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) // have ammo? - { - if( iMaxClip() == m_iClip ) return FALSE; - if( m_iStepReload == 0 ) // try to playing step reload - { - if( SetAnimation( ACT_VM_START_RELOAD ) != -1 ) - { - // found anim, continue - m_iStepReload = 1; - m_fInReload = TRUE; // disable reload button - return TRUE; // start reload cycle. See also ItemPostFrame - } - else // init default reload - { - int i = min(iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - if( i == 0 ) return FALSE; - int iResult = -1; - ZoomReset(); // reset zoom - if( m_iClip <= 0 ) // empty clip ? - { - // iResult is error code - iResult = SetAnimation( ACT_VM_RELOAD_EMPTY ); - m_iStepReload = EMPTY_RELOAD; // it's empty reload - } - if( iResult == -1 ) - { - SetAnimation( sequence ); - m_iStepReload = NORMAL_RELOAD; // it's not empty reload - } - if( m_pSpot ) m_pSpot->Suspend( SequenceDuration( )); // suspend laserdot - SetNextAttack( SequenceDuration( )); - m_fInReload = TRUE; // disable reload button - - return TRUE; // that's all right - } - } - else if( m_iStepReload == 1 ) // continue step reload - { - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase( )) - return FALSE; - // was waiting for gun to move to side - SetAnimation( sequence ); - m_iStepReload = 2; - } - else if( m_iStepReload == 2 ) // continue step reload - { - // add them to the clip - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_iClip++; - m_iStepReload = 1; - if( m_iClip == iMaxClip()) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - } - return TRUE; - } - return FALSE; -} - -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) -{ - if( m_iPlayEmptySound ) - { - if( EmptySnd( )) - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, STRING( EmptySnd( )), 1, ATTN_NORM ); - m_iPlayEmptySound = 0; - return TRUE; - } - return FALSE; -} -//========================================================= -// Get Atatck Info by AmmoInfo -//========================================================= -Vector CBasePlayerWeapon :: GetCurrentSpread( const char *ammo ) -{ - switch( GetBulletType( ammo )) - { - case BULLET_9MM: return VECTOR_CONE_2DEGREES; - case BULLET_357: return VECTOR_CONE_2DEGREES; - case BULLET_556: return VECTOR_CONE_3DEGREES; - case BULLET_762: return VECTOR_CONE_1DEGREES; - case BULLET_12MM: return VECTOR_CONE_15DEGREES; - case BULLET_BUCKSHOT: return VECTOR_CONE_10DEGREES; - default: return VECTOR_CONE_0DEGREES; - } -} - -int CBasePlayerWeapon :: GetBulletType( const char *ammo ) -{ - if( !FStriCmp( ammo, "9mm" )) return BULLET_9MM; - else if( !FStriCmp( ammo, "357" )) return BULLET_357; - else if( !FStriCmp( ammo, "556" )) return BULLET_556; - else if( !FStriCmp( ammo, "762" )) return BULLET_762; - else if( !FStriCmp( ammo, "12mm" )) return BULLET_12MM; - else if( !FStriCmp( ammo, "buckshot" )) return BULLET_BUCKSHOT; - - return BULLET_NONE; -} - -int CBasePlayerWeapon :: GetAmmoType( const char *ammo ) -{ - const char *ammoname; - ammoname = m_pPlayer->GetAmmoName(m_iPrimaryAmmoType); - if(!FStriCmp( ammo, ammoname )) return 1; - ammoname = m_pPlayer->GetAmmoName(m_iSecondaryAmmoType); - if(!FStriCmp( ammo, ammoname )) return 2; - return 0; -} - -int CBasePlayerWeapon :: ReturnAmmoIndex( const char *ammo ) -{ - const char *ammoname; - ammoname = m_pPlayer->GetAmmoName( m_iPrimaryAmmoType ); - if( !FStriCmp( ammo, ammoname )) return m_iPrimaryAmmoType; - ammoname = m_pPlayer->GetAmmoName( m_iSecondaryAmmoType ); - if( !FStriCmp( ammo, ammoname )) return m_iSecondaryAmmoType; - return 0; -} - -int CBasePlayerWeapon :: GetCurrentAttack( const char *ammo, int firemode ) -{ - int iResult; - if( !FStriCmp( ammo, "none" )) //no ammo - { - //just play animation and sound - if(!firemode) iResult = PlayRangeAttack(); // anim is present ? - else iResult = PlayMeleeAttack(); - - SetPlayerEffects( ammo, firemode ); - PlayAttackSound( firemode ); - } - else if( !FStriCmp( ammo, "9mm" )) iResult = Shoot ( ammo, GetCurrentSpread(ammo), firemode ); - else if( !FStriCmp( ammo, "357" )) iResult = Shoot ( ammo, GetCurrentSpread(ammo), firemode ); - else if( !FStriCmp( ammo, "556" )) iResult = Shoot ( ammo, GetCurrentSpread(ammo), firemode ); - else if( !FStriCmp( ammo, "762" )) iResult = Shoot ( ammo, GetCurrentSpread(ammo), firemode ); - else if( !FStriCmp( ammo, "12mm" )) iResult = Shoot ( ammo, GetCurrentSpread(ammo), firemode ); - else if( !FStriCmp( ammo, "buckshot" )) - { - if(firemode) iResult = Shoot ( ammo, GetCurrentSpread(ammo), m_iClip == 1 ? 0 : 1, 2 );//HACK - else iResult = Shoot ( ammo, GetCurrentSpread(ammo) ); - } - else if( !FStriCmp( ammo, "rockets" )) iResult = Launch( ammo, firemode ); - else if( !FStriCmp( ammo, "m203" )) iResult = Launch( ammo, firemode ); - else if( !FStriCmp( ammo, "nuke" )) iResult = Launch( ammo, firemode ); - else if( !FStriCmp( ammo, "bolts" )) iResult = Launch( ammo, firemode ); - else if( !FStriCmp( ammo, "uranium" )) iResult = -1; - else if( !FStriCmp( ammo, "grenade" )) - { - if ( !m_flHoldTime && m_pPlayer->m_rgAmmo[ ReturnAmmoIndex( ammo ) ] > 0 ) - { - m_flHoldTime = UTIL_WeaponTimeBase();// set hold time - m_iOnControl = 3; // grenade "on control" - SetAnimation( ACT_VM_START_CHARGE ); // pinpull - } - iResult = -1; - } - return iResult; -} - -//========================================================= -// Play Action -//========================================================= -int CBasePlayerWeapon :: PlayCurrentAttack( int action, int firemode ) -{ - int iResult = 0; - if(pev->button)firemode = m_iBody; // enable switching firemode - - if( action == ZOOM ) iResult = 1; // See void ZoomUpdate( void ); for details - else if( action == AMMO1 ) iResult = GetCurrentAttack( pszAmmo1(), firemode ); - else if( action == AMMO2 ) iResult = GetCurrentAttack( pszAmmo2(), firemode ); - else if( action == LASER_DOT ) - { - m_iSpot = !m_iSpot; - if( !m_iSpot && m_pSpot ) // disable laser dot - { - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/spot_off.wav", 1, ATTN_NORM ); - m_pSpot->Killed(); - m_pSpot = NULL; - m_iSkin = 0; // disable screen - } - iResult = 1; - } - else if ( action == FLASHLIGHT ) - { - if(FBitSet(m_pPlayer->pev->effects, EF_DIMLIGHT)) - { - ClearBits(m_pPlayer->pev->effects, EF_DIMLIGHT); - EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, 1.0, ATTN_NORM, 0, PITCH_NORM ); - } - else - { - SetBits(m_pPlayer->pev->effects, EF_DIMLIGHT); - EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, SOUND_FLASHLIGHT_ON, 1.0, ATTN_NORM, 0, PITCH_NORM ); - } - iResult = 1; - } - else if( action == SWITCHMODE) - { - if(!m_iBody) - { - m_iBody = 1; - pev->button = 1;//enable custom firemode - SetAnimation(ACT_VM_TURNON); - } - else - { - SetAnimation( ACT_VM_TURNOFF ); - pev->button = 0;//disable custom firemode - m_iClientBody = m_iBody = 0;//make delay before change - } - iResult = 1; - } - else if( action == SWING) - { - if (!Swing(TRUE)) Swing (FALSE); - iResult = 1; - } - else if( action == NONE) return -1; - else //just command - { - char command[64]; - if(!strncmp( STRING(action), "fire ", 5)) - { - char *target = (char*)STRING(action); - target = target + 5;//remove "fire " - UTIL_FireTargets( target, m_pPlayer, this, USE_TOGGLE );//activate target - } - else - { - sprintf( command, "%s\n", STRING(action)); - SERVER_COMMAND( command ); - } - //just play animation and sound - if(!firemode) iResult = PlayRangeAttack();//anim is present ? - else iResult = PlayMeleeAttack(); - - m_pPlayer->SetAnimation( PLAYER_ATTACK1 );//player animation - PlayAttackSound( firemode ); - } - return iResult; -} - -int CBasePlayerWeapon :: UseAmmo( const char *ammo, int count ) -{ - int ammoType = GetAmmoType( ammo ); - - if( !ammoType ) return -1;//uncnown ammo ? - else if( ammoType == 1)//it's primary ammo - { - if(iMaxClip() == -1 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0)//may be we have clip ? - { - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < count) count = 1; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; - } - else if(m_iClip > 0)//have clip - { - if( m_iClip < count) count = 1; - m_iClip -= count; - } - else return 0;//ammo is out - } - else if( ammoType == 2 ) //it's secondary ammo - { - if(m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] > 0) //we have ammo ? - { - if( m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] < count) count = 1; - m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] -= count; - } - else return 0;//ammo is out - } - return 1;//thats all right, mr.freeman -} - -void CBasePlayerWeapon :: SetPlayerEffects( const char *ammo, int firemode ) -{ - if( !FStriCmp( ammo, "9mm" )) - { - if(firemode)//add silencer - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - } - else - { - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - } - } - else if( !FStriCmp( ammo, "762" )) //sniper rifle - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NO_GUN_FLASH; - } - else if( !FStriCmp( ammo, "buckshot" )) - { - if(firemode) //double barrels attack - { - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - } - else - { - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - } - } - else - { - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - } - m_pPlayer->SetAnimation( PLAYER_ATTACK1 );//player animation -} - -void CBasePlayerWeapon :: PlayAttackSound( int firemode ) -{ - if(firemode) //play sfx random sounds - { - if(sfxcnt()) - { - int sfxsound = RANDOM_LONG(0, sfxcnt() - 1); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, STRING(SfxSound(sfxsound)), 1.0, ATTN_NORM); - } - } - else //play normal random fire sound - { - if(sndcnt()) - { - int firesound = RANDOM_LONG(0, sndcnt() - 1); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, STRING(FireSound(firesound)), 1.0, ATTN_NORM); - } - } -} - -//========================================================= -// Shoot & Launch functions -//========================================================= -int CBasePlayerWeapon :: Shoot ( const char *ammo, Vector vecSpread, int firemode, int cShots ) -{ - if ( m_pPlayer->pev->waterlevel != 3)//have ammo and player not underwater - { - if(!UseAmmo( ammo, cShots )) return 0; - - SetPlayerEffects( ammo, firemode ); - PlayAttackSound( firemode ); - - // viewmodel animation - ZoomReset(); - if( !PlayEmptyFire( )) - { - if ( !firemode ) - PlayRangeAttack (); - else PlayMeleeAttack (); - } - - float flDistance;//set max distance - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming, vecDir; - - if( iFlags() & ITEM_FLAG_USEAUTOAIM ) - vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - else vecAiming = gpGlobals->v_forward; - - // eject brass - for( int i = 0; cShots > i; i++ ) - { - PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usEjectBrass, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, GetBulletType( ammo ), 0, firemode, 0 ); - } - if( !FStriCmp( ammo, "buckshot" ))//HACK - { - flDistance = 2048; - cShots *= 4; - } - else flDistance = MAP_SIZE; - FireBullets( cShots, vecSrc, vecAiming, vecSpread, flDistance, (Bullet)GetBulletType(ammo), 0, 0, m_pPlayer->pev ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 ); - return 1; - } - return 0; -} - -int CBasePlayerWeapon :: Launch ( const char *ammo, int type ) -{ - if(!UseAmmo(ammo)) return 0; - float fps = 0;//custom animation speed for handgrenade - - //viewmodel animation - ZoomReset(); - - if ( !FStriCmp( ammo, "m203" )) - { - // we don't add in player velocity anymore. - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - CGrenade::ShootContact( m_pPlayer->pev, m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16, gpGlobals->v_forward * 800 ); - } - else if( !FStriCmp( ammo, "rockets" )) - { - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -8; - - CRpgRocket *pRocket = CRpgRocket::Create ( vecSrc, m_pPlayer->pev->v_angle, m_pPlayer, this ); - UTIL_MakeVectors( m_pPlayer->pev->v_angle );// RpgRocket::Create stomps on globals, so remake. - pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); - } - else if( !FStriCmp( ammo, "bolts" )) - { - // we don't add in player velocity anymore. - Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - UTIL_MakeVectors( anglesAim ); - - anglesAim.x = -anglesAim.x; - Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - - CBolt *pBolt = CBolt::Create( vecSrc, anglesAim, m_pPlayer ); - if (m_pPlayer->pev->waterlevel == 3) pBolt->pev->velocity = vecDir * 1000; - else pBolt->pev->velocity = vecDir * 2000; - } - else if( !FStriCmp( ammo, "nuke" )) - { - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_up * 2; - CWHRocket *pRocket = CWHRocket::Create ( vecSrc, m_pPlayer->pev->v_angle, m_pPlayer, this, type ); - } - else if( !FStriCmp( ammo, "grenade" )) - { - Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - - if ( angThrow.x < 0 ) angThrow.x = -10 + angThrow.x * ( ( 90 - 10 ) / 90.0 ); - else angThrow.x = -10 + angThrow.x * ( ( 90 + 10 ) / 90.0 ); - - float flVel = ( 90 - angThrow.x ) * 4; - if ( flVel > 500 ) flVel = 500; - - UTIL_MakeVectors( angThrow ); - Vector vecSrc = m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16; - Vector vecThrow = gpGlobals->v_forward * flVel + m_pPlayer->pev->velocity; - - // alway explode 3 seconds after the pin was pulled - float time = m_flHoldTime - UTIL_WeaponTimeBase() + 3.0; - if (time < 0) time = 0; - - CGrenade::ShootTimed( m_pPlayer->pev, vecSrc, vecThrow, time ); - fps = flVel * 0.08; - if(fps < 12) fps = 12; - - m_flHoldTime = 0; - m_iOnControl = 4; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - - m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; - m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - //play random shooting animation - if(!PlayEmptyFire()) PlayMeleeAttack( fps ); - - return 1; -} - -int CBasePlayerWeapon::Swing( int fFirst ) -{ - int fDidHit = FALSE; - BOOL bHit = FALSE; - TraceResult tr; - TraceResult m_trHit; - - if ( m_flTimeUpdate > UTIL_WeaponTimeBase() ) return fDidHit; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecEnd = vecSrc + gpGlobals->v_forward * 32; - - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); - - if ( tr.flFraction >= 1.0 ) - { - UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr ); - if ( tr.flFraction < 1.0 ) - { - // Calculate the point of intersection of the line (or hull) and the object we hit - // This is and approximation of the "best" intersection - CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); - if ( !pHit || pHit->IsBSPModel() ) - UTIL_FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() ); - vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space) - } - } - - if ( tr.flFraction >= 1.0) - { - if(fFirst) - { - switch( (g_iSwing++) % 3 ) - { - case 0: SetAnimation ( ACT_VM_MELEE_ATTACK1 ); break; - case 1: SetAnimation ( ACT_VM_MELEE_ATTACK2 ); break; - case 2: SetAnimation ( ACT_VM_MELEE_ATTACK3 ); break; - } - - if(EmptySnd()) EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, STRING(EmptySnd()), 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xF)); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - } - } - else - { - // hit - fDidHit = TRUE; - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - switch( (g_iSwing++) % 3 ) - { - case 0: SetAnimation ( ACT_VM_RANGE_ATTACK1 ); break; - case 1: SetAnimation ( ACT_VM_RANGE_ATTACK2 ); break; - case 2: SetAnimation ( ACT_VM_RANGE_ATTACK3 ); break; - } - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - ClearMultiDamage( ); - pEntity->TraceAttack(m_pPlayer->pev, CROWBAR_DMG, gpGlobals->v_forward, &tr, DMG_CLUB ); - ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; - - // play thwack, smack, or dong sound - float flVol = 1.0; - int fHitWorld = TRUE; - - if (pEntity) - { - if ( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE ) - { - if(sndcnt())//HitBody sound - { - int firesound = RANDOM_LONG(0, sndcnt() - 1); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, STRING(FireSound(firesound)), 1, ATTN_NORM); - } - m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME; - if ( !pEntity->IsAlive() ) - { - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - return TRUE; - } - else flVol = 0.1; - fHitWorld = FALSE; - } - } - - if (fHitWorld) - { - float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_CROWBAR); - - if ( IsMultiplayer() ) fvolbar = 1; - - // also play crowbar strike - if(sndcnt())//CBAR Hit sound - { - int sfxsound = RANDOM_LONG(0, sfxcnt() - 1); - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, STRING(SfxSound(sfxsound)), fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); - } - } - - // delay the decal a bit - m_trHit = tr; - - m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; - - DecalGunshot( &m_trHit, BULLET_CROWBAR ); - m_flTimeUpdate = UTIL_WeaponTimeBase() + 0.2; - } - return fDidHit; -} - -//========================================================= -// Zoom In\Out -//========================================================= -void CBasePlayerWeapon::ZoomUpdate( void ) -{ - if(( iAttack1() == ZOOM && m_pPlayer->pev->button & IN_ATTACK ) || ( iAttack2() == ZOOM && m_pPlayer->pev->button & IN_ATTACK2 )) - { - if( m_iZoom == 0 ) - { - if( m_flHoldTime > UTIL_WeaponTimeBase( )) return; - m_iZoom = 1; - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/zoom.wav", 1, ATTN_NORM ); - m_flHoldTime = UTIL_WeaponTimeBase() + 0.8; - } - if( m_iZoom == 1 ) - { - m_pPlayer->pev->fov = 50.0f; - m_pPlayer->pev->viewmodel = NULL; - m_iZoom = 2; // ready to zooming, wait for 0.8 secs - } - if( m_iZoom == 2 && m_pPlayer->pev->fov > MAX_ZOOM ) - { - if( m_flHoldTime < UTIL_WeaponTimeBase( )) - { - m_pPlayer->pev->fov = UTIL_Approach( 20.0f, m_pPlayer->pev->fov, 0.8f ); - m_flHoldTime = UTIL_WeaponTimeBase(); - } - } - if( m_iZoom == 3 ) ZoomReset(); - } - else if( m_iZoom > 1 ) m_iZoom = 3; - - MESSAGE_BEGIN( MSG_ONE, gmsg.ZoomHUD, NULL, m_pPlayer->pev ); - WRITE_BYTE( m_iZoom ); - MESSAGE_END(); -} - -void CBasePlayerWeapon::ZoomReset( void ) -{ - // return viewmodel - if( m_iZoom ) - { - m_pPlayer->pev->viewmodel = iViewModel(); - m_flHoldTime = UTIL_WeaponTimeBase() + 0.5; - m_pPlayer->pev->fov = 90.0f; - m_iZoom = 0; // clear zoom - MESSAGE_BEGIN( MSG_ONE, gmsg.ZoomHUD, NULL, m_pPlayer->pev ); - WRITE_BYTE( m_iZoom ); - MESSAGE_END(); - m_pPlayer->UpdateClientData(); // update client data manually - } -} - -//========================================================= -// Virtual base functions -//========================================================= -void CBasePlayerWeapon :: Deploy( void ) -{ - m_iStepReload = 0; - if( iMaxClip() && m_iClip <= 0 ) // weapon have clip and clip is empty ? - { - if(!DefaultDeploy( ACT_VM_DEPLOY_EMPTY ))// try to playing "deploy_empty" anim - DefaultDeploy( ACT_VM_DEPLOY );// custom animation not found, play standard animation - } - else DefaultDeploy( ACT_VM_DEPLOY ); // just playing standard anim -} - -void CBasePlayerWeapon :: Holster( void ) -{ - if( iMaxClip() && m_iClip <= 0 ) // weapon have clip and clip is empty ? - { - if(!DefaultHolster(ACT_VM_HOLSTER_EMPTY))// try to playing "holster_empty" anim - DefaultHolster( ACT_VM_HOLSTER ); - } - else DefaultHolster(ACT_VM_HOLSTER); // just playing standard anim -} - -//========================================================= -// NOT USED:HoldDown weapon -//========================================================= -int CBasePlayerWeapon :: FoundAlly( void ) -{ - CBaseEntity *pEntity = UTIL_FindEntityForward( m_pPlayer ); - if( pEntity ) - { - CBaseMonster *pMonster = pEntity->MyMonsterPointer(); - if( pMonster ) - { - int m_class = pMonster->Classify(); - if( m_class == CLASS_PLAYER_ALLY || m_class == CLASS_HUMAN_PASSIVE ) - { - return 1; - } - } - } - return 0; -} - -//========================================================= -// Weapon Frame - main function -//========================================================= -void CBasePlayerWeapon::ItemPreFrame( void ) -{ - -} - -void CBasePlayerWeapon::ItemPostFrame( void ) -{ - if( !b_restored ) - { - m_iClientSkin = -1; // reset last skin info for new weapon - m_iClientBody = -1; // reset last body info for new weapon - m_iClientFov = -1; // reset last fov info for new weapon - - if( iMaxClip() && !m_iClip ) - SetAnimation( ACT_VM_IDLE_EMPTY ); // restore last animation - else SetAnimation( ACT_VM_IDLE1 ); - b_restored = TRUE; - } - if( !m_iSpot && m_pSpot ) // disable laser dot - { - m_iSkin = 0; // disable screen - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/spot_off.wav", 1, ATTN_NORM ); - m_pSpot->Killed(); - m_pSpot = NULL; - } - if( m_iSpot && !m_pSpot ) // enable laser dot - { - m_pSpot = CLaserSpot::CreateSpot( m_pPlayer->pev ); - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/spot_on.wav", 1, ATTN_NORM ); - m_iSkin = 1; // enable screen - } - if( m_pSpot ) m_pSpot->Update( m_pPlayer ); - - ZoomUpdate(); // update zoom - - if( !m_iStepReload ) m_fInReload = FALSE; // reload done - if( m_flTimeUpdate < UTIL_WeaponTimeBase()) PostIdle(); // catch all - if( m_fInReload && m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) - { - if( m_iStepReload > 2 ) - { - // complete the reload. - int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - // add them to the clip - m_iClip += j; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.01; // play PostReload - // m_iStepReload = 1; - m_fInReload = FALSE; - } - } - - if((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack ) && !m_iOnControl ) - { - SecondaryAttack(); - m_pPlayer->pev->button &= ~IN_ATTACK2; - } - else if((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack )) - { - if( m_iOnControl == 1 ) // destroy controllable rocket - { - m_iOnControl = 2; // destroy nuke - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; - return; - } - PrimaryAttack(); - m_pPlayer->pev->button &= ~IN_ATTACK; - } - else if( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) - { - // reload when reload is pressed, or if no buttons are down and weapon is empty. - Reload(); - } - else if(!(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2))) - { - // play sequence holster/deploy if player find or lose suit - if((PLAYER_HAS_SUIT && !PLAYER_DRAW_SUIT) || (!PLAYER_HAS_SUIT && PLAYER_DRAW_SUIT)) - { - m_pPlayer->m_pActiveItem->Holster( ); - m_pPlayer->QueueItem( this ); - if( m_pPlayer->m_pActiveItem ) m_pPlayer->m_pActiveItem->Deploy( ); - } - if( !CanDeploy() && m_flNextPrimaryAttack < gpGlobals->time ) - { - // weapon isn't useable, switch. - if( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this )) - { - m_flNextPrimaryAttack = gpGlobals->time + 0.3; - return; - } - } - else - { - // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing - if( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->time ) - { - Reload(); - return; - } - } - m_iPlayEmptySound = 1; // reset empty sound - if( iFlags() & ITEM_FLAG_USEAUTOAIM ) - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if(m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) // step reload - { - if (m_iStepReload > 0 ) - { - if (m_iClip != iMaxClip() && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - Reload(); - } - else - { - // reload debounce has timed out - if( IsEmptyReload()) - { - if( SetAnimation( ACT_VM_PUMP_EMPTY ) == -1 ) - SetAnimation( ACT_VM_PUMP ); - } - else SetAnimation( ACT_VM_PUMP ); - if( iFlags() & ITEM_FLAG_HIDEAMMO ) - m_iBody = 0; // reset ammo - PostReload(); // post effects - m_iStepReload = 0; - } - } - else if( m_iOnControl > 3 ) // item deploy - { - m_iOnControl = 0; - if( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - SetAnimation( ACT_VM_DEPLOY ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_LONG( 10, 15 ); - } - else Holster(); - } - else WeaponIdle(); - } - } -} - -int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) -{ - BOOL bSend = FALSE; - int state = 0; - - // update weapon body - if( m_iClientBody != m_iBody ) - { - pev->body = (pev->body % NUM_HANDS) + NUM_HANDS * m_iBody; // calculate body - MESSAGE_BEGIN( MSG_ONE, gmsg.SetBody, NULL, m_pPlayer->pev ); - WRITE_BYTE( pev->body ); // weaponmodel body - MESSAGE_END(); - m_iClientBody = m_iBody;//synched - } - - // update weapon skin - if( m_iClientSkin != m_iSkin ) - { - pev->skin = m_iSkin; // calculate skin - MESSAGE_BEGIN( MSG_ONE, gmsg.SetSkin, NULL, m_pPlayer->pev ); - WRITE_BYTE( pev->skin ); //weaponmodel skin. - MESSAGE_END(); - m_iClientSkin = m_iSkin;//synched - } - - if( pPlayer->m_pActiveItem == this ) - { - if( pPlayer->m_fOnTarget ) - state = 0x40; // weapon is ontarget - else state = 1; - } - - // forcing send of all data! - if( !pPlayer->m_fWeapon ) bSend = TRUE; - - // This is the current or last weapon, so the state will need to be updated - if( this == pPlayer->m_pActiveItem || this == pPlayer->m_pClientActiveItem ) - { - if( pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem ) bSend = TRUE; - } - - // if the ammo, state, or fov has changed, update the weapon - if( m_iClip != m_iClientClip || state != m_iClientWeaponState || Q_rint( m_iClientFov ) != Q_rint( m_pPlayer->pev->fov )) - { - bSend = TRUE; - } - - if( bSend ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.CurWeapon, NULL, pPlayer->pev ); - WRITE_BYTE( state ); - WRITE_BYTE( m_iId ); - WRITE_BYTE( m_iClip ); - MESSAGE_END(); - - m_iClientFov = m_pPlayer->pev->fov; - m_iClientClip = m_iClip; - m_iClientWeaponState = state; - pPlayer->m_fWeapon = TRUE; - } - - if( m_pNext ) m_pNext->UpdateClientData( pPlayer ); - return 1; -} - -void CBasePlayerWeapon :: SetNextThink( float delay ) -{ - m_fNextThink = UTIL_WeaponTimeBase() + delay; - pev->nextthink = m_fNextThink; -} - -//========================================================= -// Attach\drop operations -//========================================================= -void CBasePlayerWeapon::DestroyItem( void ) -{ - // if attached to a player, remove. - if ( m_pPlayer ) m_pPlayer->RemovePlayerItem( this ); - Drop(); -} - -void CBasePlayerWeapon::Drop( void ) -{ - SetTouch( NULL ); - SetThink( Remove ); - SetNextThink( 0.1 ); -} - -void CBasePlayerWeapon::AttachToPlayer( CBasePlayer *pPlayer ) -{ - SetObjectClass( ED_STATIC ); // disable client updates - - // make cross-links for consitency - pev->aiment = pPlayer->edict(); - pev->owner = pPlayer->edict(); - - pev->movetype = MOVETYPE_FOLLOW; - pev->solid = SOLID_NOT; - pev->effects |= EF_NODRAW; - pev->modelindex = 0; // server won't send down to clients if modelindex == 0 - pev->targetname = iStringNull; // don't try remove this weapon from map - pev->model = iStringNull; - SetNextThink( 0.1 ); - SetTouch( NULL ); - SetThink( NULL ); -} - -int CBasePlayerWeapon::AddDuplicate( CBasePlayerWeapon *pOriginal ) -{ - if(iFlags() & ITEM_FLAG_NODUPLICATE) return FALSE; - - if ( m_iDefaultAmmo || m_iDefaultAmmo2 ) - return ExtractAmmo( (CBasePlayerWeapon *)pOriginal ); - return ExtractClipAmmo( (CBasePlayerWeapon *)pOriginal ); -} - -int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) -{ - m_pPlayer = pPlayer; // Give global pointer to player - pPlayer->pev->weapons |= (1<GetAmmoIndex( pszAmmo1() ); - m_iSecondaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo2() ); - } - - MESSAGE_BEGIN( MSG_ONE, gmsg.WeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - - return AddWeapon(); -} - -//========================================================= -// Ammo base operations -//========================================================= -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) -{ - int iIdAmmo; - if (iMaxClip < 1) - { - m_iClip = -1; - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - } - else if (m_iClip == 0 ) //add ammo in clip only for new weapons - { - int i; - i = min( m_iClip + iCount, iMaxClip ) - m_iClip; - m_iClip += i; - iIdAmmo = m_pPlayer->GiveAmmo( iCount - i, szName, iMaxCarry ); - } - else iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - - if (iIdAmmo > 0) - { - m_iPrimaryAmmoType = iIdAmmo; - if( m_pPlayer->HasPlayerItem( this )) - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM ); - } - return iIdAmmo > 0 ? TRUE : FALSE; -} - -BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) -{ - int iIdAmmo; - - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMax ); - - if (iIdAmmo > 0) - { - m_iSecondaryAmmoType = iIdAmmo; - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM ); - } - return iIdAmmo > 0 ? TRUE : FALSE; -} - -int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iReturn; - if ( pszAmmo1() != NULL ) - { - iReturn = pWeapon->AddPrimaryAmmo( m_iDefaultAmmo, (char *)pszAmmo1(), iMaxClip(), iMaxAmmo1() ); - m_iDefaultAmmo = 0; - } - - if ( pszAmmo2() != NULL ) - { - iReturn = pWeapon->AddSecondaryAmmo( m_iDefaultAmmo2, (char *)pszAmmo2(), iMaxAmmo2() ); - } - return iReturn; -} - -int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iAmmo; - - if ( m_iClip == WEAPON_NOCLIP ) iAmmo = 0;// guns with no clips always come empty if they are second-hand - else iAmmo = m_iClip; - return pWeapon->m_pPlayer->GiveAmmo( iAmmo, (char *)pszAmmo1(), iMaxAmmo1() ); -} - -void CBasePlayerWeapon :: SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector(-24, -24, 0); - pev->absmax = pev->origin + Vector(24, 24, 16); -} \ No newline at end of file diff --git a/server/ents/baseweapon.h b/server/ents/baseweapon.h deleted file mode 100644 index e0db55c1..00000000 --- a/server/ents/baseweapon.h +++ /dev/null @@ -1,371 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef WEAPONS_H -#define WEAPONS_H - -#include "basebeams.h" -#include "player.h" -#include "bullets.h" -#include "sfx.h" -#include "baserockets.h" -#include "damage.h" -#include "defaults.h" - -class CLaserSpot; - -// weapon flags -#define ITEM_FLAG_SELECTONEMPTY 1 // this weapon can choose without ammo -#define ITEM_FLAG_NOAUTORELOAD 2 // only manual reload -#define ITEM_FLAG_NOAUTOSWITCHEMPTY 4 // don't switch from this weapon -#define ITEM_FLAG_LIMITINWORLD 8 // limit in world -#define ITEM_FLAG_EXHAUSTIBLE 16 // A player can totally exhaust their ammo supply and lose this weapon -#define ITEM_FLAG_NODUPLICATE 32 // player can't give this weapon again -#define ITEM_FLAG_USEAUTOAIM 64 // weapon uses autoaim -#define ITEM_FLAG_HIDEAMMO 128 // hide ammo in round - -// suit definitions -#define BARNEY_SUIT 0 // just in case -#define GORDON_SUIT 1 // gordon suit -#define NUM_HANDS 2 // number of hands: barney and gordon - -#define PLAYER_HAS_SUIT (m_pPlayer->pev->weapons & ITEM_SUIT) -#define PLAYER_DRAW_SUIT (pev->body & GORDON_SUIT) -#define MAX_SHOOTSOUNDS 3 // max of random shoot sounds - -enum { - NONE = 0, - AMMO1, // fire primary ammo - AMMO2, // fire seondary ammo - LASER_DOT, // enable laser dot - ZOOM, // enable zoom - FLASHLIGHT, // enable flashlight - SWITCHMODE, // play two beetwen anims and change body - SWING, // crowbar swing -}; - -#define BATTACK_FIREMODE0 0 //both attack firemode 0 -#define PATTACK_FIREMODE1 1 //primary attack firemode 1 -#define SATTACK_FIREMODE1 2 //secondary attack firemode 2 - -#define EMPTY_RELOAD 3 -#define NORMAL_RELOAD 4 - -typedef struct -{ - int iSlot; // hud slot - int iPosition; // hud position - int iViewModel; // path to viewmodel - int iWorldModel; // path to worldmodel - char szAnimExt[16]; // player anim postfix - string_t iszAmmo1; // ammo 1 type - int iMaxAmmo1; // max ammo 1 - string_t iszAmmo2; // ammo 2 type - int iMaxAmmo2; // max ammo 2 - string_t iszName; // weapon name - int iMaxClip; // clip size - int iId; // unique weapon Id number - int iFlags; // weapon flags - int iWeight; // for autoselect weapon - int attack1; // attack1 type - int attack2; // attack2 type - float fNextAttack; // nextattack - float fNextAttack2; // next secondary attack - string_t firesound[MAX_SHOOTSOUNDS]; // firesounds - string_t sfxsound[MAX_SHOOTSOUNDS]; // sfxsound - int sndcount; // fire sound count - int sfxcount; // sfx sound count - int emptysnd; // empty sound - RandomRange punchangle1; // punchangle 1 attack - RandomRange punchangle2; // punchangle 2 attack - RandomRange recoil1; // recoil 1 attack - RandomRange recoil2; // recoil 2 attack -} ItemInfo; - -typedef struct -{ - string_t iszName; - int iMaxCarry; - int iId; -} AmmoInfo; - -class CBasePlayerWeapon : public CBaseAnimating -{ - DECLARE_CLASS( CBasePlayerWeapon, CBaseAnimating ); -public: - virtual void SetObjectCollisionBox( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() | FCAP_ACROSS_TRANSITION; } - virtual int AddToPlayer( CBasePlayer *pPlayer ); // return TRUE if the item you want the item added to the player inventory - virtual int AddDuplicate( CBasePlayerWeapon *pItem ); // return TRUE if you want your duplicate removed from world - void EXPORT DestroyItem( void ); - void EXPORT DefaultTouch( CBaseEntity *pOther ); // default weapon touch - void EXPORT FallThink ( void ); // when an item is first spawned, this think is run to determine when the object has hit the ground. - void EXPORT Materialize( void ); // make a weapon visible and tangible - void EXPORT AttemptToMaterialize( void ); // the weapon desires to become visible and tangible, if the game rules allow for it - BOOL IsWeapon( void ) { return !strncmp( STRING(pev->classname), "weapon_", 5 ); } - CBaseEntity* Respawn ( void );// copy a weapon - void CheckRespawn( void ); - virtual int GetItemInfo(ItemInfo *p); // get weapon default info - virtual BOOL CanDeploy( void ); - virtual BOOL CanHolster( void ) { return ( m_iOnControl == 0 ); }; // can this weapon be put away right now? - virtual void SetNextThink( float delay ); - virtual void Precache( void ); - void EXPORT ItemTouch( CBaseEntity *pOther ); - virtual void Drop( void ); - virtual void AttachToPlayer ( CBasePlayer *pPlayer ); - virtual void Spawn(void); - virtual int UpdateClientData( CBasePlayer *pPlayer ); // sends hud info to client dll, if things have changed - virtual CBasePlayerWeapon *GetWeaponPtr( void ) { return (CBasePlayerWeapon *)this; }; - int FoundAlly( void ); - inline BOOL CanAttack( float attack_time ) { return ( attack_time <= gpGlobals->time ) ? TRUE : FALSE; } - - //ammo operations - virtual int ExtractAmmo( CBasePlayerWeapon *pWeapon ); // Return TRUE if you can add ammo to yourself when picked up - virtual int ExtractClipAmmo( CBasePlayerWeapon *pWeapon ); // Return TRUE if you can add ammo to yourself when picked up - virtual int AddWeapon( void ) { ExtractAmmo( this ); return TRUE; }; // Return TRUE if you want to add yourself to the player - BOOL AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ); - BOOL AddSecondaryAmmo( int iCount, char *szName, int iMaxCarry ); - int GetAmmoType( const char *ammo );//determine ammo type primary or secondary - int ReturnAmmoIndex( const char *ammo );//return primary or secondary ammo index - int UseAmmo( const char *ammo, int count = 1 ); //Determine and use ammo type - - // parse weapon script files - int ParseWeaponFile( ItemInfo *II, const char *pfile ); // parse weapon_*.txt - int ParseWeaponData( ItemInfo *II, const char *file ); // parse WeaponData {} - int ParsePrimaryAttack( ItemInfo *II, const char *pfile ); // parse PrimaryAttack {} - int ParseSecondaryAttack( ItemInfo *II, const char *pfile ); // parse SeconadryAttack {} - int ParseSoundData( ItemInfo *II, const char *pfile ); // parse SoundData {} - // HudData parses on client side - void ResetParse( ItemInfo *II ); //reset ItemInfo - void GenerateID( void );//generate unicum ID number for each weapon - - - //Play Animation methods - int SetAnimation( Activity activity, float fps = 0 ); - int SetAnimation( char *name, float fps = 0 ); - int PlaySequence( Activity activity, float fps = 0 ); - void SetPlayerEffects( const char *ammo, int firemode ); - void PlayAttackSound( int firemode ); - void SendWeaponAnim( int sequence, float fps = 0 ); - float SetNextAttack( float delay ) { return m_pPlayer->m_flNextAttack = gpGlobals->time + delay; } - float SetNextIdle( float delay ) { return m_flTimeWeaponIdle = gpGlobals->time + delay; } - float SequenceDuration( int sequence = -1, float fps = 0 ); - float SequenceFPS( int sequence = -1 ); - - int GetNumBodies( void ) - { - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)(GET_MODEL_PTR( ENT( pev ))); - if( pstudiohdr ) - { - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + NUM_HANDS; - return pbodypart->nummodels; - } - return 0; - } - - //main frame - virtual void ItemPreFrame( void ); // called each frame by the player PreThink - virtual void ItemPostFrame( void ); // called each frame by the player PostThink - - //global weapon info struct (refresh on save\load) - static ItemInfo ItemInfoArray[ MAX_WEAPONS ]; - static AmmoInfo AmmoInfoArray[ MAX_AMMO_SLOTS ]; - - CBasePlayer *m_pPlayer; - CBasePlayerWeapon *m_pNext; - int m_iId; // Weapon unique Id (0 - MAX_WEAPONS) - - //don't save this - CLaserSpot *m_pSpot; // LTD spot - - //virtual methods for ItemInfo acess - int iItemPosition(void) { return ItemInfoArray[ m_iId ].iPosition; } - int iItemSlot( void ) { return ItemInfoArray[ m_iId ].iSlot + 1; } - int iViewModel( void ) { return ItemInfoArray[ m_iId ].iViewModel; } - int iWorldModel( void ) { return ItemInfoArray[ m_iId ].iWorldModel; } - int iMaxAmmo1( void ) { return ItemInfoArray[ m_iId ].iMaxAmmo1; } - int iMaxAmmo2( void ) { return ItemInfoArray[ m_iId ].iMaxAmmo2; } - int iMaxClip( void ) { return ItemInfoArray[ m_iId ].iMaxClip; } - int iWeight( void ) { return ItemInfoArray[ m_iId ].iWeight; } - int iFlags( void ) { return ItemInfoArray[ m_iId ].iFlags; } - int iAttack1( void ) { return ItemInfoArray[ m_iId ].attack1; } - int FireSound( int i ) { return ItemInfoArray[ m_iId ].firesound[i]; } - int SfxSound( int i ) { return ItemInfoArray[ m_iId ].sfxsound[i]; } - int EmptySnd( void ) { return ItemInfoArray[ m_iId ].emptysnd; } - int sndcnt( void ) { return ItemInfoArray[ m_iId ].sndcount; } - int sfxcnt( void ) { return ItemInfoArray[ m_iId ].sfxcount; } - int iAttack2( void ) { return ItemInfoArray[ m_iId ].attack2; } - char *szAnimExt( void ) { return ItemInfoArray[ m_iId ].szAnimExt; } - float fNextAttack1( void ){ return ItemInfoArray[ m_iId ].fNextAttack; } - float fNextAttack2( void ){ return ItemInfoArray[ m_iId ].fNextAttack2; } - float fPunchAngle1( void ){ return ItemInfoArray[ m_iId ].punchangle1.Random(); } - float fPunchAngle2( void ){ return ItemInfoArray[ m_iId ].punchangle2.Random(); } - float fRecoil1( void ) { return ItemInfoArray[ m_iId ].recoil1.Random(); } - float fRecoil2( void ) { return ItemInfoArray[ m_iId ].recoil2.Random(); } - const char *pszAmmo1( void ) { return STRING( ItemInfoArray[ m_iId ].iszAmmo1 ); } - const char *pszAmmo2( void ) { return STRING( ItemInfoArray[ m_iId ].iszAmmo2 ); } - const char *pszName( void ) { return STRING( ItemInfoArray[ m_iId ].iszName ); } - - BOOL PlayEmptySound( void );//universal empty sound - - // default functions - BOOL DefaultDeploy( Activity sequence ); - BOOL DefaultHolster( Activity sequence ); - BOOL DefaultReload( Activity sequence ); - void DefaultIdle( void ); - int Shoot ( const char *ammo, Vector vecSpread, int firemode = 0, int cShots = 1 ); //bullet shoot - int Launch ( const char *ammo, int type = 0 ); //rocket launch - int Swing( int fFirst ); //crowbar swing - - void ZoomUpdate( void ); - void ZoomReset( void ); - - // virtaul weapon functions - int PlayCurrentAttack( int action, int firemode ); - int GetCurrentAttack( const char *ammo, int firemode ); - Vector GetCurrentSpread( const char *ammo ); - int GetBulletType( const char *ammo ); - - inline int PlayRangeAttack( float fps = 0 ) - { - //play random "range" animation - float flRand = RANDOM_FLOAT(0.0, 1.0); - if( flRand < 0.5 && SetAnimation( ACT_VM_RANGE_ATTACK1, fps ) == -1) return 0; - if( flRand > 0.8 && SetAnimation( ACT_VM_RANGE_ATTACK2, fps ) == -1) - { - if(SetAnimation( ACT_VM_RANGE_ATTACK1, fps ) == -1) return 0; - } - if( flRand < 0.8 && flRand > 0.5 && SetAnimation( ACT_VM_RANGE_ATTACK3, fps ) == -1) - { - if(SetAnimation( ACT_VM_RANGE_ATTACK1, fps ) == -1) return 0; - } - return 1; - } - - inline int PlayMeleeAttack( float fps = 0 ) - { - //play random "range" animation - float flRand = RANDOM_FLOAT(0.0, 1.0); - if( flRand < 0.5 && SetAnimation( ACT_VM_MELEE_ATTACK1, fps ) == -1) return 0; - if( flRand > 0.8 && SetAnimation( ACT_VM_MELEE_ATTACK2, fps ) == -1) - { - if(SetAnimation( ACT_VM_MELEE_ATTACK1, fps ) == -1) return 0; - } - if( flRand < 0.8 && flRand > 0.5 && SetAnimation( ACT_VM_MELEE_ATTACK3, fps ) == -1) - { - if(SetAnimation( ACT_VM_MELEE_ATTACK1, fps ) == -1) return 0; - } - return 1; - } - - inline int PlayEmptyFire( float fps = 0 ) - { - if(iMaxClip() && !m_iClip)//last round - { - return SetAnimation( ACT_VM_SHOOT_EMPTY, fps ) == -1 ? FALSE : TRUE; - } - return 0; - } - - //GENERIC WEAPON FUNCTIONS - virtual void PrimaryPostAttack( void ) {} - virtual void SecondaryPostAttack( void ) {} - virtual void PostReload( void ) {} - inline int IsEmptyReload( void ) { return m_iStepReload == EMPTY_RELOAD ? TRUE : FALSE; } - - virtual void PrimaryAttack( void ) // do "+ATTACK" - { - int iResult = PlayCurrentAttack( iAttack1(), FBitSet(pev->impulse, PATTACK_FIREMODE1) ? 1 : 0 ); - if(iResult == 1) - { - m_pPlayer->pev->punchangle.x = fPunchAngle1(); - m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * fRecoil1(); - if ( (iFlags() & ITEM_FLAG_HIDEAMMO ) && m_iClip < GetNumBodies() && m_iClip ) m_iBody++; - - PrimaryPostAttack(); //run post effects - if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + fNextAttack1() + 0.02; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + fNextAttack1(); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_LONG(10, 15); - } - else if(iResult == 0) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - } - m_iStepReload = 0;//reset reload - } - virtual void SecondaryAttack( void ) // do "+ATTACK2" - { - int iResult = PlayCurrentAttack( iAttack2(), FBitSet(pev->impulse, SATTACK_FIREMODE1) ? 1 : 0 ); - if(iResult == 1) - { - m_pPlayer->pev->punchangle.x = fPunchAngle2(); - m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * fRecoil2(); - - SecondaryPostAttack(); //run post effects - if ( m_flNextSecondaryAttack < UTIL_WeaponTimeBase() ) - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + fNextAttack2() + 0.02; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + fNextAttack2(); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_LONG(10, 15); - } - else if(iResult == 0) - { - PlayEmptySound( ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - } - m_iStepReload = 0;//reset reload - } - - virtual void Reload( void ){ DefaultReload( ACT_VM_RELOAD ); } // do "+RELOAD" - virtual void PostIdle( void ) {} // calling every frame - virtual void WeaponIdle( void ) // called when no buttons pressed - { - if( !stricmp( pszAmmo1(), "grenade" )) - { - if(m_flHoldTime) Launch( pszAmmo1()); - else DefaultIdle(); - } - else DefaultIdle(); - } - virtual void Deploy( void ); // deploy function - virtual void Holster( void ); // holster function - - //weapon saved variables - 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 - float m_flTimeUpdate; // special time for additional effects - int m_iPrimaryAmmoType; // "primary" ammo index into players m_rgAmmo[] - int m_iSecondaryAmmoType; // "secondary" ammo index into players m_rgAmmo[] - int m_iDefaultAmmo; // how much primary ammo you get - int m_iDefaultAmmo2; // how much secondary ammo you get - int m_cActiveRocket; // how many rockets is now active ? - int m_iOnControl; // controllable rocket is on control now - int m_iStepReload; // reload state - int m_iSequence; // current weaponmodel sequence - int m_iClip; // current clip state - int m_iBody; // viewmodel body - int m_iSkin; // viewmodel skin - int m_iSpot; // enable laser dot - int m_iZoom; // zoom current level - - //weapon nonsaved variables - float m_flHoldTime; // button holdtime - int m_iClientClip; // the last version of m_iClip sent to hud dll - int m_iClientFov; // g-cont. just to right update crosshairs - int m_iClientWeaponState; // the last version of the weapon state sent to hud dll (is current weapon, is on target) - int m_iPlayEmptySound; // trigger for empty sound - int m_fInReload; // Are we in the middle of a reload; - int m_iClientSkin; // synch server and client skin - int m_iClientBody; // synch server and client body - int b_restored; // restore body and skin -}; - -#endif // WEAPONS_H diff --git a/server/ents/baseworld.cpp b/server/ents/baseworld.cpp deleted file mode 100644 index 2210cad5..00000000 --- a/server/ents/baseworld.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" - -#define SF_WORLD_DARK 0x0001 -#define SF_WORLD_TITLE 0x0002 - -void CWorld :: Precache( void ) -{ - g_pWorld = this; - m_pLinkList = NULL; - InitWorld(); - - if( pev->spawnflags & SF_WORLD_DARK ) - { - CVAR_SET_FLOAT( "v_dark", 1.0f ); - ClearBits( pev->spawnflags, SF_WORLD_DARK ); - } - else CVAR_SET_FLOAT( "v_dark", 0.0f ); -} - -void CWorld :: KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "skyname" )) - { - CVAR_SET_STRING( "sv_skyname", pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "chaptertitle") ) - { - pev->netname = ALLOC_STRING( pkvd->szValue ); - CVAR_SET_FLOAT( "sv_newunit", 1 ); //new chapter - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "gametitle") ) - { - SetBits( pev->spawnflags, SF_WORLD_TITLE ); - pkvd->fHandled = TRUE; - } -} - -void CWorld :: Spawn( void ) -{ - g_fGameOver = FALSE; - Precache(); -} - -void CWorld :: PostActivate( void ) -{ - // run post messages - if ( pev->netname ) - { - UTIL_ShowMessageAll( STRING(pev->netname) ); - pev->netname = iStringNull; - } - - if ( pev->spawnflags & SF_WORLD_TITLE ) - { - SERVER_COMMAND( "gametitle\n" ); - ClearBits( pev->spawnflags, SF_WORLD_TITLE ); - } -} -LINK_ENTITY_TO_CLASS( worldspawn, CWorld ); \ No newline at end of file diff --git a/server/ents/baseworld.h b/server/ents/baseworld.h deleted file mode 100644 index 46b53573..00000000 --- a/server/ents/baseworld.h +++ /dev/null @@ -1,20 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef BASEWORLD_H -#define BASEWORLD_H - -class CWorld : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void PostActivate( void ); -}; - -extern BOOL g_startSuit; -extern CWorld *g_pWorld; - -#endif //BASEWORLD_H \ No newline at end of file diff --git a/server/game/game.cpp b/server/game/game.cpp deleted file mode 100644 index 9443a32c..00000000 --- a/server/game/game.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "utils.h" -#include "game.h" - -cvar_t *sv_maxspeed; - -// Register your console variables here -// This gets called one time when the game is initialized -void GameDLLInit( void ) -{ - ALERT( at_aiconsole, "GameDLLInit();\n" ); - - sv_maxspeed = CVAR_REGISTER( "sv_maxspeed", "320", 0, "maximum speed a player can accelerate to when on ground" ); - - // register cvars here: - CVAR_REGISTER( "sv_soundlist", "0", 0, "show server sound list" ); - - CVAR_REGISTER( "mp_teamplay", "0", FCVAR_SERVERINFO, "sets to 1 to indicate teamplay" ); - CVAR_REGISTER( "mp_fraglimit", "0", FCVAR_SERVERINFO, "limit of frags for current server" ); - CVAR_REGISTER( "mp_timelimit", "0", FCVAR_SERVERINFO, "server timelimit" ); - CVAR_REGISTER( "mp_footsteps", "0", FCVAR_SERVERINFO|FCVAR_PHYSICINFO, "can hear footsteps from other players" ); - - CVAR_REGISTER( "mp_fragsleft", "0", FCVAR_SERVERINFO, "counter that indicated how many frags remaining" ); - CVAR_REGISTER( "mp_timeleft", "0" , FCVAR_SERVERINFO, "counter that indicated how many time remaining" ); - - CVAR_REGISTER( "mp_friendlyfire", "0", FCVAR_SERVERINFO, "enables firedlyfire for teamplay" ); - CVAR_REGISTER( "mp_falldamage", "0", FCVAR_SERVERINFO, "falldamage multiplier" ); - CVAR_REGISTER( "mp_weaponstay", "0", FCVAR_SERVERINFO, "weapon leave stays on ground" ); - CVAR_REGISTER( "mp_forcerespawn", "1", FCVAR_SERVERINFO, "force client respawn after his death" ); - CVAR_REGISTER( "mp_flashlight", "0", FCVAR_SERVERINFO, "attempt to use flashlight in multiplayer" ); - CVAR_REGISTER( "mp_autocrosshair", "1", FCVAR_SERVERINFO, "enables auto-aim in multiplayer" ); - CVAR_REGISTER( "decalfrequency", "30", FCVAR_SERVERINFO, "how many decals can be spawned" ); - CVAR_REGISTER( "mp_teamlist", "hgrunt,scientist", FCVAR_SERVERINFO, "names of default teams" ); - CVAR_REGISTER( "mp_teamoverride", "1", 0, "can ovveride teams from map settings ?" ); - CVAR_REGISTER( "mp_defaultteam", "0", 0, "use default team instead ?" ); - CVAR_REGISTER( "mp_chattime", "10", FCVAR_SERVERINFO, "time beetween messages" ); -} - -// perform any shutdown operations -void GameDLLShutdown( void ) -{ -} \ No newline at end of file diff --git a/server/game/game.h b/server/game/game.h deleted file mode 100644 index eff96188..00000000 --- a/server/game/game.h +++ /dev/null @@ -1,26 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef GAME_H -#define GAME_H - -#include "cvardef.h" - -extern void GameDLLInit( void ); -extern void GameDLLShutdown( void ); - -extern cvar_t *sv_maxspeed; - -#endif // GAME_H diff --git a/server/game/gamerules.cpp b/server/game/gamerules.cpp deleted file mode 100644 index a4494828..00000000 --- a/server/game/gamerules.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// GameRules.cpp -//========================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "player.h" -#include "baseweapon.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "game.h" - -extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); - -DLL_GLOBAL CGameRules* g_pGameRules = NULL; -extern DLL_GLOBAL BOOL g_fGameOver; - -int g_teamplay = 0; - -//========================================================= -//========================================================= -BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry ) -{ - int iAmmoIndex; - - if ( pszAmmoName ) - { - iAmmoIndex = pPlayer->GetAmmoIndex( pszAmmoName ); - - if ( iAmmoIndex > -1 ) - { - if ( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry ) - { - // player has room for more of this type of ammo - return TRUE; - } - } - } - - return FALSE; -} - -//========================================================= -//========================================================= -edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer ) -{ - edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer ); - - pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector( 0, 0, 1 ); - pPlayer->pev->v_angle = g_vecZero; - pPlayer->pev->velocity = g_vecZero; - pPlayer->pev->angles = VARS( pentSpawnSpot )->angles; - pPlayer->pev->punchangle = g_vecZero; - pPlayer->pev->fixangle = TRUE; - - if( pentSpawnSpot->v.spawnflags & 1 ) // the START WITH SUIT flag - { - g_startSuit = TRUE; - } - return pentSpawnSpot; -} - -//========================================================= -//========================================================= -BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ) -{ - // only living players can have items - if ( pPlayer->pev->deadflag != DEAD_NO ) - return FALSE; - - if ( pWeapon->pszAmmo1() ) - { - if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) ) - { - // we can't carry anymore ammo for this gun. We can only - // have the gun if we aren't already carrying one of this type - if ( pPlayer->HasPlayerItem( pWeapon ) ) - { - return FALSE; - } - } - } - else - { - // weapon doesn't use ammo, don't take another if you already have it. - if ( pPlayer->HasPlayerItem( pWeapon ) ) - { - return FALSE; - } - } - - // note: will fall through to here if GetItemInfo doesn't fill the struct! - return TRUE; -} - -//========================================================= -// load the SkillData struct with the proper values based on the skill level. -//========================================================= -void CGameRules::RefreshSkillData ( void ) -{ -} - -//========================================================= -// instantiate the proper game rules object -//========================================================= - -CGameRules *InstallGameRules( void ) -{ - SERVER_COMMAND( "exec game.rc\n" ); - g_engfuncs.pfnServerExecute(); - - ALERT( at_aiconsole, "InstallGameRules\n" ); - - if ( !gpGlobals->deathmatch ) - { - // generic half-life - g_teamplay = 0; - return new CHalfLifeRules; - } - else - { - if( CVAR_GET_FLOAT( "mp_teamplay" ) > 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/server/game/gamerules.h b/server/game/gamerules.h deleted file mode 100644 index 512f9240..00000000 --- a/server/game/gamerules.h +++ /dev/null @@ -1,307 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// GameRules -//========================================================= - -class CBasePlayerWeapon; -class CBasePlayer; -class CItem; -class CBasePlayerAmmo; - -// weapon respawning return codes -enum -{ - GR_NONE = 0, - - GR_WEAPON_RESPAWN_YES, - GR_WEAPON_RESPAWN_NO, - - GR_AMMO_RESPAWN_YES, - GR_AMMO_RESPAWN_NO, - - GR_ITEM_RESPAWN_YES, - GR_ITEM_RESPAWN_NO, - - GR_PLR_DROP_GUN_ALL, - GR_PLR_DROP_GUN_ACTIVE, - GR_PLR_DROP_GUN_NO, - - GR_PLR_DROP_AMMO_ALL, - GR_PLR_DROP_AMMO_ACTIVE, - GR_PLR_DROP_AMMO_NO, -}; - -// Player relationship return codes -enum -{ - GR_NOTTEAMMATE = 0, - GR_TEAMMATE, - GR_ENEMY, - GR_ALLY, - GR_NEUTRAL, -}; - -class CGameRules -{ -public: - virtual void RefreshSkillData( void );// fill skill data struct with proper values - virtual void Think( void ) = 0;// GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc. - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg monsters don't spawn in deathmatch). - - virtual BOOL FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight? - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ) = 0;// should the player switch to this weapon? - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pCurrentWeapon ) = 0;// I can't use this weapon anymore, get me the next best one. - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch) - virtual BOOL IsDeathmatch( void ) = 0;//is this a deathmatch game? - virtual BOOL IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules? - virtual BOOL IsCoOp( void ) = 0;// is this a coop game? - -// Client connection/disconnection - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ) = 0; // a client just connected to the server (player hasn't spawned yet) - virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server - virtual void UpdateGameMode( CBasePlayer *pPlayer ) {} // the client needs to be informed of the current game mode - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage? - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) {return TRUE;};// can this player take damage from this attacker? - virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; } - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game - virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now? - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn? - virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction. - - virtual BOOL AllowAutoTargetCrosshair( void ) { return TRUE; }; - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { return FALSE; }; // handles the user commands; returns TRUE if command handled properly - virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) {} // the player has changed userinfo; can change it now - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player? - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) = 0;// Called each time a player dies - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )= 0;// Call this from within a GameRules class to report an obituary. -// Weapon retrieval - virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon );// The player is touching an CBasePlayerWeapon, do I give it to him? - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ) = 0;// Called each time a player picks up a weapon from the ground - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerWeapon *pWeapon ) = 0;// should this weapon respawn? - virtual float FlWeaponRespawnTime( CBasePlayerWeapon *pWeapon ) = 0;// when may this weapon respawn? - virtual float FlWeaponTryRespawn( CBasePlayerWeapon *pWeapon ) = 0; // can i respawn now, and if not, when should i try again? - virtual Vector VecWeaponRespawnSpot( CBasePlayerWeapon *pWeapon ) = 0;// where in the world should this weapon respawn? - -// Ammo retrieval - virtual BOOL CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry );// can this player take more of this ammo? - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself? - virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself? - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed? - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much? - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) = 0;// what team is this entity on? - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity? - virtual int GetTeamIndex( const char *pTeamName ) { return -1; } - virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; } - virtual BOOL IsValidTeam( const char *pTeamName ) { return TRUE; } - virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {} - virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } - -// Sounds - virtual BOOL PlayTextureSounds( void ) { return TRUE; } - virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; } - -// Monsters - virtual BOOL FAllowMonsters( void ) = 0;//are monsters allowed - - // Immediately end a multiplayer game - virtual void EndMultiplayerGame( void ) {} -}; - -extern CGameRules *InstallGameRules( void ); - - -//========================================================= -// CHalfLifeRules - rules for the single player Half-Life -// game. -//========================================================= -class CHalfLifeRules : public CGameRules -{ -public: - CHalfLifeRules ( void ); - -// GR_Think - virtual void Think( void ); - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); - virtual BOOL FAllowFlashlight( void ) { return TRUE; }; - - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ); - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pCurrentWeapon ); - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ); - virtual BOOL IsDeathmatch( void ); - virtual BOOL IsCoOp( void ); - -// Client connection/disconnection - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ); - virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ); - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ); - virtual void PlayerThink( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); - - virtual BOOL AllowAutoTargetCrosshair( void ); - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - -// Weapon retrieval - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ); - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerWeapon *pWeapon ); - virtual float FlWeaponRespawnTime( CBasePlayerWeapon *pWeapon ); - virtual float FlWeaponTryRespawn( CBasePlayerWeapon *pWeapon ); - virtual Vector VecWeaponRespawnSpot( CBasePlayerWeapon *pWeapon ); - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ); - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); - -// Monsters - virtual BOOL FAllowMonsters( void ); - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); -}; - -//========================================================= -// CHalfLifeMultiplay - rules for the basic half life multiplayer -// competition -//========================================================= -class CHalfLifeMultiplay : public CGameRules -{ -public: - CHalfLifeMultiplay(); - -// GR_Think - virtual void Think( void ); - virtual void RefreshSkillData( void ); - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); - virtual BOOL FAllowFlashlight( void ); - - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ); - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pCurrentWeapon ); - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ); - virtual BOOL IsDeathmatch( void ); - virtual BOOL IsCoOp( void ); - -// Client connection/disconnection - // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in - // svRejectReason - // Only the client's name and remote address are provided to the dll for verification. - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ); - virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ); - virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ); - virtual void PlayerThink( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); - virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); - - virtual BOOL AllowAutoTargetCrosshair( void ); - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - -// Weapon retrieval - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ); - virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon );// The player is touching an CBasePlayerWeapon, do I give it to him? - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerWeapon *pWeapon ); - virtual float FlWeaponRespawnTime( CBasePlayerWeapon *pWeapon ); - virtual float FlWeaponTryRespawn( CBasePlayerWeapon *pWeapon ); - virtual Vector VecWeaponRespawnSpot( CBasePlayerWeapon *pWeapon ); - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ); - virtual float FlHEVChargerRechargeTime( void ); - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";} - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - - virtual BOOL PlayTextureSounds( void ) { return FALSE; } - virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ); - -// Monsters - virtual BOOL FAllowMonsters( void ); - - // Immediately end a multiplayer game - virtual void EndMultiplayerGame( void ) { GoToIntermission(); } - -protected: - virtual void ChangeLevel( void ); - virtual void GoToIntermission( void ); - float m_flIntermissionEndTime; - BOOL m_iEndIntermissionButtonHit; - void SendMOTDToClient( edict_t *client ); -}; - -extern DLL_GLOBAL CGameRules* g_pGameRules; diff --git a/server/game/lights.cpp b/server/game/lights.cpp deleted file mode 100644 index e3c1ea24..00000000 --- a/server/game/lights.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== lights.cpp ======================================================== - - spawn and think functions for editor-placed lights - -*/ - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" - -class CLight : public CBaseLogic -{ -public: - void KeyValue( KeyValueData* pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int GetStyle( void ) { return m_iszCurrentStyle; }; - void SetStyle( int iszPattern ); - void SetCorrectStyle( void ); - -private: - int m_iOnStyle; // style to use while on - int m_iOffStyle; // style to use while off - int m_iTurnOnStyle; // style to use while turning on - int m_iTurnOffStyle; // style to use while turning off - int m_iTurnOnTime; // time taken to turn on - int m_iTurnOffTime; // time taken to turn off - int m_iszPattern; // custom style to use while on - int m_iszCurrentStyle; // current style string -}; -LINK_ENTITY_TO_CLASS( light, CLight ); -LINK_ENTITY_TO_CLASS( light_spot, CLight ); - -TYPEDESCRIPTION CLight::m_SaveData[] = -{ - DEFINE_FIELD( CLight, m_iState, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iszPattern, FIELD_STRING ), - DEFINE_FIELD( CLight, m_iszCurrentStyle, FIELD_STRING ), - DEFINE_FIELD( CLight, m_iOnStyle, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iOffStyle, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iTurnOnStyle, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iTurnOffStyle, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iTurnOnTime, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iTurnOffTime, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CLight, CBaseLogic ); - -// -// Cache user-entity-field values until spawn is called. -// -void CLight :: KeyValue( KeyValueData* pkvd) -{ - if (FStrEq(pkvd->szKeyName, "m_iOnStyle")) - { - m_iOnStyle = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iOffStyle")) - { - m_iOffStyle = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iTurnOnStyle")) - { - m_iTurnOnStyle = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iTurnOffStyle")) - { - m_iTurnOffStyle = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iTurnOnTime")) - { - m_iTurnOnTime = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iTurnOffTime")) - { - m_iTurnOffTime = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - pev->angles.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pattern")) - { - m_iszPattern = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CLight :: SetStyle ( int iszPattern ) -{ - if (m_iStyle < 32) // if it's using a global style, don't change it - return; - m_iszCurrentStyle = iszPattern; - LIGHT_STYLE(m_iStyle, (char *)STRING( iszPattern )); -} - -void CLight :: SetCorrectStyle ( void ) -{ - if (m_iStyle >= 32) - { - switch (m_iState) - { - case STATE_ON: - if (m_iszPattern) // custom styles have priority over standard ones - SetStyle( m_iszPattern ); - else if (m_iOnStyle) - SetStyle(GetStdLightStyle(m_iOnStyle)); - else SetStyle(MAKE_STRING("m")); - break; - case STATE_OFF: - if (m_iOffStyle) - SetStyle(GetStdLightStyle(m_iOffStyle)); - else SetStyle(MAKE_STRING("a")); - break; - case STATE_TURN_ON: - if (m_iTurnOnStyle) - SetStyle(GetStdLightStyle(m_iTurnOnStyle)); - else SetStyle(MAKE_STRING("a")); - break; - case STATE_TURN_OFF: - if (m_iTurnOffStyle) - SetStyle(GetStdLightStyle(m_iTurnOffStyle)); - else SetStyle(MAKE_STRING("m")); - break; - } - } - else m_iszCurrentStyle = GetStdLightStyle( m_iStyle ); -} - -void CLight :: Think( void ) -{ - switch (GetState()) - { - case STATE_TURN_ON: - m_iState = STATE_ON; - UTIL_FireTargets( pev->target, this, this, USE_ON ); - break; - case STATE_TURN_OFF: - m_iState = STATE_OFF; - UTIL_FireTargets(pev->target, this, this, USE_OFF ); - break; - } - SetCorrectStyle(); -} - -void CLight :: Spawn( void ) -{ - if( FStringNull( pev->targetname )) - { - // inert light - REMOVE_ENTITY(ENT( pev )); - return; - } - - if (FBitSet(pev->spawnflags,SF_LIGHT_START_OFF)) - m_iState = STATE_OFF; - else m_iState = STATE_ON; - SetCorrectStyle(); -} - -void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (m_iStyle >= 32) - { - if (useType == USE_TOGGLE) - { - if(m_iState == STATE_ON || m_iState == STATE_TURN_ON) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON) - { - if (m_iTurnOnTime) - { - m_iState = STATE_TURN_ON; - SetNextThink( m_iTurnOnTime ); - } - else m_iState = STATE_ON; - } - else if(useType == USE_OFF) - { - if (m_iTurnOffTime) - { - m_iState = STATE_TURN_OFF; - SetNextThink( m_iTurnOffTime ); - } - else m_iState = STATE_OFF; - } - SetCorrectStyle(); - } -} - -class CEnvLight : public CLight -{ -public: - void KeyValue( KeyValueData* pkvd ); - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( light_environment, CEnvLight ); - -void CEnvLight::KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "_light")) - { - int r, g, b, v, j; - char szColor[64]; - j = sscanf( pkvd->szValue, "%d %d %d %d\n", &r, &g, &b, &v ); - if (j == 1) - { - g = b = r; - } - else if (j == 4) - { - r = r * (v / 255.0); - g = g * (v / 255.0); - b = b * (v / 255.0); - } - - // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling - r = pow( r / 114.0, 0.6 ) * 264; - g = pow( g / 114.0, 0.6 ) * 264; - b = pow( b / 114.0, 0.6 ) * 264; - - pkvd->fHandled = TRUE; - sprintf( szColor, "%d", r ); - CVAR_SET_STRING( "sv_skycolor_r", szColor ); - sprintf( szColor, "%d", g ); - CVAR_SET_STRING( "sv_skycolor_g", szColor ); - sprintf( szColor, "%d", b ); - CVAR_SET_STRING( "sv_skycolor_b", szColor ); - } - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - pev->angles.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - - -void CEnvLight :: Spawn( void ) -{ - char szVector[64]; - UTIL_MakeAimVectors( pev->angles ); - - sprintf( szVector, "%f", gpGlobals->v_forward.x ); - CVAR_SET_STRING( "sv_skyvec_x", szVector ); - sprintf( szVector, "%f", gpGlobals->v_forward.y ); - CVAR_SET_STRING( "sv_skyvec_y", szVector ); - sprintf( szVector, "%f", gpGlobals->v_forward.z ); - CVAR_SET_STRING( "sv_skyvec_z", szVector ); - - CLight::Spawn( ); -} \ No newline at end of file diff --git a/server/game/maprules.cpp b/server/game/maprules.cpp deleted file mode 100644 index ce7a4491..00000000 --- a/server/game/maprules.cpp +++ /dev/null @@ -1,961 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// ------------------------------------------- -// -// maprules.cpp -// -// This module contains entities for implementing/changing game -// rules dynamically within each map (.BSP) -// -// ------------------------------------------- - -#include "extdll.h" -#include "utils.h" -#include "gamerules.h" -#include "cbase.h" -#include "player.h" - -class CRuleEntity : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; } - -protected: - BOOL CanFireForActivator( CBaseEntity *pActivator ); - -private: - string_t m_iszMaster; -}; - -TYPEDESCRIPTION CRuleEntity::m_SaveData[] = -{ - DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), -}; - -IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ); - - -void CRuleEntity::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; -} - - -void CRuleEntity::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "master")) - { - SetMaster( ALLOC_STRING(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) -{ - if (!pActivator) - { - return TRUE; - } - else if ( m_iszMaster ) - { - if ( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) - return TRUE; - else - return FALSE; - } - - return TRUE; -} - -// -// CRulePointEntity -- base class for all rule "point" entities (not brushes) -// -class CRulePointEntity : public CRuleEntity -{ -public: - void Spawn( void ); -}; - -void CRulePointEntity::Spawn( void ) -{ - CRuleEntity::Spawn(); - pev->frame = 0; - pev->model = 0; -} - -// -// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) -// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing -// -class CRuleBrushEntity : public CRuleEntity -{ -public: - void Spawn( void ); - -private: -}; - -void CRuleBrushEntity::Spawn( void ) -{ - SET_MODEL( edict(), STRING(pev->model) ); - CRuleEntity::Spawn(); -} - - -// CGameScore / game_score -- award points to player / team -// Points +/- total -// Flag: Allow negative scores SF_SCORE_NEGATIVE -// Flag: Award points to team in teamplay SF_SCORE_TEAM - -#define SF_SCORE_NEGATIVE 0x0001 -#define SF_SCORE_TEAM 0x0002 - -class CGameScore : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Points( void ) { return pev->frags; } - inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } - inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } - - inline void SetPoints( int points ) { pev->frags = points; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_score, CGameScore ); - - -void CGameScore::Spawn( void ) -{ - CRulePointEntity::Spawn(); -} - - -void CGameScore::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "points")) - { - SetPoints( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - - -void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - // Only players can use this - if ( pActivator->IsPlayer() ) - { - if ( AwardToTeam() ) - { - pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); - } - else - { - pActivator->AddPoints( Points(), AllowNegativeScore() ); - } - } -} - - -// CGameEnd / game_end -- Ends the game in MP - -class CGameEnd : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -private: -}; - -LINK_ENTITY_TO_CLASS( game_end, CGameEnd ); - - -void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - g_pGameRules->EndMultiplayerGame(); -} - - -// -// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) -// Flag: All players SF_ENVTEXT_ALLPLAYERS -// - - -#define SF_ENVTEXT_ALLPLAYERS 0x0001 -#define SF_ENVTEXT_ONLY_ONCE 0x0002 - - -class CGameText : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); } - inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING( pMessage ); } - inline const char *MessageGet( void ) { return STRING(pev->message); } - - void EXPORT TriggerThink( void ); - -private: - - hudtextparms_t m_textParms; - CBaseEntity *m_pActivator; -}; - -LINK_ENTITY_TO_CLASS( game_text, CGameText ); - -// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so -// it can't impact saved Half-Life games. -TYPEDESCRIPTION CGameText::m_SaveData[] = -{ - DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), - DEFINE_FIELD( CGameText, m_pActivator, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ); - - -void CGameText::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "channel")) - { - m_textParms.channel = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "x")) - { - m_textParms.x = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "y")) - { - m_textParms.y = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "effect")) - { - m_textParms.effect = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r1 = color[0]; - m_textParms.g1 = color[1]; - m_textParms.b1 = color[2]; - m_textParms.a1 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color2")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r2 = color[0]; - m_textParms.g2 = color[1]; - m_textParms.b2 = color[2]; - m_textParms.a2 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_textParms.fadeinTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_textParms.fadeoutTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - m_textParms.holdTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fxtime")) - { - m_textParms.fxTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( MessageToAll() ) - { - UTIL_HudMessageAll( m_textParms, MessageGet() ); - } - else - { - if ( pActivator && pActivator->IsNetClient() ) - { - UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); - } - } - - if ( pev->target ) - { - m_pActivator = pActivator; - SetThink( TriggerThink ); - SetNextThink( m_textParms.fadeinTime + m_textParms.holdTime + m_textParms.fadeoutTime ); - } - else if ( pev->spawnflags & SF_ENVTEXT_ONLY_ONCE ) - { - SetThink( Remove ); - SetNextThink( 0.1 ); - } -} - -void CGameText::TriggerThink( void ) -{ - UTIL_FireTargets( pev->target, m_pActivator, this, USE_TOGGLE, 0 ); - - if ( pev->spawnflags & SF_ENVTEXT_ONLY_ONCE ) - { - SetThink( Remove ); - SetNextThink( 0.1 ); - } -} - - - -// -// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator -// Only allows mastered entity to fire if the team matches my team -// -// team index (pulled from server team list "mp_teamlist" -// Flag: Remove on Fire -// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) -// - -#define SF_TEAMMASTER_FIREONCE 0x0001 -#define SF_TEAMMASTER_ANYTEAM 0x0002 - -class CGameTeamMaster : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -// int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; } - - BOOL IsTriggered( CBaseEntity *pActivator ); - const char *TeamID( void ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; } - inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; } - -private: - BOOL TeamMatch( CBaseEntity *pActivator ); - - int m_teamIndex; - USE_TYPE triggerType; -}; - -LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ); - -void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "teamindex")) - { - m_teamIndex = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( useType == USE_SET ) - { - if ( value < 0 ) - { - m_teamIndex = -1; - } - else - { - m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() ); - } - return; - } - - if ( TeamMatch( pActivator ) ) - { - UTIL_FireTargets( pev->target, pActivator, this, triggerType, value ); - - if ( RemoveOnFire() ) - UTIL_Remove( this ); - } -} - - -BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) -{ - return TeamMatch( pActivator ); -} - - -const char *CGameTeamMaster::TeamID( void ) -{ - if ( m_teamIndex < 0 ) // Currently set to "no team" - return ""; - - return g_pGameRules->GetIndexedTeamName( m_teamIndex ); // UNDONE: Fill this in with the team from the "teamlist" -} - - -BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) -{ - if ( m_teamIndex < 0 && AnyTeam() ) - return TRUE; - - if ( !pActivator ) - return FALSE; - - return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); -} - - -// -// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team -// Flag: Fire once -// Flag: Clear team -- Sets the team to "NONE" instead of activator - -#define SF_TEAMSET_FIREONCE 0x0001 -#define SF_TEAMSET_CLEARTEAM 0x0002 - -class CGameTeamSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ); - - -void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( ShouldClearTeam() ) - { - UTIL_FireTargets( pev->target, pActivator, this, USE_SET, -1 ); - } - else - { - UTIL_FireTargets( pev->target, pActivator, this, USE_SET, 0 ); - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired -// -// Needs master? -class CGamePlayerZone : public CRuleBrushEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - string_t m_iszInTarget; - string_t m_iszOutTarget; - string_t m_iszInCount; - string_t m_iszOutCount; -}; - -LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ); -TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = -{ - DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ); - -void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "intarget")) - { - m_iszInTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outtarget")) - { - m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "incount")) - { - m_iszInCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outcount")) - { - m_iszOutCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRuleBrushEntity::KeyValue( pkvd ); -} - -void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int playersInCount = 0; - int playersOutCount = 0; - - if ( !CanFireForActivator( pActivator ) ) - return; - - CBaseEntity *pPlayer = NULL; - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - { - TraceResult trace; - int hullNumber; - BOOL inside = FALSE; - - if (pev->origin == g_vecZero) //LRC - to support movewith - { - hullNumber = human_hull; - if ( pPlayer->pev->flags & FL_DUCKING ) - { - hullNumber = head_hull; - } - UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); - inside = trace.fStartSolid; - } - else - { - // LIMITATION: this doesn't allow for non-cuboid game_zone_player entities. - // (is that a problem?) - inside = this->Intersects(pPlayer); - } - - if ( inside ) - { - playersInCount++; - if ( m_iszInTarget ) - { - UTIL_FireTargets( m_iszInTarget, pPlayer, pActivator, useType, value ); - } - } - else - { - playersOutCount++; - if ( m_iszOutTarget ) - { - UTIL_FireTargets( m_iszOutTarget, pPlayer, pActivator, useType, value ); - } - } - } - } - - if ( m_iszInCount ) - { - UTIL_FireTargets( m_iszInCount, pActivator, this, USE_SET, playersInCount ); - } - - if ( m_iszOutCount ) - { - UTIL_FireTargets( m_iszOutCount, pActivator, this, USE_SET, playersOutCount ); - } -} - - - -// -// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it -// Flag: Fire once - -#define SF_PKILL_FIREONCE 0x0001 -class CGamePlayerHurt : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ); - - -void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - if ( pev->dmg < 0 ) - pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); - else - pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); - } - - UTIL_FireTargets( pev->target, pActivator, this, useType, value ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - - -// -// CGameCounter / game_counter -- Counts events and fires target -// Flag: Fire once -// Flag: Reset on Fire - -#define SF_GAMECOUNT_FIREONCE 0x0001 -#define SF_GAMECOUNT_RESET 0x0002 - -class CGameCounter : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; } - inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; } - - inline void CountUp( void ) { pev->frags++; } - inline void CountDown( void ) { pev->frags--; } - inline void ResetCount( void ) { pev->frags = pev->dmg; } - inline int CountValue( void ) { return pev->frags; } - inline int LimitValue( void ) { return pev->health; } - - inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } - -private: - - inline void SetCountValue( int value ) { pev->frags = value; } - inline void SetInitialValue( int value ) { pev->dmg = value; } -}; - -LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ); - -void CGameCounter::Spawn( void ) -{ - // Save off the initial count - SetInitialValue( CountValue() ); - CRulePointEntity::Spawn(); -} - - -void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - switch( useType ) - { - case USE_ON: - case USE_TOGGLE: - CountUp(); - break; - - case USE_OFF: - CountDown(); - break; - - case USE_SET: - SetCountValue( (int)value ); - break; - } - - if ( HitLimit() ) - { - UTIL_FireTargets( pev->target, pActivator, this, USE_TOGGLE, 0 ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } - - if ( ResetOnFire() ) - { - ResetCount(); - } - } -} - - - -// -// CGameCounterSet / game_counter_set -- Sets the counter's value -// Flag: Fire once - -#define SF_GAMECOUNTSET_FIREONCE 0x0001 - -class CGameCounterSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ); - - -void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - UTIL_FireTargets( pev->target, pActivator, this, USE_SET, pev->frags ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerEquip / game_playerequip -- Sets the default player equipment -// Flag: USE Only - -#define SF_PLAYEREQUIP_USEONLY 0x0001 -#define MAX_EQUIP 32 - -class CGamePlayerEquip : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; } - -private: - - void EquipPlayer( CBaseEntity *pPlayer ); - - string_t m_weaponNames[MAX_EQUIP]; - int m_weaponCount[MAX_EQUIP]; -}; - -LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ); - - -void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) -{ - CRulePointEntity::KeyValue( pkvd ); - - if ( !pkvd->fHandled ) - { - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - - m_weaponNames[i] = ALLOC_STRING(tmp); - m_weaponCount[i] = atoi(pkvd->szValue); - m_weaponCount[i] = max(1,m_weaponCount[i]); - pkvd->fHandled = TRUE; - break; - } - } - } -} - - -void CGamePlayerEquip::Touch( CBaseEntity *pOther ) -{ - if ( !CanFireForActivator( pOther ) ) - return; - - if ( UseOnly() ) - return; - - EquipPlayer( pOther ); -} - -void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) -{ - CBasePlayer *pPlayer = NULL; - - if ( pEntity->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pEntity; - } - - if ( !pPlayer ) - return; - - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - break; - for ( int j = 0; j < m_weaponCount[i]; j++ ) - { - pPlayer->GiveNamedItem( STRING(m_weaponNames[i]) ); - } - } -} - - -void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - EquipPlayer( pActivator ); -} - - -// -// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it -// Flag: Fire once -// Flag: Kill Player -// Flag: Gib Player - -#define SF_PTEAM_FIREONCE 0x0001 -#define SF_PTEAM_KILL 0x0002 -#define SF_PTEAM_GIB 0x0004 - -class CGamePlayerTeam : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: - - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; } - inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; } - - const char *TargetTeamName( const char *pszTargetName ); -}; - -LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ); - - -const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) -{ - CBaseEntity *pTeamEntity = NULL; - - while ((pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName )) != NULL) - { - if ( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) - return pTeamEntity->TeamID(); - } - - return NULL; -} - - -void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); - if ( pszTargetTeam ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pActivator; - g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() ); - } - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - diff --git a/server/game/multiplay_gamerules.cpp b/server/game/multiplay_gamerules.cpp deleted file mode 100644 index b9a95c9f..00000000 --- a/server/game/multiplay_gamerules.cpp +++ /dev/null @@ -1,1441 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "player.h" -#include "baseweapon.h" -#include "gamerules.h" - -#include "game.h" -#include "defaults.h" - -extern DLL_GLOBAL CGameRules *g_pGameRules; -extern DLL_GLOBAL BOOL g_fGameOver; -extern int g_teamplay; - -#define ITEM_RESPAWN_TIME 30 -#define WEAPON_RESPAWN_TIME 20 -#define AMMO_RESPAWN_TIME 20 - -float g_flIntermissionStartTime = 0; - -//********************************************************* -// Rules for the half-life multiplayer game. -//********************************************************* - -CHalfLifeMultiplay :: CHalfLifeMultiplay() -{ - RefreshSkillData(); - m_flIntermissionEndTime = 0; - g_flIntermissionStartTime = 0; - - // 11/8/98 - // Modified by YWB: Server .cfg file is now a cvar, so that - // server ops can run multiple game servers, with different server .cfg files, - // from a single installed directory. - // Mapcyclefile is already a cvar. - - // 3/31/99 - // Added lservercfg file cvar, since listen and dedicated servers should not - // share a single config file. (sjb) - if ( IS_DEDICATED_SERVER() ) - { - // dedicated server - char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); - - if ( servercfgfile && servercfgfile[0] ) - { - char szCommand[256]; - - ALERT( at_console, "Executing dedicated server config file\n" ); - sprintf( szCommand, "exec %s\n", servercfgfile ); - SERVER_COMMAND( szCommand ); - } - } - else - { - // listen server - char *lservercfgfile = (char *)CVAR_GET_STRING( "lservercfgfile" ); - - if ( lservercfgfile && lservercfgfile[0] ) - { - char szCommand[256]; - - ALERT( at_console, "Executing listen server config file\n" ); - sprintf( szCommand, "exec %s\n", lservercfgfile ); - SERVER_COMMAND( szCommand ); - } - } -} - -BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) -{ - return CGameRules::ClientCommand(pPlayer, pcmd); -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay::RefreshSkillData( void ) -{ -} - -// longest the intermission can last, in seconds -#define MAX_INTERMISSION_TIME 120 - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: Think ( void ) -{ - ///// Check game rules ///// - static int last_frags; - static int last_time; - - int frags_remaining = 0; - int time_remaining = 0; - - if ( g_fGameOver ) // someone else quit the game already - { - // bounds check - int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); - if ( time < 1 ) - CVAR_SET_STRING( "mp_chattime", "1" ); - else if ( time > MAX_INTERMISSION_TIME ) - CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); - - m_flIntermissionEndTime = g_flIntermissionStartTime + CVAR_GET_FLOAT( "mp_chattime" ); - - // check to see if we should change levels now - if ( m_flIntermissionEndTime < gpGlobals->time ) - { - if ( m_iEndIntermissionButtonHit // check that someone has pressed a key, or the max intermission time is over - || ( ( g_flIntermissionStartTime + MAX_INTERMISSION_TIME ) < gpGlobals->time) ) - ChangeLevel(); // intermission is over - } - - return; - } - - float flTimeLimit = CVAR_GET_FLOAT( "mp_timelimit" ) * 60; - float flFragLimit = CVAR_GET_FLOAT( "mp_fraglimit" ); - - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) - { - GoToIntermission(); - return; - } - - if ( flFragLimit ) - { - int bestfrags = 9999; - int remain; - - // check if any player is over the frag limit - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( pPlayer && pPlayer->pev->frags >= flFragLimit ) - { - GoToIntermission(); - return; - } - - - if ( pPlayer ) - { - remain = flFragLimit - pPlayer->pev->frags; - if ( remain < bestfrags ) - { - bestfrags = remain; - } - } - - } - frags_remaining = bestfrags; - } - - // Updates when frags change - if ( frags_remaining != last_frags ) - { - g_engfuncs.pfnCVarSetString( "mp_fragsleft", UTIL_VarArgs( "%i", frags_remaining ) ); - } - - // Updates once per second - if( CVAR_GET_FLOAT( "mp_timeleft" ) != last_time ) - { - g_engfuncs.pfnCVarSetString( "mp_timeleft", UTIL_VarArgs( "%i", time_remaining ) ); - } - - last_frags = frags_remaining; - last_time = time_remaining; -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsMultiplayer( void ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsDeathmatch( void ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsCoOp( void ) -{ - return gpGlobals->coop; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ) -{ - if ( !pWeapon->CanDeploy() ) - { - // that weapon can't deploy anyway. - return FALSE; - } - - if ( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if ( !pPlayer->m_pActiveItem->CanHolster() ) - { - // can't put away the active item. - return FALSE; - } - - if ( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) - { - return TRUE; - } - - return FALSE; -} - -BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pCurrentWeapon ) -{ - - CBasePlayerWeapon *pCheck; - CBasePlayerWeapon *pBest;// this will be used in the event that we don't find a weapon in the same category. - int iBestWeight; - int i; - - iBestWeight = -1;// no weapon lower than -1 can be autoswitched to - pBest = NULL; - - if ( !pCurrentWeapon->CanHolster() ) - { - // can't put this gun away right now, so can't switch. - return FALSE; - } - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pCheck = pPlayer->m_rgpPlayerItems[ i ]; - - while ( pCheck ) - { - if ( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) - { - // this weapon is from the same category. - if ( pCheck->CanDeploy() ) - { - if ( pPlayer->SwitchWeapon( pCheck ) ) - { - return TRUE; - } - } - } - else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of - { - //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); - // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight - // that the player was using. This will end up leaving the player with his heaviest-weighted - // weapon. - if ( pCheck->CanDeploy() ) - { - // if this weapon is useable, flag it as the best - iBestWeight = pCheck->iWeight(); - pBest = pCheck; - } - } - - pCheck = pCheck->m_pNext; - } - } - - // if we make it here, we've checked all the weapons and found no useable - // weapon in the same catagory as the current weapon. - - // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always - // at least get the crowbar, but ya never know. - if ( !pBest ) - { - return FALSE; - } - - pPlayer->SwitchWeapon( pBest ); - - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ) -{ - return TRUE; -} - -void CHalfLifeMultiplay :: UpdateGameMode( CBasePlayer *pPlayer ) -{ - MESSAGE_BEGIN( MSG_ONE, gmsg.GameMode, NULL, pPlayer->edict() ); - WRITE_BYTE( 0 ); // game mode none - MESSAGE_END(); -} - -void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) -{ - // notify other clients of player joining the game - UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has joined the game\n", - ( pl->pev->netname && STRING(pl->pev->netname)[0] != 0 ) ? STRING(pl->pev->netname) : "unconnected" ) ); - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" entered the game\n", - STRING( pl->pev->netname ), - GETPLAYERUSERID( pl->edict() ), - GETPLAYERAUTHID( pl->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pl->edict() ), "model" ) ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" entered the game\n", - STRING( pl->pev->netname ), - GETPLAYERUSERID( pl->edict() ), - GETPLAYERAUTHID( pl->edict() ), - GETPLAYERUSERID( pl->edict() ) ); - } - - UpdateGameMode( pl ); - - // sending just one score makes the hud scoreboard active; otherwise - // it is just disabled for single play - MESSAGE_BEGIN( MSG_ONE, gmsg.ScoreInfo, NULL, pl->edict() ); - WRITE_BYTE( ENTINDEX(pl->edict()) ); - WRITE_SHORT( 0 ); - WRITE_SHORT( 0 ); - WRITE_SHORT( 0 ); - WRITE_SHORT( 0 ); - MESSAGE_END(); - - SendMOTDToClient( pl->edict() ); - - // loop through all active players and send their score info to the new client - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - // FIXME: Probably don't need to cast this just to read m_iDeaths - CBasePlayer *plr = (CBasePlayer *)UTIL_PlayerByIndex( i ); - - if ( plr ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.ScoreInfo, NULL, pl->edict() ); - WRITE_BYTE( i ); // client number - WRITE_SHORT( plr->pev->frags ); - WRITE_SHORT( plr->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( GetTeamIndex( plr->m_szTeamName ) + 1 ); - MESSAGE_END(); - } - } - - if ( g_fGameOver ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.Intermission, NULL, pl->edict() ); - MESSAGE_END(); - } -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) -{ - if ( pClient ) - { - CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); - - if ( pPlayer ) - { - UTIL_FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE ); - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected\n", - STRING( pPlayer->pev->netname ), - GETPLAYERUSERID( pPlayer->edict() ), - GETPLAYERAUTHID( pPlayer->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ) ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" disconnected\n", - STRING( pPlayer->pev->netname ), - GETPLAYERUSERID( pPlayer->edict() ), - GETPLAYERAUTHID( pPlayer->edict() ), - GETPLAYERUSERID( pPlayer->edict() ) ); - } - - pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items - } - } -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay :: FlPlayerFallDamage( CBasePlayer *pPlayer ) -{ - int iFallDamage = (int)CVAR_GET_FLOAT( "mp_falldamage" ); - - switch ( iFallDamage ) - { - case 1://progressive - pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; - return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; - break; - default: - case 0:// fixed - return 10; - break; - } -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: PlayerThink( CBasePlayer *pPlayer ) -{ - if ( g_fGameOver ) - { - // check for button presses - if ( pPlayer->m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) - m_iEndIntermissionButtonHit = TRUE; - - // clear attack/use commands from player - pPlayer->m_afButtonPressed = 0; - pPlayer->pev->button = 0; - pPlayer->m_afButtonReleased = 0; - } -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer ) -{ - BOOL addDefault; - CBaseEntity *pWeaponEntity = NULL; - - pPlayer->pev->weapons |= ITEM_SUIT; - - addDefault = TRUE; - - while ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" )) - { - pWeaponEntity->Touch( pPlayer ); - addDefault = FALSE; - } - - if ( addDefault ) - { - pPlayer->GiveNamedItem( "weapon_crowbar" ); - pPlayer->GiveNamedItem( "weapon_glock" ); - pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY );// 4 full reloads - } -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: FPlayerCanRespawn( CBasePlayer *pPlayer ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) -{ - return gpGlobals->time;//now! -} - -BOOL CHalfLifeMultiplay :: AllowAutoTargetCrosshair( void ) -{ - return CVAR_GET_FLOAT( "mp_autocrosshair" ) ? TRUE : FALSE; -} - -//========================================================= -// IPointsForKill - how many points awarded to anyone -// that kills this player? -//========================================================= -int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - return 1; -} - - -//========================================================= -// PlayerKilled - someone/something killed this player -//========================================================= -void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ - DeathNotice( pVictim, pKiller, pInflictor ); - - pVictim->m_iDeaths += 1; - - - UTIL_FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE ); - CBasePlayer *peKiller = NULL; - CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); - if ( ktmp && (ktmp->Classify() == CLASS_PLAYER) ) - peKiller = (CBasePlayer*)ktmp; - - if ( pVictim->pev == pKiller ) - { // killed self - pKiller->frags -= 1; - } - else if ( ktmp && ktmp->IsPlayer() ) - { - // if a player dies in a deathmatch game and the killer is a client, award the killer some points - pKiller->frags += IPointsForKill( peKiller, pVictim ); - - UTIL_FireTargets( "game_playerkill", ktmp, ktmp, USE_TOGGLE ); - } - else - { // killed by the world -//MH pKiller->frags -= 1; this should be victim (we don't want to give the world frags) - pVictim->pev->frags -= 1; -//END - } - - // update the scores - // killed scores - MESSAGE_BEGIN( MSG_ALL, gmsg.ScoreInfo ); - WRITE_BYTE( ENTINDEX(pVictim->edict()) ); - WRITE_SHORT( pVictim->pev->frags ); - WRITE_SHORT( pVictim->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( GetTeamIndex( pVictim->m_szTeamName ) + 1 ); - MESSAGE_END(); - - // killers score, if it's a player - CBaseEntity *ep = CBaseEntity::Instance( pKiller ); - if ( ep && ep->Classify() == CLASS_PLAYER ) - { - CBasePlayer *PK = (CBasePlayer*)ep; - - MESSAGE_BEGIN( MSG_ALL, gmsg.ScoreInfo ); - WRITE_BYTE( ENTINDEX(PK->edict()) ); - WRITE_SHORT( PK->pev->frags ); - WRITE_SHORT( PK->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( GetTeamIndex( PK->m_szTeamName) + 1 ); - MESSAGE_END(); - - // let the killer paint another decal as soon as he'd like. - PK->m_flNextDecalTime = gpGlobals->time; - } -} - -//========================================================= -// Deathnotice. -//========================================================= -void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) -{ - // Work out what killed the player, and send a message to all clients about it - CBaseEntity *Killer = CBaseEntity::Instance( pKiller ); - - const char *killer_weapon_name = "world"; // by default, the player is killed by the world - int killer_index = 0; - - // Hack to fix name change - char *tau = "tau_cannon"; - char *gluon = "gluon gun"; - - if ( pKiller->flags & FL_CLIENT ) - { - killer_index = ENTINDEX(ENT(pKiller)); - - if ( pevInflictor ) - { - if ( pevInflictor == pKiller ) - { - // If the inflictor is the killer, then it must be their current weapon doing the damage - CBasePlayer *pPlayer = (CBasePlayer*)CBaseEntity::Instance( pKiller ); - - if ( pPlayer->m_pActiveItem ) - { - killer_weapon_name = pPlayer->m_pActiveItem->pszName(); - } - } - else - { - killer_weapon_name = STRING( pevInflictor->classname ); // it's just that easy - } - } - } - else - { - killer_weapon_name = STRING( pevInflictor->classname ); - } - - // strip the monster_* or weapon_* from the inflictor's classname - if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) - killer_weapon_name += 7; - else if ( strncmp( killer_weapon_name, "monster_", 8 ) == 0 ) - killer_weapon_name += 8; - else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) - killer_weapon_name += 5; - - MESSAGE_BEGIN( MSG_ALL, gmsg.DeathMsg ); - WRITE_BYTE( killer_index ); // the killer - WRITE_BYTE( ENTINDEX(pVictim->edict()) ); // the victim - WRITE_STRING( killer_weapon_name ); // what they were killed by (should this be a string?) - MESSAGE_END(); - - // replace the code names with the 'real' names - if ( !strcmp( killer_weapon_name, "egon" ) ) - killer_weapon_name = gluon; - else if ( !strcmp( killer_weapon_name, "gauss" ) ) - killer_weapon_name = tau; - - if ( pVictim->pev == pKiller ) - { - // killed self - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), - killer_weapon_name ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" committed suicide with \"%s\"\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - GETPLAYERUSERID( pVictim->edict() ), - killer_weapon_name ); - } - } - else if ( pKiller->flags & FL_CLIENT ) - { - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", - STRING( pKiller->netname ), - GETPLAYERUSERID( ENT(pKiller) ), - GETPLAYERAUTHID( ENT(pKiller) ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( ENT(pKiller) ), "model" ), - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), - killer_weapon_name ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" killed \"%s<%i><%s><%i>\" with \"%s\"\n", - STRING( pKiller->netname ), - GETPLAYERUSERID( ENT(pKiller) ), - GETPLAYERAUTHID( ENT(pKiller) ), - GETPLAYERUSERID( ENT(pKiller) ), - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - GETPLAYERUSERID( pVictim->edict() ), - killer_weapon_name ); - } - } - else - { - // killed by the world - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), - killer_weapon_name ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" committed suicide with \"%s\" (world)\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - GETPLAYERUSERID( pVictim->edict() ), - killer_weapon_name ); - } - } - - // Print a standard message - // TODO: make this go direct to console - return; // just remove for now -/* - char szText[ 128 ]; - - if ( pKiller->flags & FL_MONSTER ) - { - // killed by a monster - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was killed by a monster.\n" ); - return; - } - - if ( pKiller == pVictim->pev ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " commited suicide.\n" ); - } - else if ( pKiller->flags & FL_CLIENT ) - { - strcpy ( szText, STRING( pKiller->netname ) ); - - strcat( szText, " : " ); - strcat( szText, killer_weapon_name ); - strcat( szText, " : " ); - - strcat ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, "\n" ); - } - else if ( FClassnameIs ( pKiller, "worldspawn" ) ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " fell or drowned or something.\n" ); - } - else if ( pKiller->solid == SOLID_BSP ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was mooshed.\n" ); - } - else - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " died mysteriously.\n" ); - } - - UTIL_ClientPrintAll( szText ); -*/ -} - -//========================================================= -// PlayerGotWeapon - player has grabbed a weapon that was -// sitting in the world -//========================================================= -void CHalfLifeMultiplay :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ) -{ -} - -//========================================================= -// FlWeaponRespawnTime - what is the time in the future -// at which this weapon may spawn? -//========================================================= -float CHalfLifeMultiplay :: FlWeaponRespawnTime( CBasePlayerWeapon *pWeapon ) -{ - if( CVAR_GET_FLOAT( "mp_weaponstay" ) > 0 ) - { - // make sure it's only certain weapons - if ( !(pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) - { - return gpGlobals->time + 0; // weapon respawns almost instantly - } - } - - return gpGlobals->time + WEAPON_RESPAWN_TIME; -} - -// when we are within this close to running out of entities, items -// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn -#define ENTITY_INTOLERANCE 100 - -//========================================================= -// FlWeaponRespawnTime - Returns 0 if the weapon can respawn -// now, otherwise it returns the time at which it can try -// to spawn again. -//========================================================= -float CHalfLifeMultiplay :: FlWeaponTryRespawn( CBasePlayerWeapon *pWeapon ) -{ - if ( pWeapon && pWeapon->m_iId && (pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) - { - if ( gpGlobals->numEntities < (gpGlobals->maxEntities - ENTITY_INTOLERANCE) ) - return 0; - - // we're past the entity tolerance level, so delay the respawn - return FlWeaponRespawnTime( pWeapon ); - } - - return 0; -} - -//========================================================= -// VecWeaponRespawnSpot - where should this weapon spawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeMultiplay :: VecWeaponRespawnSpot( CBasePlayerWeapon *pWeapon ) -{ - return pWeapon->pev->origin; -} - -//========================================================= -// WeaponShouldRespawn - any conditions inhibiting the -// respawning of this weapon? -//========================================================= -int CHalfLifeMultiplay :: WeaponShouldRespawn( CBasePlayerWeapon *pWeapon ) -{ - if ( pWeapon->pev->spawnflags & SF_NORESPAWN ) - { - return GR_WEAPON_RESPAWN_NO; - } - - return GR_WEAPON_RESPAWN_YES; -} - -//========================================================= -// CanHaveWeapon - returns FALSE if the player is not allowed -// to pick up this weapon -//========================================================= -BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerWeapon *pItem ) -{ - if( CVAR_GET_FLOAT( "mp_weaponstay" ) > 0 ) - { - if ( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); - - // check if the player already has this weapon - for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - CBasePlayerWeapon *it = pPlayer->m_rgpPlayerItems[i]; - - while ( it != NULL ) - { - if ( it->m_iId == pItem->m_iId ) - { - return FALSE; - } - - it = it->m_pNext; - } - } - } - - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay::FlHealthChargerRechargeTime( void ) -{ - return 60; -} - - -float CHalfLifeMultiplay::FlHEVChargerRechargeTime( void ) -{ - return 30; -} - -//========================================================= -BOOL CHalfLifeMultiplay::IsAllowedToSpawn( CBaseEntity *pEntity ) -{ - return TRUE; -} - -//========================================================= - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::DeadPlayerWeapons( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_GUN_ACTIVE; -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::DeadPlayerAmmo( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_AMMO_ACTIVE; -} - -edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) -{ - edict_t *pentSpawnSpot = CGameRules::GetPlayerSpawnSpot( pPlayer ); - if ( IsMultiplayer()) - { - UTIL_FireTargets( pentSpawnSpot->v.target, pPlayer, pPlayer, USE_TOGGLE ); - } - - return pentSpawnSpot; -} - - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // half life deathmatch has only enemies - return GR_NOTTEAMMATE; -} - -BOOL CHalfLifeMultiplay :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) -{ - if( CVAR_GET_FLOAT( "mp_footsteps" ) == 0 ) - return FALSE; - - if ( pl->IsOnLadder() || pl->pev->velocity.Length2D() > 220 ) - return TRUE; // only make step sounds in multiplayer if the player is moving fast enough - - return FALSE; -} - -BOOL CHalfLifeMultiplay :: FAllowFlashlight( void ) -{ - return CVAR_GET_FLOAT( "mp_flashlight" ) ? TRUE : FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: FAllowMonsters( void ) -{ - return 0; -} - -//========================================================= -//======== CHalfLifeMultiplay private functions =========== -#define INTERMISSION_TIME 6 - -void CHalfLifeMultiplay :: GoToIntermission( void ) -{ - if ( g_fGameOver ) - return; // intermission has already been triggered, so ignore. - - MESSAGE_BEGIN( MSG_ALL, gmsg.Intermission ); - MESSAGE_END(); - - // bounds check - int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); - if ( time < 1 ) - CVAR_SET_STRING( "mp_chattime", "1" ); - else if ( time > MAX_INTERMISSION_TIME ) - CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); - - m_flIntermissionEndTime = gpGlobals->time + ((int)CVAR_GET_FLOAT( "mp_chattime" )); - g_flIntermissionStartTime = gpGlobals->time; - - g_fGameOver = TRUE; - m_iEndIntermissionButtonHit = FALSE; -} - -#define MAX_RULE_BUFFER 1024 - -typedef struct mapcycle_item_s -{ - struct mapcycle_item_s *next; - - char mapname[ 32 ]; - int minplayers, maxplayers; - char rulebuffer[ MAX_RULE_BUFFER ]; -} mapcycle_item_t; - -typedef struct mapcycle_s -{ - struct mapcycle_item_s *items; - struct mapcycle_item_s *next_item; -} mapcycle_t; - -/* -============== -DestroyMapCycle - -Clean up memory used by mapcycle when switching it -============== -*/ -void DestroyMapCycle( mapcycle_t *cycle ) -{ - mapcycle_item_t *p, *n, *start; - p = cycle->items; - if ( p ) - { - start = p; - p = p->next; - while ( p != start ) - { - n = p->next; - delete p; - p = n; - } - - delete cycle->items; - } - cycle->items = NULL; - cycle->next_item = NULL; -} - -/* -============== -COM_TokenWaiting - -Returns 1 if additional data is waiting to be processed on this line -============== -*/ -int COM_TokenWaiting( const char *buffer ) -{ - const char *p; - - p = buffer; - while ( *p && *p!='\n') - { - if ( !isspace( *p ) || isalnum( *p ) ) - return 1; - - p++; - } - - return 0; -} - - - -/* -============== -ReloadMapCycleFile - - -Parses mapcycle.txt file into mapcycle_t structure -============== -*/ -int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) -{ - char szBuffer[ MAX_RULE_BUFFER ]; - char szMap[ 32 ]; - int length; - char *pToken; - char *aFileList = (char *)LOAD_FILE( filename, &length ); - const char *pFileList = aFileList; - int hasbuffer; - mapcycle_item_s *item, *newlist = NULL, *next; - - if ( pFileList && length ) - { - // the first map name in the file becomes the default - while ( 1 ) - { - hasbuffer = 0; - memset( szBuffer, 0, MAX_RULE_BUFFER ); - - pToken = COM_Parse( &pFileList ); - if ( strlen( pToken ) <= 0 ) - break; - - strcpy( szMap, pToken ); - - // Any more tokens on this line? - if ( COM_TokenWaiting( pFileList ) ) - { - pToken = COM_Parse( &pFileList ); - if ( strlen( pToken ) > 0 ) - { - hasbuffer = 1; - strcpy( szBuffer, pToken ); - } - } - - // Check map - if ( IS_MAP_VALID( szMap ) ) - { - // Create entry - char *s; - - item = new mapcycle_item_s; - - strcpy( item->mapname, szMap ); - - item->minplayers = 0; - item->maxplayers = 0; - - memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); - - if ( hasbuffer ) - { - s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); - if ( s && s[0] ) - { - item->minplayers = atoi( s ); - item->minplayers = max( item->minplayers, 0 ); - item->minplayers = min( item->minplayers, gpGlobals->maxClients ); - } - s = g_engfuncs.pfnInfoKeyValue( szBuffer, "maxplayers" ); - if ( s && s[0] ) - { - item->maxplayers = atoi( s ); - item->maxplayers = max( item->maxplayers, 0 ); - item->maxplayers = min( item->maxplayers, gpGlobals->maxClients ); - } - - // Remove keys - // - g_engfuncs.pfnInfo_RemoveKey( szBuffer, "minplayers" ); - g_engfuncs.pfnInfo_RemoveKey( szBuffer, "maxplayers" ); - - strcpy( item->rulebuffer, szBuffer ); - } - - item->next = cycle->items; - cycle->items = item; - } - else - { - ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); - } - - } - - FREE_FILE( aFileList ); - } - - // Fixup circular list pointer - item = cycle->items; - - // Reverse it to get original order - while ( item ) - { - next = item->next; - item->next = newlist; - newlist = item; - item = next; - } - cycle->items = newlist; - item = cycle->items; - - // Didn't parse anything - if ( !item ) - { - return 0; - } - - while ( item->next ) - { - item = item->next; - } - item->next = cycle->items; - - cycle->next_item = item->next; - - return 1; -} - -/* -============== -CountPlayers - -Determine the current # of active players on the server for map cycling logic -============== -*/ -int CountPlayers( void ) -{ - int num = 0; - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pEnt = UTIL_PlayerByIndex( i ); - - if ( pEnt ) - { - num = num + 1; - } - } - - return num; -} - -/* -============== -ExtractCommandString - -Parse commands/key value pairs to issue right after map xxx command is issued on server - level transition -============== -*/ -void ExtractCommandString( char *s, char *szCommand ) -{ - // Now make rules happen - char pkey[512]; - char value[512]; // use two buffers so compares - // work without stomping on each other - char *o; - - if ( *s == '\\' ) - s++; - - while (1) - { - o = pkey; - while ( *s != '\\' ) - { - if ( !*s ) - return; - *o++ = *s++; - } - *o = 0; - s++; - - o = value; - - while (*s != '\\' && *s) - { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - - strcat( szCommand, pkey ); - if ( strlen( value ) > 0 ) - { - strcat( szCommand, " " ); - strcat( szCommand, value ); - } - strcat( szCommand, "\n" ); - - if (!*s) - return; - s++; - } -} - -/* -============== -ChangeLevel - -Server is changing to a new level, check mapcycle.txt for map name and setup info -============== -*/ -void CHalfLifeMultiplay :: ChangeLevel( void ) -{ - static char szPreviousMapCycleFile[ 256 ]; - static mapcycle_t mapcycle; - - char szNextMap[32]; - char szFirstMapInList[32]; - char szCommands[ 1500 ]; - char szRules[ 1500 ]; - int minplayers = 0, maxplayers = 0; - strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 - - int curplayers; - BOOL do_cycle = TRUE; - - // find the map to change to - char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); - ASSERT( mapcfile != NULL ); - - szCommands[ 0 ] = '\0'; - szRules[ 0 ] = '\0'; - - curplayers = CountPlayers(); - - // Has the map cycle filename changed? - if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) - { - strcpy( szPreviousMapCycleFile, mapcfile ); - - DestroyMapCycle( &mapcycle ); - - if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) - { - ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile ); - do_cycle = FALSE; - } - } - - if ( do_cycle && mapcycle.items ) - { - BOOL keeplooking = FALSE; - BOOL found = FALSE; - mapcycle_item_s *item; - - // Assume current map - strcpy( szNextMap, STRING(gpGlobals->mapname) ); - strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); - - // Traverse list - for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) - { - keeplooking = FALSE; - - ASSERT( item != NULL ); - - if ( item->minplayers != 0 ) - { - if ( curplayers >= item->minplayers ) - { - found = TRUE; - minplayers = item->minplayers; - } - else - { - keeplooking = TRUE; - } - } - - if ( item->maxplayers != 0 ) - { - if ( curplayers <= item->maxplayers ) - { - found = TRUE; - maxplayers = item->maxplayers; - } - else - { - keeplooking = TRUE; - } - } - - if ( keeplooking ) - continue; - - found = TRUE; - break; - } - - if ( !found ) - { - item = mapcycle.next_item; - } - - // Increment next item pointer - mapcycle.next_item = item->next; - - // Perform logic on current item - strcpy( szNextMap, item->mapname ); - - ExtractCommandString( item->rulebuffer, szCommands ); - strcpy( szRules, item->rulebuffer ); - } - - if ( !IS_MAP_VALID(szNextMap) ) - { - strcpy( szNextMap, szFirstMapInList ); - } - - g_fGameOver = TRUE; - - ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); - if ( minplayers || maxplayers ) - { - ALERT( at_console, "PLAYER COUNT: min %i max %i current %i\n", minplayers, maxplayers, curplayers ); - } - if ( strlen( szRules ) > 0 ) - { - ALERT( at_console, "RULES: %s\n", szRules ); - } - - CHANGE_LEVEL( szNextMap, NULL ); - if ( strlen( szCommands ) > 0 ) - { - SERVER_COMMAND( szCommands ); - } -} - -#define MAX_MOTD_CHUNK 60 -#define MAX_MOTD_LENGTH 1536 // (MAX_MOTD_CHUNK * 4) - -void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) -{ - // read from the MOTD.txt file - int length, char_count = 0; - char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE ((char *)CVAR_GET_STRING( "motdfile" ), &length ); - - // send the server name - MESSAGE_BEGIN( MSG_ONE, gmsg.ServerName, NULL, client ); - WRITE_STRING( CVAR_GET_STRING("hostname") ); - MESSAGE_END(); - - // Send the message of the day - // read it chunk-by-chunk, and send it in parts - - while ( pFileList && *pFileList && char_count < MAX_MOTD_LENGTH ) - { - char chunk[MAX_MOTD_CHUNK+1]; - - if ( strlen( pFileList ) < MAX_MOTD_CHUNK ) - { - strcpy( chunk, pFileList ); - } - else - { - strncpy( chunk, pFileList, MAX_MOTD_CHUNK ); - chunk[MAX_MOTD_CHUNK] = 0; // strncpy doesn't always append the null terminator - } - - char_count += strlen( chunk ); - if ( char_count < MAX_MOTD_LENGTH ) - pFileList = aFileList + char_count; - else - *pFileList = 0; - - MESSAGE_BEGIN( MSG_ONE, gmsg.MOTD, NULL, client ); - WRITE_BYTE( *pFileList ? FALSE : TRUE ); // FALSE means there is still more message to come - WRITE_STRING( chunk ); - MESSAGE_END(); - } - - FREE_FILE( aFileList ); -} - - diff --git a/server/game/singleplay_gamerules.cpp b/server/game/singleplay_gamerules.cpp deleted file mode 100644 index 789cee5f..00000000 --- a/server/game/singleplay_gamerules.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "player.h" -#include "baseweapon.h" -#include "gamerules.h" - -extern DLL_GLOBAL CGameRules *g_pGameRules; -extern DLL_GLOBAL BOOL g_fGameOver; - -//========================================================= -//========================================================= -CHalfLifeRules::CHalfLifeRules( void ) -{ - RefreshSkillData(); -} - -//========================================================= -//========================================================= -void CHalfLifeRules::Think ( void ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsMultiplayer( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsDeathmatch ( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsCoOp( void ) -{ - return FALSE; -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ) -{ - if ( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if ( !pPlayer->m_pActiveItem->CanHolster() ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pCurrentWeapon ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ) -{ - return TRUE; -} - -void CHalfLifeRules :: InitHUD( CBasePlayer *pl ) -{ -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: ClientDisconnected( edict_t *pClient ) -{ -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlPlayerFallDamage( CBasePlayer *pPlayer ) -{ - // subtract off the speed at which a player is allowed to fall without being hurt, - // so damage will be based on speed beyond that, not the entire fall - pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; - return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: PlayerSpawn( CBasePlayer *pPlayer ) -{ - if( g_startSuit ) - pPlayer->pev->weapons |= ITEM_SUIT; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: AllowAutoTargetCrosshair( void ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: PlayerThink( CBasePlayer *pPlayer ) -{ -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: FPlayerCanRespawn( CBasePlayer *pPlayer ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -float CHalfLifeRules :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) -{ - return gpGlobals->time;//now! -} - -//========================================================= -// IPointsForKill - how many points awarded to anyone -// that kills this player? -//========================================================= -int CHalfLifeRules :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - return 1; -} - -//========================================================= -// PlayerKilled - someone/something killed this player -//========================================================= -void CHalfLifeRules :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// Deathnotice -//========================================================= -void CHalfLifeRules::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// PlayerGotWeapon - player has grabbed a weapon that was -// sitting in the world -//========================================================= -void CHalfLifeRules :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon ) -{ -} - -//========================================================= -// FlWeaponRespawnTime - what is the time in the future -// at which this weapon may spawn? -//========================================================= -float CHalfLifeRules :: FlWeaponRespawnTime( CBasePlayerWeapon *pWeapon ) -{ - return -1; -} - -//========================================================= -// FlWeaponRespawnTime - Returns 0 if the weapon can respawn -// now, otherwise it returns the time at which it can try -// to spawn again. -//========================================================= -float CHalfLifeRules :: FlWeaponTryRespawn( CBasePlayerWeapon *pWeapon ) -{ - return 0; -} - -//========================================================= -// VecWeaponRespawnSpot - where should this weapon spawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeRules :: VecWeaponRespawnSpot( CBasePlayerWeapon *pWeapon ) -{ - return pWeapon->pev->origin; -} - -//========================================================= -BOOL CHalfLifeRules::IsAllowedToSpawn( CBaseEntity *pEntity ) -{ - return TRUE; -} - -//========================================================= - -//========================================================= -// WeaponShouldRespawn - any conditions inhibiting the -// respawning of this weapon? -//========================================================= -int CHalfLifeRules :: WeaponShouldRespawn( CBasePlayerWeapon *pWeapon ) -{ - return GR_WEAPON_RESPAWN_NO; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlHealthChargerRechargeTime( void ) -{ - return 0;// don't recharge -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerWeapons( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_GUN_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerAmmo( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_AMMO_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // why would a single player in half life need this? - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: FAllowMonsters( void ) -{ - return TRUE; -} diff --git a/server/game/sound.cpp b/server/game/sound.cpp deleted file mode 100644 index 58c32f3a..00000000 --- a/server/game/sound.cpp +++ /dev/null @@ -1,1952 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// sound.cpp -//========================================================= - -#include - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "baseweapon.h" -#include "player.h" -#include "talkmonster.h" -#include "gamerules.h" -#include "client.h" - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ); - - -// ==================== GENERIC AMBIENT SOUND ====================================== - -// runtime pitch shift and volume fadein/out structure - -// NOTE: IF YOU CHANGE THIS STRUCT YOU MUST CHANGE THE SAVE/RESTORE VERSION NUMBER -// SEE BELOW (in the typedescription for the class) -typedef struct dynpitchvol -{ - // NOTE: do not change the order of these parameters - // NOTE: unless you also change order of rgdpvpreset array elements! - int preset; - - int pitchrun; // pitch shift % when sound is running 0 - 255 - int pitchstart; // pitch shift % when sound stops or starts 0 - 255 - int spinup; // spinup time 0 - 100 - int spindown; // spindown time 0 - 100 - - int volrun; // volume change % when sound is running 0 - 10 - int volstart; // volume change % when sound stops or starts 0 - 10 - int fadein; // volume fade in time 0 - 100 - int fadeout; // volume fade out time 0 - 100 - - // Low Frequency Oscillator - int lfotype; // 0) off 1) square 2) triangle 3) random - int lforate; // 0 - 1000, how fast lfo osciallates - - int lfomodpitch; // 0-100 mod of current pitch. 0 is off. - int lfomodvol; // 0-100 mod of current volume. 0 is off. - - int cspinup; // each trigger hit increments counter and spinup pitch - - - int cspincount; - - int pitch; - int spinupsav; - int spindownsav; - int pitchfrac; - - int vol; - int fadeinsav; - int fadeoutsav; - int volfrac; - - int lfofrac; - int lfomult; - - -} dynpitchvol_t; - -#define CDPVPRESETMAX 27 - -// presets for runtime pitch and vol modulation of ambient sounds - -dynpitchvol_t rgdpvpreset[CDPVPRESETMAX] = -{ -//pitch pstart spinup spindwn volrun volstrt fadein fadeout lfotype lforate modptch modvol cspnup -{1, 255, 75, 95, 95, 10, 1, 50, 95, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{2, 255, 85, 70, 88, 10, 1, 20, 88, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{3, 255, 100, 50, 75, 10, 1, 10, 75, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{4, 100, 100, 0, 0, 10, 1, 90, 90, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{5, 100, 100, 0, 0, 10, 1, 80, 80, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{6, 100, 100, 0, 0, 10, 1, 50, 70, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{7, 100, 100, 0, 0, 5, 1, 40, 50, 1, 50, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{8, 100, 100, 0, 0, 5, 1, 40, 50, 1, 150, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{9, 100, 100, 0, 0, 5, 1, 40, 50, 1, 750, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{10, 128, 100, 50, 75, 10, 1, 30, 40, 2, 8, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{11, 128, 100, 50, 75, 10, 1, 30, 40, 2, 25, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{12, 128, 100, 50, 75, 10, 1, 30, 40, 2, 70, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{13, 50, 50, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{14, 70, 70, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{15, 90, 90, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{16, 120, 120, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{17, 180, 180, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{18, 255, 255, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{19, 200, 75, 90, 90, 10, 1, 50, 90, 2, 100, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{20, 255, 75, 97, 90, 10, 1, 50, 90, 1, 40, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{21, 100, 100, 0, 0, 10, 1, 30, 50, 3, 15, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{22, 160, 160, 0, 0, 10, 1, 50, 50, 3, 500, 25, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{23, 255, 75, 88, 0, 10, 1, 40, 0, 0, 0, 0, 0, 5, 0,0,0,0,0,0,0,0,0,0}, -{24, 200, 20, 95, 70, 10, 1, 70, 70, 3, 20, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{25, 180, 100, 50, 60, 10, 1, 40, 60, 2, 90, 100, 100, 0, 0,0,0,0,0,0,0,0,0,0}, -{26, 60, 60, 0, 0, 10, 1, 40, 70, 3, 80, 20, 50, 0, 0,0,0,0,0,0,0,0,0,0}, -{27, 128, 90, 10, 10, 10, 1, 20, 40, 1, 5, 10, 20, 0, 0,0,0,0,0,0,0,0,0,0} -}; - -class CAmbientGeneric : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); -// void PostSpawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT StartPlayFrom( void ); - void EXPORT RampThink( void ); - void InitModulationParms(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - float m_flAttenuation; // attenuation value - dynpitchvol_t m_dpv; - - BOOL m_fActive; // only TRUE when the entity is playing a looping sound - BOOL m_fLooping; // TRUE when the sound played will loop - edict_t *m_pPlayFrom; //LRC - the entity to play from - int m_iChannel; //LRC - the channel to play from, for "play from X" sounds -}; - -LINK_ENTITY_TO_CLASS( ambient_generic, CAmbientGeneric ); - -TYPEDESCRIPTION CAmbientGeneric::m_SaveData[] = -{ - DEFINE_FIELD( CAmbientGeneric, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CAmbientGeneric, m_fActive, FIELD_BOOLEAN ), - DEFINE_FIELD( CAmbientGeneric, m_fLooping, FIELD_BOOLEAN ), - DEFINE_FIELD( CAmbientGeneric, m_iChannel, FIELD_INTEGER ), //LRC - DEFINE_FIELD( CAmbientGeneric, m_pPlayFrom, FIELD_EDICT ), //LRC - - // HACKHACK - This is not really in the spirit of the save/restore design, but save this - // out as a binary data block. If the dynpitchvol_t is changed, old saved games will NOT - // load these correctly, so bump the save/restore version if you change the size of the struct - // The right way to do this is to split the input parms (read in keyvalue) into members and re-init this - // struct in Precache(), but it's unlikely that the struct will change, so it's not worth the time right now. - DEFINE_ARRAY( CAmbientGeneric, m_dpv, FIELD_CHARACTER, sizeof(dynpitchvol_t) ), -}; - -IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CAmbientGeneric :: Spawn( void ) -{ -/* - -1 : "Default" - 0 : "Everywhere" - 200 : "Small Radius" - 125 : "Medium Radius" - 80 : "Large Radius" -*/ - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) - { - m_flAttenuation = ATTN_NONE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS) ) - { - m_flAttenuation = ATTN_IDLE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS) ) - { - m_flAttenuation = ATTN_STATIC; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS) ) - { - m_flAttenuation = ATTN_NORM; - } - else - {// if the designer didn't set a sound attenuation, default to one. - m_flAttenuation = ATTN_STATIC; - } - - if( !pev->health ) pev->health = 10; // just get full volume - - char* szSoundFile = (char*) STRING(pev->message); - - if ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) - { - ALERT( at_error, "ambient_generic \"%s\" at (%f, %f, %f) has no sound file\n", - STRING(pev->targetname), pev->origin.x, pev->origin.y, pev->origin.z ); - SetNextThink( 0.1 ); - SetThink( Remove ); - return; - } - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - // Set up think function for dynamic modification - // of ambient sound's pitch or volume. Don't - // start thinking yet. - - SetThink(RampThink); - DontThink(); - - // allow on/off switching via 'use' function. - - SetUse( ToggleUse ); - - m_fActive = FALSE; - - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) - m_fLooping = FALSE; - else - m_fLooping = TRUE; - - Precache( ); -} - -// this function needs to be called when the game is loaded, not just when the entity spawns. -// Don't make this a PostSpawn function. -void CAmbientGeneric :: Precache( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - if ( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) - { - if (*szSoundFile != '!') - PRECACHE_SOUND(szSoundFile); - } - // init all dynamic modulation parms - InitModulationParms(); - - if ( !FBitSet (pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) - { - // start the sound ASAP - if (m_fLooping) - m_fActive = TRUE; - } - - if( pev->target ) - { - CBaseEntity *pTarget = UTIL_FindEntityByTargetname( NULL, STRING(pev->target)); - - if( !pTarget ) - { - ALERT( at_warning, "ambient_generic \"%s\" can't find \"%s\", its entity to play from.\n", - STRING(pev->targetname), STRING(pev->target)); - } - else m_pPlayFrom = ENT( pTarget->pev ); - } - - if ( m_fActive ) - { - if (m_pPlayFrom) - { - SetThink(&CAmbientGeneric ::StartPlayFrom); //LRC -// EMIT_SOUND_DYN( m_pPlayFrom, m_iChannel, szSoundFile, //LRC -// (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); - -// ALERT(at_console, "AMBGEN: spawn start\n"); - } - else - { - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); - } - SetNextThink( 0.1 ); - } -} - -//LRC - for some reason, I can't get other entities to start playing sounds during Activate; -// this function is used to delay the effect until the first Think, which seems to fix the problem. -void CAmbientGeneric :: StartPlayFrom( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - EMIT_SOUND_DYN( m_pPlayFrom, m_iChannel, szSoundFile, //LRC - (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); - - SetThink(&CAmbientGeneric ::RampThink); - SetNextThink( 0.1 ); -} - -// RampThink - Think at 5hz if we are dynamically modifying -// pitch or volume of the playing sound. This function will -// ramp pitch and/or volume up or down, modify pitch/volume -// with lfo if active. - -void CAmbientGeneric :: RampThink( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - int pitch = m_dpv.pitch; - int vol = m_dpv.vol; - int flags = 0; - int fChanged = 0; // FALSE if pitch and vol remain unchanged this round - int prev; - - if (!m_dpv.spinup && !m_dpv.spindown && !m_dpv.fadein && !m_dpv.fadeout && !m_dpv.lfotype) - return; // no ramps or lfo, stop thinking - - // ============== - // pitch envelope - // ============== - if (m_dpv.spinup || m_dpv.spindown) - { - prev = m_dpv.pitchfrac >> 8; - - if (m_dpv.spinup > 0) - m_dpv.pitchfrac += m_dpv.spinup; - else if (m_dpv.spindown > 0) - m_dpv.pitchfrac -= m_dpv.spindown; - - pitch = m_dpv.pitchfrac >> 8; - - if (pitch > m_dpv.pitchrun) - { - pitch = m_dpv.pitchrun; - m_dpv.spinup = 0; // done with ramp up - } - - if (pitch < m_dpv.pitchstart) - { - pitch = m_dpv.pitchstart; - m_dpv.spindown = 0; // done with ramp down - - // shut sound off - if (m_pPlayFrom) - { - STOP_SOUND( m_pPlayFrom, m_iChannel, szSoundFile); //LRC - } - else - { - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - } - - // return without setting nextthink - return; - } - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - m_dpv.pitch = pitch; - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - // ================== - // amplitude envelope - // ================== - if (m_dpv.fadein || m_dpv.fadeout) - { - prev = m_dpv.volfrac >> 8; - - if (m_dpv.fadein > 0) - m_dpv.volfrac += m_dpv.fadein; - else if (m_dpv.fadeout > 0) - m_dpv.volfrac -= m_dpv.fadeout; - - vol = m_dpv.volfrac >> 8; - - if (vol > m_dpv.volrun) - { - vol = m_dpv.volrun; - m_dpv.fadein = 0; // done with ramp up - } - - if (vol < m_dpv.volstart) - { - vol = m_dpv.volstart; - m_dpv.fadeout = 0; // done with ramp down - - // shut sound off - if (m_pPlayFrom) - { - STOP_SOUND( m_pPlayFrom, m_iChannel, szSoundFile); //LRC - } - else - { - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - } - - // return without setting nextthink - return; - } - - if (vol > 100) vol = 100; - if (vol < 1) vol = 1; - - m_dpv.vol = vol; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - // =================== - // pitch/amplitude LFO - // =================== - if (m_dpv.lfotype) - { - int pos; - - if (m_dpv.lfofrac > 0x6fffffff) - m_dpv.lfofrac = 0; - - // update lfo, lfofrac/255 makes a triangle wave 0-255 - m_dpv.lfofrac += m_dpv.lforate; - pos = m_dpv.lfofrac >> 8; - - if (m_dpv.lfofrac < 0) - { - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - pos = 0; - } - else if (pos > 255) - { - pos = 255; - m_dpv.lfofrac = (255 << 8); - m_dpv.lforate = -abs(m_dpv.lforate); - } - - switch(m_dpv.lfotype) - { - case LFO_SQUARE: - if (pos < 128) - m_dpv.lfomult = 255; - else - m_dpv.lfomult = 0; - - break; - case LFO_RANDOM: - if (pos == 255) - m_dpv.lfomult = RANDOM_LONG(0, 255); - break; - case LFO_TRIANGLE: - default: - m_dpv.lfomult = pos; - break; - } - - if (m_dpv.lfomodpitch) - { - prev = pitch; - - // pitch 0-255 - pitch += ((m_dpv.lfomult - 128) * m_dpv.lfomodpitch) / 100; - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - if (m_dpv.lfomodvol) - { - // vol 0-100 - prev = vol; - - vol += ((m_dpv.lfomult - 128) * m_dpv.lfomodvol) / 100; - - if (vol > 100) vol = 100; - if (vol < 0) vol = 0; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - } - - // Send update to playing sound only if we actually changed - // pitch or volume in this routine. - - if (flags && fChanged) - { - if (pitch == PITCH_NORM) - pitch = PITCH_NORM + 1; // don't send 'no pitch' ! - - if (m_pPlayFrom) - { - EMIT_SOUND_DYN( m_pPlayFrom, m_iChannel, szSoundFile, (vol * 0.01), //LRC - m_flAttenuation, flags, pitch); - } - else - { - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (vol * 0.01), m_flAttenuation, flags, pitch); - } - } - - // update ramps at 5hz - SetNextThink( 0.2 ); - return; -} - -// Init all ramp params in preparation to -// play a new sound - -void CAmbientGeneric :: InitModulationParms(void) -{ - int pitchinc; - - m_dpv.volrun = pev->health * 10; // 0 - 100 - if (m_dpv.volrun > 100) m_dpv.volrun = 100; - if (m_dpv.volrun < 0) m_dpv.volrun = 0; - - // get presets - if (m_dpv.preset != 0 && m_dpv.preset <= CDPVPRESETMAX) - { - // load preset values - m_dpv = rgdpvpreset[m_dpv.preset - 1]; - - // fixup preset values, just like - // fixups in KeyValue routine. - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - - m_dpv.volstart *= 10; - m_dpv.volrun *= 10; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - - m_dpv.lforate *= 256; - - m_dpv.fadeinsav = m_dpv.fadein; - m_dpv.fadeoutsav = m_dpv.fadeout; - m_dpv.spinupsav = m_dpv.spinup; - m_dpv.spindownsav = m_dpv.spindown; - } - - m_dpv.fadein = m_dpv.fadeinsav; - m_dpv.fadeout = 0; - - if (m_dpv.fadein) - m_dpv.vol = m_dpv.volstart; - else - m_dpv.vol = m_dpv.volrun; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - if (m_dpv.spinup) - m_dpv.pitch = m_dpv.pitchstart; - else - m_dpv.pitch = m_dpv.pitchrun; - - if (m_dpv.pitch == 0) - m_dpv.pitch = PITCH_NORM; - - m_dpv.pitchfrac = m_dpv.pitch << 8; - m_dpv.volfrac = m_dpv.vol << 8; - - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - - m_dpv.cspincount = 1; - - if (m_dpv.cspinup) - { - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - } - - if ((m_dpv.spinupsav || m_dpv.spindownsav || (m_dpv.lfotype && m_dpv.lfomodpitch)) - && (m_dpv.pitch == PITCH_NORM)) - m_dpv.pitch = PITCH_NORM + 1; // must never send 'no pitch' as first pitch - // if we intend to pitch shift later! -} - -// -// ToggleUse - turns an ambient sound on or off. If the -// ambient is a looping sound, mark sound as active (m_fActive) -// if it's playing, innactive if not. If the sound is not -// a looping sound, never mark it as active. -// -void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - char* szSoundFile = (char*) STRING(pev->message); - float fraction; - - if ( useType != USE_TOGGLE ) - { - if ( (m_fActive && useType == USE_ON) || (!m_fActive && useType == USE_OFF) ) - return; - } - - // Directly change pitch if arg passed. Only works if sound is already playing. - if (useType == USE_SET && m_fActive) // Momentary buttons will pass down a float in here - { - - fraction = value; - - if ( fraction > 1.0 ) - fraction = 1.0; - if (fraction < 0.0) - fraction = 0.01; - - m_dpv.pitch = fraction * 255; - - if (m_pPlayFrom) - { - EMIT_SOUND_DYN( m_pPlayFrom, m_iChannel, szSoundFile, 0, 0, SND_CHANGE_PITCH, m_dpv.pitch); - } - else - { - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_CHANGE_PITCH, m_dpv.pitch); - } - - return; - } - - // Toggle - - // m_fActive is TRUE only if a looping sound is playing. - - if ( m_fActive ) - {// turn sound off - - if (m_dpv.cspinup) - { - // Don't actually shut off. Each toggle causes - // incremental spinup to max pitch - - if (m_dpv.cspincount <= m_dpv.cspinup) - { - int pitchinc; - - // start a new spinup - m_dpv.cspincount++; - - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc * m_dpv.cspincount; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - - SetNextThink( 0.1 ); - } - - } - else - { - m_fActive = FALSE; - - // HACKHACK - this makes the code in Precache() work properly after a save/restore - pev->spawnflags |= AMBIENT_SOUND_START_SILENT; - - if (m_dpv.spindownsav || m_dpv.fadeoutsav) - { - // spin it down (or fade it) before shutoff if spindown is set - m_dpv.spindown = m_dpv.spindownsav; - m_dpv.spinup = 0; - - m_dpv.fadeout = m_dpv.fadeoutsav; - m_dpv.fadein = 0; - SetNextThink( 0.1 ); - } - else if (m_pPlayFrom) - { - STOP_SOUND( m_pPlayFrom, m_iChannel, szSoundFile); - } - else - { - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - } - } - } - else - {// turn sound on - - // only toggle if this is a looping sound. If not looping, each - // trigger will cause the sound to play. If the sound is still - // playing from a previous trigger press, it will be shut off - // and then restarted. - - if (m_fLooping) - { - m_fActive = TRUE; - } - else if (m_pPlayFrom) - { - STOP_SOUND( m_pPlayFrom, m_iChannel, szSoundFile); //LRC - } - else - { - // shut sound off now - may be interrupting a long non-looping sound - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - } - - // init all ramp params for startup - - InitModulationParms(); - - if (m_pPlayFrom) - { - - EMIT_SOUND_DYN( m_pPlayFrom, m_iChannel, szSoundFile, //LRC - (m_dpv.vol * 0.01), m_flAttenuation, 0, m_dpv.pitch); - } - else - { - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, 0, m_dpv.pitch); - } - - SetNextThink( 0.1 ); - } -} -// KeyValue - load keyvalue pairs into member data of the -// ambient generic. NOTE: called BEFORE spawn! - -void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) -{ - // NOTE: changing any of the modifiers in this code - // NOTE: also requires changing InitModulationParms code. - - // channel (e.g. CHAN_STATIC, etc) - if (FStrEq(pkvd->szKeyName, "channel")) - { - m_iChannel = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - // preset - else if (FStrEq(pkvd->szKeyName, "preset")) - { - m_dpv.preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - - // pitchrun - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - m_dpv.pitchrun = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - if (m_dpv.pitchrun < 0) m_dpv.pitchrun = 0; - } - - // pitchstart - else if (FStrEq(pkvd->szKeyName, "pitchstart")) - { - m_dpv.pitchstart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchstart > 255) m_dpv.pitchstart = 255; - if (m_dpv.pitchstart < 0) m_dpv.pitchstart = 0; - } - - // spinup - else if (FStrEq(pkvd->szKeyName, "spinup")) - { - m_dpv.spinup = atoi(pkvd->szValue); - - if (m_dpv.spinup > 100) m_dpv.spinup = 100; - if (m_dpv.spinup < 0) m_dpv.spinup = 0; - - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - m_dpv.spinupsav = m_dpv.spinup; - pkvd->fHandled = TRUE; - } - - // spindown - else if (FStrEq(pkvd->szKeyName, "spindown")) - { - m_dpv.spindown = atoi(pkvd->szValue); - - if (m_dpv.spindown > 100) m_dpv.spindown = 100; - if (m_dpv.spindown < 0) m_dpv.spindown = 0; - - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - m_dpv.spindownsav = m_dpv.spindown; - pkvd->fHandled = TRUE; - } - - // volstart - else if (FStrEq(pkvd->szKeyName, "volstart")) - { - m_dpv.volstart = atoi(pkvd->szValue); - - if (m_dpv.volstart > 10) m_dpv.volstart = 10; - if (m_dpv.volstart < 0) m_dpv.volstart = 0; - - m_dpv.volstart *= 10; // 0 - 100 - - pkvd->fHandled = TRUE; - } - - // fadein - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_dpv.fadein = atoi(pkvd->szValue); - - if (m_dpv.fadein > 100) m_dpv.fadein = 100; - if (m_dpv.fadein < 0) m_dpv.fadein = 0; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - m_dpv.fadeinsav = m_dpv.fadein; - pkvd->fHandled = TRUE; - } - - // fadeout - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_dpv.fadeout = atoi(pkvd->szValue); - - if (m_dpv.fadeout > 100) m_dpv.fadeout = 100; - if (m_dpv.fadeout < 0) m_dpv.fadeout = 0; - - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - m_dpv.fadeoutsav = m_dpv.fadeout; - pkvd->fHandled = TRUE; - } - - // lfotype - else if (FStrEq(pkvd->szKeyName, "lfotype")) - { - m_dpv.lfotype = atoi(pkvd->szValue); - if (m_dpv.lfotype > 4) m_dpv.lfotype = LFO_TRIANGLE; - pkvd->fHandled = TRUE; - } - - // lforate - else if (FStrEq(pkvd->szKeyName, "lforate")) - { - m_dpv.lforate = atoi(pkvd->szValue); - - if (m_dpv.lforate > 1000) m_dpv.lforate = 1000; - if (m_dpv.lforate < 0) m_dpv.lforate = 0; - - m_dpv.lforate *= 256; - - pkvd->fHandled = TRUE; - } - // lfomodpitch - else if (FStrEq(pkvd->szKeyName, "lfomodpitch")) - { - m_dpv.lfomodpitch = atoi(pkvd->szValue); - if (m_dpv.lfomodpitch > 100) m_dpv.lfomodpitch = 100; - if (m_dpv.lfomodpitch < 0) m_dpv.lfomodpitch = 0; - - - pkvd->fHandled = TRUE; - } - - // lfomodvol - else if (FStrEq(pkvd->szKeyName, "lfomodvol")) - { - m_dpv.lfomodvol = atoi(pkvd->szValue); - if (m_dpv.lfomodvol > 100) m_dpv.lfomodvol = 100; - if (m_dpv.lfomodvol < 0) m_dpv.lfomodvol = 0; - - pkvd->fHandled = TRUE; - } - - // cspinup - else if (FStrEq(pkvd->szKeyName, "cspinup")) - { - m_dpv.cspinup = atoi(pkvd->szValue); - if (m_dpv.cspinup > 100) m_dpv.cspinup = 100; - if (m_dpv.cspinup < 0) m_dpv.cspinup = 0; - - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -// ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ====================================== - -#define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group - -// group of related sentences - -typedef struct sentenceg -{ - char szgroupname[CBSENTENCENAME_MAX]; - int count; - unsigned char rgblru[CSENTENCE_LRU_MAX]; - -} SENTENCEG; - -#define CSENTENCEG_MAX 200 // max number of sentence groups -// globals - -SENTENCEG rgsentenceg[CSENTENCEG_MAX]; -int fSentencesInit = FALSE; - -char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; -int gcallsentences = 0; - -// randomize list of sentence name indices - -void USENTENCEG_InitLRU(unsigned char *plru, int count) -{ - int i, j, k; - unsigned char temp; - - if (!fSentencesInit) - return; - - if (count > CSENTENCE_LRU_MAX) - count = CSENTENCE_LRU_MAX; - - for (i = 0; i < count; i++) - plru[i] = (unsigned char) i; - - // randomize array - for (i = 0; i < (count * 4); i++) - { - j = RANDOM_LONG(0,count-1); - k = RANDOM_LONG(0,count-1); - temp = plru[j]; - plru[j] = plru[k]; - plru[k] = temp; - } -} - -// ignore lru. pick next sentence from sentence group. Go in order until we hit the last sentence, -// then repeat list if freset is true. If freset is false, then repeat last sentence. -// ipick is passed in as the requested sentence ordinal. -// ipick 'next' is returned. -// return of -1 indicates an error. - -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset) -{ - char *szgroupname; - unsigned char count; - char sznum[8]; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - - if (count == 0) - return -1; - - if (ipick >= count) - ipick = count-1; - - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - - if (ipick >= count) - { - if (freset) - // reset at end of list - return 0; - else - return count; - } - - return ipick + 1; -} - - - -// pick a random sentence from rootname0 to rootnameX. -// picks from the rgsentenceg[isentenceg] least -// recently used, modifies lru array. returns the sentencename. -// note, lru must be seeded with 0-n randomized sentence numbers, with the -// rest of the lru filled with -1. The first integer in the lru is -// actually the size of the list. Returns ipick, the ordinal -// of the picked sentence within the group. - -int USENTENCEG_Pick(int isentenceg, char *szfound) -{ - char *szgroupname; - unsigned char *plru; - unsigned char i; - unsigned char count; - char sznum[8]; - unsigned char ipick; - int ffound = FALSE; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - plru = rgsentenceg[isentenceg].rgblru; - - while (!ffound) - { - for (i = 0; i < count; i++) - if (plru[i] != 0xFF) - { - ipick = plru[i]; - plru[i] = 0xFF; - ffound = TRUE; - break; - } - - if (!ffound) - USENTENCEG_InitLRU(plru, count); - else - { - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - return ipick; - } - } - return -1; -} - -// ===================== SENTENCE GROUPS, MAIN ROUTINES ======================== - -// Given sentence group rootname (name without number suffix), -// get sentence group index (isentenceg). Returns -1 if no such name. - -int SENTENCEG_GetIndex(const char *szgroupname) -{ - int i; - - if (!fSentencesInit || !szgroupname) - return -1; - - // search rgsentenceg for match on szgroupname - - i = 0; - while (rgsentenceg[i].count) - { - if (!strcmp(szgroupname, rgsentenceg[i].szgroupname)) - return i; - i++; - } - - return -1; -} - -// given sentence group index, play random sentence for given entity. -// returns ipick - which sentence was picked to -// play from the group. Ipick is only needed if you plan on stopping -// the sound before playback is done (see SENTENCEG_Stop). - -int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick > 0 && name) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipick; -} - -// same as above, but takes sentence group name instead of index - -int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - { - ALERT( at_console, "No such sentence group %s\n", szgroupname ); - return -1; - } - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - - return ipick; -} - -// play sentences in sequential order from sentence group. Reset after last sentence. - -int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch, int ipick, int freset) -{ - char name[64]; - int ipicknext; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - return -1; - - ipicknext = USENTENCEG_PickSequential(isentenceg, name, ipick, freset); - if (ipicknext >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipicknext; -} - - -// for this entity, for the given sentence within the sentence group, stop -// the sentence. - -void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick) -{ - char buffer[64]; - char sznum[8]; - - if (!fSentencesInit) - return; - - if (isentenceg < 0 || ipick < 0) - return; - - strcpy(buffer, "!"); - strcat(buffer, rgsentenceg[isentenceg].szgroupname); - sprintf(sznum, "%d", ipick); - strcat(buffer, sznum); - - STOP_SOUND(entity, CHAN_VOICE, buffer); -} - -// open sentences.txt, scan for groups, build rgsentenceg -// Should be called from world spawn, only works on the -// first call and is ignored subsequently. - -void SENTENCEG_Init() -{ - char buffer[512]; - char szgroup[64]; - int i, j; - int isentencegs; - - if (fSentencesInit) - return; - - memset(gszallsentencenames, 0, CVOXFILESENTENCEMAX * CBSENTENCENAME_MAX); - gcallsentences = 0; - - memset(rgsentenceg, 0, CSENTENCEG_MAX * sizeof(SENTENCEG)); - memset(buffer, 0, 512); - memset(szgroup, 0, 64); - isentencegs = -1; - - - int filePos = 0, fileSize; - byte *pMemFile = g_engfuncs.pfnLoadFile( "sound/sentences.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while ( memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL ) - { - // skip whitespace - i = 0; - while(buffer[i] && buffer[i] == ' ') - i++; - - if (!buffer[i]) - continue; - - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get sentence name - j = i; - while (buffer[j] && buffer[j] != ' ') - j++; - - if (!buffer[j]) - continue; - - if (gcallsentences > CVOXFILESENTENCEMAX) - { - ALERT (at_error, "Too many sentences in sentences.txt!\n"); - break; - } - - // null-terminate name and save in sentences array - buffer[j] = 0; - const char *pString = buffer + i; - - if ( strlen( pString ) >= CBSENTENCENAME_MAX ) - ALERT( at_warning, "Sentence %s longer than %d letters\n", pString, CBSENTENCENAME_MAX-1 ); - - strcpy( gszallsentencenames[gcallsentences++], pString ); - - j--; - if (j <= i) - continue; - if (!isdigit(buffer[j])) - continue; - - // cut out suffix numbers - while (j > i && isdigit(buffer[j])) - j--; - - if (j <= i) - continue; - - buffer[j+1] = 0; - - // if new name doesn't match previous group name, - // make a new group. - - if (strcmp(szgroup, &(buffer[i]))) - { - // name doesn't match with prev name, - // copy name into group, init count to 1 - isentencegs++; - if (isentencegs >= CSENTENCEG_MAX) - { - ALERT (at_error, "Too many sentence groups in sentences.txt!\n"); - break; - } - - strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); - rgsentenceg[isentencegs].count = 1; - - strcpy(szgroup, &(buffer[i])); - - continue; - } - else - { - //name matches with previous, increment group count - if (isentencegs >= 0) - rgsentenceg[isentencegs].count++; - } - } - - FREE_FILE( pMemFile ); - - fSentencesInit = TRUE; - - // init lru lists - - i = 0; - - while (rgsentenceg[i].count && i < CSENTENCEG_MAX) - { - USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); - i++; - } - -} - -// convert sentence (sample) name to !sentencenum, return !sentencenum - -int SENTENCEG_Lookup(const char *sample, char *sentencenum) -{ - char sznum[8]; - - int i; - // this is a sentence name; lookup sentence number - // and give to engine as string. - for (i = 0; i < gcallsentences; i++) - if (!stricmp(gszallsentencenames[i], sample+1)) - { - if (sentencenum) - { - strcpy(sentencenum, "!"); - sprintf(sznum, "%d", i); - strcat(sentencenum, sznum); - } - return i; - } - // sentence name not found! - return -1; -} - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch) -{ - if (sample && *sample == '!') - { - char name[32]; - if (SENTENCEG_Lookup(sample, name) >= 0) - EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); - else - ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample ); - } - else - EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch); -} - -// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename - -void EMIT_SOUND_SUIT(edict_t *entity, const char *sample) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - EMIT_SOUND_DYN(entity, CHAN_STATIC, sample, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in group id, over the HEV suit speaker - -void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndI(entity, isentenceg, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in groupname - -void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndSz(entity, groupname, fvol, ATTN_NORM, 0, pitch); -} - -// ===================== MATERIAL TYPE DETECTION, MAIN ROUTINES ======================== -// -// Used to detect the texture the player is standing on, map the -// texture name to a material type. Play footstep sound based -// on material type. - -int fTextureTypeInit = FALSE; - -#define CTEXTURESMAX 512 // max number of textures loaded - -int gcTextures = 0; -char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; // texture names -char grgchTextureType[CTEXTURESMAX]; // parallel array of texture types - -// open materials.txt, get size, alloc space, -// save in array. Only works first time called, -// ignored on subsequent calls. - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ) -{ - // Bullet-proofing - if ( !pMemFile || !pBuffer ) - return NULL; - - if ( filePos >= fileSize ) - return NULL; - - int i = filePos; - int last = fileSize; - - // fgets always NULL terminates, so only read bufferSize-1 characters - if ( last - filePos > (bufferSize-1) ) - last = filePos + (bufferSize-1); - - int stop = 0; - - // Stop at the next newline (inclusive) or end of buffer - while ( i < last && !stop ) - { - if ( pMemFile[i] == '\n' ) - stop = 1; - i++; - } - - - // If we actually advanced the pointer, copy it over - if ( i != filePos ) - { - // We read in size bytes - int size = i - filePos; - // copy it out - memcpy( pBuffer, pMemFile + filePos, sizeof(byte)*size ); - - // If the buffer isn't full, terminate (this is always true) - if ( size < bufferSize ) - pBuffer[size] = 0; - - // Update file pointer - filePos = i; - return pBuffer; - } - - // No data read, bail - return NULL; -} - - -void TEXTURETYPE_Init() -{ - char buffer[512]; - int i, j; - byte *pMemFile; - int fileSize, filePos; - - if (fTextureTypeInit) - return; - - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); - - gcTextures = 0; - memset(buffer, 0, 512); - - pMemFile = g_engfuncs.pfnLoadFile( "sound/materials.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while (memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL && (gcTextures < CTEXTURESMAX)) - { - // skip whitespace - i = 0; - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); - - // skip whitespace - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // get sentence name - j = i; - while (buffer[j] && !isspace(buffer[j])) - j++; - - if (!buffer[j]) - continue; - - // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); - buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); - } - - FREE_FILE( pMemFile ); - - fTextureTypeInit = TRUE; -} - -// given texture name, find texture type -// if not found, return type 'concrete' - -// NOTE: this routine should ONLY be called if the -// current texture under the player changes! - -char TEXTURETYPE_Find(char *name) -{ - // CONSIDER: pre-sort texture names and perform faster binary search here - - for (int i = 0; i < gcTextures; i++) - { - if (!strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) - return (grgchTextureType[i]); - } - - return CHAR_TEX_CONCRETE; -} - -// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the -// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. -// returns volume of strike instrument (crowbar) to play -// (this is not used for footsteps, only attack sound effects. --LRC) - -float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType) -{ -// hit the world, try to play sound based on texture material type - - char chTextureType; - float fvol; - float fvolbar; - char szbuffer[64]; - const char *pTextureName; - float rgfl1[3]; - float rgfl2[3]; - char *rgsz[4]; - int cnt; - float fattn = ATTN_NORM; - - if ( !g_pGameRules->PlayTextureSounds() ) - return 0.0; - - CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); - CBaseBrush *pBrush = pEntity->MyBrushPointer(); - - if(pBrush && pBrush->m_Material) return MatVolume(pBrush->m_Material); - - chTextureType = 0; - if (pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) - // hit body - chTextureType = CHAR_TEX_FLESH; - else - { - // hit world - - // find texture under strike, get material type - - // copy trace vector into array for trace_texture - - vecSrc.CopyToArray(rgfl1); - vecEnd.CopyToArray(rgfl2); - - // get texture from entity or world (world is ent(0)) - if (pEntity) - pTextureName = TRACE_TEXTURE( ENT(pEntity->pev), rgfl1, rgfl2 ); - else - pTextureName = TRACE_TEXTURE( ENT(0), rgfl1, rgfl2 ); - - if ( pTextureName ) - { - // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') - pTextureName += 2; - - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') - pTextureName++; - // '}}' - strcpy(szbuffer, pTextureName); - szbuffer[CBTEXTURENAMEMAX - 1] = 0; - - // ALERT ( at_console, "texture hit: %s\n", szbuffer); - - // get texture type - chTextureType = TEXTURETYPE_Find(szbuffer); - } - } - - switch (chTextureType) - { - default: - case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; - rgsz[0] = "player/pl_step1.wav"; - rgsz[1] = "player/pl_step2.wav"; - cnt = 2; - break; - case CHAR_TEX_METAL: fvol = 0.9; fvolbar = 0.3; - rgsz[0] = "player/pl_metal1.wav"; - rgsz[1] = "player/pl_metal2.wav"; - cnt = 2; - break; - case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; - rgsz[0] = "player/pl_dirt1.wav"; - rgsz[1] = "player/pl_dirt2.wav"; - rgsz[2] = "player/pl_dirt3.wav"; - cnt = 3; - break; - case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; - rgsz[0] = "player/pl_duct1.wav"; - rgsz[1] = "player/pl_duct1.wav"; - cnt = 2; - break; - case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; - rgsz[0] = "player/pl_grate1.wav"; - rgsz[1] = "player/pl_grate4.wav"; - cnt = 2; - break; - case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "player/pl_tile1.wav"; - rgsz[1] = "player/pl_tile3.wav"; - rgsz[2] = "player/pl_tile2.wav"; - rgsz[3] = "player/pl_tile4.wav"; - cnt = 4; - break; - case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; - rgsz[0] = "player/pl_slosh1.wav"; - rgsz[1] = "player/pl_slosh3.wav"; - rgsz[2] = "player/pl_slosh2.wav"; - rgsz[3] = "player/pl_slosh4.wav"; - cnt = 4; - break; - case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; - rgsz[0] = "materials/wood/wood1.wav"; - rgsz[1] = "materials/wood/wood2.wav"; - rgsz[2] = "materials/wood/wood3.wav"; - cnt = 3; - break; - case CHAR_TEX_GLASS: - case CHAR_TEX_COMPUTER: - fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "materials/glass/glass1.wav"; - rgsz[1] = "materials/glass/glass2.wav"; - rgsz[2] = "materials/glass/glass3.wav"; - cnt = 3; - break; - case CHAR_TEX_FLESH: - // crowbar already makes this sound - if (iBulletType == BULLET_CROWBAR) return 0.0; - fvol = 1.0; fvolbar = 0.2; - rgsz[0] = "weapons/bullet_hit1.wav"; - rgsz[1] = "weapons/bullet_hit2.wav"; - fattn = 1.0; - cnt = 2; - break; - } - - // did we hit a breakable? - - if (chTextureType == CHAR_TEX_COMPUTER) - { - // play random spark if computer - - if ( ptr->flFraction != 1.0 && RANDOM_LONG(0,1)) - { - UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "materials/spark5.wav", flVolume, ATTN_NORM, 0, 100); break; - case 1: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "materials/spark6.wav", flVolume, ATTN_NORM, 0, 100); break; - } - } - } - - // play material hit sound - UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, rgsz[RANDOM_LONG(0,cnt-1)], fvol, fattn, 0, 96 + RANDOM_LONG(0,0xf)); - - return fvolbar; -} - -// =================================================================================== -// -// Speaker class. Used for announcements per level, for door lock/unlock spoken voice. -// - -class CSpeaker : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT SpeakerThink( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - int m_preset; // preset number -}; - -LINK_ENTITY_TO_CLASS( speaker, CSpeaker ); -TYPEDESCRIPTION CSpeaker::m_SaveData[] = -{ - DEFINE_FIELD( CSpeaker, m_preset, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CSpeaker :: Spawn( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - if ( !m_preset && (FStringNull( pev->message ) || strlen( szSoundFile ) < 1 )) - { - ALERT( at_error, "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); - SetNextThink( 0.1 ); - SetThink( Remove ); - return; - } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - - SetThink(&CSpeaker ::SpeakerThink); - DontThink(); - - // allow on/off switching via 'use' function. - - SetUse(&CSpeaker :: ToggleUse ); - - Precache( ); -} - -#define ANNOUNCE_MINUTES_MIN 0.25 -#define ANNOUNCE_MINUTES_MAX 2.25 - -void CSpeaker :: Precache( void ) -{ - if ( !FBitSet (pev->spawnflags, SPEAKER_START_SILENT ) ) - // set first announcement time for random n second - SetNextThink( RANDOM_FLOAT(5.0, 15.0) ); -} -void CSpeaker :: SpeakerThink( void ) -{ - char* szSoundFile; - float flvolume = pev->health * 0.1; - float flattenuation = 0.3; - int flags = 0; - int pitch = 100; - - - // Wait for the talkmonster to finish first. - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - { - AbsoluteNextThink( CTalkMonster::g_talkWaitTime + RANDOM_FLOAT( 5, 10 ) ); - return; - } - - if (m_preset) - { - // go lookup preset text, assign szSoundFile - switch (m_preset) - { - case 1: szSoundFile = "C1A0_"; break; - case 2: szSoundFile = "C1A1_"; break; - case 3: szSoundFile = "C1A2_"; break; - case 4: szSoundFile = "C1A3_"; break; - case 5: szSoundFile = "C1A4_"; break; - case 6: szSoundFile = "C2A1_"; break; - case 7: szSoundFile = "C2A2_"; break; - case 8: szSoundFile = "C2A3_"; break; - case 9: szSoundFile = "C2A4_"; break; - case 10: szSoundFile = "C2A5_"; break; - case 11: szSoundFile = "C3A1_"; break; - case 12: szSoundFile = "C3A2_"; break; - } - } else - szSoundFile = (char*) STRING(pev->message); - - if (szSoundFile[0] == '!') - { - // play single sentence, one shot - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - flvolume, flattenuation, flags, pitch); - - // shut off and reset - DontThink(); - } - else - { - // make random announcement from sentence group - - if( SENTENCEG_PlayRndSz( ENT( pev ), szSoundFile, flvolume, flattenuation, flags, pitch ) < 0 ) - ALERT( at_console, "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile); - - // set next announcement time for random 5 to 10 minute delay - SetNextThink( RANDOM_FLOAT(ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0) ); - - CTalkMonster::g_talkWaitTime = gpGlobals->time + 5; // time delay until it's ok to speak: used so that two NPCs don't talk at once - } - - return; -} - - -// -// ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one. -// -void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int fActive = (m_fNextThink > 0.0); - - // fActive is TRUE only if an announcement is pending - - if ( useType != USE_TOGGLE ) - { - // ignore if we're just turning something on that's already on, or - // turning something off that's already off. - if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) ) - return; - } - - if ( useType == USE_ON ) - { - // turn on announcements - SetNextThink( 0.1 ); - return; - } - - if ( useType == USE_OFF ) - { - // turn off announcements - DontThink(); - return; - - } - - // Toggle announcements - - - if ( fActive ) - { - // turn off announcements - DontThink(); - } - else - { - // turn on announcements - SetNextThink( 0.1 ); - } -} - -// KeyValue - load keyvalue pairs into member data -// NOTE: called BEFORE spawn! - -void CSpeaker :: KeyValue( KeyValueData *pkvd ) -{ - - // preset - if (FStrEq(pkvd->szKeyName, "preset")) - { - m_preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -#define SF_LOOP 2 - -class CFMODAudio : public CBaseLogic -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void StartMessage( CBasePlayer *pPlayer ); -}; -LINK_ENTITY_TO_CLASS( ambient_music, CFMODAudio ); - -void CFMODAudio::Spawn( void ) -{ - if(pev->spawnflags & SF_START_ON ) - { - SetBits( pev->impulse, SF_START_ON ); - m_iState = STATE_ON; - } - if(pev->spawnflags & SF_LOOP) SetBits( pev->impulse, SF_LOOP ); -} - -void CFMODAudio::StartMessage( CBasePlayer *pPlayer ) -{ - MESSAGE_BEGIN( MSG_ONE, gmsg.Fsound, NULL, pPlayer->pev ); - WRITE_STRING( STRING( pev->message )); - WRITE_SHORT( pev->button ); // position - WRITE_SHORT( pev->impulse ); // flags - MESSAGE_END(); -} - -void CFMODAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if(pActivator && pActivator->IsPlayer( )) // only at player - { - m_hActivator = pActivator;//save activator - } - else m_hActivator = UTIL_PlayerByIndex( 1 ); - - if( useType == USE_TOGGLE ) - { - if(m_iState == STATE_OFF) useType = USE_ON; - else useType = USE_OFF; - } - if( useType == USE_ON ) - { - m_iState = STATE_ON; - SetBits( pev->impulse, SF_START_ON ); - StartMessage( (CBasePlayer *)(CBaseEntity *)m_hActivator ); - } - else if( useType == USE_OFF ) - { - ClearBits( pev->impulse, SF_START_ON ); - StartMessage( (CBasePlayer *)(CBaseEntity *)m_hActivator ); - m_iState = STATE_OFF; - } - else if( useType == USE_SHOWINFO ) - { - DEBUGHEAD; - ALERT(at_console, "State: %s, Song name: %s\n", GetStringForState( GetState()), STRING(pev->message)); - SHIFT; - } -} \ No newline at end of file diff --git a/server/game/spectator.h b/server/game/spectator.h deleted file mode 100644 index d459a384..00000000 --- a/server/game/spectator.h +++ /dev/null @@ -1,27 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Spectator.h - -class CBaseSpectator : public CBaseEntity -{ -public: - void Spawn(); - void SpectatorConnect(void); - void SpectatorDisconnect(void); - void SpectatorThink(void); - -private: - void SpectatorImpulseCommand(void); -}; \ No newline at end of file diff --git a/server/game/teamplay_gamerules.cpp b/server/game/teamplay_gamerules.cpp deleted file mode 100644 index 36f8e808..00000000 --- a/server/game/teamplay_gamerules.cpp +++ /dev/null @@ -1,614 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "player.h" -#include "baseweapon.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "game.h" - -static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; -static int team_scores[MAX_TEAMS]; -static int num_teams = 0; - -extern DLL_GLOBAL BOOL g_fGameOver; - -CHalfLifeTeamplay :: CHalfLifeTeamplay() -{ - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - - memset( team_names, 0, sizeof(team_names) ); - memset( team_scores, 0, sizeof(team_scores) ); - num_teams = 0; - - // Copy over the team from the server config - m_szTeamList[0] = 0; - - // Cache this because the team code doesn't want to deal with changing this in the middle of a game - strncpy( m_szTeamList, CVAR_GET_STRING( "mp_teamlist" ), TEAMPLAY_TEAMLISTLENGTH ); - - edict_t *pWorld = INDEXENT(0); - if ( pWorld && pWorld->v.team ) - { - if( CVAR_GET_FLOAT( "mp_teamoverride" )) - { - const char *pTeamList = STRING(pWorld->v.team); - if ( pTeamList && strlen(pTeamList) ) - { - strncpy( m_szTeamList, pTeamList, TEAMPLAY_TEAMLISTLENGTH ); - } - } - } - // Has the server set teams - if ( strlen( m_szTeamList ) ) - m_teamLimit = TRUE; - else - m_teamLimit = FALSE; - - RecountTeams(); -} - -void CHalfLifeTeamplay :: Think ( void ) -{ - ///// Check game rules ///// - static int last_frags; - static int last_time; - - int frags_remaining = 0; - int time_remaining = 0; - - if ( g_fGameOver ) // someone else quit the game already - { - CHalfLifeMultiplay::Think(); - return; - } - - float flTimeLimit = CVAR_GET_FLOAT("mp_timelimit") * 60; - - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) - { - GoToIntermission(); - return; - } - - float flFragLimit = CVAR_GET_FLOAT( "mp_fraglimit" ); - if ( flFragLimit ) - { - int bestfrags = 9999; - int remain; - - // check if any team is over the frag limit - for ( int i = 0; i < num_teams; i++ ) - { - if ( team_scores[i] >= flFragLimit ) - { - GoToIntermission(); - return; - } - - remain = flFragLimit - team_scores[i]; - if ( remain < bestfrags ) - { - bestfrags = remain; - } - } - frags_remaining = bestfrags; - } - - // Updates when frags change - if( frags_remaining != last_frags ) - { - g_engfuncs.pfnCVarSetString( "mp_fragsleft", UTIL_VarArgs( "%i", frags_remaining )); - } - - // Updates once per second - if( CVAR_GET_FLOAT( "mp_timeleft" ) != last_time ) - { - g_engfuncs.pfnCVarSetString( "mp_timeleft", UTIL_VarArgs( "%i", time_remaining )); - } - - last_frags = frags_remaining; - last_time = time_remaining; -} - -//========================================================= -// ClientCommand -// the user has typed a command which is unrecognized by everything else; -// this check to see if the gamerules knows anything about the command -//========================================================= -BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) -{ - if ( FStrEq( pcmd, "menuselect" ) ) - { - if ( CMD_ARGC() < 2 ) - return TRUE; - - int slot = atoi( CMD_ARGV(1) ); - - // select the item from the current menu - - return TRUE; - } - - return FALSE; -} - -void CHalfLifeTeamplay :: UpdateGameMode( CBasePlayer *pPlayer ) -{ - MESSAGE_BEGIN( MSG_ONE, gmsg.GameMode, NULL, pPlayer->edict() ); - WRITE_BYTE( 1 ); // game mode teamplay - MESSAGE_END(); -} - - -const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) -{ - // copy out the team name from the model - char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); - strncpy( pPlayer->m_szTeamName, mdls, TEAM_NAME_LENGTH ); - - RecountTeams(); - - // update the current player of the team he is joining - if ( pPlayer->m_szTeamName[0] == '\0' || !IsValidTeam( pPlayer->m_szTeamName ) || CVAR_GET_FLOAT( "mp_defaultteam" )) - { - const char *pTeamName = NULL; - - if( CVAR_GET_FLOAT( "mp_defaultteam" )) - { - pTeamName = team_names[0]; - } - else - { - pTeamName = TeamWithFewestPlayers(); - } - strncpy( pPlayer->m_szTeamName, pTeamName, TEAM_NAME_LENGTH ); - } - - return pPlayer->m_szTeamName; -} - - -//========================================================= -// InitHUD -//========================================================= -void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) -{ - int i; - - SetDefaultPlayerTeam( pPlayer ); - CHalfLifeMultiplay::InitHUD( pPlayer ); - - // Send down the team names - MESSAGE_BEGIN( MSG_ONE, gmsg.TeamNames, NULL, pPlayer->edict() ); - WRITE_BYTE( num_teams ); - for ( i = 0; i < num_teams; i++ ) - { - WRITE_STRING( team_names[ i ] ); - } - MESSAGE_END(); - - RecountTeams(); - - char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); - // update the current player of the team he is joining - char text[1024]; - if ( !strcmp( mdls, pPlayer->m_szTeamName ) ) - { - sprintf( text, "* you are on team \'%s\'\n", pPlayer->m_szTeamName ); - } - else - { - sprintf( text, "* assigned to team %s\n", pPlayer->m_szTeamName ); - } - - ChangePlayerTeam( pPlayer, pPlayer->m_szTeamName, FALSE, FALSE ); - UTIL_SayText( text, pPlayer ); - int clientIndex = pPlayer->entindex(); - RecountTeams(); - // update this player with all the other players team info - // loop through all active players and send their team info to the new client - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - if ( plr && IsValidTeam( plr->TeamID() ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.TeamInfo, NULL, pPlayer->edict() ); - WRITE_BYTE( plr->entindex() ); - WRITE_STRING( plr->TeamID() ); - MESSAGE_END(); - } - } -} - - -void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) -{ - int damageFlags = DMG_GENERIC; - int clientIndex = pPlayer->entindex(); - - if ( !bGib ) - { - damageFlags |= DMG_NEVERGIB; - } - else - { - damageFlags |= DMG_ALWAYSGIB; - } - - if ( bKill ) - { - // kill the player, remove a death, and let them start on the new team - m_DisableDeathMessages = TRUE; - m_DisableDeathPenalty = TRUE; - - entvars_t *pevWorld = VARS( INDEXENT(0) ); - pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags ); - - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - } - - // copy out the team name from the model - strncpy( pPlayer->m_szTeamName, pTeamName, TEAM_NAME_LENGTH ); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->m_szTeamName ); - - // notify everyone's HUD of the team change - MESSAGE_BEGIN( MSG_ALL, gmsg.TeamInfo ); - WRITE_BYTE( clientIndex ); - WRITE_STRING( pPlayer->m_szTeamName ); - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_ALL, gmsg.ScoreInfo ); - WRITE_BYTE( clientIndex ); - WRITE_SHORT( pPlayer->pev->frags ); - WRITE_SHORT( pPlayer->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( g_pGameRules->GetTeamIndex( pPlayer->m_szTeamName ) + 1 ); - MESSAGE_END(); -} - - -//========================================================= -// ClientUserInfoChanged -//========================================================= -void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) -{ - char text[1024]; - - // prevent skin/color/model changes - char *mdls = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); - - if ( !stricmp( mdls, pPlayer->m_szTeamName ) ) - return; - - if( CVAR_GET_FLOAT( "mp_defaultteam" )) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->m_szTeamName ); - sprintf( text, "* Not allowed to change teams in this game!\n" ); - UTIL_SayText( text, pPlayer ); - return; - } - - if( CVAR_GET_FLOAT( "mp_defaultteam" ) || !IsValidTeam( mdls )) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); - sprintf( text, "* Can't change team to \'%s\'\n", mdls ); - UTIL_SayText( text, pPlayer ); - sprintf( text, "* Server limits teams to \'%s\'\n", m_szTeamList ); - UTIL_SayText( text, pPlayer ); - return; - } - // notify everyone of the team change - sprintf( text, "* %s has changed to team \'%s\'\n", STRING(pPlayer->pev->netname), mdls ); - UTIL_SayTextAll( text, pPlayer ); - - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n", - STRING(pPlayer->pev->netname), - GETPLAYERUSERID( pPlayer->edict() ), - GETPLAYERAUTHID( pPlayer->edict() ), - pPlayer->m_szTeamName, - mdls ); - - ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); - - // recound stuff - RecountTeams( TRUE ); -} - -//========================================================= -// Deathnotice. -//========================================================= -void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) -{ - if ( m_DisableDeathMessages ) - return; - - if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) - { - CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); - - if ( pk ) - { - if ( (pk != pVictim) && (PlayerRelationship( pVictim, pk ) == GR_TEAMMATE) ) - { - MESSAGE_BEGIN( MSG_ALL, gmsg.DeathMsg ); - WRITE_BYTE( ENTINDEX(ENT(pKiller)) ); // the killer - WRITE_BYTE( ENTINDEX(pVictim->edict()) ); // the victim - WRITE_STRING( "teammate" ); // flag this as a teammate kill - MESSAGE_END(); - return; - } - } - } - - CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor ); -} - -//========================================================= -//========================================================= -void CHalfLifeTeamplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ - if ( !m_DisableDeathPenalty ) - { - CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); - RecountTeams(); - } -} - - -//========================================================= -// IsTeamplay -//========================================================= -BOOL CHalfLifeTeamplay::IsTeamplay( void ) -{ - return TRUE; -} - -BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) -{ - if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) - { - // my teammate hit me. - if( (CVAR_GET_FLOAT( "mp_friendlyfire" ) == 0) && (pAttacker != pPlayer) ) - { - // friendly fire is off, and this hit came from someone other than myself, then don't get hurt - return FALSE; - } - } - - return CHalfLifeMultiplay::FPlayerCanTakeDamage( pPlayer, pAttacker ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // half life multiplay has a simple concept of Player Relationships. - // you are either on another player's team, or you are not. - if ( !pPlayer || !pTarget || !pTarget->IsPlayer() ) - return GR_NOTTEAMMATE; - - if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) - { - return GR_TEAMMATE; - } - - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeTeamplay::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) -{ - // always autoaim, unless target is a teammate - CBaseEntity *pTgt = CBaseEntity::Instance( target ); - if ( pTgt && pTgt->IsPlayer() ) - { - if ( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) - return FALSE; // don't autoaim at teammates - } - - return CHalfLifeMultiplay::ShouldAutoAim( pPlayer, target ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - if ( !pKilled ) - return 0; - - if ( !pAttacker ) - return 1; - - if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) - return -1; - - return 1; -} - -//========================================================= -//========================================================= -const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL || pEntity->pev == NULL ) - return ""; - - // return their team name - return pEntity->TeamID(); -} - - -int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) -{ - if ( pTeamName && *pTeamName != 0 ) - { - // try to find existing team - for ( int tm = 0; tm < num_teams; tm++ ) - { - if ( !stricmp( team_names[tm], pTeamName ) ) - return tm; - } - } - - return -1; // No match -} - - -const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) -{ - if ( teamIndex < 0 || teamIndex >= num_teams ) - return ""; - - return team_names[ teamIndex ]; -} - - -BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) -{ - if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set - return TRUE; - - return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE; -} - -const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) -{ - int i; - int minPlayers = MAX_TEAMS; - int teamCount[ MAX_TEAMS ]; - char *pTeamName = NULL; - - memset( teamCount, 0, MAX_TEAMS * sizeof(int) ); - - // loop through all clients, count number of players on each team - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - int team = GetTeamIndex( plr->TeamID() ); - if ( team >= 0 ) - teamCount[team] ++; - } - } - - // Find team with least players - for ( i = 0; i < num_teams; i++ ) - { - if ( teamCount[i] < minPlayers ) - { - minPlayers = teamCount[i]; - pTeamName = team_names[i]; - } - } - - return pTeamName; -} - - -//========================================================= -//========================================================= -void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) -{ - char *pName; - char teamlist[TEAMPLAY_TEAMLISTLENGTH]; - - // loop through all teams, recounting everything - num_teams = 0; - - // Copy all of the teams from the teamlist - // make a copy because strtok is destructive - strcpy( teamlist, m_szTeamList ); - pName = teamlist; - pName = strtok( pName, ";" ); - while ( pName != NULL && *pName ) - { - if ( GetTeamIndex( pName ) < 0 ) - { - strcpy( team_names[num_teams], pName ); - num_teams++; - } - pName = strtok( NULL, ";" ); - } - - if ( num_teams < 2 ) - { - num_teams = 0; - m_teamLimit = FALSE; - } - - // Sanity check - memset( team_scores, 0, sizeof(team_scores) ); - - // loop through all clients - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - const char *pTeamName = plr->TeamID(); - // try add to existing team - int tm = GetTeamIndex( pTeamName ); - - if ( tm < 0 ) // no team match found - { - if ( !m_teamLimit ) - { - // add to new team - tm = num_teams; - num_teams++; - team_scores[tm] = 0; - strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); - } - } - - if ( tm >= 0 ) - { - team_scores[tm] += plr->pev->frags; - } - - if ( bResendInfo ) //Someone's info changed, let's send the team info again. - { - if ( plr && IsValidTeam( plr->TeamID() ) ) - { - MESSAGE_BEGIN( MSG_ALL, gmsg.TeamInfo, NULL ); - WRITE_BYTE( plr->entindex() ); - WRITE_STRING( plr->TeamID() ); - MESSAGE_END(); - } - } - } - } -} diff --git a/server/game/teamplay_gamerules.h b/server/game/teamplay_gamerules.h deleted file mode 100644 index 529e22bd..00000000 --- a/server/game/teamplay_gamerules.h +++ /dev/null @@ -1,56 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.h -// - -#define MAX_TEAMNAME_LENGTH 16 -#define MAX_TEAMS 32 - -#define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH - -class CHalfLifeTeamplay : public CHalfLifeMultiplay -{ -public: - CHalfLifeTeamplay(); - - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); - virtual BOOL IsTeamplay( void ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - virtual const char *GetTeamID( CBaseEntity *pEntity ); - virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void InitHUD( CBasePlayer *pl ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); - virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void Think ( void ); - virtual int GetTeamIndex( const char *pTeamName ); - virtual const char *GetIndexedTeamName( int teamIndex ); - virtual BOOL IsValidTeam( const char *pTeamName ); - const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); - virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ); - -private: - void RecountTeams( bool bResendInfo = FALSE ); - const char *TeamWithFewestPlayers( void ); - - BOOL m_DisableDeathMessages; - BOOL m_DisableDeathPenalty; - BOOL m_teamLimit; // This means the server set only some teams as valid - char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; -}; diff --git a/server/global/client.cpp b/server/global/client.cpp deleted file mode 100644 index a884c32b..00000000 --- a/server/global/client.cpp +++ /dev/null @@ -1,2134 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to -// have one without a hardcoded player.mdl in tf_client.cpp - -/* - -===== client.cpp ======================================================== - - client/server game specific stuff - -*/ - -#include - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "saverestore.h" -#include "shake.h" -#include "player.h" -#include "spectator.h" -#include "client.h" -#include "gamerules.h" -#include "game.h" -#include "soundent.h" -#include "baseweapon.h" -#include "weaponinfo.h" -#include "defaults.h" -#include "decals.h" -#include "nodes.h" - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern CBaseEntity *g_pLastSpawn; -extern CSoundEnt *pSoundEnt; -DLL_GLOBAL edict_t *g_pBodyQueueHead; -DLL_GLOBAL int g_serveractive = 0; -BOOL MSGSended; -BOOL NewLevel = FALSE; -float MsgDelay; -user_messages_t gmsg; -void LinkUserMessages( void ); -char text[256]; -extern int g_teamplay; - -//messages affect only player -typedef struct _SelAmmo -{ - byte Ammo1Type; - byte Ammo1; - byte Ammo2Type; - byte Ammo2; -} SelAmmo; - -/* - * used by kill command and disconnect command - * ROBIN: Moved here from player.cpp, to allow multiple player models - */ -void set_suicide_frame(entvars_t* pev) -{ - if (!FStrEq(STRING(pev->model), "models/player.mdl")) - return; // allready gibbed - -// pev->frame = $deatha11; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - pev->deadflag = DEAD_DEAD; - pev->nextthink = -1; -} - -void InitBodyQue(void) -{ - string_t istrClassname = MAKE_STRING("bodyque"); - - g_pBodyQueueHead = CREATE_NAMED_ENTITY( istrClassname ); - entvars_t *pev = VARS(g_pBodyQueueHead); - - // Reserve 3 more slots for dead bodies - for ( int i = 0; i < 3; i++ ) - { - pev->owner = CREATE_NAMED_ENTITY( istrClassname ); - pev = VARS(pev->owner); - } - - pev->owner = g_pBodyQueueHead; -} - -// -// make a body que entry for the given ent so the ent can be respawned elsewhere -// -// GLOBALS ASSUMED SET: g_eoBodyQueueHead -// -void CopyToBodyQue(entvars_t *pev) -{ - if (pev->effects & EF_NODRAW) - return; - - entvars_t *pevHead = VARS(g_pBodyQueueHead); - - pevHead->angles = pev->angles; - pevHead->model = pev->model; - pevHead->modelindex = pev->modelindex; - pevHead->frame = pev->frame; - pevHead->colormap = pev->colormap; - pevHead->movetype = MOVETYPE_TOSS; - pevHead->velocity = pev->velocity; - pevHead->flags = 0; - pevHead->deadflag = pev->deadflag; - pevHead->renderfx = kRenderFxDeadPlayer; - pevHead->renderamt = ENTINDEX( ENT( pev ) ); - - pevHead->effects = pev->effects | EF_NOINTERP; - //pevHead->goalstarttime = pev->goalstarttime; - //pevHead->goalframe = pev->goalframe; - //pevHead->goalendtime = pev->goalendtime ; - - pevHead->sequence = pev->sequence; - pevHead->animtime = pev->animtime; - - UTIL_SetEdictOrigin(g_pBodyQueueHead, pev->origin); - UTIL_SetSize(pevHead, pev->mins, pev->maxs); - g_pBodyQueueHead = pevHead->owner; -} - - -/* -=========== -ClientConnect - -called when a player connects to a server -============ -*/ -BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ) -{ - return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); - -// a client connecting during an intermission can cause problems -// if (intermission_running) -// ExitIntermission (); - -} - - -/* -=========== -ClientDisconnect - -called when a player disconnects from a server - -GLOBALS ASSUMED SET: g_fGameOver -============ -*/ -void ClientDisconnect( edict_t *pEntity ) -{ - if (g_fGameOver) - return; - - char text[256]; - sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) ); - MESSAGE_BEGIN( MSG_ALL, gmsg.SayText, NULL ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - CSound *pSound; - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); - { - // since this client isn't around to think anymore, reset their sound. - if ( pSound ) - { - pSound->Reset(); - } - } - -// since the edict doesn't get deleted, fix it so it doesn't interfere. - pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim - pEntity->v.solid = SOLID_NOT;// nonsolid - UTIL_SetEdictOrigin ( pEntity, pEntity->v.origin ); - - g_pGameRules->ClientDisconnected( pEntity ); -} - - -// called by ClientKill and DeadThink -void respawn(entvars_t* pev, BOOL fCopyCorpse) -{ - if ( gpGlobals->teamplay || gpGlobals->coop || gpGlobals->deathmatch ) - { - if ( fCopyCorpse ) - { - // make a copy of the dead body for appearances sake - CopyToBodyQue(pev); - } - - // respawn player - GetClassPtr( (CBasePlayer *)pev)->Spawn( ); - } - else - { - // restart the entire server - SERVER_COMMAND( "reload\n" ); - } -} - -/* -============ -ClientKill - -Player entered the suicide command - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -============ -*/ -void ClientKill( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - - CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev ); - - if ( pl->m_fNextSuicideTime > gpGlobals->time ) - return; // prevent suiciding too ofter - - pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding - - // have the player kill themself - pev->health = 0; - pl->Killed( pev, GIB_NEVER ); - -// pev->modelindex = g_ulModelIndexPlayer; -// pev->frags -= 2; // extra penalty -// respawn( pev ); -} - -/* -=========== -ClientPutInServer - -called each time a player is spawned -============ -*/ -void ClientPutInServer( edict_t *pEntity ) -{ - CBasePlayer *pPlayer; - - entvars_t *pev = &pEntity->v; - - pPlayer = GetClassPtr((CBasePlayer *)pev); - pPlayer->SetCustomDecalFrames(-1); // Assume none; - - // Allocate a CBasePlayer for pev, and call spawn - pPlayer->Spawn() ; - - // Reset interpolation during first frame - pPlayer->pev->effects |= EF_NOINTERP; - - g_startSuit = FALSE; -} - -//// HOST_SAY -// String comes in as -// say blah blah blah -// or as -// blah blah blah -// -void Host_Say( edict_t *pEntity, int teamonly ) -{ - CBasePlayer *client; - int j; - char *p; - char text[128]; - char szTemp[256]; - const char *cpSay = "say"; - const char *cpSayTeam = "say_team"; - const char *pcmd = CMD_ARGV(0); - - // We can get a raw string now, without the "say " prepended - if ( CMD_ARGC() == 0 ) - return; - - entvars_t *pev = &pEntity->v; - CBasePlayer* player = GetClassPtr((CBasePlayer *)pev); - - //Not yet. - if ( player->m_flNextChatTime > gpGlobals->time ) - return; - - if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) - { - if ( CMD_ARGC() >= 2 ) - { - p = (char *)CMD_ARGS(); - } - else - { - // say with a blank message, nothing to do - return; - } - } - else // Raw text, need to prepend argv[0] - { - if ( CMD_ARGC() >= 2 ) - { - sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); - } - else - { - // Just a one word command, use the first word...sigh - sprintf( szTemp, "%s", ( char * )pcmd ); - } - p = szTemp; - } - -// remove quotes if present - if (*p == '"') - { - p++; - p[strlen(p)-1] = 0; - } - -// make sure the text has content - char *pc; - for ( pc = p; pc != NULL && *pc != 0; pc++ ) - { - if ( isprint( *pc ) && !isspace( *pc ) ) - { - pc = NULL; // we've found an alphanumeric character, so text is valid - break; - } - } - if ( pc != NULL ) - return; // no character found, so say nothing - -// turn on color set 2 (color on, no sound) - if ( teamonly ) - sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); - else - sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); - - j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator - if ( (int)strlen(p) > j ) - p[j] = 0; - - strcat( text, p ); - strcat( text, "\n" ); - - - player->m_flNextChatTime = gpGlobals->time + CHAT_INTERVAL; - - // loop through all players - // Start with the first player. - // This may return the world in single player if the client types something between levels or during spawn - // so check it, or it will infinite loop - - client = NULL; - while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) - { - if ( !client->pev ) - continue; - - if ( client->edict() == pEntity ) - continue; - - if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) - continue; - - if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) - continue; - - MESSAGE_BEGIN( MSG_ONE, gmsg.SayText, NULL, client->pev ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - } - - // print to the sending client - MESSAGE_BEGIN( MSG_ONE, gmsg.SayText, NULL, &pEntity->v ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - // echo to server console - g_engfuncs.pfnServerPrint( text ); - - char * temp; - if ( teamonly ) - temp = "say_team"; - else - temp = "say"; - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pEntity ), "model" ), - temp, - p ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" %s \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - GETPLAYERUSERID( pEntity ), - temp, - p ); - } -} - - -/* -=========== -ClientCommand -called each time a player uses a "cmd" command -============ -*/ -extern float g_flWeaponCheat; - -// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command. -void ClientCommand( edict_t *pEntity ) -{ - const char *pcmd = CMD_ARGV(0); - const char *pstr; - - // Is the client spawned yet? - if( !pEntity->pvPrivateData ) - return; - - entvars_t *pev = &pEntity->v; - - if( FStrEq( pcmd, "noclip" )) - { - if( pEntity->v.movetype == MOVETYPE_WALK ) - { - pEntity->v.movetype = MOVETYPE_NOCLIP; - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "noclip on\n" ); - } - else - { - pEntity->v.movetype = MOVETYPE_WALK; - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "noclip off\n" ); - } - } - else if( FStrEq( pcmd, "god" )) - { - pEntity->v.flags = pEntity->v.flags ^ FL_GODMODE; - - if ( !( pEntity->v.flags & FL_GODMODE )) - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "godmode OFF\n" ); - else ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "godmode ON\n" ); - } - else if( FStrEq( pcmd, "fly" )) - { - if ( pEntity->v.movetype == MOVETYPE_FLY ) - { - pEntity->v.movetype = MOVETYPE_WALK; - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "flymode OFF\n" ); - } - else - { - pEntity->v.movetype = MOVETYPE_FLY; - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "flymode ON\n" ); - } - } - else if( FStrEq( pcmd, "notarget" )) - { - pEntity->v.flags = pEntity->v.flags ^ FL_NOTARGET; - - if ( !( pEntity->v.flags & FL_NOTARGET )) - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "notarget OFF\n" ); - else ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, "notarget ON\n" ); - } - else if ( FStrEq( pcmd, "hud_color") ) //LRC - { - if (CMD_ARGC() == 4) - { - int col = (atoi(CMD_ARGV(1)) & 255) << 16; - col += (atoi(CMD_ARGV(2)) & 255) << 8; - col += (atoi(CMD_ARGV(3)) & 255); - MESSAGE_BEGIN( MSG_ONE, gmsg.HUDColor, NULL, &pEntity->v ); - WRITE_LONG( col ); - MESSAGE_END(); - } - else - { - ALERT( at_console, "Usage: hud_color \n" ); - } - } - else if( FStrEq( pcmd, "fire" )) //LRC - trigger entities manually - { - if( g_flWeaponCheat ) - { - CBaseEntity *pPlayer = CBaseEntity::Instance(pEntity); - if( CMD_ARGC() > 1 ) - { - UTIL_FireTargets( CMD_ARGV( 1 ), pPlayer, pPlayer, USE_TOGGLE ); - } - else - { - TraceResult tr; - UTIL_MakeVectors( pev->v_angle ); - UTIL_TraceLine( pev->origin + pev->view_ofs, - pev->origin + pev->view_ofs + gpGlobals->v_forward * 1000, - dont_ignore_monsters, pEntity, &tr ); - - if( tr.pHit ) - { - CBaseEntity *pHitEnt = CBaseEntity::Instance(tr.pHit); - if( pHitEnt ) - { - pHitEnt->Use( pPlayer, pPlayer, USE_TOGGLE, 0 ); - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING(pHitEnt->pev->classname), STRING(pHitEnt->pev->targetname) ) ); - } - } - } - } - } - else if( FStrEq( pcmd, "debug" )) - { - if( g_flWeaponCheat ) - { - CBaseEntity *pPlayer = CBaseEntity::Instance( pEntity ); - if( CMD_ARGC() > 1 ) - { - UTIL_FireTargets( CMD_ARGV( 1 ), pPlayer, pPlayer, USE_SHOWINFO ); - } - else - { - TraceResult tr; - UTIL_MakeVectors( pev->v_angle ); - UTIL_TraceLine( pev->origin + pev->view_ofs, - pev->origin + pev->view_ofs + gpGlobals->v_forward * 1000, - dont_ignore_monsters, pEntity, &tr ); - - if( tr.pHit ) - { - CBaseEntity *pHitEnt = CBaseEntity::Instance(tr.pHit); - if( pHitEnt ) - { - pHitEnt->Use( pPlayer, pPlayer, USE_SHOWINFO, 0 ); - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING(pHitEnt->pev->classname), STRING(pHitEnt->pev->targetname) ) ); - } - } - } - } - } - else if ( FStrEq(pcmd, "say" ) ) - { - Host_Say( pEntity, 0 ); - } - else if ( FStrEq(pcmd, "game_over" ) ) - { - if ( IsMultiplayer( )) - g_pGameRules->EndMultiplayerGame(); //loading next map - else g_engfuncs.pfnEndSection( CMD_ARGV( 1 ) ); - } - else if( FStrEq( pcmd, "gametitle" )) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.ShowGameTitle, NULL, ENT( pev )); - MESSAGE_END(); - } - else if( FStrEq( pcmd, "intermission" )) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.Intermission, NULL, ENT( pev )); - MESSAGE_END(); - } - else if( FStrEq( pcmd, "fullupdate" )) - { - GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); - } - else if( FStrEq( pcmd, "give" )) - { - if ( g_flWeaponCheat != 0.0) - { - int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname - GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); - } - } - - else if ( FStrEq(pcmd, "drop" ) ) - { - // player is dropping an item. - GetClassPtr((CBasePlayer *)pev)->DropPlayerItem((char *)CMD_ARGV(1)); - } - else if( FStrEq( pcmd, "fov" )) - { - if( g_flWeaponCheat && CMD_ARGC() > 1 ) - { - GetClassPtr((CBasePlayer *)pev)->pev->fov = atof( CMD_ARGV( 1 )); - } - else - { - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "\"fov\" is \"%g\"\n", (int)GetClassPtr((CBasePlayer *)pev)->pev->fov )); - } - } - else if ( FStrEq(pcmd, "use" ) ) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV( 1 )); - } - else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd)) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd); - } - else if( FStrEq( pcmd, "lastinv" )) - { - GetClassPtr((CBasePlayer *)pev)->SelectLastItem(); - } - else if( FStrEq( pcmd, "spectate" ) && (pev->flags & FL_PROXY) ) // added for proxy support - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - - edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); - pPlayer->StartObserver( pev->origin, VARS(pentSpawnSpot)->angles); - } - else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd )) - { - // MenuSelect returns true only if the command is properly handled, so don't print a warning - } - else - { - // tell the user they entered an unknown command - char command[128]; - - // check the length of the command (prevents crash) - // max total length is 192 ...and we're adding a string below ("Unknown command: %s\n") - strncpy( command, pcmd, 127 ); - command[127] = '\0'; - - // tell the user they entered an unknown command - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", command ) ); - } -} - - -/* -======================== -ClientUserInfoChanged - -called after the player changes -userinfo - gives dll a chance to modify it before -it gets sent into the rest of the engine. -======================== -*/ -void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) -{ - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) - if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) ) - { - char sName[256]; - char *pName = g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ); - strncpy( sName, pName, sizeof(sName) - 1 ); - sName[ sizeof(sName) - 1 ] = '\0'; - - // First parse the name and remove any %'s - for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) - { - // Replace it with a space - if ( *pApersand == '%' ) - *pApersand = ' '; - } - - // Set the name - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); - - char text[256]; - sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - MESSAGE_BEGIN( MSG_ALL, gmsg.SayText, NULL ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" changed name to \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - GETPLAYERUSERID( pEntity ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - } - g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); -} - -void ServerDeactivate( void ) -{ - // make sure they reinitialise the World in the next server - g_pWorld = NULL; - - // It's possible that the engine will call this function more times than is necessary - // Therefore, only run it one time for each call to ServerActivate - if ( g_serveractive != 1 ) - { - return; - } - - g_serveractive = 0; - - // Peform any shutdown operations here... - // -} - -void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) -{ - int i; - CBaseEntity *pClass; - - // Every call to ServerActivate should be matched by a call to ServerDeactivate - g_serveractive = 1; - // Clients have not been initialized yet - for ( i = 0; i < edictCount; i++ ) - { - if ( pEdictList[i].free ) - continue; - - // Clients aren't necessarily initialized until ClientPutInServer() - if ( i < clientMax || !pEdictList[i].pvPrivateData ) - continue; - - pClass = CBaseEntity::Instance( &pEdictList[i] ); - // Activate this entity if it's got a class & isn't dormant - if ( pClass && !(pClass->pev->flags & FL_DORMANT) ) - { - pClass->SetupPhysics(); - pClass->Activate(); - } - else Msg( "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); - } - - // Link user messages here to make sure first client can get them... - NewLevel = FALSE; - LinkUserMessages(); -} - -// a cached version of gpGlobals->frametime. The engine sets frametime to 0 if the player is frozen... so we just cache it in prethink, -// allowing it to be restored later and used by CheckDesiredList. -float cached_frametime = 0.0f; - -/* -================ -PlayerPreThink - -Called every frame before physics are run -================ -*/ -void PlayerPreThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer)pPlayer->PreThink( ); - cached_frametime = gpGlobals->frametime; -} - -/* -================ -PlayerPostThink - -Called every frame after physics are run -================ -*/ -void PlayerPostThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer)pPlayer->PostThink( ); - - // use the old frametime, even if the engine has reset it - gpGlobals->frametime = cached_frametime; - - PhysicsPostFrame(); -} - -void BuildLevelList( void ) -{ - // retrieve the pointer to the save data - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - - if( pSaveData ) - pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); -} - -//======================================================================= -// Build ChangeLevel List -//======================================================================= -int AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ) -{ - int i; - - if( !pLevelList || !pMapName ) return 0; - - for( i = 0; i < listCount; i++ ) - { - if( pLevelList[i].pentLandmark == pentLandmark && !strcmp( pLevelList[i].mapName, pMapName )) - return 0; - } - - strcpy( pLevelList[listCount].mapName, pMapName ); - strcpy( pLevelList[listCount].landmarkName, pLandmarkName ); - pLevelList[listCount].pentLandmark = pentLandmark; - - if ( FNullEnt( pentLandmark )) - pLevelList[listCount].vecLandmarkOrigin = Vector( 0, 0, 0 ); - else pLevelList[listCount].vecLandmarkOrigin = VARS( pentLandmark )->origin; - - return 1; -} - -int BuildChangeList( LEVELLIST *pLevelList, int maxList ) -{ - edict_t *pentLandmark; - int i, count; - - count = 0; - - // find all of the possible level changes on this BSP - CBaseEntity *pChangelevel = UTIL_FindEntityByClassname( NULL, "trigger_changelevel" ); - - if( !pChangelevel ) return 0; - - while ( pChangelevel ) - { - // find the corresponding landmark - pentLandmark = UTIL_FindLandmark( pChangelevel->pev->message ); - if( pentLandmark ) - { - // build a list of unique transitions - ALERT( at_aiconsole, "Map name %s, landmark name %s\n", STRING( pChangelevel->pev->netname ), STRING( pChangelevel->pev->message )); - if( AddTransitionToList( pLevelList, count, STRING( pChangelevel->pev->netname ), STRING( pChangelevel->pev->message ), pentLandmark )) - { - count++; - if( count >= maxList ) break; // list is FULL!!! - } - } - else - { - // build a list of unique transitions (direct mode, when landmark not used) - ALERT( at_aiconsole, "Map name %s\n", STRING( pChangelevel->pev->netname )); - if( AddTransitionToList( pLevelList, count, STRING( pChangelevel->pev->netname ), "", NULL )) - { - count++; - if( count >= maxList ) break; // list is FULL!!! - } - } - pChangelevel = UTIL_FindEntityByClassname( pChangelevel, "trigger_changelevel" ); - } - - if( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) - { - CSave saveHelper( (SAVERESTOREDATA *)gpGlobals->pSaveData ); - - for ( i = 0; i < count; i++ ) - { - int entityCount = 0; - CBaseEntity *pEntList[MAX_TRANSITION_ENTITY]; - int entityFlags[MAX_TRANSITION_ENTITY]; - - // Follow the linked list of entities in the PVS of the transition landmark - edict_t *pent = UTIL_EntitiesInPVS( pLevelList[i].pentLandmark ); - - if( FNullEnt( pent )) - { - // landmark is absent so use Classic Changelel: - // transfer client and him attached items - pent = UTIL_FindClientTransitions( INDEXENT( 1 )); - } - - // Build a list of valid entities in this linked list (we're going to use pent->v.chain again) - while ( !FNullEnt( pent )) - { - CBaseEntity *pEntity = CBaseEntity::Instance(pent); - if( pEntity ) - { - int caps = pEntity->ObjectCaps(); - - if(!( caps & FCAP_DONT_SAVE )) - { - int flags = 0; - - if( caps & FCAP_ACROSS_TRANSITION ) flags |= FENTTABLE_MOVEABLE; - if( pEntity->pev->globalname && !pEntity->IsDormant() ) flags |= FENTTABLE_GLOBAL; - if( flags ) - { - pEntList[entityCount] = pEntity; - entityFlags[entityCount] = flags; - entityCount++; - if( entityCount >= MAX_TRANSITION_ENTITY ) - { - ALERT( at_error, "Too many entities across a transition!" ); - break; - } - } - } - } - pent = pent->v.chain; - } - - for ( int j = 0; j < entityCount; j++ ) - { - // Check to make sure the entity isn't screened out by a trigger_transition - if( entityFlags[j] && UTIL_FindTransition( pEntList[j], pLevelList[i].landmarkName )) - { - // Mark entity table with 1< gpGlobals->time ) return; - if( plr && !plr->m_fInitHUD && !gInitHUD ) - { - for ( int i = 0; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if( pEdict->free ) continue; - pClass = CBaseEntity::Instance( pEdict ); - if( pClass && !( pClass->pev->flags & FL_DORMANT )) - { - pClass->PostActivate(); - } - } - MSGSended = TRUE;//messages sucessfully sended - } -} - -// -// GLOBALS ASSUMED SET: g_ulFrameCount -// -void StartFrame( void ) -{ - // Msg(" frametime %g\n", gpGlobals->frametime ); - if ( g_pGameRules )g_pGameRules->Think(); - if ( g_fGameOver ) return; - - gpGlobals->teamplay = (CVAR_GET_FLOAT( "mp_teamplay" ) == 1.0f) ? TRUE : FALSE; - g_ulFrameCount++; - - if( sv_maxspeed->modified ) - { - char msg[64]; - - // maxspeed is modified, refresh maxspeed for each client - for( int i = 0; i < gpGlobals->maxClients; i++ ) - { - edict_t *pClientEdict = INDEXENT( i + 1 ); - - if( pClientEdict == NULL || pClientEdict->free ) - continue; - - // can update even if client it's not active - g_engfuncs.pfnSetClientMaxspeed( pClientEdict, sv_maxspeed->value ); - } - - sprintf( msg, "sv_maxspeed is changed to %g\n", sv_maxspeed->value ); - g_engfuncs.pfnServerPrint( msg ); - sv_maxspeed->modified = false; - } - - ServerPostActivate(); // called once - PhysicsFrame(); -} - -void EndFrame( void ) -{ -} - -/* -================ -SpectatorConnect - -A spectator has joined the game -================ -*/ -void SpectatorConnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); - - if( pPlayer ) pPlayer->SpectatorConnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has left the game -================ -*/ -void SpectatorDisconnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); - - if( pPlayer ) pPlayer->SpectatorDisconnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has sent a usercmd -================ -*/ -void SpectatorThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); - - if( pPlayer ) pPlayer->SpectatorThink( ); -} - -// FIXME: implement VirtualClass GetClass instead -int AutoClassify( edict_t *pentToClassify ) -{ - CBaseEntity *pClass; - - pClass = CBaseEntity::Instance( pentToClassify ); - if( !pClass ) return ED_SPAWNED; - - const char *classname = STRING( pClass->pev->classname ); - - if ( !strnicmp( "worldspawn", classname, 10 )) - { - return ED_WORLDSPAWN; - } - - if ( !strnicmp( "bodyque", classname, 7 )) - { - return ED_NORMAL; - } - - // first pass: determine type by explicit parms - if ( pClass->pev->solid == SOLID_TRIGGER ) - { - if ( FClassnameIs( pClass->pev, "ambient_generic" ) || FClassnameIs( pClass->pev, "target_speaker" )) // FIXME - { - pClass->pev->flags |= FL_PHS_FILTER; - return ED_AMBIENT; - } - else if( pClass->pev->movetype == MOVETYPE_TOSS ) - return ED_NORMAL; // it's item or weapon - if ( FBitSet( pClass->pev->effects, EF_NODRAW )) - return ED_TRIGGER; // never sending to client - return ED_NORMAL; // e.g. friction modifier - } - else if ( pClass->pev->movetype == MOVETYPE_PHYSIC ) - return ED_RIGIDBODY; - else if ( pClass->pev->solid == SOLID_BSP ) - { - if ( pClass->pev->flags & FL_CONVEYOR ) - return ED_MOVER; - else if ( pClass->pev->flags & FL_WORLDBRUSH ) - return ED_BSPBRUSH; - else if ( pClass->pev->movetype == MOVETYPE_PUSH ) - return ED_MOVER; - else if ( pClass->pev->movetype == MOVETYPE_NONE ) - return ED_BSPBRUSH; - } - else if ( pClass->pev->flags & FL_MONSTER ) - return ED_MONSTER; - else if ( pClass->pev->flags & FL_CLIENT ) - return ED_CLIENT; - else if ( pClass->pev->flags & FL_CONVEYOR ) - return ED_MOVER; - else if ( !pClass->pev->modelindex && !pClass->pev->aiment ) - { - if ( pClass->pev->noise || pClass->pev->noise1 || pClass->pev->noise2 || pClass->pev->noise3 ) - { - pClass->pev->flags |= FL_PHS_FILTER; - return ED_AMBIENT; - } - return ED_STATIC; // never sending to client - } - - // mark as normal - if ( pClass->pev->modelindex || pClass->pev->noise ) - return ED_NORMAL; - - // fail to classify :-( - return ED_SPAWNED; -} - -int ServerClassifyEdict( edict_t *pentToClassify ) -{ - // NOTE: we can't use FNullEnt here to handle 'worldspawn' properly - // but must skip clients because they not spawned at this point - if( !pentToClassify || pentToClassify->free || !pentToClassify->pvPrivateData ) - return ED_SPAWNED; - - CBaseEntity *pClass; - - pClass = CBaseEntity::Instance( pentToClassify ); - if( !pClass ) return ED_SPAWNED; - - // user-defined - if( pClass->m_iClassType != ED_SPAWNED ) - return pClass->m_iClassType; - - int m_iNewClass = AutoClassify( pentToClassify ); - - if( m_iNewClass != ED_SPAWNED ) - { - // tell server.dll about new class - pClass->SetObjectClass( m_iNewClass ); - } - - return m_iNewClass; -} - -/* -================= -CmdStart - -We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc. -This is the time to examine the usercmd for anything extra. This call happens even if think does not. -================= -*/ -void CmdStart( const edict_t *player, const usercmd_t *cmd, unsigned int random_seed ) -{ - entvars_t *pev = (entvars_t *)&player->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - - if ( !pl ) - return; - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); - } - - pl->random_seed = random_seed; -} - -/* -================= -CmdEnd - -Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here -================= -*/ -void CmdEnd( const edict_t *player ) -{ - entvars_t *pev = (entvars_t *)&player->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - - if ( !pl ) - return; - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_UnsetGroupTrace(); - } -} - -void ClientPrecache( void ) -{ - // Material System!!! move this in next versions - PRECACHE_SOUND("player/pl_step1.wav"); // walk on concrete - PRECACHE_SOUND("player/pl_step2.wav"); - PRECACHE_SOUND("player/pl_step3.wav"); - PRECACHE_SOUND("player/pl_step4.wav"); - - PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete - PRECACHE_SOUND("common/npc_step2.wav"); - PRECACHE_SOUND("common/npc_step3.wav"); - PRECACHE_SOUND("common/npc_step4.wav"); - - PRECACHE_SOUND("player/pl_metal1.wav"); // walk on metal - PRECACHE_SOUND("player/pl_metal2.wav"); - PRECACHE_SOUND("player/pl_metal3.wav"); - PRECACHE_SOUND("player/pl_metal4.wav"); - - PRECACHE_SOUND("player/pl_dirt1.wav"); // walk on dirt - PRECACHE_SOUND("player/pl_dirt2.wav"); - PRECACHE_SOUND("player/pl_dirt3.wav"); - PRECACHE_SOUND("player/pl_dirt4.wav"); - - PRECACHE_SOUND("player/pl_duct1.wav"); // walk in duct - PRECACHE_SOUND("player/pl_duct2.wav"); - PRECACHE_SOUND("player/pl_duct3.wav"); - PRECACHE_SOUND("player/pl_duct4.wav"); - - PRECACHE_SOUND("player/pl_grate1.wav"); // walk on grate - PRECACHE_SOUND("player/pl_grate2.wav"); - PRECACHE_SOUND("player/pl_grate3.wav"); - PRECACHE_SOUND("player/pl_grate4.wav"); - - PRECACHE_SOUND("player/pl_slosh1.wav"); // walk in shallow water - PRECACHE_SOUND("player/pl_slosh2.wav"); - PRECACHE_SOUND("player/pl_slosh3.wav"); - PRECACHE_SOUND("player/pl_slosh4.wav"); - - PRECACHE_SOUND("player/pl_tile1.wav"); // walk on tile - PRECACHE_SOUND("player/pl_tile2.wav"); - PRECACHE_SOUND("player/pl_tile3.wav"); - PRECACHE_SOUND("player/pl_tile4.wav"); - PRECACHE_SOUND("player/pl_tile5.wav"); - - PRECACHE_SOUND("player/pl_swim1.wav"); // breathe bubbles - PRECACHE_SOUND("player/pl_swim2.wav"); - PRECACHE_SOUND("player/pl_swim3.wav"); - PRECACHE_SOUND("player/pl_swim4.wav"); - - PRECACHE_SOUND("player/pl_ladder1.wav"); // climb ladder rung - PRECACHE_SOUND("player/pl_ladder2.wav"); - PRECACHE_SOUND("player/pl_ladder3.wav"); - PRECACHE_SOUND("player/pl_ladder4.wav"); - - PRECACHE_SOUND("player/pl_wade1.wav"); // wade in water - PRECACHE_SOUND("player/pl_wade2.wav"); - PRECACHE_SOUND("player/pl_wade3.wav"); - PRECACHE_SOUND("player/pl_wade4.wav"); -} - -/* -=============== -GetGameDescription - -Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2 -=============== -*/ -const char *GetGameDescription( void ) -{ - char *token = NULL; - char szbuffer[128]; - char *afile = (char *)LOAD_FILE( "gameinfo.txt", NULL ); - const char *pfile = afile; - - memset( text, 0, sizeof( text )); - - if( pfile ) - { - token = COM_ParseToken( &pfile ); - - while( token ) - { - if( !stricmp( token, "title" )) - { - token = COM_ParseToken( &pfile ); - sprintf( szbuffer, "%s ", token ); - strncat( text, szbuffer, sizeof( text )); - } - else if( !stricmp( token, "version" )) - { - token = COM_ParseToken( &pfile ); - strncat( text, token, sizeof( text )); - } - token = COM_ParseToken( &pfile ); - } - - COM_FreeFile( afile ); - return text; - } - return "Xash3D"; -} - -//////////////////////////////////////////////////////// -// PAS and PVS routines for client messaging -// - -/* -================ -SetupVisibility - -A client can have a separate "view entity" indicating that his/her view should depend on the origin of that -view entity. If that's the case, then pViewEntity will be non-NULL and will be used. Otherwise, the current -entity's origin is used. Either is offset by the view_ofs to get the eye position. - -From the eye position, we set up the PAS and PVS to use for filtering network messages to the client. At this point, we could - override the actual PAS or PVS values, or use a different origin. - -NOTE: Do not cache the values of pas and pvs, as they depend on reusable memory in the engine, they are only good for this one frame -================ -*/ -void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, byte **pvs, byte **pas, int portal ) -{ - Vector org = g_vecZero; - edict_t *pView = pClient; - - if( portal ) - { - // Entity's added from portal camera PVS - if( FNullEnt( pViewEntity )) return; // broken portal ? - - CBaseEntity *pCamera = (CBaseEntity *)CBaseEntity::Instance( pViewEntity ); - - if( !pCamera ) return; - - // determine visible point - if( pCamera->m_iClassType == ED_PORTAL ) - { - // don't build visibility for mirrors - if( pCamera->pev->origin == pCamera->pev->oldorigin ) - return; - else org = pCamera->pev->oldorigin; - } - else if( pCamera->m_iClassType == ED_SKYPORTAL ) - { - org = pCamera->pev->origin; - } - else return; // other edicts can't merge pvs - } - else - { - // calc point view from client eyes or client camera's - if( FNullEnt( pClient )) HOST_ERROR( "SetupVisibility: client == NULL\n" ); - if( !FNullEnt( pViewEntity )) pView = pViewEntity; - - if( pClient->v.flags & FL_PROXY ) - { - *pvs = NULL; // the spectator proxy sees - *pas = NULL; // and hears everything - return; - } - - CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); - - if( pPlayer && pPlayer->viewFlags & 1 ) - { - CBaseEntity *pViewEnt = pPlayer->pViewEnt; - if( pPlayer->pViewEnt->edict( )) - pView = pViewEnt->edict(); - } - // NOTE: view offset always contains actual viewheight (set it in PM_Move) - org = pView->v.origin + pView->v.view_ofs; - } - - *pvs = ENGINE_SET_PVS( (float *)&org, portal ); - *pas = ENGINE_SET_PAS( (float *)&org, portal ); -} - -/* -AddToFullPack - -Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise - -state is the server maintained copy of the state info that is transmitted to the client -a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc. -e and ent are the entity that is being added to the update, if 1 is returned -host is the player's edict of the player whom we are sending the update to -player is 1 if the ent/e is a player and 0 otherwise -pSet is either the PAS or PVS that we previous set up. We can use it to ask the engine to filter the entity against the PAS or PVS. -we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. Caching the value is valid in that case, but still only for the current frame -*/ -int AddToFullPack( entity_state_t *state, edict_t *pView, edict_t *pHost, edict_t *pEdict, int hostflags, byte *pSet ) -{ - CBaseEntity *pEntity; - Vector delta; // for ambient sounds - - if( FNullEnt( pEdict )) - return 0; // never adding invalid entities - - if( FNullEnt( pView )) pView = pHost; // pfnCustomView not set - - CBaseEntity *pViewEntity = (CBaseEntity *)CBaseEntity::Instance( pView ); - - BOOL bIsPortalPass = FALSE; - - if( pViewEntity && pViewEntity->m_iClassType == ED_PORTAL ) - bIsPortalPass = TRUE; // view from portal camera - - pEntity = (CBaseEntity *)CBaseEntity::Instance( pEdict ); - - if( !pEntity ) return 0; - - // NOTE: always add himslef to list - if( !bIsPortalPass && ( pHost == pEdict )) - goto addEntity; - - // completely ignore dormant entity - if( pEdict->v.flags & FL_DORMANT ) - return 0; - - // don't send spectators to other players - if(( pEdict->v.flags & FL_SPECTATOR ) && ( pEdict != pHost )) - { - return 0; - } - - // quick reject by type - switch( pEntity->m_iClassType ) - { - case ED_SKYPORTAL: - goto addEntity; // no additional check requires - case ED_BEAM: - case ED_MOVER: - case ED_NORMAL: - case ED_PORTAL: - case ED_CLIENT: - case ED_MONSTER: - case ED_AMBIENT: - case ED_BSPBRUSH: - case ED_RIGIDBODY: break; - default: return 0; // skipped - } - - // check for ambients distance - if( pEntity->m_iClassType == ED_AMBIENT ) - { - Vector entorigin; - - // don't send sounds if they will be attenuated away - if( pEntity->pev->origin == g_vecZero ) - entorigin = (pEntity->pev->mins + pEntity->pev->maxs) * 0.5f; - else entorigin = pEntity->pev->origin; - - // precalc delta distance for sounds - delta = pView->v.origin - entorigin; - } - else delta = g_vecZero; - - // check visibility - if ( !ENGINE_CHECK_PVS( pEdict, pSet )) - { - float m_flRadius = 1024; // g-cont: tune distance by taste :) - - if ( pEntity->pev->flags & FL_PHS_FILTER ) - { - if( pEntity->pev->armorvalue > 0 ) - m_flRadius = pEntity->pev->armorvalue; - - if( delta.Length() > m_flRadius ) - return 0; - } - else //if( pEntity->m_iClassType != ED_BEAM ) - { - return 0; - } - } - - if( FNullEnt( pHost )) HOST_ERROR( "pHost == NULL\n" ); - - // don't send entity to local client if the client says it's predicting the entity itself. - if( pEntity->pev->flags & FL_SKIPLOCALHOST ) - { - if( bIsPortalPass ) return 0; - if(( hostflags & 1 ) && ( pEntity->pev->owner == pHost )) - return 0; - } - - if( !pEntity->pev->modelindex || FStringNull( pEntity->pev->model )) - { - // can't ignore ents withouts models, because portals and mirrors can't working otherwise - // and null.mdl it's no more needs to be set: ED_CLASS rejection is working fine - // so we wan't reject this entities here. - } - - if( pHost->v.groupinfo ) - { - UTIL_SetGroupTrace( pHost->v.groupinfo, GROUP_OP_AND ); - - // should always be set, of course - if( pEdict->v.groupinfo ) - { - if( g_groupop == GROUP_OP_AND ) - { - if(!( pEdict->v.groupinfo & pHost->v.groupinfo )) - return 0; - } - else if( g_groupop == GROUP_OP_NAND ) - { - if( pEdict->v.groupinfo & pHost->v.groupinfo ) - return 0; - } - } - UTIL_UnsetGroupTrace(); - } - -addEntity: - - // setup some special edict flags (engine will clearing them after the current frame) - if( state->modelindex != pEntity->pev->modelindex || ( pEntity->pev->effects & EF_NOINTERP )) - state->ed_flags |= ESF_NODELTA; - - // always keep an actual - state->number = pEdict->serialnumber; - - // copy progs values to state - state->solid = (solid_t)pEntity->pev->solid; - - state->modelindex = pEntity->pev->modelindex; - state->origin = pEntity->pev->origin; - state->angles = pEntity->pev->angles; - state->health = pEntity->pev->health; - state->skin = pEntity->pev->skin; // studio model skin - state->body = pEntity->pev->body; // studio model submodel - state->effects = pEntity->pev->effects; // shared client and render flags - state->renderfx = pEntity->pev->renderfx; // renderer flags - state->rendermode = pEntity->pev->rendermode; // rendering mode - state->renderamt = pEntity->pev->renderamt; // alpha value - state->animtime = (int)(1000.0 * pEntity->pev->animtime) * 0.001; // sequence time - state->localtime = (int)(1000.0 * pEntity->pev->ltime) * 0.001; // movement time - state->scale = pEntity->pev->scale; // shared client and render flags - state->movetype = (movetype_t)pEntity->pev->movetype; - state->frame = pEntity->pev->frame; // any model current frame - state->framerate = pEntity->pev->framerate; - state->mins = pEntity->pev->mins; - state->maxs = pEntity->pev->maxs; - state->flags = pEntity->pev->flags; - state->rendercolor = pEntity->pev->rendercolor; - state->oldorigin = pEntity->pev->oldorigin; - state->colormap = pEntity->pev->colormap; // attachments - - if( pEntity->pev->groundentity ) - state->groundent = ENTINDEX( pEntity->pev->groundentity ); - else state->groundent = -1; - - // translate attached entity - if( pEntity->pev->aiment ) - state->aiment = ENTINDEX( pEntity->pev->aiment ); - else state->aiment = -1; - - // studio model sequence - if( pEntity->pev->sequence != -1 ) - state->sequence = pEntity->pev->sequence; - - for( int i = 0; i < 16; i++ ) - { - // copy blendings and bone ctrlrs - state->blending[i] = pEntity->pev->blending[i]; - state->controller[i] = pEntity->pev->controller[i]; - } - - if( state->ed_type == ED_CLIENT ) - { - if( pEntity->pev->teleport_time ) - { - state->ed_flags |= ESF_NO_PREDICTION; - state->ed_flags |= ESF_NODELTA; - pEntity->pev->teleport_time = 0.0f; - } - - if( pEntity->pev->viewmodel ) - state->viewmodel = MODEL_INDEX( STRING( pEntity->pev->viewmodel )); - else state->viewmodel = 0; - - if( pEntity->pev->aiment ) - state->aiment = ENTINDEX( pEntity->pev->aiment ); - else state->aiment = -1; - - state->viewoffset = pEntity->pev->view_ofs; - state->viewangles = pEntity->pev->v_angle; - state->idealpitch = pEntity->pev->idealpitch; - state->punch_angles = pEntity->pev->punchangle; - state->velocity = pEntity->pev->velocity; - state->basevelocity = pEntity->pev->clbasevelocity; - state->iStepLeft = pEntity->pev->iStepLeft; - state->flFallVelocity = pEntity->pev->flFallVelocity; - - // playermodel sequence, that will be playing on a client - if( pEntity->pev->gaitsequence != -1 ) - state->gaitsequence = pEntity->pev->gaitsequence; - if( pEntity->pev->weaponmodel != iStringNull ) - state->weaponmodel = MODEL_INDEX( STRING( pEntity->pev->weaponmodel )); - else state->weaponmodel = 0; - state->weapons = pEntity->pev->weapons; - state->maxspeed = pEntity->pev->maxspeed; - - // clamp fov - if( pEntity->pev->fov < 0.0 ) pEntity->pev->fov = 0.0; - if( pEntity->pev->fov > 160 ) pEntity->pev->fov = 160; - state->fov = pEntity->pev->fov; - } - else if( state->ed_type == ED_AMBIENT ) - { - // add here specified fields e.g for trigger_teleport wind sound etc - } - else if( state->ed_type == ED_MOVER || state->ed_type == ED_BSPBRUSH || state->ed_type == ED_PORTAL ) - { - state->body = DirToBits( pEntity->pev->movedir ); - state->velocity = pEntity->pev->velocity; - - // this is conveyor - send speed to render for right texture scrolling - state->framerate = pEntity->pev->speed; - } - else if( state->ed_type == ED_BEAM ) - { - state->gaitsequence = pEntity->pev->frags; // beam type - - // translate StartBeamEntity - if( pEntity->pev->owner ) - state->owner = ENTINDEX( pEntity->pev->owner ); - else state->owner = -1; - } - - return 1; -} - -/* -================= -UpdateClientData - -Data sent to current client only -engine sets cd to 0 before calling. -================= -*/ -void UpdateClientData( const edict_t *ent, int sendweapons, clientdata_t *cd ) -{ - cd->flags = ent->v.flags; - cd->health = ent->v.health; - - cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); - - cd->waterlevel = ent->v.waterlevel; - cd->watertype = ent->v.watertype; - cd->weapons = ent->v.weapons; - - // Vectors - cd->origin = ent->v.origin; - cd->velocity = ent->v.velocity; - cd->view_ofs = ent->v.view_ofs; - cd->punchangle = ent->v.punchangle; - - cd->bInDuck = ent->v.bInDuck; - cd->flTimeStepSound = ent->v.flTimeStepSound; - cd->flDuckTime = ent->v.flDuckTime; - cd->flSwimTime = ent->v.flSwimTime; - cd->waterjumptime = ent->v.teleport_time; - - strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); - - cd->maxspeed = ent->v.maxspeed; - cd->fov = ent->v.fov; - cd->weaponanim = ent->v.weaponanim; - - cd->pushmsec = ent->v.pushmsec; -} - -void CreateBaseline( entity_state_t *baseline, edict_t *entity, int playermodelindex ) -{ - // always set nodelta's for baseline - baseline->ed_flags |= ESF_NODELTA; - - baseline->origin = entity->v.origin; - baseline->angles = entity->v.angles; - baseline->frame = entity->v.frame; - baseline->skin = (short)entity->v.skin; - - // render information - baseline->rendermode = (byte)entity->v.rendermode; - baseline->renderamt = (byte)entity->v.renderamt; - baseline->rendercolor.x = (byte)entity->v.rendercolor.x; - baseline->rendercolor.y = (byte)entity->v.rendercolor.y; - baseline->rendercolor.z = (byte)entity->v.rendercolor.z; - baseline->renderfx = (byte)entity->v.renderfx; - - baseline->mins = entity->v.mins; - baseline->maxs = entity->v.maxs; - - if( baseline->ed_type == ED_CLIENT ) - { - baseline->colormap = entity->serialnumber; - baseline->modelindex = playermodelindex; // "model" field from userinfo - baseline->friction = 1.0; - baseline->movetype = MOVETYPE_WALK; - - baseline->scale = entity->v.scale; - baseline->solid = SOLID_SLIDEBOX; - baseline->framerate = 1.0; - baseline->gravity = 1.0; - - } - else - { - baseline->colormap = 0; - baseline->modelindex = entity->v.modelindex; - baseline->movetype = (movetype_t)entity->v.movetype; - - baseline->scale = entity->v.scale; - baseline->solid = (solid_t)entity->v.solid; - baseline->framerate = entity->v.framerate; - baseline->gravity = entity->v.gravity; - } -} - -typedef struct -{ - char name[32]; - int field; -} entity_field_alias_t; - -#define FIELD_ORIGIN0 0 -#define FIELD_ORIGIN1 1 -#define FIELD_ORIGIN2 2 -#define FIELD_ANGLES0 3 -#define FIELD_ANGLES1 4 -#define FIELD_ANGLES2 5 - -static entity_field_alias_t entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, -}; - -void Entity_FieldInit( struct delta_s *pFields ) -{ - entity_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN0 ].name ); - entity_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN1 ].name ); - entity_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN2 ].name ); - entity_field_alias[ FIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES0 ].name ); - entity_field_alias[ FIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES1 ].name ); - entity_field_alias[ FIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES2 ].name ); -} - -/* -================== -Entity_Encode - -Callback for sending entity_state_t info over network. -FIXME: Move to script -================== -*/ -void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -static entity_field_alias_t player_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, -}; - -void Player_FieldInit( struct delta_s *pFields ) -{ - player_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN0 ].name ); - player_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN1 ].name ); - player_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN2 ].name ); -} - -/* -================== -Player_Encode - -Callback for sending entity_state_t for players info over network. -================== -*/ -void Player_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Player_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -#define CUSTOMFIELD_ORIGIN0 0 -#define CUSTOMFIELD_ORIGIN1 1 -#define CUSTOMFIELD_ORIGIN2 2 -#define CUSTOMFIELD_ANGLES0 3 -#define CUSTOMFIELD_ANGLES1 4 -#define CUSTOMFIELD_ANGLES2 5 -#define CUSTOMFIELD_SKIN 6 -#define CUSTOMFIELD_SEQUENCE 7 -#define CUSTOMFIELD_ANIMTIME 8 - -entity_field_alias_t custom_entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, - { "skin", 0 }, - { "sequence", 0 }, - { "animtime", 0 }, -}; - -void Custom_Entity_FieldInit( struct delta_s *pFields ) -{ - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].name ); -} - -/* -================== -Custom_Encode - -Callback for sending entity_state_t info ( for custom entities ) over network. -FIXME: Move to script -================== -*/ -void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int beamType; - static int initialized = 0; - - if ( !initialized ) - { - Custom_Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - beamType = t->rendermode; - - if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field ); - } - - if ( beamType != BEAM_POINTS ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field ); - } - - if ( beamType != BEAM_ENTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field ); - } - - // animtime is compared by rounding first - // see if we really shouldn't actually send it - if ( (int)f->animtime == (int)t->animtime ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); - } -} - -/* -================= -RegisterEncoders - -Allows game .dll to override network encoding of certain types of entities and tweak values, etc. - -disabled for now, wait for Xash 0.8 -================= -*/ -void RegisterEncoders( void ) -{ - DELTA_ADDENCODER( "Entity_Encode", Entity_Encode ); - DELTA_ADDENCODER( "Custom_Encode", Custom_Encode ); - DELTA_ADDENCODER( "Player_Encode", Player_Encode ); -} - -/* -================= -GetWeaponData - -Part of weapon predict system - -disabled for now, wait for Xash 0.8 -================= -*/ -int GetWeaponData( struct edict_s *player, weapon_data_t *info ) -{ - memset( info, 0, 32 * sizeof( weapon_data_t )); - return 1; -} - -//======================================================================= -// Link User Messages - register new client messages here -//======================================================================= -void LinkUserMessages( void ) -{ - // already taken care of? - if( gmsg.SelAmmo ) return; - - memset( &gmsg, 0, sizeof( gmsg )); - - //messages affect only player - gmsg.SelAmmo = REG_USER_MSG("SelAmmo", sizeof(SelAmmo)); - gmsg.Intermission = REG_USER_MSG( "Intermission", 0 ); - gmsg.CurWeapon = REG_USER_MSG("CurWeapon", 3); - gmsg.GeigerRange = REG_USER_MSG("Geiger", 1); - gmsg.Flashlight = REG_USER_MSG("Flashlight", 2); - gmsg.FlashBattery = REG_USER_MSG("FlashBat", 1); - gmsg.Health = REG_USER_MSG( "Health", 1 ); - gmsg.Damage = REG_USER_MSG( "Damage", 18 ); - gmsg.Battery = REG_USER_MSG( "Battery", 2); - gmsg.Train = REG_USER_MSG( "Train", 1); - gmsg.SayText = REG_USER_MSG( "SayText", -1 ); - gmsg.TextMsg = REG_USER_MSG( "TextMsg", -1 ); - gmsg.WeaponList = REG_USER_MSG("WeaponList", -1); - gmsg.ResetHUD = REG_USER_MSG("ResetHUD", 1); - gmsg.InitHUD = REG_USER_MSG("InitHUD", 0 ); - gmsg.HUDColor = REG_USER_MSG( "HUDColor", 4 ); - gmsg.DeathMsg = REG_USER_MSG( "DeathMsg", -1 ); - gmsg.ScoreInfo = REG_USER_MSG( "ScoreInfo", 9 ); - gmsg.TeamInfo = REG_USER_MSG( "TeamInfo", -1 ); - gmsg.TeamScore = REG_USER_MSG( "TeamScore", -1 ); - gmsg.GameMode = REG_USER_MSG( "GameMode", 1 ); - gmsg.MOTD = REG_USER_MSG( "MOTD", -1 ); - gmsg.ServerName = REG_USER_MSG( "ServerName", -1 ); - gmsg.AmmoPickup = REG_USER_MSG( "AmmoPickup", 2 ); - gmsg.WeapPickup = REG_USER_MSG( "WeapPickup", 1 ); - gmsg.ItemPickup = REG_USER_MSG( "ItemPickup", -1 ); - gmsg.RoomType = REG_USER_MSG( "RoomType", 1 ); - gmsg.HideWeapon = REG_USER_MSG( "HideWeapon", 1 ); - gmsg.WeaponAnim = REG_USER_MSG( "WeaponAnim", 3 ); - gmsg.ShowMenu = REG_USER_MSG( "ShowMenu", -1 ); - gmsg.Shake = REG_USER_MSG( "ScreenShake", sizeof( ScreenShake )); - gmsg.Fade = REG_USER_MSG( "ScreenFade", sizeof( ScreenFade )); - gmsg.AmmoX = REG_USER_MSG( "AmmoX", 2 ); - gmsg.TeamNames = REG_USER_MSG( "TeamNames", -1 ); - gmsg.StatusText = REG_USER_MSG( "StatusText", -1 ); - gmsg.StatusValue = REG_USER_MSG( "StatusValue", 3 ); - gmsg.SetBody = REG_USER_MSG( "SetBody", 1 ); - gmsg.SetSkin = REG_USER_MSG( "SetSkin", 1 ); - gmsg.ZoomHUD = REG_USER_MSG( "ZoomHUD", 1 ); - gmsg.WarHUD = REG_USER_MSG( "WarHUD", 1 ); - - // entity messages - gmsg.StatusIcon = REG_USER_MSG("StatusIcon", -1); - gmsg.CamData = REG_USER_MSG("CamData", -1); - gmsg.Fsound = REG_USER_MSG("Fsound", -1); - gmsg.RainData = REG_USER_MSG( "RainData", 28 ); - gmsg.HudText = REG_USER_MSG( "HudText", -1 ); - gmsg.ShowGameTitle = REG_USER_MSG("GameTitle", 0 ); - gmsg.TempEntity = REG_USER_MSG( "TempEntity", -1); - gmsg.SetFog = REG_USER_MSG("SetFog", 7 ); - gmsg.SetSky = REG_USER_MSG( "SetSky", 13 ); - gmsg.Particle = REG_USER_MSG( "Particle", -1); -} - -/* -================================ -ShouldCollide - - Called when the engine believes two entities are about to collide. Return 0 if you - want the two entities to just pass through each other without colliding or calling the - touch function. -================================ -*/ -int ShouldCollide( edict_t *pentTouched, edict_t *pentOther ) -{ - return 1; -} - -/* -================ -InitWorld - -Called ever time when worldspawn will precached -================ -*/ -void InitWorld( void ) -{ - int i; - - CVAR_SET_STRING( "sv_gravity", "800" ); // 67ft/sec - CVAR_SET_STRING( "sv_stepsize", "18" ); - CVAR_SET_STRING( "room_type", "0" ); // clear DSP - - g_pLastSpawn = NULL; - - // Set up game rules - if (g_pGameRules) delete g_pGameRules; - g_pGameRules = InstallGameRules( ); - - if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet ) - { - if ( !WorldGraph.FSetGraphPointers( )) - ALERT( at_error, "Graph pointers were not set!\n" ); - else ALERT( at_console, "**Graph Pointers Set!\n" ); - } - - UTIL_PrecacheResourse(); //precache all resource - - pSoundEnt = GetClassPtr(( CSoundEnt *)NULL ); - pSoundEnt->Spawn(); - - if( FNullEnt( pSoundEnt )) - ALERT( at_error, "couldn create soundent!\n" ); - - InitBodyQue(); - - SENTENCEG_Init(); - TEXTURETYPE_Init(); - - MSGSended = FALSE; - if( IsMultiplayer( )) - MsgDelay = 0.5 + gpGlobals->time; - else MsgDelay = 0.03 + gpGlobals->time; - - ClientPrecache(); - - // Setup light animation tables. 'a' is total darkness, 'z' is maxbright. - for( i = 0; i <= 13; i++ ) - LIGHT_STYLE( i, STRING( GetStdLightStyle( i ))); - - for( i = 0; i < DECAL_COUNT; i++ ) - gDecals[i].index = DECAL_INDEX( gDecals[i].name ); - - // init the WorldGraph. - WorldGraph.InitGraph(); - - if( !WorldGraph.CheckNODFile( STRING( gpGlobals->mapname ))) - { - WorldGraph.AllocNodes(); - } - else - { - if( !WorldGraph.FLoadGraph( STRING( gpGlobals->mapname ))) - WorldGraph.AllocNodes(); - else ALERT( at_console, "\n*Graph Loaded!\n" ); - } - - CVAR_SET_FLOAT( "sv_zmax", 0 ); // let the renderer calculate optimal value -} \ No newline at end of file diff --git a/server/global/client.h b/server/global/client.h deleted file mode 100644 index 33ac7887..00000000 --- a/server/global/client.h +++ /dev/null @@ -1,115 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef CLIENT_H -#define CLIENT_H - -extern void PhysicsPreFrame( void ); -extern void PhysicsFrame( void ); -extern void PhysicsPostFrame( void ); - -extern void respawn( entvars_t* pev, BOOL fCopyCorpse ); -extern BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ); -extern void ClientDisconnect( edict_t *pEntity ); -extern void ClientKill( edict_t *pEntity ); -extern void ClientPutInServer( edict_t *pEntity ); -extern void ClientCommand( edict_t *pEntity ); -extern void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ); -extern void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ); -extern void ServerDeactivate( void ); -extern void StartFrame( void ); -extern void RegisterEncoders( void ); -extern void PlayerPostThink( edict_t *pEntity ); -extern void PlayerPreThink( edict_t *pEntity ); -extern void BuildLevelList( void ); -extern void InitBodyQue(void); -extern void InitWorld( void ); - -extern const char *GetGameDescription( void ); -extern void SpectatorConnect ( edict_t *pEntity ); -extern void SpectatorDisconnect ( edict_t *pEntity ); -extern void SpectatorThink ( edict_t *pEntity ); - -extern void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, byte **pvs, byte **pas, int portal ); -extern void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); -extern int AddToFullPack( entity_state_t *state, edict_t *pView, edict_t *pHost, edict_t *pEdict, int hostflags, byte *pSet ); -extern void CreateBaseline( entity_state_t *baseline, edict_t *entity, int playermodelindex ); -extern int GetWeaponData( edict_t *player, struct weapon_data_s *info ); - -extern void CmdStart( const edict_t *player, const usercmd_t *cmd, unsigned int random_seed ); -extern void CmdEnd ( const edict_t *player ); - -extern int g_serveractive; - -// messages affect only player -typedef struct user_messages_s -{ - int Shake; - int Fade; - int SelAmmo; - int Intermission; - int Flashlight; - int FlashBattery; - int ResetHUD; - int InitHUD; - int HUDColor; - int CurWeapon; - int Health; - int Damage; - int Battery; - int Train; - int WeaponList; - int AmmoX; - int DeathMsg; - int ScoreInfo; - int TeamInfo; - int TeamScore; - int GameMode; - int MOTD; - int ServerName; - int AmmoPickup; - int WeapPickup; - int ItemPickup; - int HideWeapon; - int WeaponAnim; - int RoomType; - int SayText; - int ShowMenu; - int GeigerRange; - int TeamNames; - int TextMsg; - int StatusText; - int StatusValue; - int SetBody; - int SetSkin; - int ZoomHUD; - int WarHUD; - - // entity messages - int TempEntity; // completely moved from engine to user dlls - int SetFog; - int StatusIcon; - int SetSky; - int Particle; - int Fsound; - int CamData; - int RainData; - int HudText; - int ShowGameTitle; -} user_messages_t; - -extern user_messages_t gmsg; -extern BOOL MSGSended; - -#endif // CLIENT_H \ No newline at end of file diff --git a/server/global/decals.cpp b/server/global/decals.cpp deleted file mode 100644 index dd93ef20..00000000 --- a/server/global/decals.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#include "decals.h" - -DLL_DECALLIST gDecals[] = -{ - { "{shot1", 0 }, // DECAL_GUNSHOT1 - { "{shot2", 0 }, // DECAL_GUNSHOT2 - { "{shot3", 0 }, // DECAL_GUNSHOT3 - { "{shot4", 0 }, // DECAL_GUNSHOT4 - { "{shot5", 0 }, // DECAL_GUNSHOT5 - { "{lambda01", 0 }, // DECAL_LAMBDA1 - { "{lambda02", 0 }, // DECAL_LAMBDA2 - { "{lambda03", 0 }, // DECAL_LAMBDA3 - { "{lambda04", 0 }, // DECAL_LAMBDA4 - { "{lambda05", 0 }, // DECAL_LAMBDA5 - { "{lambda06", 0 }, // DECAL_LAMBDA6 - { "{scorch1", 0 }, // DECAL_SCORCH1 - { "{scorch2", 0 }, // DECAL_SCORCH2 - { "{blood1", 0 }, // DECAL_BLOOD1 - { "{blood2", 0 }, // DECAL_BLOOD2 - { "{blood3", 0 }, // DECAL_BLOOD3 - { "{blood4", 0 }, // DECAL_BLOOD4 - { "{blood5", 0 }, // DECAL_BLOOD5 - { "{blood6", 0 }, // DECAL_BLOOD6 - { "{yblood1", 0 }, // DECAL_YBLOOD1 - { "{yblood2", 0 }, // DECAL_YBLOOD2 - { "{yblood3", 0 }, // DECAL_YBLOOD3 - { "{yblood4", 0 }, // DECAL_YBLOOD4 - { "{yblood5", 0 }, // DECAL_YBLOOD5 - { "{yblood6", 0 }, // DECAL_YBLOOD6 - { "{break1", 0 }, // DECAL_GLASSBREAK1 - { "{break2", 0 }, // DECAL_GLASSBREAK2 - { "{break3", 0 }, // DECAL_GLASSBREAK3 - { "{bigshot1", 0 }, // DECAL_BIGSHOT1 - { "{bigshot2", 0 }, // DECAL_BIGSHOT2 - { "{bigshot3", 0 }, // DECAL_BIGSHOT3 - { "{bigshot4", 0 }, // DECAL_BIGSHOT4 - { "{bigshot5", 0 }, // DECAL_BIGSHOT5 - { "{spit1", 0 }, // DECAL_SPIT1 - { "{spit2", 0 }, // DECAL_SPIT2 - { "{bproof1", 0 }, // DECAL_BPROOF1 - { "{gargstomp", 0 }, // DECAL_GARGSTOMP1, // Gargantua stomp crack - { "{smscorch1", 0 }, // DECAL_SMALLSCORCH1, // Small scorch mark - { "{smscorch2", 0 }, // DECAL_SMALLSCORCH2, // Small scorch mark - { "{smscorch3", 0 }, // DECAL_SMALLSCORCH3, // Small scorch mark - { "{mommablob", 0 }, // DECAL_MOMMABIRTH // BM Birth spray - { "{mommablob", 0 }, // DECAL_MOMMASPLAT // BM Mortar spray?? need decal -}; \ No newline at end of file diff --git a/server/global/decals.h b/server/global/decals.h deleted file mode 100644 index 31442109..00000000 --- a/server/global/decals.h +++ /dev/null @@ -1,63 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= -#ifndef DECALS_H -#define DECALS_H - -enum decal_e -{ - DECAL_GUNSHOT1 = 0, - DECAL_GUNSHOT2, - DECAL_GUNSHOT3, - DECAL_GUNSHOT4, - DECAL_GUNSHOT5, - DECAL_LAMBDA1, - DECAL_LAMBDA2, - DECAL_LAMBDA3, - DECAL_LAMBDA4, - DECAL_LAMBDA5, - DECAL_LAMBDA6, - DECAL_SCORCH1, - DECAL_SCORCH2, - DECAL_BLOOD1, - DECAL_BLOOD2, - DECAL_BLOOD3, - DECAL_BLOOD4, - DECAL_BLOOD5, - DECAL_BLOOD6, - DECAL_YBLOOD1, - DECAL_YBLOOD2, - DECAL_YBLOOD3, - DECAL_YBLOOD4, - DECAL_YBLOOD5, - DECAL_YBLOOD6, - DECAL_GLASSBREAK1, - DECAL_GLASSBREAK2, - DECAL_GLASSBREAK3, - DECAL_BIGSHOT1, - DECAL_BIGSHOT2, - DECAL_BIGSHOT3, - DECAL_BIGSHOT4, - DECAL_BIGSHOT5, - DECAL_SPIT1, - DECAL_SPIT2, - DECAL_BPROOF1, // Bulletproof glass decal - DECAL_GARGSTOMP1, // Gargantua stomp crack - DECAL_SMALLSCORCH1, // Small scorch mark - DECAL_SMALLSCORCH2, // Small scorch mark - DECAL_SMALLSCORCH3, // Small scorch mark - DECAL_MOMMABIRTH, // Big momma birth splatter - DECAL_MOMMASPLAT, - - DECAL_COUNT, //Must be last in the list! -}; - -typedef struct -{ - char *name; - int index; -} DLL_DECALLIST; - -extern DLL_DECALLIST gDecals[]; - -#endif // DECALS_H \ No newline at end of file diff --git a/server/global/defaults.h b/server/global/defaults.h deleted file mode 100644 index fb482496..00000000 --- a/server/global/defaults.h +++ /dev/null @@ -1,441 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// defaults.h - default global settings for max ammo, -// monster's health, e.t.c -//======================================================================= - -#ifndef DEFAULT_H -#define DEFAULT_H - -//name of directory with mod -#define PITCHMIN 30 //min pitch -#define PITCHMAX 100 //max pitch - -#define MAX_AVELOCITY 4096 -#define MAX_VELOCITY 4096 -#define MAX_TRANSITION_ENTITY 512 -#define MAP_MAX_NAME 32 - -#define MAX_ITEM_TYPES 6 //selection slots -#define MAX_ITEMS 5 //item types - -#define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump - -//========================= -// Debug macros -//========================= -#define SHIFT Msg("\n") -#define DEBUGHEAD Msg("======/Xash Debug System/======\nclassname: %s[%i], targetname %s\n", STRING(pev->classname), entindex(), STRING(pev->targetname)) -#define MSGSTATEHEALTH Msg("State: %s, health %g\n", GetStringForState( GetState()), pev->health ) -#define MSGSTATESTRENGTH Msg("State: %s, strength %g\n", GetStringForState( GetState()), pev->health ) -#define MSGSTATEVOLUME Msg("State: %s, volume %g\n", GetStringForState( GetState()), m_flVolume ) -#define MSGSTATESPEED Msg("State: %s, speed %g\n", GetStringForState( GetState()), pev->speed ) - -//========================= -// CLOCK DEFAULTS -//========================= -#define SECONDS 60 -#define MINUTES 3600 -#define HOURS 43200 - -//========================= -// LIGHT DEFAULTS -//========================= -#define START_SWITCH_STYLE 32 - -//========================= -// WORLD DEFAULTS -//========================= -#define XEN_GRAVITY 0.6 -#define EARTH_GRAVITY 1.0 -#define MAP_SIZE 131070 -#define MAP_HALFSIZE MAP_SIZE / 2 -#define FOG_LIMIT 30000 -#define MAX_GIB_LIFETIME 30 - -//========================= -// Global spawnflag system -//========================= -#define SF_NOTSOLID 0x2 -#define SF_FIREONCE 0x2 -#define SF_NORESPAWN BIT( 30 ) - -//========================= -// FCAP DEFAULTS -//========================= -// These are caps bits to indicate what an object's capabilities (currently used for save/restore and level transitions) -#define FCAP_CUSTOMSAVE 0x00000001 -#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions -#define FCAP_MUST_SPAWN 0x00000004 // Spawn after restore -#define FCAP_IMPULSE_USE 0x00000008 // can be used by the player -#define FCAP_CONTINUOUS_USE 0x00000010 // can be used by the player -#define FCAP_ONOFF_USE 0x00000020 // can be used by the player -#define FCAP_DIRECTIONAL_USE 0x00000040 // Player sends +/- 1 when using (currently only tracktrains) -#define FCAP_FORCE_TRANSITION 0x00000080 // ALWAYS goes across transitions -#define FCAP_ONLYDIRECT_USE 0x00000100 //LRC - can't use this entity through a wall. -#define FCAP_DONT_SAVE 0x80000000 // Don't save this - -//========================= -// MONSTER CLASSIFY -//========================= -// For CLASSIFY -#define CLASS_NONE 0 -#define CLASS_MACHINE 1 -#define CLASS_PLAYER 2 -#define CLASS_HUMAN_PASSIVE 3 -#define CLASS_HUMAN_MILITARY 4 -#define CLASS_ALIEN_MILITARY 5 -#define CLASS_ALIEN_PASSIVE 6 -#define CLASS_ALIEN_MONSTER 7 -#define CLASS_ALIEN_PREY 8 -#define CLASS_ALIEN_PREDATOR 9 -#define CLASS_INSECT 10 -#define CLASS_PLAYER_ALLY 11 -#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players -#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace -#define CLASS_FACTION_A 14 // very simple new classes, for use with Behaves As -#define CLASS_FACTION_B 15 -#define CLASS_FACTION_C 16 -#define CLASS_BARNACLE 99 //special because no one pays attention to it, and it eats a wide cross-section of creatures. - -//========================= -// DAMAGE DEFAULTS -//========================= -#define DMG_GENERIC 0 // generic damage was done -#define DMG_CRUSH (1 << 0) // crushed by falling or moving object -#define DMG_BULLET (1 << 1) // shot -#define DMG_SLASH (1 << 2) // cut, clawed, stabbed -#define DMG_BURN (1 << 3) // heat burned -#define DMG_FREEZE (1 << 4) // frozen -#define DMG_FALL (1 << 5) // fell too far -#define DMG_BLAST (1 << 6) // explosive blast damage -#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt -#define DMG_SHOCK (1 << 8) // electric shock -#define DMG_SONIC (1 << 9) // sound pulse shockwave -#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam -#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death -#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. -#define DMG_DROWN (1 << 14) // Drowning -#define DMG_TIMEBASED (~(0x3fff))// mask for time-based damage -#define DMG_PARALYZE (1 << 15) // slows affected creature down -#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad -#define DMG_POISON (1 << 17) // blood poisioning -#define DMG_RADIATION (1 << 18) // radiation exposure -#define DMG_DROWNRECOVER (1 << 19) // drowning recovery -#define DMG_ACID (1 << 20) // toxic chemicals or acid burns -#define DMG_SLOWBURN (1 << 21) // in an oven -#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer -#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) -#define DMG_NUCLEAR (1 << 24) // dmg at nuclear explode - -// these are the damage types that are allowed to gib corpses -#define DMG_GIB_CORPSE ( DMG_CRUSH | DMG_FALL | DMG_BLAST | DMG_SONIC | DMG_CLUB | DMG_NUCLEAR ) -// these are the damage types that have client hud art -#define DMG_SHOWNHUD (DMG_POISON | DMG_ACID | DMG_FREEZE | DMG_SLOWFREEZE | DMG_DROWN | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION | DMG_SHOCK | DMG_NUCLEAR) - -#define PARALYZE_DURATION 2 // number of 2 second intervals to take damage -#define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval -#define NERVEGAS_DURATION 2 -#define NERVEGAS_DAMAGE 5.0 -#define POISON_DURATION 5 -#define POISON_DAMAGE 2.0 -#define RADIATION_DURATION 2 -#define RADIATION_DAMAGE 1.0 -#define ACID_DURATION 2 -#define ACID_DAMAGE 5.0 -#define SLOWBURN_DURATION 2 -#define SLOWBURN_DAMAGE 1.0 -#define SLOWFREEZE_DURATION 2 -#define SLOWFREEZE_DAMAGE 1.0 - -#define itbd_Paralyze 0 -#define itbd_NerveGas 1 -#define itbd_Poison 2 -#define itbd_Radiation 3 -#define itbd_DrownRecover 4 -#define itbd_Acid 5 -#define itbd_SlowBurn 6 -#define itbd_SlowFreeze 7 -#define CDMG_TIMEBASED 8 - -// when calling KILLED(), a value that governs gib behavior is expected to be -// one of these three values -#define GIB_NORMAL 0// gib if entity was overkilled -#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc ) -#define GIB_ALWAYS 2// always gib ( Houndeye Shock, Barnacle Bite ) - -//========================= -// CAPS DEFAULTS -//========================= -#define bits_CAP_DUCK ( 1 << 0 )// crouch -#define bits_CAP_JUMP ( 1 << 1 )// jump/leap -#define bits_CAP_STRAFE ( 1 << 2 )// strafe ( walk/run sideways) -#define bits_CAP_SQUAD ( 1 << 3 )// can form squads -#define bits_CAP_SWIM ( 1 << 4 )// proficiently navigate in water -#define bits_CAP_CLIMB ( 1 << 5 )// climb ladders/ropes -#define bits_CAP_USE ( 1 << 6 )// open doors/push buttons/pull levers -#define bits_CAP_HEAR ( 1 << 7 )// can hear forced sounds -#define bits_CAP_AUTO_DOORS ( 1 << 8 )// can trigger auto doors -#define bits_CAP_OPEN_DOORS ( 1 << 9 )// can open manual doors -#define bits_CAP_TURN_HEAD ( 1 << 10)// can turn head, always bone controller 0 - -#define bits_CAP_RANGE_ATTACK1 ( 1 << 11)// can do a range attack 1 -#define bits_CAP_RANGE_ATTACK2 ( 1 << 12)// can do a range attack 2 -#define bits_CAP_MELEE_ATTACK1 ( 1 << 13)// can do a melee attack 1 -#define bits_CAP_MELEE_ATTACK2 ( 1 << 14)// can do a melee attack 2 -#define bits_CAP_FLY ( 1 << 15)// can fly, move all around -#define bits_CAP_DOORS_GROUP (bits_CAP_USE | bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS) - - -//========================= -// WEAPON DEFAULTS -//========================= -//sound volume for different states -#define PRIMARY_CHARGE_VOLUME 256 -#define PRIMARY_FIRE_VOLUME 450 - -#define LOUD_GUN_VOLUME 1000 -#define NORMAL_GUN_VOLUME 600 -#define QUIET_GUN_VOLUME 200 - -//flash brightness -#define BRIGHT_GUN_FLASH 512 -#define NORMAL_GUN_FLASH 256 -#define DIM_GUN_FLASH 128 -#define NO_GUN_FLASH 0 - -#define WEAPON_NOCLIP -1 -#define WEAPON_NOAMMO -1 - -//default as barney hands for weapon -#define GORDON_HANDS 1 -#define BARNEY_HANDS 0 -//Bullet damage settings -//#define 9MM_BULLET_DMG 8 - -//========================= -// SETTINGS FOR EACH WEAPON -//========================= - -//Crowbar settings (weapon_crowbar) -#define CROWBAR_WEIGHT 0 -#define CROWBAR_DMG 10 -#define CROWBAR_BODYHIT_VOLUME 128 -#define CROWBAR_WALLHIT_VOLUME 512 - -//Glock settings (weapon_glock) -#define GLOCK_WEIGHT 10 -#define GLOCK_MAX_CARRY 250 -#define GLOCK_MAX_CLIP 17 -#define GLOCK_DEFAULT_GIVE 17 -#define GLOCK_RANDOM_GIVE RANDOM_LONG( 10, 17 ) - -//Desert eagle settings (weapon_eagle) -#define DESERT_MAX_CLIP 7 -#define DESERT_WEIGHT 15 -#define DESERT_DEFAULT_GIVE 7 -#define DESERT_RANDOM_GIVE RANDOM_LONG( 4, 7 ) -#define DESERT_MAX_CARRY 21 -#define DESERT_LASER_FOCUS 850 - -//mp5 settings (weapon_mp5) -#define MP5_WEIGHT 15 -#define MP5_MAX_CLIP 50 -#define MP5_DEFAULT_GIVE 25 -#define MP5_RANDOM_GIVE RANDOM_LONG( 19, 45 ) -#define MP5_M203_DEFAULT_GIVE 0 -#define MP5_M203_RANDOM_GIVE RANDOM_LONG( 0, 3 ) - -//saw settings (weapon_m249) -#define SAW_WEIGHT 25 -#define SAW_MAX_CARRY 200 -#define SAW_MAX_CLIP 100 -#define SAW_DEFAULT_GIVE 100 -#define SAW_RANDOM_GIVE RANDOM_LONG( 20, 100 ) - -//shotgun settings (weapon_shotgun) -#define SHOTGUN_WEIGHT 15 -#define SHOTGUN_MAX_CLIP 6 -#define SHOTGUN_DEFAULT_GIVE 6 -#define SHOTGUN_RANDOM_GIVE RANDOM_LONG( 1, 6 ) -#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees -#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees - -//m40a1 settings (weapon_m40a1) -#define M40A1_WEIGHT 25 -#define M40A1_MAX_CARRY 10 -#define M40A1_MAX_CLIP 5 -#define M40A1_DEFAULT_GIVE 5 -#define M40A1_RANDOM_GIVE RANDOM_LONG( 1, 5 ) -#define MAX_ZOOM 15 - -//Rpg settings (weapon_rpg) -#define RPG_WEIGHT 20 -#define RPG_MAX_CLIP 1 -#define RPG_DEFAULT_GIVE 1 -#define AMMO_RPGCLIP_GIVE 1 -#define RPG_ROCKET_DMG 100 -#define RPG_LASER_FOCUS 350 - -//gauss settings (weapon_gauss) -#define GAUSS_PRIMARY_DMG 20 -#define GAUSS_WEIGHT 20 -#define GAUSS_DEFAULT_GIVE 20 -#define GAUSS_RANDOM_GIVE RANDOM_LONG( 10, 40 ) - -//Egon settings (weapon_egon) -#define EGON_WEIGHT 20 -#define EGON_DEFAULT_GIVE 20 -#define EGON_RANDOM_GIVE RANDOM_LONG( 15, 35 ) -#define EGON_NARROW_DMG 6 -#define EGON_WIDE_DMG 14 -#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" -#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" -#define EGON_SOUND_OFF "weapons/egon_off1.wav" -#define EGON_SOUND_RUN "weapons/egon_run3.wav" -#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" -#define EGON_SWITCH_NARROW_TIME 0.75 -#define EGON_SWITCH_WIDE_TIME 1.5 -#define EGON_PULSE_INTERVAL 0.1 -#define EGON_DISCHARGE_INTERVAL 0.1 - -//Displacer settings (weapon_displacer) -#define DISPLACER_WEIGHT 10 -#define DISPLACER_DEFAULT_GIVE 80 -#define DISPLACER_RANDOM_GIVE RANDOM_LONG( 40, 100 ) -#define DBALL_DMG 100 -#define DBALL_RADIUS 400 - -//hornetgun settings (weapon_hornetgun) -#define HORNETGUN_WEIGHT 10 -#define HIVEHAND_DEFAULT_GIVE 8 - -//Handgrenade settings (weapon_handgrenade) -#define HANDGRENADE_WEIGHT 5 -#define HANDGRENADE_DMG 100 -#define HANDGRENADE_DEFAULT_GIVE 1 - -//========================= -// AMMO SETTINGS -//========================= - -//max capacity -#define _9MM_MAX_CARRY 250 -#define URANIUM_MAX_CARRY 100 -#define BUCKSHOT_MAX_CARRY 125 -#define BOLT_MAX_CARRY 50 -#define ROCKET_MAX_CARRY 3 -#define HANDGRENADE_MAX_CARRY 10 -#define HORNET_MAX_CARRY 8 -#define M203_GRENADE_MAX_CARRY 10 - -//ammo default give -#define AMMO_URANIUMBOX_GIVE 20 -#define AMMO_GLOCKCLIP_GIVE GLOCK_MAX_CLIP -#define AMMO_357BOX_GIVE 6 -#define AMMO_MP5CLIP_GIVE MP5_MAX_CLIP -#define AMMO_CHAINBOX_GIVE 200 -#define AMMO_M203BOX_GIVE 2 -#define AMMO_BUCKSHOTBOX_GIVE 12 -#define AMMO_CROSSBOWCLIP_GIVE CROSSBOW_MAX_CLIP -#define AMMO_URANIUMBOX_GIVE 20 - -//========================= -// TIME TO RESPAWN -//========================= - -#define RESPAWN_TIME_30SEC 30 -#define RESPAWN_TIME_60SEC 60 -#define RESPAWN_TIME_120SEC 120 -#define RND_RESPAWN_TIME_30 RANDOM_FLOAT( 15, 45 ) -#define RND_RESPAWN_TIME_60 RANDOM_FLOAT( 45, 80 ) -#define RND_RESPAWN_TIME_120 RANDOM_FLOAT( 80, 145 ) - -//========================= -// BATTERY AND HEALTHKIT CAPACITY -//========================= - -#define BATTERY_CHARGE 15 -#define MAX_NORMAL_BATTERY 100 - -//========================= -// MONSTERS HEALTH -//========================= -//agrunt settings -#define AGRUNT_DMG_PUNCH 10 -#define AGRUNT_HEALTH 100 - -//apache -#define APACHE_HEALTH 300 - -//barney -#define BARNEY_HEALTH 50 -#define DEAD_BARNEY_HEALTH 8 - -// HEALTH/SUIT CHARGE DISTRIBUTION -#define SUIT_CHARGER_CAP 75 -#define HEATH_CHARGER_CAP 50 -#define MEDKIT_CAP 20 - -#define BOLT_DMG 40 -#define M203_DMG 100 -#define BULLSQUID_HEALTH 40 - -#define HGRUNT_GRENADE_SPEED 400 -#define HGRUNT_SHOTGUN_PELLETS 5 -#define HGRUNT_DMG_KICK 5 -#define HGRUNT_HEALTH 70 -#define HASSASSIN_HEALTH 50 - -#define LEECH_HEALTH 2 -#define LEECH_DMG_BITE 2 - -//headcrab -#define HEADCRAB_HEALTH 10 -#define HEADCRAB_DMG_BITE 10 - -//scientist -#define SCIENTIST_HEALTH 20 -#define SCIENTIST_HEAL 25 - -//turret -#define TURRET_HEALTH 60 -#define MINITURRET_HEALTH 40 -#define SENTRY_HEALTH 50 - -//zombie -#define ZOMBIE_HEALTH 75 -#define ZOMBIE_ONE_SLASH 15 -#define ZOMBIE_BOTH_SLASH 40 - -//hitgroup setttings -#define DMG_HEAD 3 -#define DMG_CHEST 1 -#define DMG_STOMACH 1 -#define DMG_ARM 1 -#define DMG_LEG 1 - -//bullets damage -#define _9MM_DMG 10 -#define _MP5_DMG 5 -#define _12MM_DMG 20 -#define _357_DMG 40 -#define _556_DMG 30 -#define _762_DMG 50 -#define BUCKSHOT_DMG 15 - -//bullet vector cone -#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) -#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) -#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) -#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) -#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) -#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) -#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) -#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) -#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) -#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) -#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) -#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) -#define VECTOR_CONE_0DEGREES Vector( 0.00000, 0.00000, 0.00000 ) -#endif//DEFAULT_H \ No newline at end of file diff --git a/server/global/dll_int.cpp b/server/global/dll_int.cpp deleted file mode 100644 index 55563d5c..00000000 --- a/server/global/dll_int.cpp +++ /dev/null @@ -1,510 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// dll_int.cpp - dll entry points -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "saverestore.h" -#include "client.h" -#include "decals.h" -#include "gamerules.h" -#include "game.h" -#include "defaults.h" -#include "baseitem.h" -#include "baseweapon.h" - -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ); - -BOOL gTouchDisabled = FALSE; -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; - -// Main DLL entry point -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - return TRUE; -} - -void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -{ - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); - gpGlobals = pGlobals; -} - -static DLL_FUNCTIONS gFunctionTable = -{ - GameDLLInit, // pfnGameInit - DispatchSpawn, // pfnSpawn - DispatchThink, // pfnThink - DispatchUse, // pfnUse - DispatchTouch, // pfnTouch - DispatchBlocked, // pfnBlocked - DispatchKeyValue, // pfnKeyValue - DispatchSave, // pfnSave - DispatchRestore, // pfnRestore - DispatchObjectCollsionBox, // pfnAbsBox - - SaveWriteFields, // pfnSaveWriteFields - SaveReadFields, // pfnSaveReadFields - - SaveGlobalState, // pfnSaveGlobalState - RestoreGlobalState, // pfnRestoreGlobalState - ResetGlobalState, // pfnResetGlobalState - - ClientConnect, // pfnClientConnect - ClientDisconnect, // pfnClientDisconnect - ClientKill, // pfnClientKill - ClientPutInServer, // pfnClientPutInServer - ClientCommand, // pfnClientCommand - ClientUserInfoChanged, // pfnClientUserInfoChanged - - ServerActivate, // pfnServerActivate - ServerDeactivate, // pfnServerDeactivate - - PlayerPreThink, // pfnPlayerPreThink - PlayerPostThink, // pfnPlayerPostThink - - StartFrame, // pfnStartFrame - DispatchCreate, // pfnCreate - BuildLevelList, // pfnParmsChangeLevel - - GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game. - DispatchFrame, // pfnPhysicsEntity - - SpectatorConnect, // pfnSpectatorConnect - SpectatorDisconnect, // pfnSpectatorDisconnect - SpectatorThink, // pfnSpectatorThink - - ServerClassifyEdict, // pfnClassifyEdict - - PM_Move, // pfnPM_Move - PM_Init, // pfnPM_Init - PM_FindTextureType, // pfnPM_FindTextureType - - SetupVisibility, // pfnSetupVisibility - UpdateClientData, // pfnUpdateClientData - AddToFullPack, // pfnAddtoFullPack - CreateBaseline, // fpnCreateBaseline - - RegisterEncoders, // pfnRegisterEncoders Callbacks for network encoding - - GetWeaponData, // pfnGetWeaponData - CmdStart, // pfnCmdStart - CmdEnd, // pfnCmdEnd - - OnFreeEntPrivateData, // pfnOnFreeEntPrivateData - GameDLLShutdown, // pfnGameShutdown - ShouldCollide, // pfnShouldCollide -}; - -//======================================================================= -// General API entering point -//======================================================================= -int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) -{ - if ( !pFunctionTable || interfaceVersion != SV_INTERFACE_VERSION ) - { - return FALSE; - } - - memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); - return TRUE; -} - -//======================================================================= -// dispatch functions -//======================================================================= - -int DispatchSpawn( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if( pEntity ) - { - // Initialize these or entities who don't link to the world won't have anything in here - pEntity->pev->absmin = pEntity->pev->origin - Vector( 1.0f, 1.0f, 1.0f ); - pEntity->pev->absmax = pEntity->pev->origin + Vector( 1.0f, 1.0f, 1.0f ); - - pEntity->Spawn(); - pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if ( pEntity ) - { - pEntity->pev->colormap = ENTINDEX(pent); - if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) ) - return -1; // return that this entity should be deleted - if ( pEntity->pev->flags & FL_KILLME ) - return -1; - } - - - // Handle global stuff here - if ( pEntity && pEntity->pev->globalname ) - { - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) - { - // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) - pEntity->MakeDormant();// Hasn't been moved to this level yet, wait but stay alive - // In this level & not dead, continue on as normal - } - else gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); - } - } - return 0; -} - -int DispatchCreate( edict_t *pent, const char *szName ) -{ - if( FNullEnt( pent ) || FStringNull( szName )) - return -1; - - int istr = ALLOC_STRING( szName ); - - // handle virtual entities here - if( !strncmp( szName, "weapon_", 7 )) - { - CBasePlayerWeapon *pWeapon = GetClassPtr((CBasePlayerWeapon *)VARS( pent )); - if( !pWeapon ) return -1; - pWeapon->pev->netname = istr; - return 0; - } - else if( !strncmp( szName, "item_", 5 ) || !strncmp( szName, "ammo_", 5 )) - { - CItem *pItem = GetClassPtr((CItem *)VARS( pent )); - if( !pItem ) return -1; - pItem->pev->netname = istr; - return 0; - } - return -1; -} - -void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) -{ - if ( !pkvd || !pentKeyvalue )return; - - EntvarsKeyvalue( VARS(pentKeyvalue), pkvd ); - - // if the key was an entity variable, or there's no class set yet, - // don't look for the object, it may not exist yet. - if( pkvd->fHandled || pkvd->szClassName == NULL ) - return; - - // Get the actualy entity object - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue); - - if( !pEntity ) return; - pEntity->KeyValue( pkvd ); -} - -/* ------------------ -DispatchFrame - -this function can override any physics movement -and let user use custom physic. -e.g. you can replace MOVETYPE_PUSH for new movewith system -and many many other things. ------------------ -*/ -int DispatchFrame( edict_t *pent ) -{ - return 0; -} - -void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) -{ - if ( gTouchDisabled ) return; - - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentTouched); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - - if ( pEntity && pOther && ! ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) ) - pEntity->Touch( pOther ); -} - -void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentUsed); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE(pentOther); - - if( pEntity && !( pEntity->pev->flags & FL_KILLME )) - pEntity->Use( pOther, pOther, USE_TOGGLE, 0 ); -} - -void DispatchThink( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if( pEntity ) - { - if( FBitSet( pEntity->pev->flags, FL_DORMANT )) - ALERT( at_error, "Dormant entity %s is thinking!\n", STRING( pEntity->pev->classname )); - pEntity->Think(); - } -} - -void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentBlocked ); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - - if( pEntity ) pEntity->Blocked( pOther ); -} - -void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if( pEntity && pSaveData ) - { - // ALERT( at_console, "DispatchSave( %s, %i )\n", STRING( pent->v.classname ), pent->serialnumber ); - ENTITYTABLE *pTable = &pSaveData->pTable[ pSaveData->currentIndex ]; - - if( pTable->pent != pent ) - ALERT( at_error, "ENTITY TABLE OR INDEX IS WRONG!!!!\n" ); - - if( pEntity->ObjectCaps() & FCAP_DONT_SAVE ) return; - - // These don't use ltime & nextthink as times really, but we'll fudge around it. - if( pEntity->pev->movetype == MOVETYPE_PUSH ) - { - float delta = gpGlobals->time - pEntity->pev->ltime; - pEntity->pev->ltime += delta; - pEntity->pev->nextthink += delta; - pEntity->m_fPevNextThink = pEntity->pev->nextthink; - pEntity->m_fNextThink += delta; - } - - if( gpGlobals->changelevel ) - pEntity->ClearPointers(); - - pTable->location = pSaveData->size; // Remember entity position for file I/O - pTable->classname = pEntity->pev->classname; // Remember entity class for respawn - - CSave saveHelper( pSaveData ); - pEntity->Save( saveHelper ); - - pTable->size = pSaveData->size - pTable->location;// Size of entity block is data size written to block - } -} - -int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if( pEntity && pSaveData ) - { - entvars_t tmpVars; - Vector oldOffset; - - // ALERT( at_console, "DispatchRestore( %s )\n", STRING( pent->v.classname )); - CRestore restoreHelper( pSaveData ); - if ( globalEntity ) - { - CRestore tmpRestore( pSaveData ); - tmpRestore.PrecacheMode( 0 ); - tmpRestore.ReadEntVars( "ENTVARS", &tmpVars ); - - pSaveData->size = pSaveData->pTable[pSaveData->currentIndex].location; - pSaveData->pCurrentData = pSaveData->pBaseData + pSaveData->size; - - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( tmpVars.globalname ); - - // Don't overlay any instance of the global that isn't the latest - // pSaveData->szCurrentMapName is the level this entity is coming from - // pGlobla->levelName is the last level the global entity was active in. - // If they aren't the same, then this global update is out of date. - if ( !FStrEq( pSaveData->szCurrentMapName, pGlobal->levelName )) return 0; - - // Compute the new global offset - oldOffset = pSaveData->vecLandmarkOffset; - CBaseEntity *pNewEntity = UTIL_FindGlobalEntity( tmpVars.classname, tmpVars.globalname ); - if ( pNewEntity ) - { - // Tell the restore code we're overlaying a global entity from another level - restoreHelper.SetGlobalMode( 1 ); // Don't overwrite global fields - pSaveData->vecLandmarkOffset = (pSaveData->vecLandmarkOffset - pNewEntity->pev->mins) + tmpVars.mins; - pEntity = pNewEntity;// we're going to restore this data OVER the old entity - pent = ENT( pEntity->pev ); - // Update the global table to say that the global definition of this entity should come from this level - gGlobalState.EntityUpdate( pEntity->pev->globalname, gpGlobals->mapname ); - } - else - { - // This entity will be freed automatically by the engine. If we don't do a restore on a matching entity (below) - // or call EntityUpdate() to move it to this level, we haven't changed global state at all. - return 0; - } - - } - - if ( pEntity->ObjectCaps() & FCAP_MUST_SPAWN ) - { - pEntity->Restore( restoreHelper ); - pEntity->Spawn(); - } - else - { - pEntity->Restore( restoreHelper ); - pEntity->Precache( ); - } - - // Again, could be deleted, get the pointer again. - pEntity = (CBaseEntity *)GET_PRIVATE(pent); - if (pEntity )pEntity->pev->colormap = ENTINDEX(pent); - - // Is this an overriding global entity (coming over the transition), or one restoring in a level - if ( globalEntity ) - { - pSaveData->vecLandmarkOffset = oldOffset; - if ( pEntity ) - { - pEntity->RestorePhysics(); - UTIL_SetOrigin( pEntity, pEntity->pev->origin ); - pEntity->OverrideReset(); - } - } - else if ( pEntity && pEntity->pev->globalname ) - { - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) - { - // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) - { - pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive - } - // In this level & not dead, continue on as normal - } - else - { - ALERT( at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname) ); - // Spawned entities default to 'On' - gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); - } - } - } - return 0; -} - -void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - CSave saveHelper( pSaveData ); - saveHelper.WriteFields( "SWF", pname, pBaseData, pFields, fieldCount ); -} - -void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - CRestore restoreHelper( pSaveData ); - restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount ); -} - -void OnFreeEntPrivateData( edict_s *pEdict ) -{ - if( pEdict && pEdict->pvPrivateData ) - { - ((CBaseEntity*)pEdict->pvPrivateData)->~CBaseEntity(); - } -} - -void SetObjectCollisionBox( entvars_t *pev ) -{ - if (( pev->solid == SOLID_BSP ) && ( pev->angles != g_vecZero )) - { - // expand for rotation - float max = 0, v; - int i; - - for ( i = 0; i < 3; i++ ) - { - v = fabs( pev->mins[i] ); - if ( v > max ) max = v; - v = fabs( 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; - } - } - else - { - pev->absmin = pev->origin + pev->mins; - pev->absmax = pev->origin + pev->maxs; - } - - pev->absmin.x -= 1; - pev->absmin.y -= 1; - pev->absmin.z -= 1; - pev->absmax.x += 1; - pev->absmax.y += 1; - pev->absmax.z += 1; -} - -void DispatchObjectCollsionBox( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - if( pEntity ) pEntity->SetObjectCollisionBox(); - else SetObjectCollisionBox( &pent->v ); -} - -//======================================================================= -// ehandle operations -//======================================================================= - -edict_t * EHANDLE::Get( void ) -{ - if (m_pent) - { - if (m_pent->serialnumber == m_serialnumber) return m_pent; - else return NULL; - } - return NULL; -}; - -edict_t *EHANDLE::Set( edict_t *pent ) -{ - m_pent = pent; - if (pent) m_serialnumber = m_pent->serialnumber; - return pent; -}; - - -EHANDLE :: operator CBaseEntity *() -{ - return (CBaseEntity *)GET_PRIVATE(Get()); -}; - - -CBaseEntity *EHANDLE :: operator = (CBaseEntity *pEntity) -{ - if (pEntity) - { - m_pent = ENT( pEntity->pev ); - if (m_pent)m_serialnumber = m_pent->serialnumber; - } - else - { - m_pent = NULL; - m_serialnumber = 0; - } - return pEntity; -} - -EHANDLE :: operator int() -{ - return Get() != NULL; -} - -CBaseEntity *EHANDLE :: operator->() -{ - return (CBaseEntity *)GET_PRIVATE(Get()); -} \ No newline at end of file diff --git a/server/global/enginecallback.h b/server/global/enginecallback.h deleted file mode 100644 index 5f6254ed..00000000 --- a/server/global/enginecallback.h +++ /dev/null @@ -1,164 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ENGINECALLBACK_H -#define ENGINECALLBACK_H - -// Must be provided by user of this code -extern enginefuncs_t g_engfuncs; - -// The actual engine callbacks -#define MALLOC( x ) (*g_engfuncs.pfnMemAlloc)( x, __FILE__, __LINE__ ) -#define CALLOC( x, y ) (*g_engfuncs.pfnMemAlloc)((x) * (y), __FILE__, __LINE__ ) -#define FREE( x ) (*g_engfuncs.pfnMemFree)( x, __FILE__, __LINE__ ) -#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId) -#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel) -#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound) -#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric) -#define SET_MODEL (*g_engfuncs.pfnSetModel) -#define MODEL_INDEX (*g_engfuncs.pfnModelIndex) -#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames) -#define SET_SIZE (*g_engfuncs.pfnSetSize) -#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel) -#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms) -#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms) -#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw) -#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles) -#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin) -#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw) -#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch) -#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors) -#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity) -#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity) -#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity) -#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic) -#define LINK_ENTITY (*g_engfuncs.pfnLinkEdict) -#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor) -#define WALK_MOVE (*g_engfuncs.pfnWalkMove) -#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin) -#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound) -#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg) -#define TRACE_LINE (*g_engfuncs.pfnTraceLine) -#define TRACE_TOSS (*g_engfuncs.pfnTraceToss) -#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull) -#define TRACE_HULL (*g_engfuncs.pfnTraceHull) -#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) -#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) -#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) -#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) -#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) -#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex) -#define POINT_CONTENTS (*g_engfuncs.pfnPointContents) -#define CRC32_INIT (*g_engfuncs.pfnCRC_Init) -#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC_ProcessBuffer) -#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC_ProcessByte) -#define CRC32_FINAL (*g_engfuncs.pfnCRC_Final) -#define RANDOM_LONG (*g_engfuncs.pfnRandomLong) -#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) -#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) -#define CLASSIFY_EDICT (*g_engfuncs.pfnClassifyEdict) -#define COM_Parse (*g_engfuncs.pfnParseToken) - -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) -{ - (*g_engfuncs.pfnMessageBegin)( msg_dest, msg_type, pOrigin, ed ); -} - -#define MESSAGE_END (*g_engfuncs.pfnMessageEnd) -#define WRITE_BYTE (*g_engfuncs.pfnWriteByte) -#define WRITE_CHAR (*g_engfuncs.pfnWriteChar) -#define WRITE_SHORT (*g_engfuncs.pfnWriteShort) -#define WRITE_LONG (*g_engfuncs.pfnWriteLong) -#define WRITE_ANGLE (*g_engfuncs.pfnWriteAngle) -#define WRITE_COORD (*g_engfuncs.pfnWriteCoord) - -inline void WRITE_FLOAT( float flValue ) -{ - union { float f; int l; } dat; - dat.f = flValue; - WRITE_LONG( dat.l ); -} - -#define WRITE_STRING (*g_engfuncs.pfnWriteString) -#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) -#define WRITE_DIR( dir ) WRITE_BYTE(DirToBits( dir )) -#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) -#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) -#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) -#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat) -#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString) -#define ALERT (*g_engfuncs.pfnAlertMessage) -#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf) -#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData) -inline void *GET_PRIVATE( edict_t *pent ) -{ - if ( pent ) - return pent->pvPrivateData; - return NULL; -} - -// NOTE: Xash3D using custom StringTable System that using safety methods for access to strings -// and never make duplicated strings, so it make no differences between ALLOC_STRING and MAKE_STRING -// leave macros as legacy -#define ALLOC_STRING (*g_engfuncs.pfnAllocString) -#define MAKE_STRING (*g_engfuncs.pfnAllocString) -#define STRING (*g_engfuncs.pfnSzFromIndex) - -#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData) -#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString) -#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum) -#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere) -#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS) -#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound) -#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr) -#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg) -#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition) -#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName) -#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction) -#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture) -#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf) -#define CMD_ARGS (*g_engfuncs.pfnCmd_Args) -#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc) -#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv) -#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment) -#define SET_VIEW (*g_engfuncs.pfnSetView) -#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle) -#define LOAD_FILE (*g_engfuncs.pfnLoadFile) -#define FILE_EXISTS (*g_engfuncs.pfnFileExists) -#define FREE_FILE (*g_engfuncs.pfnFreeFile) -#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime) -#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir) -#define ENGINE_CANSKIP (*g_engfuncs.pfnCanSkipPlayer) -#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) -#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) -#define SET_BONE_POSITION (*g_engfuncs.pfnSetBonePos) -#define DROP_CLIENT (*g_engfuncs.pfnDropClient) -#define ENGINE_CHECK_PVS (*g_engfuncs.pfnCheckVisibility) -#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS) -#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) -#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid) -#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) -#define DELTA_SET (*g_engfuncs.pfnDeltaSetField) -#define DELTA_UNSET (*g_engfuncs.pfnDeltaUnsetField) -#define DELTA_ADDENCODER (*g_engfuncs.pfnDeltaAddEncoder) -#define ENGINE_CURRENT_PLAYER (*g_engfuncs.pfnGetCurrentPlayer) -#define HOST_ERROR (*g_engfuncs.pfnHostError) -#define ENGINE_GETPHYSINFO (*g_engfuncs.pfnGetPhysicsInfoString) -#define DELTA_FINDFIELD (*g_engfuncs.pfnDeltaFindField) -#define DELTA_SETBYINDEX (*g_engfuncs.pfnDeltaSetFieldByIndex) -#define DELTA_UNSETBYINDEX (*g_engfuncs.pfnDeltaUnsetFieldByIndex) -#define ENGINE_SETGROUPMASK (*g_engfuncs.pfnSetGroupMask) -#define PLAYER_CNX_STATS (*g_engfuncs.pfnGetPlayerStats) - -#endif //ENGINECALLBACK_H \ No newline at end of file diff --git a/server/global/extdll.h b/server/global/extdll.h deleted file mode 100644 index d67181cd..00000000 --- a/server/global/extdll.h +++ /dev/null @@ -1,57 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// extdll.h - global defines for dll's -// -//======================================================================= - -#ifndef EXTDLL_H -#define EXTDLL_H - -// Silence certain warnings -#pragma warning(disable : 4305) // int or float data truncation -#pragma warning(disable : 4201) // nameless struct/union -#pragma warning(disable : 4514) // unreferenced inline function removed -#pragma warning(disable : 4100) // unreferenced formal parameter - -#include "windows.h" -#include "basetypes.h" - -#define FALSE 0 -#define TRUE 1 - -typedef unsigned long ULONG; - -#include -#include - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) - -// misc C-runtime library headers -#include -#include -#include - -// Shared engine/DLL constants -#include "const.h" - -#include "game_shared.h" - -// Vector class -#include "vector.h" - - // Shared header describing protocol between engine and DLLs -#include "entity_def.h" -#include "svgame_api.h" - -extern Vector vec3_origin; -extern Vector vec3_angles; - -#endif // EXTDLL_H \ No newline at end of file diff --git a/server/global/globals.cpp b/server/global/globals.cpp deleted file mode 100644 index f25d5d9d..00000000 --- a/server/global/globals.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== globals.cpp ======================================================== - - DLL-wide global variable definitions. - They're all defined here, for convenient centralization. - Source files that need them should "extern ..." declare each - variable, to better document what globals they care about. - -*/ - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "baseweapon.h" -#include "soundent.h" - -DLL_GLOBAL unsigned short m_usPlayEmptySound; -DLL_GLOBAL unsigned short m_usEjectBrass; -DLL_GLOBAL unsigned short m_usPlayTexSound; -DLL_GLOBAL ULONG g_ulFrameCount; -DLL_GLOBAL ULONG g_ulModelIndexEyes; -DLL_GLOBAL ULONG g_ulModelIndexPlayer; -DLL_GLOBAL Vector g_vecAttackDir; -DLL_GLOBAL int g_iSkillLevel; -DLL_GLOBAL int gDisplayTitle; -DLL_GLOBAL BOOL g_fGameOver; -DLL_GLOBAL BOOL g_startSuit; -DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0); -DLL_GLOBAL int g_Language; -DLL_GLOBAL short g_sModelIndexLaser; -DLL_GLOBAL int g_sModelIndexLaserDot; -DLL_GLOBAL short g_sModelIndexFireball; -DLL_GLOBAL short g_sModelIndexSmoke; -DLL_GLOBAL short g_sModelIndexWExplosion; -DLL_GLOBAL short g_sModelIndexBubbles; -DLL_GLOBAL short g_sModelIndexBloodDrop; -DLL_GLOBAL short g_sModelIndexBloodSpray; -DLL_GLOBAL int g_sModelIndexErrorSprite; -DLL_GLOBAL int g_sModelIndexErrorModel; -DLL_GLOBAL int g_sModelIndexNullModel; -DLL_GLOBAL int g_sModelIndexNullSprite; - -int GetStdLightStyle (int iStyle) -{ - switch (iStyle) - { - case 0: return MAKE_STRING("m"); // 0 normal - case 1: return MAKE_STRING("mmnmmommommnonmmonqnmmo"); // 1 FLICKER (first variety) - case 2: return MAKE_STRING("abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); // 2 SLOW STRONG PULSE - case 3: return MAKE_STRING("mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); // 3 CANDLE (first variety) - case 4: return MAKE_STRING("mamamamamama"); // 4 FAST STROBE - case 5: return MAKE_STRING("jklmnopqrstuvwxyzyxwvutsrqponmlkj"); // 5 GENTLE PULSE 1 - case 6: return MAKE_STRING("nmonqnmomnmomomno"); // 6 FLICKER (second variety) - case 7: return MAKE_STRING("mmmaaaabcdefgmmmmaaaammmaamm"); // 7 CANDLE (second variety) - case 8: return MAKE_STRING("mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); // 8 CANDLE (third variety) - case 9: return MAKE_STRING("aaaaaaaazzzzzzzz"); // 9 SLOW STROBE (fourth variety) - case 10: return MAKE_STRING("mmamammmmammamamaaamammma"); // 10 FLUORESCENT FLICKER - case 11: return MAKE_STRING("abcdefghijklmnopqrrqponmlkjihgfedcba"); // 11 SLOW PULSE NOT FADE TO BLACK - case 12: return MAKE_STRING("mmnnmmnnnmmnn"); // 12 UNDERWATER LIGHT MUTATION - case 13: return MAKE_STRING("a"); // 13 OFF - case 14: return MAKE_STRING("aabbccddeeffgghhiijjkkllmmmmmmmmmmmmmm"); // 14 SLOW FADE IN - case 15: return MAKE_STRING("abcdefghijklmmmmmmmmmmmmmmmmmmmmmmmmmm"); // 15 MED FADE IN - case 16: return MAKE_STRING("acegikmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm"); // 16 FAST FADE IN - case 17: return MAKE_STRING("llkkjjiihhggffeeddccbbaaaaaaaaaaaaaaaa"); // 17 SLOW FADE OUT - case 18: return MAKE_STRING("lkjihgfedcbaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // 18 MED FADE OUT - case 19: return MAKE_STRING("kigecaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // 19 FAST FADE OUT - default: return MAKE_STRING("m"); - } -} \ No newline at end of file diff --git a/server/global/globals.h b/server/global/globals.h deleted file mode 100644 index 1d221e8c..00000000 --- a/server/global/globals.h +++ /dev/null @@ -1,107 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// globals.h - store global variables, -//======================================================================= -#ifndef GLOBALS_H -#define GLOBALS_H - -extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam -extern DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball -extern DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud -extern DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion -extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model -extern DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for blood drops -extern DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for blood spray (bigger) -extern DLL_GLOBAL int g_sModelIndexLaserDot; -extern DLL_GLOBAL unsigned short m_usPlayEmptySound; -extern DLL_GLOBAL unsigned short m_usEjectBrass; -extern DLL_GLOBAL unsigned short m_usPlayTexSound; -extern DLL_GLOBAL ULONG g_ulFrameCount; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL BOOL g_startSuit; - -// C functions for external declarations that call the appropriate C++ methods - -#ifdef _WIN32 -#define EXPORT _declspec( dllexport ) -#else -#define EXPORT /* */ -#endif - -extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); - -extern int DispatchSpawn( edict_t *pent ); -extern int DispatchCreate( edict_t *pent, const char *szName ); -extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ); -extern void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ); -extern void DispatchUse( edict_t *pentUsed, edict_t *pentOther ); -extern void DispatchThink( edict_t *pent ); -extern int DispatchFrame( edict_t *pent ); -extern void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ); -extern void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ); -extern int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); -extern void DispatchObjectCollsionBox( edict_t *pent ); -extern int ServerClassifyEdict( edict_t *pentToClassify ); -extern void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); -extern void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); -extern void SaveGlobalState( SAVERESTOREDATA *pSaveData ); -extern void RestoreGlobalState( SAVERESTOREDATA *pSaveData ); -extern void ResetGlobalState( void ); -extern void OnFreeEntPrivateData( edict_s *pEdict ); -extern int ShouldCollide( edict_t *pentTouched, edict_t *pentOther ); - -// spectator funcs -extern void SpectatorConnect( edict_t *pEntity ); -extern void SpectatorDisconnect( edict_t *pEntity ); -extern void SpectatorThink( edict_t *pEntity ); - -typedef void (CBaseEntity::*BASEPTR)(void); -typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther ); -typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -// -// EHANDLE. Safe way to point to CBaseEntities who may die between frames -// -class EHANDLE -{ -private: - edict_t *m_pent; - int m_serialnumber; -public: - edict_t *Get( void ); - edict_t *Set( edict_t *pent ); - - operator int (); - - operator CBaseEntity *(); - - CBaseEntity * operator = (CBaseEntity *pEntity); - CBaseEntity * operator ->(); -}; - - -// -// Converts a entvars_t * to a class pointer -// It will allocate the class and entity if necessary -// -template T * GetClassPtr( T *a ) -{ - entvars_t *pev = (entvars_t *)a; - - // allocate entity if necessary - if (pev == NULL) - pev = VARS(CREATE_ENTITY()); - - // get the private data - a = (T *)GET_PRIVATE(ENT(pev)); - - if (a == NULL) - { - // allocate private data - a = new(pev) T; - a->pev = pev; - } - return a; -} - -#endif //GLOBALS_H \ No newline at end of file diff --git a/server/global/hierarchy.h b/server/global/hierarchy.h deleted file mode 100644 index 51f08406..00000000 --- a/server/global/hierarchy.h +++ /dev/null @@ -1,29 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// hierarchy.h - Not real code. -// Map of relationshep between classes. -//======================================================================= -#ifndef HIERARCHY_H -#define HIERARCHY_H - -/* -Class Hierachy - -CBaseEntity - CPointEntity - CBasePlayerAmmo - CBaseLogic - CBaseAnimating - CBasePlayerWeapon - CBaseToggle - CBaseButton - CBaseDoor - CBaseTrigger - CBasePlatTrain - CBaseMonster - CCycler - CBasePlayer - CCineMonster -*/ - -#endif //HIERARCHY_H \ No newline at end of file diff --git a/server/global/parent.cpp b/server/global/parent.cpp deleted file mode 100644 index 82dd1421..00000000 --- a/server/global/parent.cpp +++ /dev/null @@ -1,324 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// parent.cpp - xash parent system -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "saverestore.h" -#include "client.h" -#include "decals.h" -#include "gamerules.h" -#include "game.h" -#include "defaults.h" - -CWorld *g_pWorld = NULL; //world pointer -extern BOOL CanAffect; -BOOL NeedUpdate( CBaseEntity *pEnt ); - -//======================================================================= -// debug utils -//======================================================================= -void GetPFlags( CBaseEntity* Ent ) //get parent system flags -{ - char szFlags[256] = "";//clear line - - CHECK_FLAG(PF_AFFECT); - CHECK_FLAG(PF_DESIRED); - CHECK_FLAG(PF_ACTION); - CHECK_FLAG(PF_MOVENONE); - CHECK_FLAG(PF_CORECTSPEED); - CHECK_FLAG(PF_MERGEPOS); - CHECK_FLAG(PF_ANGULAR); - CHECK_FLAG(PF_POSTVELOCITY); - CHECK_FLAG(PF_POSTAVELOCITY); - CHECK_FLAG(PF_SETTHINK); - CHECK_FLAG(PF_POSTAFFECT); - CHECK_FLAG(PF_LINKCHILD); - - ALERT(at_console, "=========/Xash Parent System Info:/=========\n"); - if(!Ent->pev->targetname)ALERT(at_console, "INFO: %s has follow flags:\n", STRING(Ent->pev->classname) ); - else ALERT(at_console, "INFO: %s with name %s has follow flags:\n", STRING(Ent->pev->classname), STRING(Ent->pev->targetname) ); - ALERT(at_console, "%s\n", szFlags ); - SHIFT; -} - -void GetPInfo( CBaseEntity* Ent ) //get parent system parameters -{ - int name = 0; - int parentname = 0; - int childsname = 0; - char parent[32] = ""; - char chname[256] = ""; - char buffer[32]; - - Vector pVelocity, pAvelocity, cVelocity, cAvelocity; - - if(Ent->pev->targetname)name = Ent->pev->targetname; - else name = Ent->pev->classname; - - if(Ent->m_pParent) - { - if(Ent->m_pParent->pev->targetname)parentname = Ent->m_pParent->pev->targetname; - else parentname = Ent->m_pParent->pev->classname; - pVelocity = Ent->m_pParent->pev->velocity; - pAvelocity = Ent->m_pParent->pev->avelocity; - sprintf( parent, "with parent \"%s\"", STRING(parentname) ); - } - else sprintf(parent, "without parent"); - - if( Ent->m_pChild ) - { - CBaseEntity *pInfo = Ent->m_pChild; - int sloopbreaker = MAX_CHILDS; - - while (pInfo) - { - if(pInfo->pev->targetname) childsname = pInfo->pev->targetname; - else childsname = pInfo->pev->classname; - pInfo = pInfo->m_pNextChild; - if(pInfo)sprintf(buffer, "\"%s\", ", STRING(childsname)); - else sprintf(buffer, "\"%s\"", STRING(childsname));//it,s last child - strcat( chname, buffer); - sloopbreaker--; - if (sloopbreaker <= 0)break; - } - } - else sprintf(chname, "this entity not have childs"); - - cVelocity = Ent->pev->velocity; - cAvelocity = Ent->pev->avelocity; - - //print info - Msg("=========/Xash Parent System Info:/=========\n"); - Msg("INFO: Entity \"%s\" %s, have following parameters:\n", STRING(name), parent ); - Msg("Child names: %s. Self Velocity: %g %g %g. Self Avelocity %g %g %g\n", chname, cVelocity.x, cVelocity.y, cVelocity.z, cAvelocity.x, cAvelocity.y, cAvelocity.z ); - if(Ent->m_pParent)Msg("Parent Velocity: %g %g %g. Parent Avelocity: %g %g %g.\n", pVelocity.x, pVelocity.y, pVelocity.z, pAvelocity.x, pAvelocity.y, pAvelocity.z ); - else SHIFT; -} - -//======================================================================= -// physics frame -//======================================================================= - -void PhysicsFrame( void ) -{ - CBaseEntity *pListMember; - - if ( !g_pWorld )return; - pListMember = g_pWorld; - - while ( pListMember->m_pLinkList )// handle the remaining entries in the list - { - FrameAffect(pListMember->m_pLinkList); - if (!(pListMember->m_pLinkList->pFlags & PF_LINKCHILD)) - { - CBaseEntity *pTemp = pListMember->m_pLinkList; - pListMember->m_pLinkList = pListMember->m_pLinkList->m_pLinkList; - pTemp->m_pLinkList = NULL; - } - else pListMember = pListMember->m_pLinkList; - } -} - -void PhysicsPostFrame( void ) -{ - CBaseEntity *pListMember; - int loopbreaker = 1024; //max edicts - if (CanAffect) ALERT(at_console, "Affect already applied ?!\n"); - CanAffect = TRUE; - if (!g_pWorld) return; - - pListMember = g_pWorld; - CBaseEntity *pNext; - - pListMember = g_pWorld->m_pLinkList; - - while (pListMember) - { - pNext = pListMember->m_pLinkList; - PostFrameAffect( pListMember ); - pListMember = pNext; - loopbreaker--; - if (loopbreaker <= 0)break; - } - CanAffect = FALSE; -} - -//======================================================================= -// affect & postaffect -//======================================================================= - -int FrameAffect( CBaseEntity *pEnt ) -{ - if (gpGlobals->frametime == 0)return 0; - if (!(pEnt->pFlags & PF_AFFECT)) return 0; - if (pEnt->m_fNextThink <= 0) - { - ClearBits(pEnt->pFlags, PF_AFFECT); - return 0; // cancelling think - } - float fFraction = 0; - if (pEnt->pev->movetype == MOVETYPE_PUSH) - { - if (pEnt->m_fNextThink <= pEnt->pev->ltime + gpGlobals->frametime) - fFraction = (pEnt->m_fNextThink - pEnt->pev->ltime)/gpGlobals->frametime; - } - - else if (pEnt->m_fNextThink <= gpGlobals->time + gpGlobals->frametime) - fFraction = (pEnt->m_fNextThink - gpGlobals->time)/gpGlobals->frametime; - if (fFraction) - { - if (pEnt->pFlags & PF_CORECTSPEED) - { - if (!(pEnt->pFlags & PF_POSTVELOCITY)) - { - pEnt->PostVelocity = pEnt->pev->velocity; - SetBits (pEnt->pFlags, PF_POSTVELOCITY); - } - - if (!(pEnt->pFlags & PF_POSTAVELOCITY)) - { - pEnt->PostAvelocity = pEnt->pev->avelocity; - SetBits (pEnt->pFlags, PF_POSTAVELOCITY); - } - - Vector vecVelTemp = pEnt->pev->velocity; - Vector vecAVelTemp = pEnt->pev->avelocity; - - if (pEnt->m_pParent) - { - pEnt->pev->velocity = (pEnt->pev->velocity - pEnt->m_pParent->pev->velocity)*fFraction + pEnt->m_pParent->pev->velocity; - pEnt->pev->avelocity = (pEnt->pev->avelocity - pEnt->m_pParent->pev->avelocity)*fFraction + pEnt->m_pParent->pev->avelocity; - } - else - { - pEnt->pev->velocity = pEnt->pev->velocity*fFraction; - pEnt->pev->avelocity = pEnt->pev->avelocity*fFraction; - } - - HandleAffect( pEnt, vecVelTemp - pEnt->pev->velocity, vecAVelTemp - pEnt->pev->avelocity ); - UTIL_SetPostAffect( pEnt ); - } - - UTIL_SetThink( pEnt ); - ClearBits(pEnt->pFlags, PF_AFFECT); - } - return 1; -} - -int PostFrameAffect( CBaseEntity *pEnt ) -{ - if (pEnt->pFlags & PF_DESIRED)ClearBits(pEnt->pFlags, PF_DESIRED); - else return 0; - if (pEnt->pFlags & PF_ACTION) - { - ClearBits(pEnt->pFlags, PF_ACTION); - pEnt->DesiredAction(); - if(NeedUpdate(pEnt)) SetBits(pEnt->m_pChild->pFlags, PF_MERGEPOS); - } - if (pEnt->pFlags & PF_POSTAFFECT) - { - ClearBits(pEnt->pFlags, PF_POSTAFFECT); - HandlePostAffect( pEnt ); - } - if (pEnt->pFlags & PF_SETTHINK) - { - ClearBits(pEnt->pFlags, PF_SETTHINK); - pEnt->Think(); - } - return 1; -} - -//======================================================================= -// affect handles -//======================================================================= - -void HandlePostAffect( CBaseEntity *pEnt ) -{ - if (pEnt->pFlags & PF_POSTVELOCITY) - { - pEnt->pev->velocity = pEnt->PostVelocity; - pEnt->PostVelocity = g_vecZero; - ClearBits (pEnt->pFlags, PF_POSTVELOCITY); - } - if (pEnt->pFlags & PF_POSTAVELOCITY) - { - pEnt->pev->avelocity = pEnt->PostAvelocity; - pEnt->PostAvelocity = g_vecZero; - ClearBits (pEnt->pFlags, PF_POSTAVELOCITY); - } - if (pEnt->pFlags & PF_MERGEPOS || pEnt->pFlags & PF_POSTORG) - { - UTIL_MergePos( pEnt ); - } - CBaseEntity *pChild; - for (pChild = pEnt->m_pChild; pChild != NULL; pChild = pChild->m_pNextChild) - HandlePostAffect( pChild ); -} - -void HandleAffect( CBaseEntity *pEnt, Vector vecAdjustVel, Vector vecAdjustAVel ) -{ - CBaseEntity *pChild; - for(pChild = pEnt->m_pChild; pChild != NULL; pChild = pChild->m_pNextChild) - { - if (!(pEnt->pFlags & PF_POSTVELOCITY)) - { - pChild->PostVelocity = pChild->pev->velocity; - SetBits (pEnt->pFlags, PF_POSTVELOCITY); - } - if (!(pEnt->pFlags & PF_POSTAVELOCITY)) - { - pChild->PostAvelocity = pChild->pev->avelocity; - SetBits (pEnt->pFlags, PF_POSTAVELOCITY); - } - pChild->pev->velocity = pChild->pev->velocity - vecAdjustVel; - pChild->pev->avelocity = pChild->pev->avelocity - vecAdjustAVel; - HandleAffect( pChild, vecAdjustVel, vecAdjustAVel ); - } -} - -//======================================================================= -// link operations -//======================================================================= -void LinkChild(CBaseEntity *pEnt) //add children to our list -{ - if (pEnt->m_pLinkList)return; - - if ( !g_pWorld )return;//too early ? - CBaseEntity *pListMember = g_pWorld; - - // find the last entry in the list - while (pListMember->m_pLinkList != NULL) pListMember = pListMember->m_pLinkList; - if (pListMember == pEnt)return; //entity has in list - - pListMember->m_pLinkList = pEnt;//add entity to the list. -} - -BOOL SynchLost( CBaseEntity *pEnt ) -{ - if(pEnt->pFlags & PF_PARENTMOVE)//moving parent - { - if(!pEnt->m_pParent) return FALSE; - if(pEnt->m_pParent->pev->origin != pEnt->PostOrigin) - { - if(pEnt->pev->solid != SOLID_BSP) return TRUE; - } - if(pEnt->m_pParent->pev->angles != pEnt->PostAngles) - { - if(pEnt->pev->solid != SOLID_BSP) return TRUE; - } - } - return FALSE; -} - -BOOL NeedUpdate( CBaseEntity *pEnt ) -{ - if( pEnt->m_pChild && pEnt->m_pChild->OffsetOrigin == g_vecZero)//potentially loser - { - if(pEnt->pev->origin != pEnt->m_pChild->pev->origin) - return TRUE; - } - return FALSE; -} \ No newline at end of file diff --git a/server/global/plane.h b/server/global/plane.h deleted file mode 100644 index 11ccbffe..00000000 --- a/server/global/plane.h +++ /dev/null @@ -1,176 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PLANE_H -#define PLANE_H - -//========================================================= -// Plane -//========================================================= -typedef int SideType; - -// Used to represent sides of things like planes. -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 - -#define VP_EPSILON 0.01f - - -class VPlane -{ -public: - - VPlane(); - VPlane(const Vector &vNormal, vec_t dist); - - void Init(const Vector &vNormal, vec_t dist); - void Init(const Vector &vNormal, const Vector &vecPoint); - - // Return the distance from the point to the plane. - vec_t DistTo(const Vector &vVec) const; - - // Flip the plane. - VPlane Flip(); - - // Get a point on the plane (normal*dist). - Vector GetPointOnPlane() const; - - // Copy. - VPlane& operator=(const VPlane &thePlane); - - // Snap the specified point to the plane (along the plane's normal). - Vector SnapPointToPlane(const Vector &vPoint) const; - - // Returns SIDE_ON, SIDE_FRONT, or SIDE_BACK. - // The epsilon for SIDE_ON can be passed in. - SideType GetPointSide(const Vector &vPoint, vec_t sideEpsilon=VP_EPSILON) const; - - // Returns SIDE_FRONT or SIDE_BACK. - SideType GetPointSideExact(const Vector &vPoint) const; - - // Classify the box with respect to the plane. - // Returns SIDE_ON, SIDE_FRONT, or SIDE_BACK - SideType BoxOnPlaneSide(const Vector &vMin, const Vector &vMax) const; - - -public: - - Vector m_Normal; - vec_t m_Dist; -}; - - -// ------------------------------------------------------------------------------------------- // -// Inlines. -// ------------------------------------------------------------------------------------------- // - -inline VPlane::VPlane() -{ -} - -inline VPlane::VPlane(const Vector &vNormal, vec_t dist) -{ - m_Normal = vNormal; - m_Dist = dist; -} - -inline void VPlane::Init(const Vector &vNormal, vec_t dist) -{ - m_Normal = vNormal; - m_Dist = dist; -} - -inline void VPlane::Init(const Vector &vNormal, const Vector &vecPoint) -{ - m_Normal = vNormal; - m_Dist = vNormal.Dot( vecPoint ); -} - -inline vec_t VPlane::DistTo(const Vector &vVec) const -{ - return DotProduct( vVec, m_Normal ) - m_Dist; -} - -inline VPlane VPlane::Flip() -{ - return VPlane(-m_Normal, -m_Dist); -} - -inline Vector VPlane::GetPointOnPlane() const -{ - return m_Normal * m_Dist; -} - -inline VPlane& VPlane::operator=(const VPlane &thePlane) -{ - m_Normal = thePlane.m_Normal; - m_Dist = thePlane.m_Dist; - return *this; -} - -inline Vector VPlane::SnapPointToPlane(const Vector &vPoint) const -{ - return vPoint - m_Normal * DistTo(vPoint); -} - -inline SideType VPlane::GetPointSide(const Vector &vPoint, vec_t sideEpsilon) const -{ - vec_t fDist; - - fDist = DistTo(vPoint); - if(fDist >= sideEpsilon) - return SIDE_FRONT; - else if(fDist <= -sideEpsilon) - return SIDE_BACK; - else return SIDE_ON; -} - -inline SideType VPlane::GetPointSideExact(const Vector &vPoint) const -{ - return DistTo(vPoint) > 0.0f ? SIDE_FRONT : SIDE_BACK; -} - -inline SideType VPlane::BoxOnPlaneSide(const Vector &vMin, const Vector &vMax) const -{ - int i, firstSide, side; - Vector vPoints[8] = - { - Vector(vMin.x, vMin.y, vMin.z), - Vector(vMin.x, vMin.y, vMax.z), - Vector(vMin.x, vMax.y, vMax.z), - Vector(vMin.x, vMax.y, vMin.z), - - Vector(vMax.x, vMin.y, vMin.z), - Vector(vMax.x, vMin.y, vMax.z), - Vector(vMax.x, vMax.y, vMax.z), - Vector(vMax.x, vMax.y, vMin.z), - }; - - firstSide = GetPointSideExact(vPoints[0]); - for(i=1; i < 8; i++) - { - side = GetPointSideExact(vPoints[i]); - - // Does the box cross the plane? - if(side != firstSide) - return SIDE_ON; - } - - // Ok, they're all on the same side, return that. - return firstSide; -} - - -#endif // PLANE_H diff --git a/server/global/saverestore.cpp b/server/global/saverestore.cpp deleted file mode 100644 index 372cca52..00000000 --- a/server/global/saverestore.cpp +++ /dev/null @@ -1,1250 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "defaults.h" -#include "saverestore.h" -#include -#include "shake.h" -#include "decals.h" -#include "player.h" -#include "baseweapon.h" -#include "gamerules.h" -#include "client.h" - -#define ENTVARS_COUNT ( sizeof(gEntvarsDescription) / sizeof(gEntvarsDescription[0]) ) -CGlobalState gGlobalState; - -TYPEDESCRIPTION gEntvarsDescription[] = -{ - DEFINE_ENTITY_FIELD( classname, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( oldangles, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( fixangle, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), - DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), - DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ), - - DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD_ARRAY( controller, FIELD_CHARACTER, 16 ), - DEFINE_ENTITY_FIELD_ARRAY( blending, FIELD_CHARACTER, 16 ), - - DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ), - - DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( flags, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ), - DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ), - - // Having these fields be local to the individual levels makes it easier to test those levels individually. - DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( netname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( message, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( fov, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ), -}; - -// -------------------------------------------------------------- -// -// CSave -// -// -------------------------------------------------------------- -static int gSizes[FIELD_TYPECOUNT] = -{ - sizeof(float), // FIELD_FLOAT - sizeof(int), // FIELD_STRING - sizeof(int), // FIELD_ENTITY - sizeof(int), // FIELD_CLASSPTR - sizeof(int), // FIELD_EHANDLE - sizeof(int), // FIELD_entvars_t - sizeof(int), // FIELD_EDICT - sizeof(float)*3, // FIELD_VECTOR - sizeof(float)*3, // FIELD_POSITION_VECTOR - sizeof(int *), // FIELD_POINTER - sizeof(int), // FIELD_INTEGER - sizeof(int *), // FIELD_FUNCTION - sizeof(int), // FIELD_BOOLEAN - sizeof(short), // FIELD_SHORT - sizeof(char), // FIELD_CHARACTER - sizeof(float), // FIELD_TIME - sizeof(int), // FIELD_MODELNAME - sizeof(int), // FIELD_SOUNDNAME - sizeof(float)*2, // FIELD_RANGE - sizeof(int64), // FIELD_INTEGER64 - sizeof(double), // FIELD_DOUBLE -}; - -static const char *gNames[FIELD_TYPECOUNT] = -{ - "float", // FIELD_FLOAT - "string", // FIELD_STRING - "entity", // FIELD_ENTITY - "classptr", // FIELD_CLASSPTR - "ehandle", // FIELD_EHANDLE - "entvars", // FIELD_entvars_t - "edict", // FIELD_EDICT - "vector", // FIELD_VECTOR - "position vector", // FIELD_POSITION_VECTOR - "pointer", // FIELD_POINTER - "integer", // FIELD_INTEGER - "function", // FIELD_FUNCTION - "boolean", // FIELD_BOOLEAN - "short", // FIELD_SHORT - "char", // FIELD_CHARACTER - "time", // FIELD_TIME - "modelname", // FIELD_MODELNAME - "soundname", // FIELD_SOUNDNAME - "random range", // FIELD_RANGE - "integer 64", // FIELD_INTEGER64 - "double", // FIELD_DOUBLE -}; - -// Base class includes common SAVERESTOREDATA pointer, and manages the entity table -CSaveRestoreBuffer :: CSaveRestoreBuffer( void ) -{ - m_pdata = NULL; -} - - -CSaveRestoreBuffer :: CSaveRestoreBuffer( SAVERESTOREDATA *pdata ) -{ - m_pdata = pdata; -} - - -CSaveRestoreBuffer :: ~CSaveRestoreBuffer( void ) -{ -} - -int CSaveRestoreBuffer :: EntityIndex( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL ) - return -1; - return EntityIndex( pEntity->pev ); -} - - -int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) -{ - if ( pevLookup == NULL ) - return -1; - return EntityIndex( ENT( pevLookup ) ); -} - -int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) -{ - return EntityIndex( ENT( eoLookup ) ); -} - - -int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) -{ - if ( !m_pdata || pentLookup == NULL ) - return -1; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->pent == pentLookup ) - return i; - } - return -1; -} - - -edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) -{ - if ( !m_pdata || entityIndex < 0 ) - return NULL; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->id == entityIndex ) - return pTable->pent; - } - return NULL; -} - - -int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) -{ - if ( !m_pdata || entityIndex < 0 ) - return 0; - if ( entityIndex > m_pdata->tableCount ) - return 0; - - m_pdata->pTable[ entityIndex ].flags |= flags; - - return m_pdata->pTable[ entityIndex ].flags; -} - - -void CSaveRestoreBuffer :: BufferRewind( int size ) -{ - if ( !m_pdata ) - return; - - if ( m_pdata->size < size ) - size = m_pdata->size; - - m_pdata->pCurrentData -= size; - m_pdata->size -= size; -} - -#ifndef _WIN32 -extern "C" { -unsigned _rotr ( unsigned val, int shift) -{ - register unsigned lobit; /* non-zero means lo bit set */ - register unsigned num = val; /* number to rotate */ - - shift &= 0x1f; /* modulo 32 -- this will also make - negative shifts work */ - - while (shift--) { - lobit = num & 1; /* get high bit */ - num >>= 1; /* shift right one bit */ - if (lobit) - num |= 0x80000000; /* set hi bit if lo bit was set */ - } - - return num; -} -} -#endif - -unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) -{ - unsigned int hash = 0; - - while ( *pszToken ) - hash = _rotr( hash, 4 ) ^ *pszToken++; - - return hash; -} - -unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) -{ - unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)m_pdata->tokenCount ); - -#if _DEBUG - static int tokensparsed = 0; - tokensparsed++; - if ( !m_pdata->tokenCount || !m_pdata->pTokens ) - ALERT( at_error, "No token table array in TokenHash()!" ); -#endif - - for ( int i=0; itokenCount; i++ ) - { -#if _DEBUG - static BOOL beentheredonethat = FALSE; - if ( i > 50 && !beentheredonethat ) - { - beentheredonethat = TRUE; - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is getting too full!" ); - } -#endif - - int index = hash + i; - if ( index >= m_pdata->tokenCount ) - index -= m_pdata->tokenCount; - - if ( !m_pdata->pTokens[index] || FStrCmp( pszToken, m_pdata->pTokens[index] ) == 0 ) - { - m_pdata->pTokens[index] = (char *)pszToken; - return index; - } - } - - // Token hash table full!!! - // [Consider doing overflow table(s) after the main table & limiting linear hash table search] - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!" ); - return 0; -} - -void CSave :: WriteData( const char *pname, int size, const char *pdata ) -{ - BufferField( pname, size, pdata ); -} - - -void CSave :: WriteShort( const char *pname, const short *data, int count ) -{ - BufferField( pname, sizeof(short) * count, (const char *)data ); -} - - -void CSave :: WriteInt( const char *pname, const int *data, int count ) -{ - BufferField( pname, sizeof(int) * count, (const char *)data ); -} - -void CSave :: WriteInt64( const char *pname, const int64 *data, int count ) -{ - BufferField( pname, sizeof(int64) * count, (const char *)data ); -} - -void CSave :: WriteFloat( const char *pname, const float *data, int count ) -{ - BufferField( pname, sizeof(float) * count, (const char *)data ); -} - -void CSave :: WriteDouble( const char *pname, const double *data, int count ) -{ - BufferField( pname, sizeof( double ) * count, (const char *)data ); -} - -void CSave :: WriteTime( const char *pname, const float *data, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * count ); - for ( i = 0; i < count; i++ ) - { - float tmp = data[0]; - - // Always encode time as a delta from the current time so it can be re-based if loaded in a new level - // Times of 0 are never written to the file, so they will be restored as 0, not a relative time - if( m_pdata ) tmp -= m_pdata->time; - - BufferData( (const char *)&tmp, sizeof( float )); - data++; - } -} - -void CSave :: WriteString( const char *pname, const char *pdata ) -{ -#ifdef TOKENIZE - short token = (short)TokenHash( pdata ); - WriteShort( pname, &token, 1 ); -#else - BufferField( pname, strlen(pdata) + 1, pdata ); -#endif -} - -void CSave :: WriteString( const char *pname, const int *stringId, int count ) -{ - int i, size; - -#ifdef TOKENIZE - short token = (short)TokenHash( STRING( *stringId ) ); - WriteShort( pname, &token, 1 ); -#else -#if 0 - if( count != 1 ) ALERT( at_error, "No string arrays!\n" ); - WriteString( pname, (char *)STRING(*stringId) ); -#endif - - size = 0; - for ( i = 0; i < count; i++ ) - size += strlen( STRING( stringId[i] ) ) + 1; - - BufferHeader( pname, size ); - for ( i = 0; i < count; i++ ) - { - const char *pString = STRING(stringId[i]); - BufferData( pString, strlen(pString)+1 ); - } -#endif -} - - -void CSave :: WriteVector( const char *pname, const Vector &value ) -{ - WriteVector( pname, &value.x, 1 ); -} - -void CSave :: WriteRange( const char *pname, const RandomRange &value ) -{ - WriteRange( pname, &value.m_flMin, 1 ); -} - -void CSave :: WriteRange( const char *pname, const float *value, int count ) -{ - BufferHeader( pname, sizeof(float) * 2 * count ); - BufferData( (const char *)value, sizeof(float) * 2 * count ); -} - -void CSave :: WriteVector( const char *pname, const float *value, int count ) -{ - BufferHeader( pname, sizeof(float) * 3 * count ); - BufferData( (const char *)value, sizeof(float) * 3 * count ); -} - -void CSave :: WritePositionVector( const char *pname, const Vector &value ) -{ - if( m_pdata && m_pdata->fUseLandmark ) - { - Vector tmp = value - m_pdata->vecLandmarkOffset; - WriteVector( pname, tmp ); - } - WriteVector( pname, value ); -} - -void CSave :: WritePositionVector( const char *pname, const float *value, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * 3 * count ); - - for( i = 0; i < count; i++ ) - { - Vector tmp( value[0], value[1], value[2] ); - - if( m_pdata && m_pdata->fUseLandmark ) - tmp = tmp - m_pdata->vecLandmarkOffset; - - BufferData( (const char *)&tmp.x, sizeof(float) * 3 ); - value += 3; - } -} - -void CSave :: WriteFunction( const char* cname, const char *pname, const int *data, int count ) -{ - const char *functionName; - - functionName = NAME_FOR_FUNCTION( *data ); - if( functionName ) - BufferField( pname, strlen( functionName ) + 1, functionName ); - else ALERT( at_error, "Member \"%s\" of \"%s\" contains an invalid function pointer %p!", pname, cname, *data ); -} - -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) -{ - int i; - TYPEDESCRIPTION *pField; - - for( i = 0; i < ENTVARS_COUNT; i++ ) - { - pField = &gEntvarsDescription[i]; - - if( !FStriCmp( pField->fieldName, pkvd->szKeyName )) - { - switch( pField->fieldType ) - { - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - (*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue ); - break; - case FIELD_TIME: - case FIELD_FLOAT: - (*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue ); - break; - case FIELD_DOUBLE: - (*(double *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue ); - break; - case FIELD_INTEGER: - (*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue ); - break; - case FIELD_INTEGER64: - (*(int64 *)((char *)pev + pField->fieldOffset)) = _atoi64( pkvd->szValue ); - break; - case FIELD_POSITION_VECTOR: - case FIELD_VECTOR: - UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue ); - break; - case FIELD_EVARS: - case FIELD_CLASSPTR: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_POINTER: - default: - ALERT( at_error, "Bad field in entity!!\n" ); - break; - } - pkvd->fHandled = TRUE; - return; - } - } -} - -int CSave :: WriteEntVars( const char *pname, entvars_t *pev ) -{ - if( pev->targetname ) - return WriteFields( STRING( pev->targetname ), pname, pev, gEntvarsDescription, ENTVARS_COUNT ); - return WriteFields( STRING( pev->classname ), pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - -int CSave :: WriteFields( const char *cname, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - int i, j, actualCount, emptyCount; - int entityArray[MAX_ENTITYARRAY]; - TYPEDESCRIPTION *pTest; - -#if 0 - ALERT( at_console, "CSave::WriteFields( %s [%i fields])\n", pname, fieldCount ); -#endif - // precalculate the number of empty fields - emptyCount = 0; - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pOutputData = ((char *)pBaseData + pFields[i].fieldOffset ); - if ( DataEmpty( (const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ) ) - emptyCount++; - } - - // Empty fields will not be written, write out the actual number of fields to be written - actualCount = fieldCount - emptyCount; - WriteInt( pname, &actualCount, 1 ); - - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pTest = &pFields[ i ]; - pOutputData = ((char *)pBaseData + pTest->fieldOffset ); - - // UNDONE: Must we do this twice? - if( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] )) - continue; - - switch( pTest->fieldType ) - { - case FIELD_FLOAT: - WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_DOUBLE: - WriteDouble( pTest->fieldName, (double *)pOutputData, pTest->fieldSize ); - break; - case FIELD_TIME: - WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - WriteString( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - case FIELD_CLASSPTR: - case FIELD_EVARS: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_EHANDLE: - if( pTest->fieldSize > MAX_ENTITYARRAY ) - ALERT( at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITYARRAY ); - for( j = 0; j < pTest->fieldSize; j++ ) - { - switch( pTest->fieldType ) - { - case FIELD_EVARS: - entityArray[j] = EntityIndex( ((entvars_t **)pOutputData)[j] ); - break; - case FIELD_CLASSPTR: - entityArray[j] = EntityIndex( ((CBaseEntity **)pOutputData)[j] ); - break; - case FIELD_EDICT: - entityArray[j] = EntityIndex( ((edict_t **)pOutputData)[j] ); - break; - case FIELD_ENTITY: - entityArray[j] = EntityIndex( ((EOFFSET *)pOutputData)[j] ); - break; - case FIELD_EHANDLE: - entityArray[j] = EntityIndex( (CBaseEntity *)(((EHANDLE *)pOutputData)[j]) ); - break; - } - } - WriteInt( pTest->fieldName, entityArray, pTest->fieldSize ); - break; - case FIELD_POSITION_VECTOR: - WritePositionVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_VECTOR: - WriteVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_RANGE: - WriteRange( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_BOOLEAN: - case FIELD_INTEGER: - WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - case FIELD_INTEGER64: - WriteInt64( pTest->fieldName, (int64 *)pOutputData, pTest->fieldSize ); - break; - case FIELD_SHORT: - WriteData( pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData) ); - break; - case FIELD_CHARACTER: - WriteData( pTest->fieldName, pTest->fieldSize, ((char *)pOutputData) ); - break; - // For now, just write the address out, we're not going to change memory while doing this yet! - case FIELD_POINTER: - WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); - break; - case FIELD_FUNCTION: - WriteFunction( cname, pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); - break; - default: - ALERT( at_error, "Bad field type\n" ); - break; - } - } - - return 1; -} - - -void CSave :: BufferString( char *pdata, int len ) -{ - char c = 0; - - BufferData( pdata, len ); // Write the string - BufferData( &c, 1 ); // Write a null terminator -} - - -int CSave :: DataEmpty( const char *pdata, int size ) -{ - for( int i = 0; i < size; i++ ) - { - if( pdata[i] ) - return 0; - } - return 1; -} - - -void CSave :: BufferField( const char *pname, int size, const char *pdata ) -{ - BufferHeader( pname, size ); - BufferData( pdata, size ); -} - -void CSave :: BufferHeader( const char *pname, int size ) -{ - short hashvalue = TokenHash( pname ); - if( size > 1<<( sizeof( short ) * 8 )) - ALERT( at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!" ); - BufferData( (const char *)&size, sizeof(short) ); - BufferData( (const char *)&hashvalue, sizeof(short) ); -} - -void CSave :: BufferData( const char *pdata, int size ) -{ - if( !m_pdata ) - return; - - if( m_pdata->size + size > m_pdata->bufferSize ) - { - ALERT( at_error, "Save/Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - memcpy( m_pdata->pCurrentData, pdata, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - -// -------------------------------------------------------------- -// -// CRestore -// -// -------------------------------------------------------------- - -int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ) -{ - int i, j, stringCount, fieldNumber, entityIndex; - TYPEDESCRIPTION *pTest; - float time, timeData; - Vector position; - edict_t *pent; - char *pString; - - time = 0; - position = Vector( 0, 0, 0 ); - - if( m_pdata ) - { - time = m_pdata->time; - if ( m_pdata->fUseLandmark ) - position = m_pdata->vecLandmarkOffset; - } - - for( i = 0; i < fieldCount; i++ ) - { - fieldNumber = (i + startField) % fieldCount; - pTest = &pFields[fieldNumber]; - if( !FStriCmp( pTest->fieldName, pName )) - { - if( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL) ) - { - for ( j = 0; j < pTest->fieldSize; j++ ) - { - void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j*gSizes[pTest->fieldType]) ); - void *pInputData = (char *)pData + j * gSizes[pTest->fieldType]; - - switch( pTest->fieldType ) - { - case FIELD_TIME: - timeData = *(float *)pInputData; - // re-base time variables - timeData += time; - *((float *)pOutputData) = timeData; - break; - case FIELD_FLOAT: - *((float *)pOutputData) = *(float *)pInputData; - break; - case FIELD_DOUBLE: - *((double *)pOutputData) = *(double *)pInputData; - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - // skip over j strings - pString = (char *)pData; - for ( stringCount = 0; stringCount < j; stringCount++ ) - { - while( *pString ) - pString++; - pString++; - } - pInputData = pString; - if( strlen((char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; - else - { - int string; - - string = ALLOC_STRING( (char *)pInputData ); - - *((int *)pOutputData) = string; - - if ( !FStringNull( string ) && m_precache ) - { - if ( pTest->fieldType == FIELD_MODELNAME ) - UTIL_PrecacheModel( string ); - else if ( pTest->fieldType == FIELD_SOUNDNAME ) - UTIL_PrecacheSound( string ); - } - } - break; - case FIELD_EVARS: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) *((entvars_t **)pOutputData) = VARS(pent); - else *((entvars_t **)pOutputData) = NULL; - break; - case FIELD_CLASSPTR: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); - else - { - *((CBaseEntity **)pOutputData) = NULL; - if( entityIndex != -1 ) - ALERT( at_console, "## Restore: invalid entitynum %d\n", entityIndex ); - } - break; - case FIELD_EDICT: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - *((edict_t **)pOutputData) = pent; - break; - case FIELD_EHANDLE: - // Input and Output sizes are different! - pOutputData = (char *)pOutputData + j*(sizeof(EHANDLE) - gSizes[pTest->fieldType]); - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if( pent ) *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); - else *((EHANDLE *)pOutputData) = NULL; - break; - case FIELD_ENTITY: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) *((EOFFSET *)pOutputData) = OFFSET( pent ); - else *((EOFFSET *)pOutputData) = 0; - break; - case FIELD_RANGE: - ((float *)pOutputData)[0] = ((float *)pInputData)[0]; - ((float *)pOutputData)[1] = ((float *)pInputData)[1]; - break; - case FIELD_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0]; - ((float *)pOutputData)[1] = ((float *)pInputData)[1]; - ((float *)pOutputData)[2] = ((float *)pInputData)[2]; - break; - case FIELD_POSITION_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; - ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; - ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; - break; - case FIELD_BOOLEAN: - case FIELD_INTEGER: - *((int *)pOutputData) = *( int *)pInputData; - break; - case FIELD_INTEGER64: - *((int64 *)pOutputData) = *( int64 *)pInputData; - break; - case FIELD_SHORT: - *((short *)pOutputData) = *( short *)pInputData; - break; - case FIELD_CHARACTER: - *((char *)pOutputData) = *( char *)pInputData; - break; - case FIELD_POINTER: - *((int *)pOutputData) = *( int *)pInputData; - break; - case FIELD_FUNCTION: - if( !strlen( (char *)pInputData )) - *((int *)pOutputData) = 0; - else *((int *)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); - break; - default: - ALERT( at_error, "Bad field type\n" ); - break; - } - } - } -#if 0 - else ALERT( at_console, "Skipping global field %s\n", pName ); -#endif - return fieldNumber; - } - } - return -1; -} - -int CRestore::ReadEntVars( const char *pname, entvars_t *pev ) -{ - return ReadFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - -int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - unsigned short i, token; - int lastField, fileCount; - HEADER header; - - i = ReadShort(); - ASSERT( i == sizeof( int )); // First entry should be an int - - token = ReadShort(); - - // Check the struct name - if( token != TokenHash( pname )) // Field Set marker - { - ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); - BufferRewind( 2 * sizeof( short )); - return 0; - } -#if 0 - ALERT( at_console, "CRestore:ReadFields: %s\n", pname ); -#endif - // Skip over the struct name - fileCount = ReadInt(); // Read field count - - lastField = 0; // Make searches faster, most data is read/written in the same order - - // clear out base data - for( i = 0; i < fieldCount; i++ ) - { - // Don't clear global fields - if ( !m_global || !(pFields[i].flags & FTYPEDESC_GLOBAL) ) - memset( ((char *)pBaseData + pFields[i].fieldOffset), 0, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ); - } - for ( i = 0; i < fileCount; i++ ) - { - BufferReadHeader( &header ); - lastField = ReadField( pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData ); - lastField++; - } - - return 1; -} - - -void CRestore::BufferReadHeader( HEADER *pheader ) -{ - ASSERT( pheader!=NULL ); - pheader->size = ReadShort(); // Read field size - pheader->token = ReadShort(); // Read field name token - pheader->pData = BufferPointer(); // Field Data is next - BufferSkipBytes( pheader->size ); // Advance to next field -} - - -short CRestore::ReadShort( void ) -{ - short tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(short) ); - - return tmp; -} - -int CRestore::ReadInt( void ) -{ - int tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(int) ); - - return tmp; -} - -int CRestore::ReadNamedInt( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); - return ((int *)header.pData)[0]; -} - -char *CRestore::ReadNamedString( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); -#ifdef TOKENIZE - return (char *)(m_pdata->pTokens[*(short *)header.pData]); -#else - return (char *)header.pData; -#endif -} - - -char *CRestore::BufferPointer( void ) -{ - if ( !m_pdata ) - return NULL; - - return m_pdata->pCurrentData; -} - -void CRestore::BufferReadBytes( char *pOutput, int size ) -{ - ASSERT( m_pdata !=NULL ); - - if ( !m_pdata || Empty() ) - return; - - if ( (m_pdata->size + size) > m_pdata->bufferSize ) - { - ALERT( at_error, "Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - if ( pOutput ) - memcpy( pOutput, m_pdata->pCurrentData, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - - -void CRestore::BufferSkipBytes( int bytes ) -{ - BufferReadBytes( NULL, bytes ); -} - -int CRestore::BufferSkipZString( void ) -{ - char *pszSearch; - int len; - - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - - len = 0; - pszSearch = m_pdata->pCurrentData; - while ( *pszSearch++ && len < maxLen ) - len++; - - len++; - - BufferSkipBytes( len ); - - return len; -} - -int CRestore::BufferCheckZString( const char *string ) -{ - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - int len = strlen( string ); - if ( len <= maxLen ) - { - if ( !strncmp( string, m_pdata->pCurrentData, len ) ) - return 1; - } - return 0; -} - - -//======================================================================= -// global entity states -//======================================================================= -CGlobalState::CGlobalState( void ) -{ - Reset(); -} - -void CGlobalState::Reset( void ) -{ - m_pList = NULL; - m_listCount = 0; -} - -globalentity_t *CGlobalState :: Find( string_t globalname ) -{ - if ( !globalname ) - return NULL; - - globalentity_t *pTest; - const char *pEntityName = STRING(globalname); - - - pTest = m_pList; - while ( pTest ) - { - if ( FStrEq( pEntityName, pTest->name ) ) - break; - - pTest = pTest->pNext; - } - - return pTest; -} - -void CGlobalState :: DumpGlobals( void ) -{ - static char *estates[] = { "Off", "On", "Dead" }; - globalentity_t *pTest; - - ALERT( at_console, "-- Globals --\n" ); - pTest = m_pList; - while ( pTest ) - { - Msg( "%s: %s (%s)\n", pTest->name, pTest->levelName, estates[pTest->state] ); - pTest = pTest->pNext; - } -} - -void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) -{ - ASSERT( !Find(globalname) ); - - globalentity_t *pNewEntity = (globalentity_t *)CALLOC( sizeof( globalentity_t ), 1 ); - ASSERT( pNewEntity != NULL ); - pNewEntity->pNext = m_pList; - m_pList = pNewEntity; - strcpy( pNewEntity->name, STRING( globalname ) ); - strcpy( pNewEntity->levelName, STRING(mapName) ); - pNewEntity->state = state; - m_listCount++; -} - - -void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) -{ - globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) pEnt->state = state; -} - - -const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - return pEnt; -} - - -GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) return pEnt->state; - - return GLOBAL_OFF; -} - -TYPEDESCRIPTION CGlobalState::m_SaveData[] = -{ - DEFINE_FIELD( CGlobalState, m_listCount, FIELD_INTEGER ), -}; - -TYPEDESCRIPTION gGlobalEntitySaveData[] = -{ - DEFINE_ARRAY( globalentity_t, name, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( globalentity_t, levelName, FIELD_CHARACTER, 32 ), - DEFINE_FIELD( globalentity_t, state, FIELD_INTEGER ), -}; - - -int CGlobalState::Save( CSave &save ) -{ - int i; - globalentity_t *pEntity; - - if ( !save.WriteFields( "cGLOBAL", "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) - return 0; - - pEntity = m_pList; - for ( i = 0; i < m_listCount && pEntity; i++ ) - { - if ( !save.WriteFields( "cGENT", "GENT", pEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - - pEntity = pEntity->pNext; - } - - return 1; -} - -int CGlobalState::Restore( CRestore &restore ) -{ - int i, listCount; - globalentity_t tmpEntity; - - ClearStates(); - if ( !restore.ReadFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) return 0; - - listCount = m_listCount; // Get new list count - m_listCount = 0; // Clear loaded data - - for ( i = 0; i < listCount; i++ ) - { - if ( !restore.ReadFields( "GENT", &tmpEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - EntityAdd( MAKE_STRING(tmpEntity.name), MAKE_STRING(tmpEntity.levelName), tmpEntity.state ); - } - return 1; -} - -void CGlobalState::EntityUpdate( string_t globalname, string_t mapname ) -{ - globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) strcpy( pEnt->levelName, STRING(mapname) ); -} - - -void CGlobalState::ClearStates( void ) -{ - globalentity_t *pFree = m_pList; - while ( pFree ) - { - globalentity_t *pNext = pFree->pNext; - FREE( pFree ); - pFree = pNext; - } - Reset(); -} - - -void SaveGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CSave saveHelper( pSaveData ); - gGlobalState.Save( saveHelper ); -} - - -void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CRestore restoreHelper( pSaveData ); - gGlobalState.Restore( restoreHelper ); -} - - -void ResetGlobalState( void ) -{ - gGlobalState.ClearStates(); - gInitHUD = TRUE; // Init the HUD on a new game / load game -} \ No newline at end of file diff --git a/server/global/saverestore.h b/server/global/saverestore.h deleted file mode 100644 index 6ac2daa6..00000000 --- a/server/global/saverestore.h +++ /dev/null @@ -1,167 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= -#ifndef SAVERESTORE_H -#define SAVERESTORE_H - -class CBaseEntity; - -class CSaveRestoreBuffer -{ -public: - CSaveRestoreBuffer( void ); - CSaveRestoreBuffer( SAVERESTOREDATA *pdata ); - ~CSaveRestoreBuffer( void ); - - int EntityIndex( entvars_t *pevLookup ); - int EntityIndex( edict_t *pentLookup ); - int EntityIndex( EOFFSET eoLookup ); - int EntityIndex( CBaseEntity *pEntity ); - - int EntityFlags( int entityIndex, int flags ) { return EntityFlagsSet( entityIndex, 0 ); } - int EntityFlagsSet( int entityIndex, int flags ); - - edict_t *EntityFromIndex( int entityIndex ); - - unsigned short TokenHash( const char *pszToken ); - -protected: - SAVERESTOREDATA *m_pdata; - void BufferRewind( int size ); - unsigned int HashString( const char *pszToken ); -}; - - -class CSave : public CSaveRestoreBuffer -{ -public: - CSave( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) {}; - - void WriteShort( const char *pname, const short *value, int count ); - void WriteInt( const char *pname, const int *value, int count ); // Save an int - void WriteInt64( const char *pname, const int64 *value, int count ); // Save an int64 - void WriteFloat( const char *pname, const float *value, int count ); // Save a float - void WriteDouble( const char *pname, const double *value, int count ); // Save a double - void WriteTime( const char *pname, const float *value, int count ); // Save a float (timevalue) - void WriteData( const char *pname, int size, const char *pdata ); // Save a binary data block - void WriteString( const char *pname, const char *pstring ); // Save a null-terminated string - void WriteString( const char *pname, const int *stringId, int count ); // Save a null-terminated string (engine string) - void WriteRange( const char *pname, const RandomRange &value ); - void WriteRange( const char *pname, const float *value, int count ); - void WriteVector( const char *pname, const Vector &value ); // Save a vector - void WriteVector( const char *pname, const float *value, int count ); // Save a vector - void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary - void WritePositionVector( const char *pname, const float *value, int count ); // array of pos vectors - void WriteFunction( const char *pname, const int *value, int count ); // Save a function pointer - // Save a function pointer. (LRC- also pass the classname to allow better error messages) - void WriteFunction( const char* cname, const char *pname, const int *value, int count ); - - int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) - int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); - int WriteFields( const char *cname, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); - -private: - int DataEmpty( const char *pdata, int size ); - void BufferField( const char *pname, int size, const char *pdata ); - void BufferString( char *pdata, int len ); - void BufferData( const char *pdata, int size ); - void BufferHeader( const char *pname, int size ); -}; - -typedef struct -{ - unsigned short size; - unsigned short token; - char *pData; -} HEADER; - -class CRestore : public CSaveRestoreBuffer -{ -public: - CRestore( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) { m_global = 0; m_precache = TRUE; } - - int ReadEntVars( const char *pname, entvars_t *pev ); // entvars_t - int ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); - int ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ); - int ReadInt( void ); - short ReadShort( void ); - int ReadNamedInt( const char *pName ); - char *ReadNamedString( const char *pName ); - int Empty( void ) { return (m_pdata == NULL) || ((m_pdata->pCurrentData-m_pdata->pBaseData)>=m_pdata->bufferSize); } - inline void SetGlobalMode( int global ) { m_global = global; } - void PrecacheMode( BOOL mode ) { m_precache = mode; } - -private: - char *BufferPointer( void ); - void BufferReadBytes( char *pOutput, int size ); - void BufferSkipBytes( int bytes ); - int BufferSkipZString( void ); - int BufferCheckZString( const char *string ); - - void BufferReadHeader( HEADER *pheader ); - - int m_global; // Restoring a global entity? - BOOL m_precache; -}; - -#define MAX_ENTITYARRAY 64 - -//#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) - -#define IMPLEMENT_SAVERESTORE(derivedClass,baseClass) \ - int derivedClass::Save( CSave &save )\ - {\ - if ( !baseClass::Save(save) )\ - return 0;\ - if (pev->targetname)\ - return save.WriteFields( STRING(pev->targetname), #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ - else\ - return save.WriteFields( STRING(pev->classname), #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ - }\ - int derivedClass::Restore( CRestore &restore )\ - {\ - if ( !baseClass::Restore(restore) )\ - return 0;\ - return restore.ReadFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ - } - - -typedef struct globalentity_s globalentity_t; - -struct globalentity_s -{ - char name[64]; - char levelName[32]; - GLOBALESTATE state; - globalentity_t *pNext; -}; - -class CGlobalState -{ -public: - CGlobalState(); - void Reset( void ); - void ClearStates( void ); - void EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ); - void EntitySetState( string_t globalname, GLOBALESTATE state ); - void EntityUpdate( string_t globalname, string_t mapname ); - const globalentity_t *EntityFromTable( string_t globalname ); - GLOBALESTATE EntityGetState( string_t globalname ); - int EntityInTable( string_t globalname ) { return (Find( globalname ) != NULL) ? 1 : 0; } - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -//#ifdef _DEBUG - void DumpGlobals( void ); -//#endif - -private: - globalentity_t *Find( string_t globalname ); - globalentity_t *m_pList; - int m_listCount; -}; - -extern CGlobalState gGlobalState; - -#endif //SAVERESTORE_H diff --git a/server/global/sfx.cpp b/server/global/sfx.cpp deleted file mode 100644 index 38319730..00000000 --- a/server/global/sfx.cpp +++ /dev/null @@ -1,150 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// sfx.cpp - different type special effects -// e.g. explodes, sparks, smoke e.t.c -//======================================================================= - -#include "sfx.h" -#include "client.h" - -void SFX_Explode( short model, Vector origin, float scale, int flags ) -{ - MESSAGE_BEGIN( MSG_PAS, gmsg.TempEntity, origin ); - WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound - WRITE_COORD( origin.x ); // Send to PAS because of the sound - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_SHORT( model ); - WRITE_BYTE( (byte)(scale - 30) * 0.7); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( flags ); - MESSAGE_END(); -} - -void SFX_Trail( int entindex, short model, Vector color, float life ) -{ - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT( entindex ); // entity - WRITE_SHORT( model ); // model - WRITE_BYTE( life ); // life - WRITE_BYTE( 5 ); // width - WRITE_BYTE( color.x ); // r, g, b - WRITE_BYTE( color.y ); // r, g, b - WRITE_BYTE( color.z ); // r, g, b - WRITE_BYTE( 200 ); // brightness - MESSAGE_END();// move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - -} - -void SFX_MakeGibs( int shards, Vector pos, Vector size, Vector velocity, float time, int flags) -{ - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, pos ); - WRITE_BYTE( TE_BREAKMODEL); - WRITE_COORD( pos.x ); // position - WRITE_COORD( pos.y ); - WRITE_COORD( pos.z ); - WRITE_COORD( size.x); // size - WRITE_COORD( size.y); - WRITE_COORD( size.z); - WRITE_COORD( velocity.x ); // velocity - WRITE_COORD( velocity.y ); - WRITE_COORD( velocity.z ); - WRITE_BYTE( 10 ); - WRITE_SHORT( shards ); // model id# - WRITE_BYTE( 0 ); // let client decide - WRITE_BYTE( time ); // life time - WRITE_BYTE( flags ); - MESSAGE_END(); -} - -void SFX_EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) -{ - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, vecOrigin ); - WRITE_BYTE( TE_MODEL); - WRITE_COORD( vecOrigin.x); - WRITE_COORD( vecOrigin.y); - WRITE_COORD( vecOrigin.z); - WRITE_COORD( vecVelocity.x); - WRITE_COORD( vecVelocity.y); - WRITE_COORD( vecVelocity.z); - WRITE_ANGLE( rotation ); - WRITE_SHORT( model ); - WRITE_BYTE ( soundtype); - WRITE_BYTE ( 25 );// 2.5 seconds - MESSAGE_END(); -} - -void SFX_Decal( const Vector &vecOrigin, int decalIndex, int entityIndex, int modelIndex ) -{ - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity); - WRITE_BYTE( TE_BSPDECAL ); - WRITE_COORD( vecOrigin.x ); - WRITE_COORD( vecOrigin.y ); - WRITE_COORD( vecOrigin.z ); - WRITE_SHORT( decalIndex ); - WRITE_SHORT( entityIndex ); - if ( entityIndex ) WRITE_SHORT( modelIndex ); - MESSAGE_END(); -} - -void SFX_Light ( entvars_t *pev, float iTime, float decay, int attachment ) -{ - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, pev->origin ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( ENTINDEX( ENT(pev) ) + 0x1000 * attachment );// entity, attachment - WRITE_COORD( pev->origin.x ); // X - WRITE_COORD( pev->origin.y ); // Y - WRITE_COORD( pev->origin.z ); // Z - WRITE_COORD( pev->renderamt ); // radius * 0.1 - WRITE_BYTE( pev->rendercolor.x ); // r - WRITE_BYTE( pev->rendercolor.y ); // g - WRITE_BYTE( pev->rendercolor.z ); // b - WRITE_BYTE( iTime ); // time * 10 - WRITE_COORD( decay ); // decay * 0.1 - MESSAGE_END( ); -} - -void SFX_Zap ( entvars_t *pev, const Vector &vecSrc, const Vector &vecDest ) -{ - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD(vecSrc.x); - WRITE_COORD(vecSrc.y); - WRITE_COORD(vecSrc.z); - WRITE_COORD(vecDest.x); - WRITE_COORD(vecDest.y); - WRITE_COORD(vecDest.z); - WRITE_SHORT( pev->team ); - WRITE_BYTE( 0 ); //framestart - WRITE_BYTE( (int)pev->framerate); // framerate - WRITE_BYTE( (int)(pev->armorvalue*10.0) ); // life - WRITE_BYTE( pev->button ); // width - WRITE_BYTE( pev->impulse ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( pev->renderamt ); // brightness - WRITE_BYTE( pev->speed ); // speed - MESSAGE_END(); -} - -void SFX_Ring ( entvars_t *pev, entvars_t *pev2 ) -{ - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_BEAMRING ); - WRITE_SHORT( ENTINDEX(ENT(pev)) ); - WRITE_SHORT( ENTINDEX(ENT(pev2)) ); - WRITE_SHORT( pev->team ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 20 ); // framerate - WRITE_BYTE( (int)(pev->armorvalue*10) ); // life - WRITE_BYTE( pev->button ); // width - WRITE_BYTE( pev->impulse ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( pev->renderamt ); // brightness - WRITE_BYTE( pev->speed ); // speed - MESSAGE_END(); -} \ No newline at end of file diff --git a/server/global/sfx.h b/server/global/sfx.h deleted file mode 100644 index 5cd68e12..00000000 --- a/server/global/sfx.h +++ /dev/null @@ -1,27 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2004 -// sfx.h - different type special effects -// e.g. explodes, sparks, smoke e.t.c -//======================================================================= -#ifndef SFX_H -#define SFX_H - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "baseweapon.h" -#include "player.h" -#include "defaults.h" -#include "shake.h" -#include "basebeams.h" - -void SFX_Explode( short model, Vector origin, float scale, int flags = 0 ); -void SFX_Trail( int entindex, short model, Vector color = Vector(200, 200, 200), float life = 30); -void SFX_MakeGibs( int shards, Vector pos, Vector size, Vector velocity, float time = 25, int flags = 0); -void SFX_EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ); -void SFX_Decal( const Vector &vecOrigin, int decalIndex, int entityIndex, int modelIndex ); -void SFX_Light ( entvars_t *pev, float iTime, float decay, int attachment = 0 ); -void SFX_Zap ( entvars_t *pev, const Vector &vecSrc, const Vector &vecDest ); -void SFX_Ring ( entvars_t *pev, entvars_t *pev2 ); - -#endif //SFX_H \ No newline at end of file diff --git a/server/global/soundent.h b/server/global/soundent.h deleted file mode 100644 index 40aaf59e..00000000 --- a/server/global/soundent.h +++ /dev/null @@ -1,99 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Soundent.h - the entity that spawns when the world -// spawns, and handles the world's active and free sound -// lists. -//========================================================= -#ifndef SOUNDENT_H -#define SOUNDENT_H - -#define MAX_WORLD_SOUNDS 64 // maximum number of sounds handled by the world at one time. - -#define bits_SOUND_NONE 0 -#define bits_SOUND_COMBAT ( 1 << 0 )// gunshots, explosions -#define bits_SOUND_WORLD ( 1 << 1 )// door opening/closing, glass breaking -#define bits_SOUND_PLAYER ( 1 << 2 )// all noises generated by player. walking, shooting, falling, splashing -#define bits_SOUND_CARCASS ( 1 << 3 )// dead body -#define bits_SOUND_MEAT ( 1 << 4 )// gib or pork chop -#define bits_SOUND_DANGER ( 1 << 5 )// pending danger. Grenade that is about to explode, explosive barrel that is damaged, falling crate -#define bits_SOUND_GARBAGE ( 1 << 6 )// trash cans, banana peels, old fast food bags. - -#define bits_ALL_SOUNDS 0xFFFFFFFF - -#define SOUNDLIST_EMPTY -1 - -#define SOUNDLISTTYPE_FREE 1// identifiers passed to functions that can operate on either list, to indicate which list to operate on. -#define SOUNDLISTTYPE_ACTIVE 2 - -#define SOUND_NEVER_EXPIRE -1 // with this set as a sound's ExpireTime, the sound will never expire. - -//========================================================= -// CSound - an instance of a sound in the world. -//========================================================= -class CSound -{ -public: - - void Clear ( void ); - void Reset ( void ); - - Vector m_vecOrigin; // sound's location in space - int m_iType; // what type of sound this is - int m_iVolume; // how loud the sound is - float m_flExpireTime; // when the sound should be purged from the list - int m_iNext; // index of next sound in this list ( Active or Free ) - int m_iNextAudible; // temporary link that monsters use to build a list of audible sounds - - BOOL FIsSound( void ); - BOOL FIsScent( void ); -}; - -//========================================================= -// CSoundEnt - a single instance of this entity spawns when -// the world spawns. The SoundEnt's job is to update the -// world's Free and Active sound lists. -//========================================================= -class CSoundEnt : public CBaseEntity -{ -public: - - void Precache ( void ); - void Spawn( void ); - void Think( void ); - void Initialize ( void ); - - static void InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ); - static void FreeSound ( int iSound, int iPrevious ); - static int ActiveList( void );// return the head of the active list - static int FreeList( void );// return the head of the free list - static CSound* SoundPointerForIndex( int iIndex );// return a pointer for this index in the sound list - static int ClientSoundIndex ( edict_t *pClient ); - - BOOL IsEmpty( void ) { return m_iActiveSound == SOUNDLIST_EMPTY; } - int ISoundsInList ( int iListType ); - int IAllocSound ( void ); - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - - int m_iFreeSound; // index of the first sound in the free sound list - int m_iActiveSound; // indes of the first sound in the active sound list - int m_cLastActiveSounds; // keeps track of the number of active sounds at the last update. (for diagnostic work) - BOOL m_fShowReport; // if true, dump information about free/active sounds. - -private: - CSound m_SoundPool[ MAX_WORLD_SOUNDS ]; -}; - -#endif //SOUNDENT_H \ No newline at end of file diff --git a/server/global/spectator.cpp b/server/global/spectator.cpp deleted file mode 100644 index 73b0c5b4..00000000 --- a/server/global/spectator.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// CBaseSpectator - -// YWB: UNDONE - -// Spectator functions -// -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "spectator.h" - -/* -=========== -SpectatorConnect - -called when a spectator connects to a server -============ -*/ -void CBaseSpectator::SpectatorConnect( void ) -{ - pev->flags = FL_SPECTATOR; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - m_pGoalEnt = NULL; -} - -/* -=========== -SpectatorDisconnect - -called when a spectator disconnects from a server -============ -*/ -void CBaseSpectator::SpectatorDisconnect( void ) -{ -} - -/* -================ -SpectatorImpulseCommand - -Called by SpectatorThink if the spectator entered an impulse -================ -*/ -void CBaseSpectator::SpectatorImpulseCommand( void ) -{ - static edict_t *pGoal = NULL; - edict_t *pPreviousGoal; - edict_t *pCurrentGoal; - BOOL bFound; - - switch( pev->impulse ) - { - case 1: - // teleport the spectator to the next spawn point - // note that if the spectator is tracking, this doesn't do - // much - pPreviousGoal = pGoal; - pCurrentGoal = pGoal; - // Start at the current goal, skip the world, and stop if we looped - // back around - - bFound = FALSE; - while( 1 ) - { - pCurrentGoal = FIND_ENTITY_BY_CLASSNAME( pCurrentGoal, "info_player_deathmatch" ); - // Looped around, failure - if( pCurrentGoal == pPreviousGoal ) - { - ALERT( at_console, "Could not find a spawn spot.\n" ); - break; - } - // found a non-world entity, set success, otherwise, look for the next one. - if( !FNullEnt( pCurrentGoal )) - { - bFound = TRUE; - break; - } - } - - if( !bFound ) // Didn't find a good spot. - break; - - pGoal = pCurrentGoal; - UTIL_SetOrigin( this, pGoal->v.origin ); - pev->angles = pGoal->v.angles; - pev->fixangle = FALSE; - break; - default: - ALERT( at_console, "Unknown spectator impulse\n" ); - break; - } - pev->impulse = 0; -} - -/* -================ -SpectatorThink - -Called every frame after physics are run -================ -*/ -void CBaseSpectator::SpectatorThink( void ) -{ - if( !( pev->flags & FL_SPECTATOR )) - { - pev->flags = FL_SPECTATOR; - } - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - if( pev->impulse ) SpectatorImpulseCommand(); -} - -/* -=========== -Spawn - - Called when spectator is initialized: - UNDONE: Is this actually being called because spectators are not allocated in normal fashion? -============ -*/ -void CBaseSpectator::Spawn( void ) -{ - pev->flags = FL_SPECTATOR; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - m_pGoalEnt = NULL; -} \ No newline at end of file diff --git a/server/global/utils.cpp b/server/global/utils.cpp deleted file mode 100644 index db4957da..00000000 --- a/server/global/utils.cpp +++ /dev/null @@ -1,3112 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// utils.cpp - Utility code. -// Really not optional after all. -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "defaults.h" -#include "saverestore.h" -#include -#include "shake.h" -#include "decals.h" -#include "player.h" -#include "baseweapon.h" -#include "gamerules.h" -#include "client.h" - -FILE_GLOBAL char st_szNextMap[MAP_MAX_NAME]; -FILE_GLOBAL char st_szNextSpot[MAP_MAX_NAME]; -extern DLL_GLOBAL BOOL NewLevel; -int giAmmoIndex = 0; -BOOL CanAffect; - -static const float bytedirs[NUMVERTEXNORMALS][3] = -{ -#include "anorms.h" -}; - -//========================================================= -// COM_Functions (text files parsing) -//========================================================= -#define COM_Format(x) va_list szCommand; \ - static char value[1024]; \ - va_start( szCommand, x ); \ - vsprintf( value, x, szCommand ); \ - va_end( szCommand ); - -void Msg( char *message, ... ) -{ - COM_Format( message ); - g_engfuncs.pfnAlertMessage( at_console, "%s", value ); -} - -void DevMsg( char *message, ... ) -{ - COM_Format( message ); - g_engfuncs.pfnAlertMessage( at_aiconsole, "%s", value ); -} - -DLL_GLOBAL int DirToBits( const Vector dir ) -{ - int i, best = 0; - float d, bestd = 0; - BOOL normalized = FALSE; - - if( dir == g_vecZero ) - return NUMVERTEXNORMALS; - - if(( dir.x * dir.x + dir.y * dir.y + dir.z * dir.z ) == 1 ) - normalized = TRUE; - - for( i = 0; i < NUMVERTEXNORMALS; i++ ) - { - d = (dir.x * bytedirs[i][0] + dir.y * bytedirs[i][1] + dir.z * bytedirs[i][2] ); - if(( d == 1 ) && normalized ) - return i; - if( d > bestd ) - { - bestd = d; - best = i; - } - } - return best; -} - -char *COM_ParseToken( const char **data ) -{ - char *com_token = COM_Parse( data ); - - // debug -// ALERT( at_console, "ParseToken: %s\n", com_token ); - - return com_token; -} - -void COM_FreeFile( char *buffer ) -{ - if( buffer ) FREE_FILE( buffer ); -} - -//========================================================= -// check for null ents -//========================================================= - -inline BOOL FNullEnt(EOFFSET eoffset) { return eoffset == 0; } -inline BOOL FNullEnt(const edict_t* pent) { return pent == NULL || FNullEnt(OFFSET(pent)); } -inline BOOL FNullEnt(entvars_t* pev) { return pev == NULL || FNullEnt(OFFSET(pev)); } -inline BOOL FNullEnt( CBaseEntity *ent ) { return ent == NULL || FNullEnt( ent->edict()); } - -//========================================================= -// calculate brush model origin -//========================================================= -Vector VecBModelOrigin( entvars_t* pevBModel ) -{ - return (pevBModel->absmin + pevBModel->absmax) * 0.5; -} - -BOOL FClassnameIs(CBaseEntity *pEnt, const char* szClassname) -{ - return FStrEq(STRING(pEnt->pev->classname), szClassname); -} - -//======================================================================== -// UTIL_FireTargets - supported prefix "+", "-", "!", ">", "<", "?". -// supported also this and self pointers - e.g. "fadein(mywall)" -//======================================================================== -void UTIL_FireTargets( int targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - //overload version UTIL_FireTargets - if (!targetName) return;//no execute code, if target blank - - UTIL_FireTargets( STRING(targetName), pActivator, pCaller, useType, value); -} - -void UTIL_FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) -{ - - const char *inputTargetName = targetName; - CBaseEntity *inputActivator = pActivator; - CBaseEntity *pTarget = NULL; - int i,j, found = false; - char szBuf[80]; - - if ( !targetName ) return; - - // HACKHACK - if( FStrEq( targetName, "tr_endchange" )) - { - SERVER_COMMAND("game_over\n"); - return; - } - - if (targetName[0] == '+') - { - targetName++; - useType = USE_ON; - } - else if (targetName[0] == '-') - { - targetName++; - useType = USE_OFF; - } - else if (targetName[0] == '!') - { - targetName++; - useType = USE_REMOVE; - } - else if (targetName[0] == '<') - { - targetName++; - useType = USE_SET; - } - else if (targetName[0] == '>') - { - targetName++; - useType = USE_RESET; - } - else if (targetName[0] == '?') - { - targetName++; - useType = USE_SHOWINFO; - } - - pTarget = UTIL_FindEntityByTargetname(pTarget, targetName, pActivator); - - if( !pTarget )//smart field name ? - { - //try to extract value from name (it's more usefully than "locus" specifier) - for (i = 0; targetName[i]; i++) - { - if (targetName[i] == '.')//value specifier - { - value = atof(&targetName[i+1]); - sprintf(szBuf, targetName); - szBuf[i] = 0; - targetName = szBuf; - pTarget = UTIL_FindEntityByTargetname(NULL, targetName, inputActivator); - break; - } - } - if( !pTarget )//try to extract activator specified - { - for (i = 0; targetName[i]; i++) - { - if (targetName[i] == '(') - { - i++; - for (j = i; targetName[j]; j++) - { - if (targetName[j] == ')') - { - strncpy(szBuf, targetName+i, j-i); - szBuf[j-i] = 0; - pActivator = UTIL_FindEntityByTargetname(NULL, szBuf, inputActivator); - if (!pActivator) return; //it's a locus specifier, but the locus is invalid. - found = true; - break; - } - } - if (!found) ALERT(at_error, "Missing ')' in targetname: %s", inputTargetName); - break; - } - } - if (!found) return; // no, it's not a locus specifier. - - strncpy(szBuf, targetName, i-1); - szBuf[i-1] = 0; - targetName = szBuf; - pTarget = UTIL_FindEntityByTargetname(NULL, targetName, inputActivator); - - if( !pTarget ) return; // it's a locus specifier all right, but the target's invalid. - } - } - - ALERT( at_aiconsole, "Firing: (%s) with %s and value %g\n", targetName, GetStringForUseType( useType ), value ); - - do //start firing targets - { - if ( !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents - { - if (useType == USE_REMOVE) UTIL_Remove( pTarget ); - else pTarget->Use( pActivator, pCaller, useType, value ); - } - pTarget = UTIL_FindEntityByTargetname(pTarget, targetName, inputActivator); - - } while (pTarget); -} - -//========================================================= -// UTIL_StripToken - for redundant keynames -//========================================================= -void UTIL_StripToken( const char *pKey, char *pDest ) -{ - int i = 0; - - while ( pKey[i] && pKey[i] != '#' ) - { - pDest[i] = pKey[i]; - i++; - } - pDest[i] = 0; -} - - -char* GetStringForUseType( USE_TYPE useType ) -{ - switch(useType) - { - case USE_ON: return "USE_ON"; - case USE_OFF: return "USE_OFF"; - case USE_TOGGLE: return "USE_TOGGLE"; - case USE_REMOVE: return "USE_REMOVE"; - case USE_SET: return "USE_SET"; - case USE_RESET: return "USE_RESET"; - case USE_SHOWINFO: return "USE_SHOWINFO"; - default: - return "UNKNOWN USE_TYPE!"; - } -} - -char* GetStringForState( STATE state ) -{ - switch(state) - { - case STATE_ON: return "ON"; - case STATE_OFF: return "OFF"; - case STATE_TURN_ON: return "TURN ON"; - case STATE_TURN_OFF: return "TURN OFF"; - case STATE_IN_USE: return "IN USE"; - case STATE_DEAD: return "DEAD"; - default: - return "UNKNOWN STATE!"; - } -} - -char* GetStringForDecalName( int decalname ) -{ - char *name = ""; - int m_decal = UTIL_LoadDecalPreset( decalname ); - switch(m_decal) - { - case 1: name = gDecals[ DECAL_GUNSHOT1 + RANDOM_LONG(0,4)].name; break; - case 2: name = gDecals[ DECAL_BLOOD1 + RANDOM_LONG(0,5)].name; break; - case 3: name = gDecals[ DECAL_YBLOOD1 + RANDOM_LONG(0,5)].name; break; - case 4: name = gDecals[ DECAL_GLASSBREAK1 + RANDOM_LONG(0,2)].name; break; - case 5: name = gDecals[ DECAL_BIGSHOT1 + RANDOM_LONG(0,4)].name; break; - case 6: name = gDecals[ DECAL_SCORCH1 + RANDOM_LONG(0,1)].name; break; - case 7: name = gDecals[ DECAL_SPIT1 + RANDOM_LONG(0,1)].name; break; - default: name = (char *)STRING( decalname ); break; - } - return name; -} - -void PrintStringForDamage( int dmgbits ) -{ - char szDmgBits[256]; - strcat(szDmgBits, "DAMAGE: " ); - if( dmgbits & DMG_GENERIC) strcat(szDmgBits, "Generic " ); - if( dmgbits & DMG_CRUSH) strcat(szDmgBits, "Crush " ); - if( dmgbits & DMG_BULLET) strcat(szDmgBits, "Bullet " ); - if( dmgbits & DMG_SLASH) strcat(szDmgBits, "Slash " ); - if( dmgbits & DMG_BURN) strcat(szDmgBits, "Burn " ); - if( dmgbits & DMG_FREEZE) strcat(szDmgBits, "Freeze " ); - if( dmgbits & DMG_FALL) strcat(szDmgBits, "Fall " ); - if( dmgbits & DMG_BLAST) strcat(szDmgBits, "Blast " ); - if( dmgbits & DMG_CLUB) strcat(szDmgBits, "Club " ); - if( dmgbits & DMG_SHOCK) strcat(szDmgBits, "Shock " ); - if( dmgbits & DMG_SONIC) strcat(szDmgBits, "Sonic " ); - if( dmgbits & DMG_ENERGYBEAM) strcat(szDmgBits, "Energy Beam " ); - if( dmgbits & DMG_NEVERGIB) strcat(szDmgBits, "Never Gib " ); - if( dmgbits & DMG_ALWAYSGIB) strcat(szDmgBits, "Always Gib " ); - if( dmgbits & DMG_DROWN) strcat(szDmgBits, "Drown " ); - if( dmgbits & DMG_PARALYZE) strcat(szDmgBits, "Paralyze Gas " ); - if( dmgbits & DMG_NERVEGAS) strcat(szDmgBits, "Nerve Gas " ); - if( dmgbits & DMG_POISON) strcat(szDmgBits, "Poison " ); - if( dmgbits & DMG_RADIATION) strcat(szDmgBits, "Radiation " ); - if( dmgbits & DMG_DROWNRECOVER) strcat(szDmgBits, "Drown Recover " ); - if( dmgbits & DMG_ACID) strcat(szDmgBits, "Acid " ); - if( dmgbits & DMG_SLOWBURN) strcat(szDmgBits, "Slow Burn " ); - if( dmgbits & DMG_SLOWFREEZE) strcat(szDmgBits, "Slow Freeze " ); - if( dmgbits & DMG_MORTAR) strcat(szDmgBits, "Mortar " ); - if( dmgbits & DMG_NUCLEAR) strcat(szDmgBits, "Nuclear Explode " ); - Msg("%s\n", szDmgBits ); -} -char* GetContentsString( int contents ) -{ - switch( contents ) - { - case -1: return "EMPTY"; - case -2: return "SOLID"; - case -3: return "WATER"; - case -4: return "SLIME"; - case -5: return "LAVA"; - case -6: return "SKY"; - case -16: return "LADDER"; - case -17: return "FLYFIELD"; - case -18: return "GRAVITY_FLYFIELD"; - case -19: return "FOG"; - case -20: return "SPECIAL 1"; - case -21: return "SPECIAL 2"; - case -22: return "SPECIAL 3"; - default: return "NO CONTENTS!"; - } -} - -char* GetStringForGlobalState( GLOBALESTATE state ) -{ - switch(state) - { - case GLOBAL_ON: return "GLOBAL ON"; - case GLOBAL_OFF: return "GLOBAL OFF"; - case GLOBAL_DEAD: return "GLOBAL DEAD"; - default: - return "UNKNOWN STATE!"; - } -} - -void UTIL_Remove( CBaseEntity *pEntity ) -{ - if( !pEntity ) return; - - pEntity->UpdateOnRemove(); - pEntity->pev->flags |= FL_KILLME; - pEntity->pev->targetname = 0; - pEntity->pev->health = 0; -} - -void UTIL_AngularVector( CBaseEntity *pEnt ) -{ - Vector movedir; - - UTIL_MakeVectors( pEnt->pev->angles ); - movedir.z = fabs(gpGlobals->v_forward.x); - movedir.x = fabs(gpGlobals->v_forward.y); - movedir.y = fabs(gpGlobals->v_forward.z); - - pEnt->pev->movedir = movedir; - pEnt->pev->angles = g_vecZero; -} - -void UTIL_LinearVector( CBaseEntity *pEnt ) -{ - if( pEnt->pev->angles == Vector( 0, -1, 0 )) - { - pEnt->pev->movedir = Vector( 0, 0, 1 ); - } - else if( pEnt->pev->angles == Vector( 0, -2, 0 )) - { - pEnt->pev->movedir = Vector( 0, 0, -1); - } - else - { - UTIL_MakeVectors( pEnt->pev->angles ); - pEnt->pev->movedir = gpGlobals->v_forward; - } - pEnt->pev->angles = g_vecZero; -} - -Vector UTIL_GetAngleDistance( Vector vecAngles, float distance ) -{ - //set one length vector - if(vecAngles.x != 0) vecAngles.x = 1; - if(vecAngles.y != 0) vecAngles.y = 1; - if(vecAngles.z != 0) vecAngles.z = 1; - return vecAngles * distance; -} - -Vector UTIL_RandomVector(void) -{ - Vector out; - out.x = RANDOM_FLOAT(-1.0, 1.0); - out.y = RANDOM_FLOAT(-1.0, 1.0); - out.z = RANDOM_FLOAT(-1.0, 1.0); - return out; -} - -Vector UTIL_RandomVector( Vector vmin, Vector vmax ) -{ - Vector out; - out.x = RANDOM_FLOAT( vmin.x, vmax.x ); - out.y = RANDOM_FLOAT( vmin.y, vmax.y ); - out.z = RANDOM_FLOAT( vmin.z, vmax.z ); - return out; -} - -CBaseEntity *UTIL_FindGlobalEntity( string_t classname, string_t globalname ) -{ - CBaseEntity *pReturn = UTIL_FindEntityByString( NULL, "globalname", STRING(globalname) ); - if ( pReturn ) - { - if( !FClassnameIs( pReturn->pev, STRING( classname ))) - { - ALERT( at_console, "Global entity found %s, wrong class %s\n", STRING(globalname), STRING(pReturn->pev->classname) ); - pReturn = NULL; - } - } - - return pReturn; -} - -void UTIL_FindBreakable( CBaseEntity *Brush ) -{ - Vector mins = Brush->pev->absmin; - Vector maxs = Brush->pev->absmax; - mins.z = Brush->pev->absmax.z; - maxs.z += 8; - - CBaseEntity *pList[256]; - int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); - if ( count ) - { - for ( int i = 0; i < count; i++ ) - { - ClearBits( pList[i]->pev->flags, FL_ONGROUND ); - pList[i]->pev->groundentity = NULL; - } - } -} - -CBaseEntity *UTIL_FindEntityForward( CBaseEntity *pMe ) -{ - TraceResult tr; - - UTIL_MakeVectors( pMe->pev->v_angle ); - UTIL_TraceLine( pMe->pev->origin + pMe->pev->view_ofs, pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 8192, dont_ignore_monsters, pMe->edict(), &tr ); - if( tr.flFraction != 1.0 && !FNullEnt( tr.pHit )) - { - CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); - return pHit; - } - return NULL; -} - -void UTIL_FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ) -{ - int i, j, k; - float distance; - float *minmaxs[2] = {mins, maxs}; - TraceResult tmpTrace; - Vector vecHullEnd = tr.vecEndPos; - Vector vecEnd; - - distance = 1e6f; - - vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2); - UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if ( tmpTrace.flFraction < 1.0 ) - { - tr = tmpTrace; - return; - } - - for ( i = 0; i < 2; i++ ) - { - for ( j = 0; j < 2; j++ ) - { - for ( k = 0; k < 2; k++ ) - { - vecEnd.x = vecHullEnd.x + minmaxs[i][0]; - vecEnd.y = vecHullEnd.y + minmaxs[j][1]; - vecEnd.z = vecHullEnd.z + minmaxs[k][2]; - - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if ( tmpTrace.flFraction < 1.0 ) - { - float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length(); - if ( thisDistance < distance ) - { - tr = tmpTrace; - distance = thisDistance; - } - } - } - } - } -} - -edict_t *UTIL_FindLandmark( string_t iLandmarkName ) -{ - return UTIL_FindLandmark( STRING( iLandmarkName )); -} - -edict_t *UTIL_FindLandmark( const char *pLandmarkName ) -{ - CBaseEntity *pLandmark; - - if( FStringNull( pLandmarkName ) || FStrEq( pLandmarkName, "" )) - return NULL; // landmark not specified - - pLandmark = UTIL_FindEntityByTargetname( NULL, pLandmarkName ); - while( pLandmark ) - { - // Found the landmark - if( FClassnameIs( pLandmark->pev, "info_landmark" )) - return ENT( pLandmark->pev ); - else pLandmark = UTIL_FindEntityByTargetname( pLandmark, pLandmarkName ); - } - - Msg( "ERROR: Can't find landmark %s\n", pLandmarkName ); - return NULL; -} - -int UTIL_FindTransition( CBaseEntity *pEntity, string_t iVolumeName ) -{ - return UTIL_FindTransition( pEntity, STRING( iVolumeName )); -} - -int UTIL_FindTransition( CBaseEntity *pEntity, const char *pVolumeName ) -{ - CBaseEntity *pVolume; - - if( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) return 1; - - // if you're following another entity, follow it through the transition (weapons follow the player) - if( pEntity->pev->movetype == MOVETYPE_FOLLOW && pEntity->pev->aiment != NULL ) - { - pEntity = CBaseEntity::Instance( pEntity->pev->aiment ); - } - - int inVolume = 1; // Unless we find a trigger_transition, everything is in the volume - - pVolume = UTIL_FindEntityByTargetname( NULL, pVolumeName ); - while( pVolume ) - { - if( FClassnameIs( pVolume->pev, "trigger_transition" )) - { - if( pVolume->Intersects( pEntity )) // it touches one, it's in the volume - return 1; - else inVolume = 0; // found a trigger_transition, but I don't intersect it - } - pVolume = UTIL_FindEntityByTargetname( pVolume, pVolumeName ); - } - return inVolume; -} - -/* -======================================================================== - UTIL_FindClientTransitions - returns list of client attached entites - e.g. weapons, items and other followed entities -======================================================================== -*/ -edict_t *UTIL_FindClientTransitions( edict_t *pClient ) -{ - edict_t *pEdict, *chain; - int i; - - chain = NULL; - pClient->v.chain = chain; // client is always add to tail of chain - chain = pClient; - - if( !pClient || pClient->free ) - return chain; - - for( i = 0; i < gpGlobals->numEntities; i++ ) - { - pEdict = INDEXENT( i ); - if( pEdict->free ) continue; - if( pEdict->v.movetype == MOVETYPE_FOLLOW && pEdict->v.aiment == pClient ) - { - pEdict->v.chain = chain; - chain = pEdict; - } - } - return chain; -} -//======================================================================== -// UTIL_ChangeLevel - used for loading next level -//======================================================================== -void UTIL_ChangeLevel( string_t mapname, string_t spotname ) -{ - UTIL_ChangeLevel( STRING( mapname ), STRING( spotname )); -} - -void UTIL_ChangeLevel( const char *szNextMap, const char *szNextSpot ) -{ - edict_t *pentLandmark; - - ASSERT( !FStrEq( szNextMap, "" )); - - // don't work in deathmatch - if( IsMultiplayer()) return; - - // some people are firing these multiple times in a frame, disable - if( NewLevel ) return; - - CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 ); - if( !UTIL_FindTransition( pPlayer, szNextSpot )) - { - DevMsg( "Player isn't in the transition volume %s, aborting\n", szNextSpot ); - return; - } - - // this object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory - strcpy( st_szNextMap, szNextMap ); - st_szNextSpot[0] = 0; // Init landmark to NULL - - // look for a landmark entity - pentLandmark = UTIL_FindLandmark( szNextSpot ); - if( !FNullEnt( pentLandmark )) - { - strcpy( st_szNextSpot, szNextSpot ); - gpGlobals->vecLandmarkOffset = VARS( pentLandmark )->origin; - } - - // map must exist and contain info_player_start - if( IS_MAP_VALID( st_szNextMap )) - { - ALERT( at_aiconsole, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); - CHANGE_LEVEL( st_szNextMap, st_szNextSpot ); - } - else ALERT( at_warning, "map %s not found!\n", st_szNextMap ); - NewLevel = TRUE; // UTIL_ChangeLevel is called -} - -//======================================================================== -// Parent system utils -// Used for physics code too -//======================================================================== -void UTIL_MarkChild ( CBaseEntity *pEnt, BOOL correctSpeed, BOOL desired ) -{ - if(desired) //post affect - { - SetBits(pEnt->pFlags, PF_DESIRED); - if (CanAffect) - { //apply post affect now - PostFrameAffect( pEnt ); - return; - } - } - else - { - SetBits(pEnt->pFlags, PF_AFFECT); - - if (correctSpeed) - SetBits (pEnt->pFlags, PF_CORECTSPEED); - else ClearBits (pEnt->pFlags, PF_CORECTSPEED); - } - LinkChild( pEnt );//link children -} - -void UTIL_SetThink ( CBaseEntity *pEnt ) -{ - SetBits (pEnt->pFlags, PF_SETTHINK); - pEnt->DontThink(); - UTIL_MarkChild( pEnt ); -} - -void UTIL_SetPostAffect( CBaseEntity *pEnt ) -{ - SetBits(pEnt->pFlags, PF_POSTAFFECT); - UTIL_MarkChild( pEnt ); -} - -void UTIL_SetAction( CBaseEntity *pEnt ) -{ - SetBits(pEnt->pFlags, PF_ACTION); - UTIL_MarkChild( pEnt ); -} -//======================================================================== -// Assign origin and angles -//======================================================================== -void UTIL_AssignOrigin( CBaseEntity *pEntity, const Vector vecOrigin, BOOL bInitiator) -{ - Vector vecDiff = vecOrigin - pEntity->pev->origin; - - UTIL_SetOrigin(pEntity, vecOrigin ); - - if (bInitiator && pEntity->m_pParent) - { - pEntity->OffsetOrigin = pEntity->pev->origin - pEntity->m_pParent->pev->origin; - } - if (pEntity->m_pChild) - { - CBaseEntity* pChild = pEntity->m_pChild; - - Vector vecTemp; - while (pChild) - { - if (pChild->pev->movetype != MOVETYPE_PUSH || pChild->pev->velocity == pEntity->pev->velocity) - { - UTIL_AssignOrigin( pChild, vecOrigin + pChild->OffsetOrigin, FALSE ); - } - else - { - vecTemp = vecDiff + pChild->pev->origin; - UTIL_AssignOrigin( pChild, vecTemp, FALSE ); - } - pChild = pChild->m_pNextChild; - } - } -} -void UTIL_AssignAngles( CBaseEntity *pEntity, const Vector vecAngles, BOOL bInitiator) -{ - Vector vecDiff = vecAngles - pEntity->pev->angles; - - UTIL_SetAngles(pEntity, vecAngles); - - if (bInitiator && pEntity->m_pParent) - pEntity->OffsetAngles = vecAngles - pEntity->m_pParent->pev->angles; - - if (pEntity->m_pChild) // now I've moved pEntity, does anything else have to move with it? - { - CBaseEntity* pChild = pEntity->m_pChild; - Vector vecTemp; - while (pChild) - { - if (pChild->pev->avelocity == pEntity->pev->avelocity) - UTIL_AssignAngles( pChild, vecAngles + pChild->OffsetAngles, FALSE ); - else - { - vecTemp = vecDiff + pChild->pev->angles; - UTIL_AssignAngles( pChild, vecTemp, FALSE ); - } - pChild = pChild->m_pNextChild; - } - } -} - -//======================================================================== -// Set origin and angles -//======================================================================== -void UTIL_MergePos ( CBaseEntity *pEnt, int loopbreaker ) -{ - if (loopbreaker <= 0)return; - if (!pEnt->m_pParent)return; - - Vector forward, right, up, vecOrg, vecAngles; - - UTIL_MakeVectorsPrivate( pEnt->m_pParent->pev->angles, forward, right, up ); - - if(pEnt->m_pParent->pev->flags & FL_MONSTER) - vecOrg = pEnt->PostOrigin = pEnt->m_pParent->pev->origin + (forward * pEnt->OffsetOrigin.x) + ( right * pEnt->OffsetOrigin.y) + (up * pEnt->OffsetOrigin.z); - else vecOrg = pEnt->PostOrigin = pEnt->m_pParent->pev->origin + (forward * pEnt->OffsetOrigin.x) + (-right * pEnt->OffsetOrigin.y) + (up * pEnt->OffsetOrigin.z); - - vecAngles = pEnt->PostAngles = pEnt->m_pParent->pev->angles + pEnt->OffsetAngles; - SetBits(pEnt->pFlags, PF_POSTAFFECT | PF_DESIRED ); - - if ( pEnt->m_pChild ) - { - CBaseEntity *pMoving = pEnt->m_pChild; - int sloopbreaker = MAX_CHILDS; - while (pMoving) - { - UTIL_MergePos(pMoving, loopbreaker - 1 ); - pMoving = pMoving->m_pNextChild; - sloopbreaker--; - if (sloopbreaker <= 0)break; - } - } - - if(pEnt->pFlags & PF_MERGEPOS) - { - UTIL_AssignOrigin( pEnt, vecOrg ); - UTIL_AssignAngles( pEnt, vecAngles ); - ClearBits(pEnt->pFlags, PF_MERGEPOS); - } - if(pEnt->pFlags & PF_POSTORG) - { - pEnt->pev->origin = vecOrg; - pEnt->pev->angles = vecAngles; - } -} - -void UTIL_ComplexRotate( CBaseEntity *pParent, CBaseEntity *pChild, const Vector &dest, float m_flTravelTime ) -{ - float time = m_flTravelTime; - Vector vel = pParent->pev->velocity; - - // Attempt at getting the train to rotate properly around the origin of the trackchange - if ( time <= 0 ) return; - - Vector offset = pChild->pev->origin - pParent->pev->origin; - Vector delta = dest - pParent->pev->angles; - // Transform offset into local coordinates - UTIL_MakeInvVectors( delta, gpGlobals ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - local = local - offset; - pChild->pev->velocity = vel + (local * (1.0 / time)); - pChild->pev->avelocity = pParent->pev->avelocity; -} - -void UTIL_SetOrigin( CBaseEntity *pEntity, const Vector &vecOrigin ) -{ - SET_ORIGIN(ENT(pEntity->pev), vecOrigin ); -} - -void UTIL_SetAngles( CBaseEntity *pEntity, const Vector &vecAngles ) -{ - pEntity->pev->angles = vecAngles; -} - -void UTIL_SynchDoors( CBaseEntity *pEntity ) -{ - CBaseDoor *pDoor = NULL; - - if ( !FStringNull( pEntity->pev->targetname ) ) - { - while(1) - { - pDoor = (CBaseDoor *)UTIL_FindEntityByTargetname (pDoor, STRING(pEntity->pev->targetname)); - - if ( pDoor != pEntity ) - { - if (FNullEnt(pDoor)) break; - - if ( FClassnameIs ( pDoor, "func_door" ) && pDoor->m_flWait >= 0 ) - { - if (pDoor->pev->velocity == pEntity->pev->velocity) - { - UTIL_SetOrigin( pDoor, pEntity->pev->origin ); - UTIL_SetVelocity( pDoor, g_vecZero ); - } - if (pDoor->GetState() == STATE_TURN_ON) pDoor->DoorGoDown(); - else if (pDoor->GetState() == STATE_TURN_OFF) pDoor->DoorGoUp(); - } - if( FClassnameIs ( pDoor, "func_door_rotating" ) && pDoor->m_flWait >= 0 ) - { - if(pDoor->pev->avelocity == pEntity->pev->avelocity) - { - UTIL_SetAngles( pDoor, pEntity->pev->angles ); - UTIL_SetAvelocity( pDoor, g_vecZero ); - } - if (pDoor->GetState() == STATE_TURN_ON) pDoor->DoorGoDown(); - else if (pDoor->GetState() == STATE_TURN_OFF) pDoor->DoorGoUp(); - } - } - } - } -} - -//======================================================================== -// Set childs velocity and avelocity -//======================================================================== -void UTIL_SetChildVelocity ( CBaseEntity *pEnt, const Vector vecSet, int loopbreaker ) -{ - if (loopbreaker <= 0)return; - if (!pEnt->m_pParent)return; - - Vector vecNew; - vecNew = (pEnt->pev->velocity - pEnt->m_pParent->pev->velocity) + vecSet; - - if ( pEnt->m_pChild ) - { - CBaseEntity *pMoving = pEnt->m_pChild; - int sloopbreaker = MAX_CHILDS; - while (pMoving) - { - UTIL_SetChildVelocity(pMoving, vecNew, loopbreaker - 1 ); - pMoving = pMoving->m_pNextChild; - sloopbreaker--; - if (sloopbreaker <= 0)break; - } - } - pEnt->pev->velocity = vecNew; -} - -void UTIL_SetVelocity ( CBaseEntity *pEnt, const Vector vecSet ) -{ - Vector vecNew; - if (pEnt->m_pParent) - vecNew = vecSet + pEnt->m_pParent->pev->velocity; - else vecNew = vecSet; - - if ( pEnt->m_pChild ) - { - CBaseEntity *pMoving = pEnt->m_pChild; - int sloopbreaker = MAX_CHILDS; - while (pMoving) - { - UTIL_SetChildVelocity(pMoving, vecNew, MAX_CHILDS ); - if(vecSet != g_vecZero)SetBits(pMoving->pFlags, PF_PARENTMOVE); - else ClearBits(pMoving->pFlags, PF_PARENTMOVE); - - pMoving = pMoving->m_pNextChild; - sloopbreaker--; - if (sloopbreaker <= 0)break; - } - } - pEnt->pev->velocity = vecNew; -} - -void UTIL_SetChildAvelocity ( CBaseEntity *pEnt, const Vector vecSet, int loopbreaker ) -{ - if (loopbreaker <= 0)return; - if (!pEnt->m_pParent)return; - - Vector vecNew = (pEnt->pev->avelocity - pEnt->m_pParent->pev->avelocity) + vecSet; - - if ( pEnt->m_pChild ) - { - CBaseEntity *pMoving = pEnt->m_pChild; - int sloopbreaker = MAX_CHILDS; - while (pMoving) - { - UTIL_SetChildAvelocity(pMoving, vecNew, loopbreaker - 1 ); - pMoving = pMoving->m_pNextChild; - sloopbreaker--; - if (sloopbreaker <= 0)break; - } - } - - pEnt->pev->avelocity = vecNew; -} - -void UTIL_SetAvelocity ( CBaseEntity *pEnt, const Vector vecSet ) -{ - Vector vecNew; - - if (pEnt->m_pParent) - vecNew = vecSet + pEnt->m_pParent->pev->avelocity; - else vecNew = vecSet; - - if ( pEnt->m_pChild ) - { - CBaseEntity *pMoving = pEnt->m_pChild; - int sloopbreaker = MAX_CHILDS; - while (pMoving) - { - UTIL_SetChildAvelocity(pMoving, vecNew, MAX_CHILDS ); - UTIL_MergePos( pMoving ); - if(vecSet != g_vecZero)SetBits(pMoving->pFlags, PF_PARENTMOVE); - else ClearBits(pMoving->pFlags, PF_PARENTMOVE); - - pMoving = pMoving->m_pNextChild; - sloopbreaker--; - if (sloopbreaker <= 0)break; - } - } - pEnt->pev->avelocity = vecNew; -} - -//======================================================================== -// Precache and set resources - add check for present or invalid name -// NOTE: game will not crashed if model not specified, this code is legacy -//======================================================================== -void UTIL_SetModel( edict_t *e, string_t s, const char *c ) // set default model if not found -{ - if( FStringNull( s )) UTIL_SetModel( e, c ); - else UTIL_SetModel( e, s ); -} - -void UTIL_SetModel( edict_t *e, string_t model ) -{ - UTIL_SetModel( e, STRING( model )); -} - -void UTIL_SetModel( edict_t *e, const char *model ) -{ - if( !model || !*model ) - { - g_engfuncs.pfnSetModel( e, "models/common/null.mdl" ); - return; - } - - // is this brush model? - if( model[0] == '*' ) - { - g_engfuncs.pfnSetModel( e, model ); - return; - } - - // verify file exists - if( FILE_EXISTS( model )) - { - g_engfuncs.pfnSetModel( e, model ); - return; - } - - if( !strcmp( UTIL_FileExtension( model ), "mdl" )) - { - // this is model - g_engfuncs.pfnSetModel(e, "models/common/error.mdl" ); - } - else if( !strcmp( UTIL_FileExtension( model ), "spr" )) - { - // this is sprite - g_engfuncs.pfnSetModel( e, "sprites/error.spr" ); - } - else - { - // set null model - g_engfuncs.pfnSetModel( e, "models/common/null.mdl" ); - } -} - -int UTIL_PrecacheModel( string_t s, const char *e ) // precache default model if not found -{ - if( FStringNull( s )) - return UTIL_PrecacheModel( e ); - return UTIL_PrecacheModel( s ); -} - -int UTIL_PrecacheModel( string_t s ){ return UTIL_PrecacheModel( STRING( s )); } -int UTIL_PrecacheModel( const char* s ) -{ - if( FStringNull( s )) - { - // set null model - return g_sModelIndexNullModel; - } - - // no need to precache brush - if( s[0] == '*' ) return 0; - - if( FILE_EXISTS( s )) - { - return g_engfuncs.pfnPrecacheModel( s ); - } - - if( !strcmp( UTIL_FileExtension( s ), "mdl" )) - { - ALERT( at_warning, "model \"%s\" not found!\n", s ); - return g_sModelIndexErrorModel; - } - else if( !strcmp( UTIL_FileExtension( s ), "spr" )) - { - ALERT( at_warning, "sprite \"%s\" not found!\n", s ); - return g_sModelIndexErrorSprite; - } - else - { - ALERT( at_error, "invalid name \"%s\"!\n", s ); - return g_sModelIndexNullModel; - } -} - -//======================================================================== -// Precaches the ammo and queues the ammo info for sending to clients -//======================================================================== -void AddAmmoName( string_t iAmmoName ) -{ - // make sure it's not already in the registry - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - if( !CBasePlayerWeapon::AmmoInfoArray[i].iszName ) continue; - if( CBasePlayerWeapon::AmmoInfoArray[i].iszName == iAmmoName ) - return; // ammo already in registry, just quite - } - - giAmmoIndex++; - ASSERT( giAmmoIndex < MAX_AMMO_SLOTS ); - if( giAmmoIndex >= MAX_AMMO_SLOTS ) - giAmmoIndex = 0; - - CBasePlayerWeapon::AmmoInfoArray[giAmmoIndex].iszName = iAmmoName; - CBasePlayerWeapon::AmmoInfoArray[giAmmoIndex].iId = giAmmoIndex; // yes, this info is redundant -} - -//======================================================================== -// Precaches entity from other entity -//======================================================================== -void UTIL_PrecacheEntity( string_t szClassname ) { UTIL_PrecacheEntity( STRING( szClassname )); } -void UTIL_PrecacheEntity( const char *szClassname ) -{ - edict_t *pent; - int istr = ALLOC_STRING( szClassname ); - - pent = CREATE_NAMED_ENTITY( istr ); - if( FNullEnt( pent )) return; - - CBaseEntity *pEntity = CBaseEntity::Instance( VARS( pent )); - if( pEntity ) pEntity->Precache(); - REMOVE_ENTITY( pent ); -} - -//======================================================================== -// Precaches aurora particle and set it -//======================================================================== -int UTIL_PrecacheAurora( string_t s ) { return UTIL_PrecacheAurora( STRING( s )); } -int UTIL_PrecacheAurora( const char *s ) -{ - if ( !s || !*s ) - { - ALERT( at_console, "Warning: aurora not specified\n" ); - return MAKE_STRING( "scripts/aurora/error.aur" ); // assume error - } - - char path[256]; - - sprintf( path, "scripts/aurora/%s.aur", s ); - - char *token = NULL; - char *afile = (char *)LOAD_FILE( path, NULL ); - const char *pfile = afile; - - if( !afile ) - { - // verify file exists - ALERT( at_warning, "couldn't load %s\n", path ); - return MAKE_STRING( "scripts/aurora/error.aur" ); - } - - token = COM_ParseToken( &pfile ); - - while( token ) - { - if( !stricmp( token, "sprite" )) - { - token = COM_ParseToken( &pfile ); - UTIL_PrecacheModel( token ); - } - token = COM_ParseToken( &pfile ); - } - - FREE_FILE( afile ); - return MAKE_STRING( path ); -} - -void UTIL_SetAurora( CBaseEntity *pAttach, int aur, int attachment ) -{ - if( FNullEnt( pAttach )) return; - - MESSAGE_BEGIN( MSG_ALL, gmsg.Particle ); - WRITE_SHORT( pAttach->entindex() ); - WRITE_STRING( STRING( aur )); - MESSAGE_END(); -} - -//======================================================================== -// Precaches and play sound -//======================================================================== -int UTIL_PrecacheSound( string_t s, const char *e ) // precache default model if not found -{ - if (FStringNull( s )) - return UTIL_PrecacheSound( e ); - return UTIL_PrecacheSound( s ); -} -int UTIL_PrecacheSound( string_t s ){ return UTIL_PrecacheSound( STRING( s )); } -int UTIL_PrecacheSound( const char* s ) -{ - if( !s || !*s ) return MAKE_STRING( "common/null.wav" ); // set null sound - if( *s == '!' ) return MAKE_STRING( s ); // sentence - just make string - - char path[256]; - sprintf( path, "sound/%s", s ); - - // check file for existing - if( FILE_EXISTS( path )) - { - g_engfuncs.pfnPrecacheSound( s ); - return MAKE_STRING( s ); - } - - if( !strcmp( UTIL_FileExtension( s ), "wav" )) - { - // this is sound - ALERT( at_warning, "sound \"%s\" not found!\n", s ); - } - else if( !strcmp( UTIL_FileExtension( s ), "ogg" )) - { - // this is sound - ALERT( at_warning, "sound \"%s\" not found!\n", s ); - } - else - { - // unknown format - ALERT( at_error, "invalid name \"%s\"!\n", s ); - } - - g_engfuncs.pfnPrecacheSound("common/null.wav"); - return MAKE_STRING( "common/null.wav" ); -} - -int UTIL_LoadSoundPreset( string_t pString ) { return UTIL_LoadSoundPreset( STRING( pString )); } -int UTIL_LoadSoundPreset( const char *pString ) -{ - // try to load direct sound path - // so we supported 99 presets... - int m_sound, namelen = strlen( pString ) - 1; - - if( namelen > 2 ) // yes, it's sound path - m_sound = ALLOC_STRING( pString ); - else if( pString[0] == '!' ) // sentence - m_sound = ALLOC_STRING( pString ); - else m_sound = atoi( pString ); // no, it's preset - return m_sound; -} - -int UTIL_LoadDecalPreset( string_t pString ) { return UTIL_LoadDecalPreset( STRING( pString )); } -int UTIL_LoadDecalPreset( const char *pString ) -{ - // try to load direct sound path - // so we supported 9 decal groups... - int m_decal, namelen = strlen(pString) - 1; - - if( namelen > 1 ) // yes, it's decal name - m_decal = ALLOC_STRING( pString ); - else m_decal = atoi( pString ); // no, it's preset - return m_decal; -} - -float UTIL_CalcDistance( Vector vecAngles ) -{ - for(int i = 0; i < 3; i++ ) - { - if(vecAngles[i] < -180) vecAngles[i] += 360; - else if(vecAngles[i] > 180) vecAngles[i] -= 360; - } - return vecAngles.Length(); -} - -//======================================================================== -// Watches for pWatching enetity and rotate pWatcher entity angles -//======================================================================== -void UTIL_WatchTarget( CBaseEntity *pWatcher, CBaseEntity *pTarget) -{ - Vector vecGoal = UTIL_VecToAngles( (pTarget->pev->origin - pWatcher->pev->origin).Normalize() ); - vecGoal.x = -vecGoal.x; - - if (pWatcher->pev->angles.y > 360) pWatcher->pev->angles.y -= 360; - if (pWatcher->pev->angles.y < 0) pWatcher->pev->angles.y += 360; - - float dx = vecGoal.x - pWatcher->pev->angles.x; - float dy = vecGoal.y - pWatcher->pev->angles.y; - - if (dx < -180) dx += 360; - if (dx > 180) dx = dx - 360; - - if (dy < -180) dy += 360; - if (dy > 180) dy = dy - 360; - - pWatcher->pev->avelocity.x = dx * pWatcher->pev->speed * gpGlobals->frametime; - pWatcher->pev->avelocity.y = dy * pWatcher->pev->speed * gpGlobals->frametime; -} - -float UTIL_Approach( float target, float value, float speed ) -{ - float delta = target - value; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_ApproachAngle( float target, float value, float speed ) -{ - target = UTIL_AngleMod( target ); - value = UTIL_AngleMod( target ); - - float delta = target - value; - - // Speed is assumed to be positive - if ( speed < 0 ) - speed = -speed; - - if ( delta < -180 ) - delta += 360; - else if ( delta > 180 ) - delta -= 360; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_AngleDistance( float next, float cur ) -{ - float delta = next - cur; - - while ( delta < -180 ) - delta += 360; - while ( delta > 180 ) - delta -= 360; - - return delta; -} - -BOOL UTIL_EntIsVisible( entvars_t* pev, entvars_t* pevTarget ) -{ - Vector vecSpot1 = pev->origin + pev->view_ofs; - Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; - TraceResult tr; - - UTIL_TraceLine( vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr ); - - if ( tr.fInOpen && tr.fInWater ) return FALSE; // sight line crossed contents - if ( tr.flFraction == 1.0f ) return TRUE; - return FALSE; -} - -//======================================================================== -// Place all system resourses here -//======================================================================== -void UTIL_PrecacheResourse( void ) -{ - // null and errors stuff - g_sModelIndexErrorModel = UTIL_PrecacheModel("models/common/error.mdl");//last crash point - g_sModelIndexErrorSprite = UTIL_PrecacheModel("sprites/error.spr"); - g_sModelIndexNullModel = UTIL_PrecacheModel("models/common/null.mdl"); - g_sModelIndexNullSprite = UTIL_PrecacheModel("sprites/null.spr"); - - // global sprites and models - g_sModelIndexFireball = UTIL_PrecacheModel ("sprites/zerogxplode.spr");// fireball - g_sModelIndexWExplosion = UTIL_PrecacheModel ("sprites/WXplo1.spr");// underwater fireball - g_sModelIndexSmoke = UTIL_PrecacheModel ("sprites/steam1.spr");// smoke - g_sModelIndexBubbles = UTIL_PrecacheModel ("sprites/bubble.spr");//bubbles - g_sModelIndexLaser = UTIL_PrecacheModel( "sprites/laserbeam.spr" ); - g_sModelIndexBloodSpray = UTIL_PrecacheModel ("sprites/bloodspray.spr"); - g_sModelIndexBloodDrop = UTIL_PrecacheModel ("sprites/blood.spr"); - - // events - m_usEjectBrass = UTIL_PrecacheEvent( "evEjectBrass" ); - - // player items and weapons - memset( CBasePlayerWeapon::ItemInfoArray, 0, sizeof( CBasePlayerWeapon::ItemInfoArray )); - memset( CBasePlayerWeapon::AmmoInfoArray, 0, sizeof( CBasePlayerWeapon::AmmoInfoArray )); - giAmmoIndex = 0; - - // custom precaches - char *token; - const char *pfile = (const char *)LOAD_FILE( "scripts/precache.txt", NULL ); - if( pfile ) - { - char *afile = (char *)pfile; - - token = COM_ParseToken( &pfile ); - - while( token ) - { - if( !FStriCmp( token, "entity" )) - { - token = COM_ParseToken( &pfile ); - UTIL_PrecacheEntity( ALLOC_STRING( token )); - } - else if( !FStriCmp( token, "dmentity" )) - { - token = COM_ParseToken( &pfile ); - if( IsDeatchmatch()) UTIL_PrecacheEntity( ALLOC_STRING( token )); - } - else if( !FStriCmp( token, "model" )) - { - token = COM_ParseToken( &pfile ); - UTIL_PrecacheModel( ALLOC_STRING( token )); - } - else if( !FStriCmp( token, "dmmodel" )) - { - token = COM_ParseToken( &pfile ); - if( IsDeatchmatch()) UTIL_PrecacheModel( ALLOC_STRING( token )); - } - else if( !FStriCmp( token, "sound" )) - { - token = COM_ParseToken( &pfile ); - UTIL_PrecacheSound( ALLOC_STRING( token )); - } - else if( !FStriCmp( token, "dmsound" )) - { - token = COM_ParseToken( &pfile ); - if( IsDeatchmatch()) UTIL_PrecacheSound( ALLOC_STRING( token )); - } - else if( !FStriCmp( token, "aurora" )) - { - token = COM_ParseToken( &pfile ); - UTIL_PrecacheAurora( ALLOC_STRING( token )); - } - token = COM_ParseToken( &pfile ); - } - COM_FreeFile( afile ); - } -} - -BOOL IsMultiplayer( void ) -{ - if( g_pGameRules->IsMultiplayer()) - return TRUE; - return FALSE; -} - -BOOL IsDeatchmatch( void ) -{ - if( g_pGameRules->IsDeathmatch() ) - return TRUE; - return FALSE; -} - -float UTIL_WeaponTimeBase( void ) -{ - return gpGlobals->time; -} - -static unsigned int glSeed = 0; - -unsigned int seed_table[ 256 ] = -{ - 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, - 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, - 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, - 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, - 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, - 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, - 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, - 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, - 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, - 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, - 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, - 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, - 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, - 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, - 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, - 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 -}; - -unsigned int U_Random( void ) -{ - glSeed *= 69069; - glSeed += seed_table[ glSeed & 0xff ]; - - return ( ++glSeed & 0x0fffffff ); -} - -void U_Srand( unsigned int seed ) -{ - glSeed = seed_table[ seed & 0xff ]; -} - -/* -===================== -UTIL_SharedRandomLong -===================== -*/ -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) -{ - unsigned int range; - - U_Srand( (int)seed + low + high ); - - range = high - low + 1; - if ( !(range - 1) ) - { - return low; - } - else - { - int offset; - int rnum; - - rnum = U_Random(); - - offset = rnum % range; - - return (low + offset); - } -} - -/* -===================== -UTIL_SharedRandomFloat -===================== -*/ -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) -{ - // - unsigned int range; - - U_Srand( (int)seed + *(int *)&low + *(int *)&high ); - - U_Random(); - U_Random(); - - range = high - low; - if ( !range ) - { - return low; - } - else - { - int tensixrand; - float offset; - - tensixrand = U_Random() & 65535; - - offset = (float)tensixrand / 65536.0; - - return (low + offset * range ); - } -} - -int g_groupmask = 0; -int g_groupop = 0; - -// Normal overrides -void UTIL_SetGroupTrace( int groupmask, int op ) -{ - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -void UTIL_UnsetGroupTrace( void ) -{ - g_groupmask = 0; - g_groupop = 0; - - ENGINE_SETGROUPMASK( 0, 0 ); -} - -// Smart version, it'll clean itself up when it pops off stack -UTIL_GroupTrace::UTIL_GroupTrace( int groupmask, int op ) -{ - m_oldgroupmask = g_groupmask; - m_oldgroupop = g_groupop; - - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -UTIL_GroupTrace::~UTIL_GroupTrace( void ) -{ - g_groupmask = m_oldgroupmask; - g_groupop = m_oldgroupop; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -#ifdef _DEBUG -edict_t *DBG_EntOfVars( const entvars_t *pev ) -{ - if( pev->pContainingEntity != NULL ) - return pev->pContainingEntity; - - ALERT( at_console, "entvars_t pContainingEntity is NULL, calling into engine" ); - edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); - - if( pent == NULL ) ALERT( at_console, "DAMN! Even the engine couldn't FindEntityByVars!" ); - ((entvars_t *)pev)->pContainingEntity = pent; - return pent; -} -#endif //DEBUG - - -#ifdef DEBUG -void DBG_AssertFunction( BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage ) -{ - if( fExpr ) return; - - char szOut[512]; - if( szMessage != NULL ) - sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s\n", szExpr, szFile, szLine, szMessage ); - else sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n", szExpr, szFile, szLine ); - ALERT( at_console, szOut ); -} -#endif // DEBUG - -BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pCurrentWeapon ) -{ - return g_pGameRules->GetNextBestWeapon( pPlayer, pCurrentWeapon ); -} - -unsigned short UTIL_PrecacheEvent( const char *s ) -{ - return g_engfuncs.pfnPrecacheEvent( 1, s ); -} - - -// ripped this out of the engine -float UTIL_AngleMod(float a) -{ - if (a < 0) - { - a = a + 360 * ((int)(a / 360) + 1); - } - else if (a >= 360) - { - a = a - 360 * ((int)(a / 360)); - } - // a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); - return a; -} - -float UTIL_AngleDiff( float destAngle, float srcAngle ) -{ - float delta; - - delta = destAngle - srcAngle; - if ( destAngle > srcAngle ) - { - if ( delta >= 180 ) - delta -= 360; - } - else - { - if ( delta <= -180 ) - delta += 360; - } - return delta; -} - -Vector UTIL_VecToAngles( const Vector &vec ) -{ - float rgflVecOut[3]; - - VEC_TO_ANGLES( vec, rgflVecOut ); - - return Vector( rgflVecOut ); -} - -//LRC - pass in a normalised axis vector and a number of degrees, and this returns the corresponding -// angles value for an entity. -inline Vector UTIL_AxisRotationToAngles( const Vector &vecAxis, float flDegs ) -{ - Vector vecTemp = UTIL_AxisRotationToVec( vecAxis, flDegs ); - float rgflVecOut[3]; - //ugh, mathsy. - rgflVecOut[0] = asin(vecTemp.z) * (-180.0 / M_PI); - rgflVecOut[1] = acos(vecTemp.x) * (180.0 / M_PI); - if (vecTemp.y < 0) - rgflVecOut[1] = -rgflVecOut[1]; - rgflVecOut[2] = 0; //for now - return Vector(rgflVecOut); -} - -//LRC - as above, but returns the position of point 1 0 0 under the given rotation -Vector UTIL_AxisRotationToVec( const Vector &vecAxis, float flDegs ) -{ - float rgflVecOut[3]; - float flRads = flDegs * (M_PI / 180.0); - float c = cos(flRads); - float s = sin(flRads); - float v = vecAxis.x * (1-c); - //ugh, more maths. Thank goodness for internet geometry sites... - rgflVecOut[0] = vecAxis.x*v + c; - rgflVecOut[1] = vecAxis.y*v + vecAxis.z*s; - rgflVecOut[2] = vecAxis.z*v - vecAxis.y*s; - return Vector(rgflVecOut); -} - -void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType ) -{ - MOVE_TO_ORIGIN( pent, vecGoal, flDist, iMoveType ); -} - -int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - - count = 0; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( flagMask && !(pEdict->v.flags & flagMask) ) // Does it meet the criteria? - continue; - - if ( mins.x > pEdict->v.absmax.x || - mins.y > pEdict->v.absmax.y || - mins.z > pEdict->v.absmax.z || - maxs.x < pEdict->v.absmin.x || - maxs.y < pEdict->v.absmin.y || - maxs.z < pEdict->v.absmin.z ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - return count; -} - - -int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - float distance, delta; - - count = 0; - float radiusSquared = radius * radius; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( !(pEdict->v.flags & (FL_CLIENT|FL_MONSTER)) ) // Not a client/monster ? - continue; - - // Use origin for X & Y since they are centered for all monsters - // Now X - delta = center.x - pEdict->v.origin.x;//(pEdict->v.absmin.x + pEdict->v.absmax.x)*0.5; - delta *= delta; - - if ( delta > radiusSquared ) - continue; - distance = delta; - - // Now Y - delta = center.y - pEdict->v.origin.y;//(pEdict->v.absmin.y + pEdict->v.absmax.y)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - // Now Z - delta = center.z - (pEdict->v.absmin.z + pEdict->v.absmax.z)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - - return count; -} - - -CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) -{ - edict_t *pentEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); - - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - -CBaseEntity *UTIL_FindPlayerInSphere( const Vector &vecCenter, float flRadius ) -{ - edict_t *pentEntity = NULL; - - pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); - while(!FNullEnt(pentEntity)) - { - if(pentEntity->v.flags & FL_CLIENT) break; //found player - pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); - } - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - -CBasePlayer *UTIL_FindPlayerInPVS( edict_t *pent ) -{ - edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pent ); - CBasePlayer *pPlayer = NULL; - - if(!FNullEnt(pentPlayer)) //get pointer to player - pPlayer = GetClassPtr((CBasePlayer *)VARS(pentPlayer)); - return pPlayer; -} - -CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ) -{ - edict_t *pentEntity; - CBaseEntity *pEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - for (;;) - { - // Don't change this to use UTIL_FindEntityByString! - pentEntity = FIND_ENTITY_BY_STRING( pentEntity, szKeyword, szValue ); - - // if pentEntity (the edict) is null, we're at the end of the entities. Give up. - if (FNullEnt(pentEntity)) - { - return NULL; - } - else - { - // ...but if only pEntity (the classptr) is null, we've just got one dud, so we try again. - pEntity = CBaseEntity::Instance(pentEntity); - if (pEntity) - return pEntity; - } - } -} - -CBaseEntity *UTIL_FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "classname", szName ); -} - -CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "targetname", szName ); -} - -CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pActivator ) -{ - return UTIL_FindEntityByTargetname( pStartEntity, szName ); -} - -CBaseEntity *UTIL_FindEntityByTarget( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "target", szName ); -} - -CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, float flRadius ) -{ - CBaseEntity *pEntity = NULL; - - pEntity = UTIL_FindEntityByTargetname( NULL, szWhatever ); - if (pEntity) - return pEntity; - - CBaseEntity *pSearch = NULL; - float flMaxDist2 = flRadius * flRadius; - while ((pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever )) != NULL) - { - float flDist2 = (pSearch->pev->origin - vecSrc).Length(); - flDist2 = flDist2 * flDist2; - if (flMaxDist2 > flDist2) - { - pEntity = pSearch; - flMaxDist2 = flDist2; - } - } - return pEntity; -} - - -// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected -// otherwise returns NULL -// Index is 1 based -CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) -{ - CBaseEntity *pPlayer = NULL; - - if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) - { - edict_t *pPlayerEdict = INDEXENT( playerIndex ); - if ( pPlayerEdict && !pPlayerEdict->free ) - { - pPlayer = CBaseEntity::Instance( pPlayerEdict ); - } - } - - return pPlayer; -} - - -void UTIL_MakeVectors( const Vector &vecAngles ) -{ - MAKE_VECTORS( vecAngles ); -} - - -void UTIL_MakeAimVectors( const Vector &vecAngles ) -{ - float rgflVec[3]; - vecAngles.CopyToArray(rgflVec); - rgflVec[0] = -rgflVec[0]; - MAKE_VECTORS(rgflVec); -} - - -#define SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) - -void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) -{ - MAKE_VECTORS(vec); - - float tmp; - pgv->v_right = pgv->v_right * -1; - - SWAP(pgv->v_forward.y, pgv->v_right.x, tmp); - SWAP(pgv->v_forward.z, pgv->v_up.x, tmp); - SWAP(pgv->v_right.z, pgv->v_up.y, tmp); -} - - -void UTIL_EmitAmbientSound( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ) -{ - float rgfl[3]; - vecOrigin.CopyToArray(rgfl); - - if (samp && *samp == '!') - { - char name[32]; - if (SENTENCEG_Lookup(samp, name) >= 0) - EMIT_AMBIENT_SOUND(entity, rgfl, name, vol, attenuation, fFlags, pitch); - } - else - EMIT_AMBIENT_SOUND(entity, rgfl, samp, vol, attenuation, fFlags, pitch); -} - -unsigned short FixedUnsigned16( float value, float scale ) -{ - int output; - - output = value * scale; - if ( output < 0 ) - output = 0; - if ( output > 0xFFFF ) - output = 0xFFFF; - - return (unsigned short)output; -} - -short FixedSigned16( float value, float scale ) -{ - int output; - - output = value * scale; - - if ( output > 32767 ) - output = 32767; - - if ( output < -32768 ) - output = -32768; - - return (short)output; -} - -// Shake the screen of all clients within radius -// radius == 0, shake all clients -// UNDONE: Allow caller to shake clients not ONGROUND? -// UNDONE: Fix falloff model (disabled)? -// UNDONE: Affect user controls? -//LRC UNDONE: Work during trigger_camera? -//----------------------------------------------------------------------------- -// Compute shake amplitude -//----------------------------------------------------------------------------- -float ComputeShakeAmplitude( const Vector ¢er, const Vector &shakePt, float amplitude, float radius ) -{ - if( radius <= 0 ) - return amplitude; - - float localAmplitude = -1; - Vector delta = center - shakePt; - float distance = delta.Length(); - - if( distance <= radius ) - { - // make the amplitude fall off over distance - float flPerc = 1.0 - (distance / radius); - localAmplitude = amplitude * flPerc; - } - - return localAmplitude; -} - -void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, BOOL bAirShake ) -{ - int i; - float localAmplitude; - ScreenShake shake; - - shake.command = (unsigned short)eCommand; - shake.duration = FixedUnsigned16( duration, 1<<12 ); // 4.12 fixed - shake.frequency = FixedUnsigned16( frequency, 1<<8 ); // 8.8 fixed - - for( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - // - // Only shake players that are on the ground. - // - if( !pPlayer || (!bAirShake && !FBitSet( pPlayer->pev->flags, FL_ONGROUND ))) - { - continue; - } - - localAmplitude = ComputeShakeAmplitude( center, pPlayer->pev->origin, amplitude, radius ); - - // This happens if the player is outside the radius, in which case we should ignore - // all commands - if( localAmplitude < 0 ) continue; - - if (( localAmplitude > 0 ) || ( eCommand == SHAKE_STOP )) - { - if ( eCommand == SHAKE_STOP ) localAmplitude = 0; - - shake.amplitude = FixedUnsigned16( localAmplitude, 1<<12 ); // 4.12 fixed - - MESSAGE_BEGIN( MSG_ONE, gmsg.Shake, NULL, pPlayer->edict() ); - WRITE_SHORT( shake.command ); // shake command (SHAKE_START, STOP, FREQUENCY, AMPLITUDE) - WRITE_SHORT( shake.amplitude ); // shake magnitude/amplitude - WRITE_SHORT( shake.duration ); // shake lasts this long - WRITE_SHORT( shake.frequency ); // shake noise frequency - MESSAGE_END(); - } - } -} - -void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius ) -{ - UTIL_ScreenShake( center, amplitude, frequency, duration, radius, SHAKE_START, FALSE ); -} - -void UTIL_ScreenShakeAll( const Vector ¢er, float amplitude, float frequency, float duration ) -{ - UTIL_ScreenShake( center, amplitude, frequency, duration, 0, SHAKE_START, FALSE ); -} - -void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - if(IsMultiplayer()) - { - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - UTIL_ScreenFade( color, fadeTime, fadeHold, alpha, flags, i ); - } - else UTIL_ScreenFade( color, fadeTime, fadeHold, alpha, flags ); -} - - -void UTIL_ScreenFade( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags, int playernum ) -{ - CBasePlayer *pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( playernum ); - - if ( pPlayer ) - { - if ( flags & FFADE_CUSTOMVIEW ) - { - if ( pPlayer->viewFlags == 0 ) return; - ClearBits( flags, FFADE_CUSTOMVIEW ); // don't send this flag to engine!!! - } - - if ( flags & FFADE_OUT && fadeHold == 0 ) - SetBits( flags, FFADE_STAYOUT ); - else ClearBits( flags, FFADE_STAYOUT ); - - pPlayer->m_FadeColor = color; - pPlayer->m_FadeAlpha = alpha; - pPlayer->m_iFadeFlags = flags; - pPlayer->m_flFadeTime = fadeTime; - pPlayer->m_flFadeHold = fadeHold; - pPlayer->fadeNeedsUpdate = TRUE; - } -} - - -void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, gmsg.TempEntity, NULL, pEntity->edict() ); - WRITE_BYTE( TE_TEXTMESSAGE ); - WRITE_BYTE( textparms.channel & 0xFF ); - - WRITE_SHORT( FixedSigned16( textparms.x, 1<<13 ) ); - WRITE_SHORT( FixedSigned16( textparms.y, 1<<13 ) ); - WRITE_BYTE( textparms.effect ); - - WRITE_BYTE( textparms.r1 ); - WRITE_BYTE( textparms.g1 ); - WRITE_BYTE( textparms.b1 ); - WRITE_BYTE( textparms.a1 ); - - WRITE_BYTE( textparms.r2 ); - WRITE_BYTE( textparms.g2 ); - WRITE_BYTE( textparms.b2 ); - WRITE_BYTE( textparms.a2 ); - - WRITE_SHORT( FixedUnsigned16( textparms.fadeinTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.fadeoutTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.holdTime, 1<<8 ) ); - - if ( textparms.effect == 2 ) - WRITE_SHORT( FixedUnsigned16( textparms.fxTime, 1<<8 ) ); - - if ( strlen( pMessage ) < 512 ) - { - WRITE_STRING( pMessage ); - } - else - { - char tmp[512]; - strncpy( tmp, pMessage, 511 ); - tmp[511] = 0; - WRITE_STRING( tmp ); - } - MESSAGE_END(); -} - -void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ) -{ - int i; - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - UTIL_HudMessage( pPlayer, textparms, pMessage ); - } -} - -void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - MESSAGE_BEGIN( MSG_ALL, gmsg.TextMsg ); - WRITE_BYTE( msg_dest ); - WRITE_STRING( msg_name ); - - if ( param1 ) - WRITE_STRING( param1 ); - if ( param2 ) - WRITE_STRING( param2 ); - if ( param3 ) - WRITE_STRING( param3 ); - if ( param4 ) - WRITE_STRING( param4 ); - - MESSAGE_END(); -} - -void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - MESSAGE_BEGIN( MSG_ONE, gmsg.TextMsg, NULL, client ); - WRITE_BYTE( msg_dest ); - WRITE_STRING( msg_name ); - - if ( param1 ) - WRITE_STRING( param1 ); - if ( param2 ) - WRITE_STRING( param2 ); - if ( param3 ) - WRITE_STRING( param3 ); - if ( param4 ) - WRITE_STRING( param4 ); - - MESSAGE_END(); -} - -void UTIL_SayText( const char *pText, CBaseEntity *pEntity ) -{ - if ( !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, gmsg.SayText, NULL, pEntity->edict() ); - WRITE_BYTE( pEntity->entindex() ); - WRITE_STRING( pText ); - MESSAGE_END(); -} - -void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ) -{ - MESSAGE_BEGIN( MSG_ALL, gmsg.SayText, NULL ); - WRITE_BYTE( pEntity->entindex() ); - WRITE_STRING( pText ); - MESSAGE_END(); -} - - -char *UTIL_dtos1( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos2( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos3( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos4( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, gmsg.HudText, NULL, pEntity->edict() ); - WRITE_STRING( pString ); - MESSAGE_END(); -} - - -void UTIL_ShowMessageAll( const char *pString ) -{ - // loop through all players - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) UTIL_ShowMessage( pString, pPlayer ); - } -} -void UTIL_SetFogAll( Vector color, int iFadeTime, int iStartDist, int iEndDist ) -{ - // loop through all players - - if( IsMultiplayer( )) - { - for ( int i = 0; i < gpGlobals->maxClients; i++ ) - UTIL_SetFog( color, iFadeTime, iStartDist, iEndDist, i+1 ); - } - else UTIL_SetFog( color, iFadeTime, iStartDist, iEndDist ); -} - -void UTIL_SetFog( Vector color, int iFadeTime, int iStartDist, int iEndDist, int playernum ) -{ - CBasePlayer *pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( playernum ); - if ( pPlayer ) - { - if(pPlayer->m_FogFadeTime != 0) return;//fading in progress !!!TODO: make smooth re-fading - if(IsMultiplayer()) iFadeTime = 0; //disable fading in multiplayer - if( iFadeTime > 0 ) - { - pPlayer->m_iFogEndDist = FOG_LIMIT; - pPlayer->m_iFogFinalEndDist = iEndDist; - } - else if( iFadeTime < 0 ) - { - pPlayer->m_iFogEndDist = iEndDist; - pPlayer->m_iFogFinalEndDist = iEndDist; - } - else pPlayer->m_iFogEndDist = iEndDist; - pPlayer->m_iFogStartDist = iStartDist; - pPlayer->m_FogColor = color; - pPlayer->m_FogFadeTime = iFadeTime; - pPlayer->m_flStartTime = gpGlobals->time; - pPlayer->fogNeedsUpdate = TRUE; - } -} - -// Overloaded to add IGNORE_GLASS -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr ); -} - - -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr ); -} - - -void UTIL_TraceHull( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_HULL( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), hullNumber, pentIgnore, ptr ); -} - -void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr ) -{ - g_engfuncs.pfnTraceModel( vecStart, vecEnd, pentModel, ptr ); -} - - -TraceResult UTIL_GetGlobalTrace( void ) -{ - TraceResult tr; - - tr.fAllSolid = gpGlobals->trace_allsolid; - tr.fStartSolid = gpGlobals->trace_startsolid; - tr.fInOpen = gpGlobals->trace_inopen; - tr.fInWater = gpGlobals->trace_inwater; - tr.flFraction = gpGlobals->trace_fraction; - tr.flPlaneDist = gpGlobals->trace_plane_dist; - tr.pHit = gpGlobals->trace_ent; - tr.vecEndPos = gpGlobals->trace_endpos; - tr.vecPlaneNormal = gpGlobals->trace_plane_normal; - tr.iHitgroup = gpGlobals->trace_hitgroup; - - return tr; -} - - -void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) -{ - SET_SIZE( ENT(pev), vecMin, vecMax ); -} - - -float UTIL_VecToYaw( const Vector &vec ) -{ - return VEC_TO_YAW(vec); -} - -void UTIL_SetEdictOrigin( edict_t *pEdict, const Vector &vecOrigin ) -{ - SET_ORIGIN(pEdict, vecOrigin ); -} - -// 'links' the entity into the world - - -void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ) -{ - PARTICLE_EFFECT( vecOrigin, vecDirection, (float)ulColor, (float)ulCount ); -} - - -float UTIL_SplineFraction( float value, float scale ) -{ - value = scale * value; - float valueSquared = value * value; - - // Nice little ease-in, ease-out spline-like curve - return 3 * valueSquared - 2 * valueSquared * value; -} - - -char* UTIL_VarArgs( char *format, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start (argptr, format); - vsprintf (string, format,argptr); - va_end (argptr); - - return string; -} - -Vector UTIL_GetAimVector( edict_t *pent, float flSpeed ) -{ - Vector tmp; - GET_AIM_VECTOR(pent, flSpeed, tmp); - return tmp; -} - -BOOL UTIL_IsMasterTriggered(string_t iszMaster, CBaseEntity *pActivator) -{ - int i, j, found = false; - const char *szMaster; - char szBuf[80]; - CBaseEntity *pMaster; - int reverse = false; - - - if (iszMaster) - { - //Msg( "IsMasterTriggered(%s, %s \"%s\")\n", STRING(iszMaster), STRING(pActivator->pev->classname), STRING(pActivator->pev->targetname)); - szMaster = STRING(iszMaster); - if (szMaster[0] == '~') //inverse master - { - reverse = true; - szMaster++; - } - - pMaster = UTIL_FindEntityByTargetname( NULL, szMaster ); - if ( !pMaster ) - { - for (i = 0; szMaster[i]; i++) - { - if (szMaster[i] == '(') - { - for (j = i+1; szMaster[j]; j++) - { - if (szMaster[j] == ')') - { - strncpy(szBuf, szMaster+i+1, (j-i)-1); - szBuf[(j-i)-1] = 0; - pActivator = UTIL_FindEntityByTargetname( NULL, szBuf ); - found = true; - break; - } - } - if (!found) // no ) found - { - ALERT(at_error, "Missing ')' in master \"%s\"\n", szMaster); - return FALSE; - } - break; - } - } - - if( !found ) // no ( found - { - ALERT( at_console, "Master \"%s\" not found!\n", szMaster ); - return TRUE; - } - - strncpy(szBuf, szMaster, i); - szBuf[i] = 0; - pMaster = UTIL_FindEntityByTargetname( NULL, szBuf ); - } - - if( pMaster ) - { - if( reverse ) - return (pMaster->GetState( pActivator ) != STATE_ON ); - return (pMaster->GetState( pActivator ) == STATE_ON); - } - } - - // if the entity has no master (or the master is missing), just say yes. - return TRUE; -} - -BOOL UTIL_ShouldShowBlood( int color ) -{ - if ( color != DONT_BLEED ) - { - if ( color == BLOOD_COLOR_RED ) - { - if ( CVAR_GET_FLOAT("violence_hblood") != 0 ) - return TRUE; - } - else - { - if ( CVAR_GET_FLOAT("violence_ablood") != 0 ) - return TRUE; - } - } - return FALSE; -} - -int UTIL_PointContents( const Vector &vec ) -{ - return POINT_CONTENTS( vec ); -} - -void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, origin ); - WRITE_BYTE( TE_BLOODSTREAM ); - WRITE_COORD( origin.x ); - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_COORD( direction.x ); - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_BYTE( color ); - WRITE_BYTE( min( amount, 255 ) ); - MESSAGE_END(); -} - -void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - if ( color == DONT_BLEED || amount == 0 ) - return; - - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) - color = 0; - - if ( g_pGameRules->IsMultiplayer() ) - { - // scale up blood effect in multiplayer for better visibility - amount *= 2; - } - - if ( amount > 255 ) - amount = 255; - - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, origin ); - WRITE_BYTE( TE_BLOODSPRITE ); - WRITE_COORD( origin.x); // pos - WRITE_COORD( origin.y); - WRITE_COORD( origin.z); - WRITE_SHORT( g_sModelIndexBloodSpray ); // initial sprite model - WRITE_SHORT( g_sModelIndexBloodDrop ); // droplet sprite models - WRITE_BYTE( color ); // color index into host_basepal - WRITE_BYTE( min( max( 3, amount / 10 ), 16 ) ); // size - MESSAGE_END(); -} - -Vector UTIL_RandomBloodVector( void ) -{ - Vector direction; - - direction.x = RANDOM_FLOAT ( -1, 1 ); - direction.y = RANDOM_FLOAT ( -1, 1 ); - direction.z = RANDOM_FLOAT ( 0, 1 ); - - return direction; -} - - -void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ) -{ - if ( UTIL_ShouldShowBlood( bloodColor ) ) - { - if ( bloodColor == BLOOD_COLOR_RED ) - UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG(0,5) ); - else - UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG(0,5) ); - } -} - - -void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) -{ - short entityIndex; - int index; - int message; - - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - - if ( index < 0 ) - return; - - if (pTrace->flFraction == 1.0) - return; - - // Only decal BSP models - if ( pTrace->pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( pTrace->pHit ); - if ( pEntity && !pEntity->IsBSPModel() ) - return; - entityIndex = ENTINDEX( pTrace->pHit ); - } - else - entityIndex = 0; - - message = TE_DECAL; - if ( entityIndex != 0 ) - { - if ( index > 255 ) - { - message = TE_DECALHIGH; - index -= 256; - } - } - else - { - message = TE_WORLDDECAL; - if ( index > 255 ) - { - message = TE_WORLDDECALHIGH; - index -= 256; - } - } - - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( message ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_BYTE( index ); - if ( entityIndex ) - WRITE_SHORT( entityIndex ); - MESSAGE_END(); -} - -/* -============== -UTIL_PlayerDecalTrace - -A player is trying to apply his custom decal for the spray can. -Tell connected clients to display it, or use the default spray can decal -if the custom can't be loaded. -============== -*/ -void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ) -{ - int index; - - if (!bIsCustom) - { - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - } - else - index = decalNumber; - - if (pTrace->flFraction == 1.0) - return; - - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_PLAYERDECAL ); - WRITE_BYTE ( playernum ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); - WRITE_BYTE( index ); - MESSAGE_END(); -} - -void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) -{ - if ( decalNumber < 0 ) - return; - - int index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - - if( pTrace->flFraction == 1.0 ) - return; - - MESSAGE_BEGIN( MSG_PAS, gmsg.TempEntity, pTrace->vecEndPos ); - WRITE_BYTE( TE_GUNSHOTDECAL ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX( pTrace->pHit )); - WRITE_BYTE( index ); - MESSAGE_END(); -} - - -void UTIL_Sparks( const Vector &position ) -{ - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, position ); - WRITE_BYTE( TE_SPARKS ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - MESSAGE_END(); -} - -void UTIL_Explode( const Vector ¢er, edict_t *pOwner, int radius, int name ) -{ - CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, g_vecZero, pOwner ); - if( !pExplosion ) return; - - if( name ) pExplosion->pev->classname = name; - pExplosion->pev->dmg = radius; - pExplosion->pev->spawnflags |= SF_FIREONCE; //remove entity after explode - pExplosion->Use( NULL, NULL, USE_ON, 0 ); -} - -void UTIL_Ricochet( const Vector &position, float scale ) -{ - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, position ); - WRITE_BYTE( TE_ARMOR_RICOCHET ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - WRITE_BYTE( (int)( scale * 10 )); - MESSAGE_END(); -} - - -BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) -{ - // Everyone matches unless it's teamplay - if ( !g_pGameRules->IsTeamplay() ) - return TRUE; - - // Both on a team? - if ( *pTeamName1 != 0 && *pTeamName2 != 0 ) - { - if ( !FStriCmp( pTeamName1, pTeamName2 ) ) // Same Team? - return TRUE; - } - - return FALSE; -} - -BOOL UTIL_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; -} - -void UTIL_StringToVector( float *pVector, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - if (j < 2) - { - /* - ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n", - pkvd->szClassName, pkvd->szKeyName, pkvd->szValue ); - */ - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } -} - - -//LRC - randomized vectors of the form "0 0 0 .. 1 0 0" -void UTIL_StringToRandomVector( float *pVector, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - float pAltVec[3]; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) pstr++; - if (!*pstr) break; - pstr++; - pfront = pstr; - } - if (j < 2) - { - /* - ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n", - pkvd->szClassName, pkvd->szKeyName, pkvd->szValue ); - */ - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } - else if (*pstr == '.') - { - pstr++; - if (*pstr != '.') return; - pstr++; - if (*pstr != ' ') return; - - UTIL_StringToVector(pAltVec, pstr); - - pVector[0] = RANDOM_FLOAT( pVector[0], pAltVec[0] ); - pVector[1] = RANDOM_FLOAT( pVector[1], pAltVec[1] ); - pVector[2] = RANDOM_FLOAT( pVector[2], pAltVec[2] ); - } -} - - -void UTIL_StringToIntArray( int *pVector, int count, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < count; j++ ) // lifted from pr_edict.c - { - pVector[j] = atoi( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - - for ( j++; j < count; j++ ) - { - pVector[j] = 0; - } -} - -Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ) -{ - Vector sourceVector = input; - - if ( sourceVector.x > clampSize.x ) - sourceVector.x -= clampSize.x; - else if ( sourceVector.x < -clampSize.x ) - sourceVector.x += clampSize.x; - else - sourceVector.x = 0; - - if ( sourceVector.y > clampSize.y ) - sourceVector.y -= clampSize.y; - else if ( sourceVector.y < -clampSize.y ) - sourceVector.y += clampSize.y; - else - sourceVector.y = 0; - - if ( sourceVector.z > clampSize.z ) - sourceVector.z -= clampSize.z; - else if ( sourceVector.z < -clampSize.z ) - sourceVector.z += clampSize.z; - else - sourceVector.z = 0; - - return sourceVector.Normalize(); -} - - -float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) -{ - Vector midUp = position; - midUp.z = minz; - - if( UTIL_PointContents( midUp ) != CONTENTS_WATER ) - return minz; - - midUp.z = maxz; - if( UTIL_PointContents( midUp ) == CONTENTS_WATER ) - return maxz; - - float diff = maxz - minz; - while( diff > 1.0 ) - { - midUp.z = minz + diff/2.0; - if( UTIL_PointContents( midUp ) == CONTENTS_WATER ) - { - minz = midUp.z; - } - else - { - maxz = midUp.z; - } - diff = maxz - minz; - } - return midUp.z; -} - -void UTIL_Bubbles( Vector mins, Vector maxs, int count ) -{ - Vector mid = (mins + maxs) * 0.5; - - float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); - flHeight = flHeight - mins.z; - - MESSAGE_BEGIN( MSG_PAS, gmsg.TempEntity, mid ); - WRITE_BYTE( TE_BUBBLES ); - WRITE_COORD( mins.x ); // mins - WRITE_COORD( mins.y ); - WRITE_COORD( mins.z ); - WRITE_COORD( maxs.x ); // maxz - WRITE_COORD( maxs.y ); - WRITE_COORD( maxs.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - -void UTIL_BubbleTrail( Vector from, Vector to, int count ) -{ - float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 ); - flHeight = flHeight - from.z; - - if (flHeight < 8) - { - flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 ); - flHeight = flHeight - to.z; - if (flHeight < 8) - return; - - // UNDONE: do a ploink sound - flHeight = flHeight + to.z - from.z; - } - - if (count > 255) - count = 255; - - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_BUBBLETRAIL ); - WRITE_COORD( from.x ); // mins - WRITE_COORD( from.y ); - WRITE_COORD( from.z ); - WRITE_COORD( to.x ); // maxz - WRITE_COORD( to.y ); - WRITE_COORD( to.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - -BOOL UTIL_IsValidEntity( edict_t *pent ) -{ - if ( !pent || pent->free || (pent->v.flags & FL_KILLME) ) - return FALSE; - return TRUE; -} - -//========================================================= -// UTIL_LogPrintf - Prints a logged message to console. -// Preceded by LOG: ( timestamp ) < message > -//========================================================= -void UTIL_LogPrintf( char *fmt, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start ( argptr, fmt ); - vsprintf ( string, fmt, argptr ); - va_end ( argptr ); - - // Print to server console - ALERT( at_logged, "%s", string ); -} - -//============ -// UTIL_FileExtension -// returns file extension -//============ -const char *UTIL_FileExtension( const char *in ) -{ - const char *separator, *backslash, *colon, *dot; - - separator = strrchr( in, '/' ); - backslash = strrchr( in, '\\' ); - if( !separator || separator < backslash ) - separator = backslash; - colon = strrchr( in, ':' ); - if( !separator || separator < colon ) - separator = colon; - dot = strrchr( in, '.' ); - if( dot == NULL || (separator && ( dot < separator ))) - return ""; - return dot + 1; -} - -//========================================================= -// UTIL_DotPoints - returns the dot product of a line from -// src to check and vecdir. -//========================================================= -float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ) -{ - Vector2D vec2LOS; - - vec2LOS = ( vecCheck - vecSrc ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - return DotProduct (vec2LOS , ( vecDir.Make2D() ) ); -} - -//for trigger_viewset -int HaveCamerasInPVS( edict_t* edict ) -{ - CBaseEntity *pViewEnt = NULL; - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pEntity = UTIL_PlayerByIndex( i ); - if (!pEntity) continue; - CBasePlayer *pPlayer = (CBasePlayer *)pEntity; - if (pPlayer && pPlayer->viewFlags & 1) // custom view active - { - pViewEnt = pPlayer->pViewEnt; - if (!pViewEnt->edict())return 0; - - edict_t *view = pViewEnt->edict(); - edict_t *pent = UTIL_EntitiesInPVS( edict ); - - while ( !FNullEnt( pent ) ) - { - if (pent == view)return TRUE; - pent = pent->v.chain; - } - } - } - return 0; -} -void UTIL_SetView( int ViewEntity, int flags ) -{ - // light version of SetView - // please don't use this in multiplayer - CBaseEntity *m_pPlayer = UTIL_PlayerByIndex( 1 ); - UTIL_SetView( m_pPlayer, ViewEntity, flags ); -} - -void UTIL_SetView( CBaseEntity *pActivator, int ViewEntity, int flags ) -{ - CBaseEntity *pViewEnt = 0; - - if ( ViewEntity ) - { - // try to find by targetname - pViewEnt = UTIL_FindEntityByString( NULL, "targetname", STRING( ViewEntity )); - // try to find by classname - if( FNullEnt( pViewEnt )) - pViewEnt = UTIL_FindEntityByString( NULL, "classname", STRING( ViewEntity )); - if( pViewEnt && pViewEnt->pev->flags & FL_MONSTER ) flags |= MONSTER_VIEW; // detect monster view - } - UTIL_SetView( pActivator, pViewEnt, flags ); -} - -void UTIL_SetView( CBaseEntity *pActivator, CBaseEntity *pViewEnt, int flags ) -{ - ((CBasePlayer *)pActivator)->pViewEnt = pViewEnt; - ((CBasePlayer *)pActivator)->viewFlags = flags; - ((CBasePlayer *)pActivator)->viewNeedsUpdate = 1; -} \ No newline at end of file diff --git a/server/global/utils.h b/server/global/utils.h deleted file mode 100644 index 49291e34..00000000 --- a/server/global/utils.h +++ /dev/null @@ -1,847 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// utils.h - Utility code. -// Really not optional after all. -//======================================================================= - -#ifndef UTIL_H -#define UTIL_H - -#include - -#include "te_shared.h" -#include "event_api.h" -#include "shake.h" - -#ifndef ACTIVITY_H -#include "activity.h" -#endif - -#ifndef ENGINECALLBACK_H -#include "enginecallback.h" -#endif - -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ); // implementation later in this file - -extern globalvars_t *gpGlobals; - -#define MAX_CHILDS 100 - - -inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "classname", pszName); -} - -inline edict_t *FIND_ENTITY_BY_TARGETNAME(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName); -} - -// for doing a reverse lookup. Say you have a door, and want to find its button. -inline edict_t *FIND_ENTITY_BY_TARGET(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "target", pszName); -} - -// Keeps clutter down a bit, when writing key-value pairs -#define WRITEKEY_INT(pf, szKeyName, iKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%d\"\n", szKeyName, iKeyValue) -#define WRITEKEY_FLOAT(pf, szKeyName, flKeyValue) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%f\"\n", szKeyName, flKeyValue) -#define WRITEKEY_STRING(pf, szKeyName, szKeyValue) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%s\"\n", szKeyName, szKeyValue) -#define WRITEKEY_VECTOR(pf, szKeyName, flX, flY, flZ) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%f %f %f\"\n", szKeyName, flX, flY, flZ) - -// Keeps clutter down a bit, when using a float as a bit-vector -#define SetBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits)) -#define ClearBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits)) -#define FBitSet(flBitVector, bit) ((int)(flBitVector) & (bit)) - -// Makes these more explicit, and easier to find -#define FILE_GLOBAL static -#define DLL_GLOBAL - -extern DLL_GLOBAL int DirToBits( const Vector dir ); - -extern DLL_GLOBAL int g_sModelIndexErrorModel; -extern DLL_GLOBAL int g_sModelIndexErrorSprite; -extern DLL_GLOBAL int g_sModelIndexNullModel; -extern DLL_GLOBAL int g_sModelIndexNullSprite; - -// Until we figure out why "const" gives the compiler problems, we'll just have to use -// this bogus "empty" define to mark things as constant. -#define CONSTANT - -// More explicit than "int" -typedef int EOFFSET; - -// In case it's not alread defined -typedef int BOOL; - -// Keeps clutter down a bit, when declaring external entity/global method prototypes -#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName( void ) -#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void) - -// This is the glue that hooks .MAP entity class names to our CPP classes -// The _declspec forces them to be exported by name so we can do a lookup with GetProcAddress() -// The function is used to intialize / allocate the object for the entity -#ifdef _WIN32 -#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ - extern "C" _declspec( dllexport ) void mapClassName( entvars_t *pev ); \ - void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } -#else -#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) extern "C" void mapClassName( entvars_t *pev ); void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } -#endif - - -// -// Conversion among the three types of "entity", including identity-conversions. -// -#ifdef _DEBUG - extern edict_t *DBG_EntOfVars(const entvars_t *pev); - inline edict_t *ENT(const entvars_t *pev) { return DBG_EntOfVars(pev); } -#else - inline edict_t *ENT(const entvars_t *pev) { return pev->pContainingEntity; } -#endif -inline edict_t *ENT(edict_t *pent) { return pent; } -inline edict_t *ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); } -inline EOFFSET OFFSET(EOFFSET eoffset) { return eoffset; } -inline EOFFSET OFFSET(const edict_t *pent) -{ -#if _DEBUG - if ( !pent ) - ALERT( at_error, "Bad ent in OFFSET()\n" ); -#endif - return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); -} -inline EOFFSET OFFSET(entvars_t *pev) -{ -#if _DEBUG - if ( !pev ) - ALERT( at_error, "Bad pev in OFFSET()\n" ); -#endif - return OFFSET(ENT(pev)); -} -inline entvars_t *VARS(entvars_t *pev) { return pev; } - -inline entvars_t *VARS(edict_t *pent) -{ - if ( !pent ) - return NULL; - - return &pent->v; -} - -inline entvars_t* VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); } -inline int ENTINDEX(edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); } -inline edict_t* INDEXENT( int iEdictNum ) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); } -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ) { - (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ENT(ent)); -} - - -class CBaseEntity; -class CBasePlayer; - -//========================================================= -// RandomRange - for random values -//========================================================= -class RandomRange -{ -public: - float m_flMax, m_flMin; // class members - - RandomRange() { m_flMin = m_flMax = 0; } - RandomRange( float fValue ) { m_flMin = m_flMax = fValue; } - RandomRange( float fMin, float fMax ) { m_flMin = fMin; m_flMax = fMax; } - RandomRange( const char *szToken ) - { - char *cOneDot = NULL; - m_flMin = m_flMax = 0; - - for( const char *c = szToken; *c; c++ ) - { - if( *c == '.' ) - { - if( cOneDot != NULL ) - { - // found two dots in a row - it's a range - *cOneDot = 0; // null terminate the first number - m_flMin = atof( szToken ); // parse the first number - *cOneDot = '.'; // change it back, just in case - c++; - m_flMax = atof( c ); // parse the second number - return; - } - else cOneDot = (char *)c; - } - else cOneDot = NULL; - } - - // no range, just record the number - m_flMax = m_flMin = atof( szToken ); - } - - float Random() { return RANDOM_FLOAT( m_flMin, m_flMax ); } - - // array access... - float operator[](int i) const { return ((float*)this)[i];} - float& operator[](int i) { return ((float*)this)[i];} -}; - -// Testing the three types of "entity" for nullity -//LRC- four types, rather; see cbase.h -#define eoNullEntity 0 -extern BOOL FNullEnt(EOFFSET eoffset); -extern BOOL FNullEnt(const edict_t* pent); -extern BOOL FNullEnt(entvars_t* pev); -extern BOOL FNullEnt( CBaseEntity *ent ); - -// Testing strings for nullity -// g-cont. radnomize hull nullity yep! -// and Doom3 colloisation -#define iStringNull 0 -inline BOOL FStringNull( int iString ) { return iString == iStringNull; } -inline BOOL FStringNull( const char *szString ) { return (szString && *szString) ? FALSE : TRUE; }; -inline BOOL FStringNull( Vector vString ) { return vString == Vector( 0, 0, 0); } - -#define cchMapNameMost 32 - -// Dot products for view cone checking -#define VIEW_FIELD_FULL (float)-1.0 // +-180 degrees -#define VIEW_FIELD_WIDE (float)-0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks -#define VIEW_FIELD_NARROW (float)0.7 // +-45 degrees, more narrow check used to set up ranged attacks -#define VIEW_FIELD_ULTRA_NARROW (float)0.9 // +-25 degrees, more narrow check used to set up ranged attacks - -// All monsters need this data -#define DONT_BLEED -1 -#define BLOOD_COLOR_RED (byte)247 -#define BLOOD_COLOR_YELLOW (byte)195 -#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW - -typedef enum -{ - MONSTERSTATE_NONE = 0, - MONSTERSTATE_IDLE, - MONSTERSTATE_COMBAT, - MONSTERSTATE_ALERT, - MONSTERSTATE_HUNT, - MONSTERSTATE_PRONE, - MONSTERSTATE_SCRIPT, - MONSTERSTATE_PLAYDEAD, - MONSTERSTATE_DEAD - -} MONSTERSTATE; - -//LRC- the values used for the new "global states" mechanism. -typedef enum -{ - STATE_OFF = 0, // disabled, inactive, invisible, closed, or stateless. Or non-alert monster. - STATE_ON, // enabled, active, visisble, or open. Or alert monster. - STATE_TURN_ON, // door opening, env_fade fading in, etc. - STATE_TURN_OFF, // door closing, monster dying (?). - STATE_IN_USE, // player is in control (train/tank/barney/scientist). - STATE_DEAD, // entity dead -} STATE; - -typedef enum -{ - GLOBAL_OFF = 0, - GLOBAL_ON = 1, - GLOBAL_DEAD = 2 -} GLOBALESTATE; - - //list of use type -typedef enum -{ - USE_OFF = 0, //deactivate entity - USE_ON = 1, //activate entity - USE_SET = 2, //control over entity - e.g tracktrain, tank, camera etc. - USE_RESET = 3, //reset entity to initial position - USE_TOGGLE = 4, //default command - toggle on/off - USE_REMOVE = 5, //remove entity from map - USE_SHOWINFO = 6, //show different info (debug mode) -} USE_TYPE; - -extern char* GetStringForUseType( USE_TYPE useType ); -extern char* GetStringForState( STATE state ); -extern char* GetStringForGlobalState( GLOBALESTATE state ); -extern char* GetContentsString( int contents ); -extern void PrintStringForDamage( int dmgbits ); -extern char* GetStringForDecalName( int decalname ); -extern DLL_GLOBAL - -// Misc useful -// this safe verisons of strcmp and stricmp -inline int FStrCmp( const char *s1, const char *s2 ) -{ - int c1, c2; - int n = 9999; - - if( s1 == NULL ) - { - if ( s2 == NULL ) return 0; - else return -1; - } - else if ( s2 == NULL ) return 1; - - do { - c1 = *s1++; - c2 = *s2++; - - // strings are equal until end point - if ( !n-- ) return 0; - if ( c1 != c2 ) return c1 < c2 ? -1 : 1; - - } while ( c1 ); - - // strings are equal - return 0; -} - -inline int FStriCmp( const char *s1, const char *s2 ) -{ - int c1, c2; - int n = 9999; - - if( s1 == NULL ) - { - if ( s2 == NULL ) return 0; - else return -1; - } - else if ( s2 == NULL ) return 1; - - do { - c1 = *s1++; - c2 = *s2++; - - if ( !n-- ) return 0; // strings are equal until end point - - if ( c1 != c2 ) - { - if ( c1 >= 'a' && c1 <= 'z' ) c1 -= ('a' - 'A'); - if ( c2 >= 'a' && c2 <= 'z' ) c2 -= ('a' - 'A'); - if ( c1 != c2 ) return c1 < c2 ? -1 : 1; - } - } while ( c1 ); - - // strings are equal - return 0; -} - -inline BOOL FStrEq( const char*sz1, const char*sz2 ) { return (FStrCmp( sz1, sz2 ) == 0); } -inline BOOL FClassnameIs(edict_t* pent, const char* szClassname) { return FStrEq(STRING(VARS(pent)->classname), szClassname); } -inline BOOL FClassnameIs(entvars_t* pev, const char* szClassname) { return FStrEq(STRING(pev->classname), szClassname); } - -// Ugly technique to override base member functions -// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a -// member function of a base class. static_cast is a sleezy way around that problem. -#ifdef _DEBUG - -#define SetThink( a ) ThinkSet( static_cast (a), #a ) -#define SetTouch( a ) TouchSet( static_cast (a), #a ) -#define SetUse( a ) UseSet( static_cast (a), #a ) -#define SetBlocked( a ) BlockedSet( static_cast (a), #a ) - -#else - -#define SetThink( a ) m_pfnThink = static_cast (a) -#define SetTouch( a ) m_pfnTouch = static_cast (a) -#define SetUse( a ) m_pfnUse = static_cast (a) -#define SetBlocked( a ) m_pfnBlocked = static_cast (a) - -#endif - -// Misc. Prototypes -extern void UTIL_SetSize (entvars_t* pev, const Vector &vecMin, const Vector &vecMax); -extern float UTIL_VecToYaw (const Vector &vec); -extern Vector UTIL_VecToAngles (const Vector &vec); -extern float UTIL_AngleMod (float a); -extern float UTIL_AngleDiff ( float destAngle, float srcAngle ); - -extern Vector UTIL_AxisRotationToAngles (const Vector &vec, float angle); //LRC -extern Vector UTIL_AxisRotationToVec (const Vector &vec, float angle); //LRC - -extern CBaseEntity *UTIL_FindEntityInSphere(CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius); -extern CBaseEntity *UTIL_FindEntityByString(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ); -extern CBaseEntity *UTIL_FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName ); -extern CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName ); -extern CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pActivator ); //LRC - for $locus references -extern CBaseEntity *UTIL_FindEntityByTarget(CBaseEntity *pStartEntity, const char *szName ); -extern CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, float flRadius ); -extern CBaseEntity *UTIL_FindGlobalEntity( string_t classname, string_t globalname ); -extern CBaseEntity *UTIL_FindPlayerInSphere( const Vector &vecCenter, float flRadius ); -extern edict_t *UTIL_FindClientTransitions( edict_t *pClient ); -extern CBasePlayer *UTIL_FindPlayerInPVS( edict_t *pent ); - -// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected -// otherwise returns NULL -// Index is 1 based -extern CBaseEntity *UTIL_PlayerByIndex( int playerIndex ); - - -#define UTIL_EntitiesInPVS( pent ) (*g_engfuncs.pfnEntitiesInPVS)(pent) -extern void UTIL_MakeVectors( const Vector &vecAngles ); - -// Pass in an array of pointers and an array size, it fills the array and returns the number inserted -extern int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ); -extern int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ); - -inline void UTIL_MakeVectorsPrivate( const Vector &vecAngles, float *p_vForward, float *p_vRight, float *p_vUp ) -{ - g_engfuncs.pfnAngleVectors( vecAngles, p_vForward, p_vRight, p_vUp ); -} - -extern void UTIL_MakeAimVectors ( const Vector &vecAngles ); // like MakeVectors, but assumes pitch isn't inverted -extern void UTIL_MakeInvVectors ( const Vector &vec, globalvars_t *pgv ); - -extern void UTIL_SetEdictOrigin ( edict_t *pEdict, const Vector &vecOrigin ); - -extern void UTIL_EmitAmbientSound( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ); -extern void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ); -extern void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius ); -extern void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, BOOL bAirShake ); -extern void UTIL_ScreenShakeAll( const Vector ¢er, float amplitude, float frequency, float duration, ShakeCommand_t eCommand, BOOL bAirShake ); -extern void UTIL_ShowMessage( const char *pString, CBaseEntity *pPlayer ); -extern void UTIL_ShowMessageAll( const char *pString ); - -extern void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ); -extern void UTIL_ScreenFade( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags, int playernum = 1); - -extern void UTIL_SetFog ( Vector color, int iFadeTime, int iStartDist, int iEndDist, int playernum = 1 ); -extern void UTIL_SetFogAll ( Vector color, int iFadeTime, int iStartDist, int iEndDist ); - -extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr); -extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr); -extern void UTIL_TraceHull (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr); -extern TraceResult UTIL_GetGlobalTrace (void); -extern void UTIL_TraceModel (const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr); -extern Vector UTIL_GetAimVector (edict_t* pent, float flSpeed); -extern int UTIL_PointContents (const Vector &vec); - -extern int UTIL_IsMasterTriggered (string_t sMaster, CBaseEntity *pActivator); -extern void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ); -extern void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ); -extern Vector UTIL_RandomBloodVector( void ); -extern BOOL UTIL_ShouldShowBlood( int bloodColor ); -extern void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ); -extern void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ); -extern void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ); -extern void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ); -extern void UTIL_Sparks( const Vector &position ); -extern void UTIL_Explode( const Vector ¢er, edict_t *pOwner, int radius, int name = 0 ); -extern void UTIL_Ricochet( const Vector &position, float scale ); -extern void UTIL_StringToVector( float *pVector, const char *pString ); -extern void UTIL_StringToRandomVector( float *pVector, const char *pString ); //LRC -extern void UTIL_StringToIntArray( int *pVector, int count, const char *pString ); -extern Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ); -extern float UTIL_Approach( float target, float value, float speed ); -extern float UTIL_ApproachAngle( float target, float value, float speed ); -extern float UTIL_AngleDistance( float next, float cur ); - -extern char *UTIL_VarArgs( char *format, ... ); -extern void UTIL_Remove( CBaseEntity *pEntity ); -extern BOOL UTIL_IsValidEntity( edict_t *pent ); -extern BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ); -extern BOOL UTIL_IsFacing( entvars_t *pevTest, const Vector &reference ); //LRC - -// Use for ease-in, ease-out style interpolation (accel/decel) -extern float UTIL_SplineFraction( float value, float scale ); - -// Search for water transition along a vertical line -extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); -extern void UTIL_Bubbles( Vector mins, Vector maxs, int count ); -extern void UTIL_BubbleTrail( Vector from, Vector to, int count ); - -// allows precacheing of other entities -// prints a message to each client -extern void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); -inline void UTIL_CenterPrintAll( const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ) -{ - UTIL_ClientPrintAll( HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 ); -} - -class CBasePlayerWeapon; -class CBasePlayer; -extern BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerWeapon *pCurrentWeapon ); - -// prints messages through the HUD -extern void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); - -// prints a message to the HUD say (chat) -extern void UTIL_SayText( const char *pText, CBaseEntity *pEntity ); -extern void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ); - - -typedef struct hudtextparms_s -{ - float x; - float y; - int effect; - byte r1, g1, b1, a1; - byte r2, g2, b2, a2; - float fadeinTime; - float fadeoutTime; - float holdTime; - float fxTime; - int channel; -} hudtextparms_t; - -// prints as transparent 'title' to the HUD -extern void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ); -extern void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ); - -// for handy use with ClientPrint params -extern char *UTIL_dtos1( int d ); -extern char *UTIL_dtos2( int d ); -extern char *UTIL_dtos3( int d ); -extern char *UTIL_dtos4( int d ); - -// Writes message to console with timestamp and FragLog header. -extern void UTIL_LogPrintf( char *fmt, ... ); -extern const char *UTIL_FileExtension( const char *in ); - -// Sorta like FInViewCone, but for nonmonsters. -extern float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ); - -extern void UTIL_StripToken( const char *pKey, char *pDest );// for redundant keynames - -// Misc functions -extern void UTIL_SetMovedir(entvars_t* pev); -extern void UTIL_SynchDoors( CBaseEntity *pEntity ); -extern Vector UTIL_GetMovedir( Vector vecAngles ); -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern int BuildChangeList( LEVELLIST *pLevelList, int maxList ); - -// -// How did I ever live without ASSERT? -// -#ifdef DEBUG -void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage); -#define ASSERT(f) DBG_AssertFunction(f, #f, __FILE__, __LINE__, NULL) -#define ASSERTSZ(f, sz) DBG_AssertFunction(f, #f, __FILE__, __LINE__, sz) -#else // !DEBUG -#define ASSERT(f) -#define ASSERTSZ(f, sz) -#endif // !DEBUG - - -extern DLL_GLOBAL const Vector g_vecZero; - -// -// Constants that were used only by QC (maybe not used at all now) -// -// Un-comment only as needed -// -#define LANGUAGE_ENGLISH 0 -#define LANGUAGE_GERMAN 1 -#define LANGUAGE_FRENCH 2 -#define LANGUAGE_BRITISH 3 - -extern DLL_GLOBAL int g_Language; - -#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation -#define AMBIENT_SOUND_EVERYWHERE 1 -#define AMBIENT_SOUND_SMALLRADIUS 2 -#define AMBIENT_SOUND_MEDIUMRADIUS 4 -#define AMBIENT_SOUND_LARGERADIUS 8 -#define AMBIENT_SOUND_START_SILENT 16 -#define AMBIENT_SOUND_NOT_LOOPING 32 - -#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements - -#define LFO_SQUARE 1 -#define LFO_TRIANGLE 2 -#define LFO_RANDOM 3 - -// func_rotating -#define SF_BRUSH_ROTATE_Y_AXIS 0 //!?! (LRC) -#define SF_BRUSH_ROTATE_INSTANT 1 -#define SF_BRUSH_ROTATE_BACKWARDS 2 -#define SF_BRUSH_ROTATE_Z_AXIS 4 -#define SF_BRUSH_ROTATE_X_AXIS 8 -#define SF_PENDULUM_AUTO_RETURN 16 -#define SF_PENDULUM_PASSABLE 32 - -#define SF_BRUSH_ROTATE_SMALLRADIUS 128 -#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256 -#define SF_BRUSH_ROTATE_LARGERADIUS 512 - -#define PUSH_BLOCK_ONLY_X 1 -#define PUSH_BLOCK_ONLY_Y 2 - -#define VEC_HULL_MIN gpGlobals->hullmins[0] -#define VEC_HULL_MAX gpGlobals->hullmaxs[0] -#define VEC_HUMAN_HULL_MIN Vector( -16, -16, 0 ) -#define VEC_HUMAN_HULL_MAX Vector( 16, 16, 72 ) -#define VEC_HUMAN_HULL_DUCK Vector( 16, 16, 36 ) - -#define VEC_VIEW Vector( 0, 0, gpGlobals->viewheight[0] ) - -#define VEC_DUCK_HULL_MIN gpGlobals->hullmins[1] -#define VEC_DUCK_HULL_MAX gpGlobals->hullmaxs[1] -#define VEC_DUCK_VIEW Vector( 0, 0, gpGlobals->viewheight[1] ) - -// triggers -#define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger -#define SF_TRIGGER_NOCLIENTS 2// players not allowed to fire this trigger -#define SF_TRIGGER_PUSHABLES 4// only pushables can fire this trigger -#define SF_TRIGGER_EVERYTHING 8// everything else can fire this trigger (e.g. gibs, rockets) - -// func breakable -#define SF_BREAK_TRIGGER_ONLY 1// may only be broken by trigger -#define SF_BREAK_TOUCH 2// can be 'crashed through' by running player (plate glass) -#define SF_BREAK_PRESSURE 4// can be broken by a player standing on it -#define SF_BREAK_CROWBAR 256// instant break if hit with crowbar - -// func_pushable (it's also func_breakable, so don't collide with those flags) -#define SF_PUSH_BREAKABLE 128 -#define SF_PUSH_NOPULL 512//LRC -#define SF_PUSH_USECUSTOMSIZE 0x800000 //LRC, not yet used - -#define SF_LIGHT_START_OFF 1 - -#define SPAWNFLAG_NOMESSAGE 1 -#define SPAWNFLAG_NOTOUCH 1 -#define SPAWNFLAG_DROIDONLY 4 - -#define SPAWNFLAG_USEONLY 1 // can't be touched, must be used (buttons) - -#define TELE_PLAYER_ONLY 1 -#define TELE_SILENT 2 - -#define SF_TRIG_PUSH_ONCE 1 - - -// Sound Utilities - -// sentence groups -#define CBSENTENCENAME_MAX 16 -#define CVOXFILESENTENCEMAX 1536 // max number of sentences in game. NOTE: this must match - // CVOXFILESENTENCEMAX in engine\sound.h!!! - -extern unsigned short FixedUnsigned16( float value, float scale ); -extern short FixedSigned16( float value, float scale ); - -extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; -extern int gcallsentences; - -int USENTENCEG_Pick(int isentenceg, char *szfound); -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset); -void USENTENCEG_InitLRU(unsigned char *plru, int count); - -void SENTENCEG_Init(); -void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick); -int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch); -int SENTENCEG_PlayRndSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch); -int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch, int ipick, int freset); -int SENTENCEG_GetIndex(const char *szrootname); -int SENTENCEG_Lookup(const char *sample, char *sentencenum); - -void TEXTURETYPE_Init(); -char TEXTURETYPE_Find(char *name); -float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); - -// NOTE: use EMIT_SOUND_DYN to set the pitch of a sound. Pitch of 100 -// is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 -// down to 1 is a lower pitch. 150 to 70 is the realistic range. -// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as -// fast as EMIT_SOUND (the pitchshift mixer is not native coded). - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch); - - -inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation) -{ - EMIT_SOUND_DYN(entity, channel, sample, volume, attenuation, 0, PITCH_NORM); -} - -inline void STOP_SOUND(edict_t *entity, int channel, const char *sample) -{ - EMIT_SOUND_DYN(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM); -} - -void EMIT_SOUND_SUIT(edict_t *entity, const char *sample); -void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg); -void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname); - -#define PRECACHE_SOUND_ARRAY( a ) \ - { for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); } - -#define EMIT_SOUND_ARRAY_DYN( chan, array ) \ - EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) ); - -#define RANDOM_SOUND_ARRAY( array ) (array) [ RANDOM_LONG(0,ARRAYSIZE( (array) )-1) ] - -#define PLAYBACK_EVENT( flags, who, index ) PLAYBACK_EVENT_FULL( flags, who, index, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); -#define PLAYBACK_EVENT_DELAY( flags, who, index, delay ) PLAYBACK_EVENT_FULL( flags, who, index, delay, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - -#define GROUP_OP_AND 0 -#define GROUP_OP_NAND 1 - -extern int g_groupmask; -extern int g_groupop; - -class UTIL_GroupTrace -{ -public: - UTIL_GroupTrace( int groupmask, int op ); - ~UTIL_GroupTrace( void ); - -private: - int m_oldgroupmask, m_oldgroupop; -}; - -void UTIL_SetGroupTrace( int groupmask, int op ); -void UTIL_UnsetGroupTrace( void ); - -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); - -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); - -float UTIL_WeaponTimeBase( void ); -int GetStdLightStyle (int iStyle); //LRC- declared here so it can be used by everything that - // needs to deal with the standard lightstyles. -// for trigger_viewset -int HaveCamerasInPVS( edict_t* edict ); -BOOL IsMultiplayer ( void ); -BOOL IsDeatchmatch ( void ); - -void UTIL_SetView( int ViewEntity = 0, int flags = 0 ); -void UTIL_SetView( CBaseEntity *pActivator, int ViewEntity = 0, int flags = 0 ); -void UTIL_SetView( CBaseEntity *pActivator, CBaseEntity *pViewEnt = 0, int flags = 0 ); - -void UTIL_SetModel( edict_t *e, string_t s, const char *c ); -void UTIL_SetModel( edict_t *e, const char *model ); -void UTIL_SetModel( edict_t *e, string_t model ); -int UTIL_PrecacheModel( const char* s ); -int UTIL_PrecacheModel( string_t s, const char *e ); -int UTIL_PrecacheSound( const char* s ); -int UTIL_PrecacheSound( string_t s, const char *e ); -int UTIL_PrecacheModel( string_t s ); -int UTIL_PrecacheSound( string_t s ); -void UTIL_PrecacheEntity( const char *szClassname ); - -int UTIL_PrecacheAurora( string_t s ); -int UTIL_PrecacheAurora( const char *s ); -void UTIL_SetAurora( CBaseEntity *pAttach, int aur, int attachment = 0 ); - -extern int giAmmoIndex; - -Vector UTIL_GetAngleDistance( Vector vecAngles, float distance ); -void UTIL_SetThink ( CBaseEntity *pEnt ); - -void UTIL_AssignOrigin( CBaseEntity* pEntity, const Vector vecOrigin, BOOL bInitiator = TRUE); -void UTIL_AssignAngles( CBaseEntity *pEntity, const Vector vecAngles, BOOL bInitiator = TRUE); -void UTIL_ComplexRotate( CBaseEntity *pParent, CBaseEntity *pChild, const Vector &dest, float m_flTravelTime ); - -void UTIL_SetAngles ( CBaseEntity* pEntity, const Vector &vecAngles ); -void UTIL_SetOrigin ( CBaseEntity* pEntity, const Vector &vecOrigin ); - -void UTIL_SetVelocity ( CBaseEntity *pEnt, const Vector vecSet ); -void UTIL_SetAvelocity( CBaseEntity *pEnt, const Vector vecSet ); - -void UTIL_SetChildVelocity( CBaseEntity *pEnt, const Vector vecSet, int loopbreaker ); -void UTIL_SetChildAvelocity( CBaseEntity *pEnt, const Vector vecSet, int loopbreaker ); -void UTIL_MergePos ( CBaseEntity *pEnt, int loopbreaker = MAX_CHILDS); - -#define CHECK_FLAG(x) if(Ent->pFlags & x) strcat(szFlags,#x", ") -#define clamp(a,min,max) ((a < min)?(min):((a > max)?(max):(a))) -#define DECLARE_CLASS( className, baseClassName ) \ - typedef baseClassName BaseClass; \ - typedef className ThisClass; - -//COM_Utils -void UTIL_PrecacheResourse( void ); -void Msg( char *szText, ... ); -void DevMsg( char *szText, ... ); -char *COM_ParseToken( const char **data ); -void COM_FreeFile (char *buffer); - - -//Xash Parent System Flags -#define PF_AFFECT (1<<0) //this is child entity -#define PF_DESIRED (1<<1) -#define PF_ACTION (1<<2) //this is chain entity (set automatically) -#define PF_MOVENONE (1<<3) //this entity has MOVETYPE_NONE before set parent (needs for return) -#define PF_CORECTSPEED (1<<4) //force child to parent coordintes e.g. sprite to attachment -#define PF_MERGEPOS (1<<5) //Merge current pos for entity -#define PF_POSTVELOCITY (1<<6) //apply and correct velocity from parent -#define PF_POSTAVELOCITY (1<<7) //apply and correct avelocity from parent -#define PF_SETTHINK (1<<8) //manually force entity to think -#define PF_POSTAFFECT (1<<9) //apply -#define PF_PARENTMOVE (1<<10) //parent give me velocity or avelocity -#define PF_ANGULAR (1<<11) //parent has angular moving -#define PF_POSTORG (1<<12) //this entity MUST changed origin only -#define PF_POINTENTITY (1<<13) -#define PF_LINKCHILD (PF_AFFECT|PF_DESIRED|PF_MERGEPOS|PF_POSTORG) - -BOOL FClassnameIs(CBaseEntity *pEnt, const char* szClassname); - -//affects -int FrameAffect( CBaseEntity *pEnt ); -int PostFrameAffect( CBaseEntity *pEnt ); - -//childs affect -void ChildAffect( CBaseEntity *pEnt, Vector vecAdjustVel, Vector vecAdjustAVel ); -void ChildPostAffect ( CBaseEntity *pEnt ); - -//link operations -void LinkChild(CBaseEntity *pEnt); - -void UnlinkFromParent( CBaseEntity *pRemove ); -void TransferChildren( CBaseEntity *pOldParent, CBaseEntity *pNewParent ); -void LinkChild( CBaseEntity *pParent, CBaseEntity *pChild ); -void UnlinkAllChildren( CBaseEntity *pParent ); -bool EntityIsParentOf( CBaseEntity *pParent, CBaseEntity *pEntity ); - -//handles -void HandleAffect( CBaseEntity *pEnt, Vector vecAdjustVel, Vector vecAdjustAVel ); -void HandlePostAffect( CBaseEntity *pEnt ); - -//debug -void GetPFlags( CBaseEntity* Ent ); -void GetPInfo( CBaseEntity* Ent ); - -//Parent utils -void UTIL_MarkChild ( CBaseEntity *pEnt, BOOL correctSpeed = FALSE, BOOL desired = TRUE); -void UTIL_SetPostAffect( CBaseEntity *pEnt ); -void UTIL_SetThink ( CBaseEntity *pEnt ); -void UTIL_SetAction( CBaseEntity *pEnt ); -BOOL SynchLost( CBaseEntity *pEnt );//watching for synchronize - -Vector UTIL_RandomVector(void); -Vector UTIL_RandomVector( Vector vmin, Vector vmax ); -void UTIL_AngularVector( CBaseEntity *pEnt ); -void UTIL_LinearVector( CBaseEntity *pEnt ); -float UTIL_CalcDistance( Vector vecAngles ); -void UTIL_WatchTarget( CBaseEntity *pWatcher, CBaseEntity *pTarget); -void UTIL_FindBreakable( CBaseEntity *Brush ); -edict_t *UTIL_FindLandmark( string_t iLandmarkName ); -edict_t *UTIL_FindLandmark( const char *pLandmarkName ); -int UTIL_FindTransition( CBaseEntity *pEntity, const char *pVolumeName ); -int UTIL_FindTransition( CBaseEntity *pEntity, string_t iVolumeName ); -void UTIL_FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value = 0); -void UTIL_FireTargets( int targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value = 0); -CBaseEntity *UTIL_FindEntityForward( CBaseEntity *pMe ); -void UTIL_FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ); -int UTIL_LoadSoundPreset( string_t pString ); -int UTIL_LoadSoundPreset( const char *pString ); -int UTIL_LoadDecalPreset( string_t pString ); -int UTIL_LoadDecalPreset( const char *pString ); -void UTIL_ChangeLevel( string_t mapname, string_t spotname ); -void UTIL_ChangeLevel( const char *szNextMap, const char *szNextSpot ); -void AddAmmoName( string_t iAmmoName ); - -// precache utils -void UTIL_PrecacheEntity( string_t szClassname ); -BOOL UTIL_EntIsVisible( entvars_t* pev, entvars_t* pevTarget); - -// events stuff -unsigned short UTIL_PrecacheEvent( const char *pString ); - -#endif //UTIL_H \ No newline at end of file diff --git a/server/monsters/activity.h b/server/monsters/activity.h deleted file mode 100644 index a6ba9a8c..00000000 --- a/server/monsters/activity.h +++ /dev/null @@ -1,132 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef ACTIVITY_H -#define ACTIVITY_H - -typedef enum -{ - ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity - ACT_IDLE = 1, - ACT_GUARD, - ACT_WALK, - ACT_RUN, - ACT_FLY, // Fly (and flap if appropriate) - ACT_SWIM, - ACT_HOP, // vertical jump - ACT_LEAP, // long forward jump - ACT_FALL, - ACT_LAND, - ACT_STRAFE_LEFT, - ACT_STRAFE_RIGHT, - ACT_ROLL_LEFT, // tuck and roll, left - ACT_ROLL_RIGHT, // tuck and roll, right - ACT_TURN_LEFT, // turn quickly left (stationary) - ACT_TURN_RIGHT, // turn quickly right (stationary) - ACT_CROUCH, // the act of crouching down from a standing position - ACT_CROUCHIDLE, // holding body in crouched position (loops) - ACT_STAND, // the act of standing from a crouched position - ACT_USE, - ACT_SIGNAL1, - ACT_SIGNAL2, - ACT_SIGNAL3, - ACT_TWITCH, - ACT_COWER, - ACT_SMALL_FLINCH, - ACT_BIG_FLINCH, - ACT_RANGE_ATTACK1, - ACT_RANGE_ATTACK2, - ACT_MELEE_ATTACK1, - ACT_MELEE_ATTACK2, - ACT_RELOAD, - ACT_ARM, // pull out gun, for instance - ACT_DISARM, // reholster gun - ACT_EAT, // monster chowing on a large food item (loop) - ACT_DIESIMPLE, - ACT_DIEBACKWARD, - ACT_DIEFORWARD, - ACT_DIEVIOLENT, - ACT_BARNACLE_HIT, // barnacle tongue hits a monster - ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop ) - ACT_BARNACLE_CHOMP, // barnacle latches on to the monster - ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop ) - ACT_SLEEP, - ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor - ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you - ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop) - ACT_WALK_HURT, // limp (loop) - ACT_RUN_HURT, // limp (loop) - ACT_HOVER, // Idle while in flight - ACT_GLIDE, // Fly (don't flap) - ACT_FLY_LEFT, // Turn left in flight - ACT_FLY_RIGHT, // Turn right in flight - ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air - ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster - ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops. - ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc ) - ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of - ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever - ACT_SPECIAL_ATTACK1,// very monster specific special attacks. - ACT_SPECIAL_ATTACK2, - ACT_COMBAT_IDLE, // agitated idle. - ACT_WALK_SCARED, - ACT_RUN_SCARED, - ACT_VICTORY_DANCE, // killed a player, do a victory dance. - ACT_DIE_HEADSHOT, // die, hit in head. - ACT_DIE_CHESTSHOT, // die, hit in chest - ACT_DIE_GUTSHOT, // die, hit in gut - ACT_DIE_BACKSHOT, // die, hit in back - ACT_FLINCH_HEAD, - ACT_FLINCH_CHEST, - ACT_FLINCH_STOMACH, - ACT_FLINCH_LEFTARM, - ACT_FLINCH_RIGHTARM, - ACT_FLINCH_LEFTLEG, - ACT_FLINCH_RIGHTLEG, - ACT_VM_NONE, // weapon viewmodel animations - ACT_VM_DEPLOY, // deploy - ACT_VM_DEPLOY_EMPTY,// deploy empty weapon - ACT_VM_HOLSTER, // holster empty weapon - ACT_VM_HOLSTER_EMPTY, - ACT_VM_IDLE1, - ACT_VM_IDLE2, - ACT_VM_IDLE3, - ACT_VM_RANGE_ATTACK1, - ACT_VM_RANGE_ATTACK2, - ACT_VM_RANGE_ATTACK3, - ACT_VM_MELEE_ATTACK1, - ACT_VM_MELEE_ATTACK2, - ACT_VM_MELEE_ATTACK3, - ACT_VM_SHOOT_EMPTY, - ACT_VM_START_RELOAD, - ACT_VM_RELOAD, - ACT_VM_RELOAD_EMPTY, - ACT_VM_TURNON, - ACT_VM_TURNOFF, - ACT_VM_PUMP, // pumping gun - ACT_VM_PUMP_EMPTY, - ACT_VM_START_CHARGE, - ACT_VM_CHARGE, - ACT_VM_OVERLOAD, - ACT_VM_IDLE_EMPTY, -} Activity; - -// studio activity map conversion -typedef struct { int type; char *name; } activity_map_t; - -extern activity_map_t activity_map[]; - - -#endif//ACTIVITY_H \ No newline at end of file diff --git a/server/monsters/activitymap.h b/server/monsters/activitymap.h deleted file mode 100644 index af156fde..00000000 --- a/server/monsters/activitymap.h +++ /dev/null @@ -1,121 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -activity_map_t activity_map[] = -{ -{ACT_IDLE, "ACT_IDLE" }, -{ACT_GUARD, "ACT_GUARD" }, -{ACT_WALK, "ACT_WALK" }, -{ACT_RUN, "ACT_RUN" }, -{ACT_FLY, "ACT_FLY" }, -{ACT_SWIM, "ACT_SWIM", }, -{ACT_HOP, "ACT_HOP", }, -{ACT_LEAP, "ACT_LEAP" }, -{ACT_FALL, "ACT_FALL" }, -{ACT_LAND, "ACT_LAND" }, -{ACT_STRAFE_LEFT, "ACT_STRAFE_LEFT" }, -{ACT_STRAFE_RIGHT, "ACT_STRAFE_RIGHT" }, -{ACT_ROLL_LEFT, "ACT_ROLL_LEFT" }, -{ACT_ROLL_RIGHT, "ACT_ROLL_RIGHT" }, -{ACT_TURN_LEFT, "ACT_TURN_LEFT" }, -{ACT_TURN_RIGHT, "ACT_TURN_RIGHT" }, -{ACT_CROUCH, "ACT_CROUCH" }, -{ACT_CROUCHIDLE, "ACT_CROUCHIDLE" }, -{ACT_STAND, "ACT_STAND" }, -{ACT_USE, "ACT_USE" }, -{ACT_SIGNAL1, "ACT_SIGNAL1" }, -{ACT_SIGNAL2, "ACT_SIGNAL2" }, -{ACT_SIGNAL3, "ACT_SIGNAL3" }, -{ACT_TWITCH, "ACT_TWITCH" }, -{ACT_COWER, "ACT_COWER" }, -{ACT_SMALL_FLINCH, "ACT_SMALL_FLINCH" }, -{ACT_BIG_FLINCH, "ACT_BIG_FLINCH" }, -{ACT_RANGE_ATTACK1, "ACT_RANGE_ATTACK1" }, -{ACT_RANGE_ATTACK2, "ACT_RANGE_ATTACK2" }, -{ACT_MELEE_ATTACK1, "ACT_MELEE_ATTACK1" }, -{ACT_MELEE_ATTACK2, "ACT_MELEE_ATTACK2" }, -{ACT_RELOAD, "ACT_RELOAD" }, -{ACT_ARM, "ACT_ARM" }, -{ACT_DISARM, "ACT_DISARM" }, -{ACT_EAT, "ACT_EAT" }, -{ACT_DIESIMPLE, "ACT_DIESIMPLE" }, -{ACT_DIEBACKWARD, "ACT_DIEBACKWARD" }, -{ACT_DIEFORWARD, "ACT_DIEFORWARD" }, -{ACT_DIEVIOLENT, "ACT_DIEVIOLENT" }, -{ACT_BARNACLE_HIT, "ACT_BARNACLE_HIT" }, -{ACT_BARNACLE_PULL, "ACT_BARNACLE_PULL" }, -{ACT_BARNACLE_CHOMP, "ACT_BARNACLE_CHOMP" }, -{ACT_BARNACLE_CHEW, "ACT_BARNACLE_CHEW" }, -{ACT_SLEEP, "ACT_SLEEP" }, -{ACT_INSPECT_FLOOR, "ACT_INSPECT_FLOOR" }, -{ACT_INSPECT_WALL, "ACT_INSPECT_WALL" }, -{ACT_IDLE_ANGRY, "ACT_IDLE_ANGRY" }, -{ACT_WALK_HURT, "ACT_WALK_HURT" }, -{ACT_RUN_HURT, "ACT_RUN_HURT" }, -{ACT_HOVER, "ACT_HOVER" }, -{ACT_GLIDE, "ACT_GLIDE" }, -{ACT_FLY_LEFT, "ACT_FLY_LEFT" }, -{ACT_FLY_RIGHT, "ACT_FLY_RIGHT" }, -{ACT_DETECT_SCENT, "ACT_DETECT_SCENT" }, -{ACT_SNIFF, "ACT_SNIFF" }, -{ACT_BITE, "ACT_BITE" }, -{ACT_THREAT_DISPLAY, "ACT_THREAT_DISPLAY" }, -{ACT_FEAR_DISPLAY, "ACT_FEAR_DISPLAY" }, -{ACT_EXCITED, "ACT_EXCITED" }, -{ACT_SPECIAL_ATTACK1, "ACT_SPECIAL_ATTACK1" }, -{ACT_SPECIAL_ATTACK2, "ACT_SPECIAL_ATTACK2" }, -{ACT_COMBAT_IDLE, "ACT_COMBAT_IDLE" }, -{ACT_WALK_SCARED, "ACT_WALK_SCARED" }, -{ACT_RUN_SCARED, "ACT_RUN_SCARED" }, -{ACT_VICTORY_DANCE, "ACT_VICTORY_DANCE" }, -{ACT_DIE_HEADSHOT, "ACT_DIE_HEADSHOT" }, -{ACT_DIE_CHESTSHOT, "ACT_DIE_CHESTSHOT" }, -{ACT_DIE_GUTSHOT, "ACT_DIE_GUTSHOT" }, -{ACT_DIE_BACKSHOT, "ACT_DIE_BACKSHOT" }, -{ACT_FLINCH_HEAD, "ACT_FLINCH_HEAD" }, -{ACT_FLINCH_CHEST, "ACT_FLINCH_CHEST" }, -{ACT_FLINCH_STOMACH, "ACT_FLINCH_STOMACH" }, -{ACT_FLINCH_LEFTARM, "ACT_FLINCH_LEFTARM" }, -{ACT_FLINCH_RIGHTARM, "ACT_FLINCH_RIGHTARM" }, -{ACT_FLINCH_LEFTLEG, "ACT_FLINCH_LEFTLEG" }, -{ACT_FLINCH_RIGHTLEG, "ACT_FLINCH_RIGHTLEG" }, -{ACT_VM_NONE, "ACT_VM_NONE" }, // invalid animation -{ACT_VM_DEPLOY, "ACT_VM_DEPLOY" }, // deploy -{ACT_VM_DEPLOY_EMPTY, "ACT_VM_DEPLOY_EMPTY" }, // deploy empty weapon -{ACT_VM_HOLSTER, "ACT_VM_HOLSTER" }, // holster empty weapon -{ACT_VM_HOLSTER_EMPTY, "ACT_VM_HOLSTER_EMPTY" }, -{ACT_VM_IDLE1, "ACT_VM_IDLE1" }, -{ACT_VM_IDLE2, "ACT_VM_IDLE2" }, -{ACT_VM_IDLE3, "ACT_VM_IDLE3" }, -{ACT_VM_RANGE_ATTACK1, "ACT_VM_RANGE_ATTACK1" }, -{ACT_VM_RANGE_ATTACK2, "ACT_VM_RANGE_ATTACK2" }, -{ACT_VM_RANGE_ATTACK3, "ACT_VM_RANGE_ATTACK3" }, -{ACT_VM_MELEE_ATTACK1, "ACT_VM_MELEE_ATTACK1" }, -{ACT_VM_MELEE_ATTACK2, "ACT_VM_MELEE_ATTACK2" }, -{ACT_VM_MELEE_ATTACK3, "ACT_VM_MELEE_ATTACK3" }, -{ACT_VM_SHOOT_EMPTY, "ACT_VM_SHOOT_EMPTY" }, -{ACT_VM_START_RELOAD, "ACT_VM_START_RELOAD" }, -{ACT_VM_RELOAD, "ACT_VM_RELOAD" }, -{ACT_VM_RELOAD_EMPTY, "ACT_VM_RELOAD_EMPTY" }, -{ACT_VM_TURNON, "ACT_VM_TURNON" }, -{ACT_VM_TURNOFF, "ACT_VM_TURNOFF" }, -{ACT_VM_PUMP, "ACT_VM_PUMP" }, // user animations -{ACT_VM_PUMP_EMPTY, "ACT_VM_PUMP_EMPTY" }, -{ACT_VM_START_CHARGE, "ACT_VM_START_CHARGE" }, -{ACT_VM_CHARGE, "ACT_VM_CHARGE" }, -{ACT_VM_OVERLOAD, "ACT_VM_OVERLOAD" }, -{ACT_VM_IDLE_EMPTY, "ACT_VM_IDLE_EMPTY" }, -{0, NULL }, -}; diff --git a/server/monsters/ai_sound.cpp b/server/monsters/ai_sound.cpp deleted file mode 100644 index 88577ff6..00000000 --- a/server/monsters/ai_sound.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" - - -LINK_ENTITY_TO_CLASS( soundent, CSoundEnt ); - -CSoundEnt *pSoundEnt; - -//========================================================= -// CSound - Clear - zeros all fields for a sound -//========================================================= -void CSound :: Clear ( void ) -{ - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_flExpireTime = 0; - m_iNext = SOUNDLIST_EMPTY; - m_iNextAudible = 0; -} - -//========================================================= -// Reset - clears the volume, origin, and type for a sound, -// but doesn't expire or unlink it. -//========================================================= -void CSound :: Reset ( void ) -{ - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_iNext = SOUNDLIST_EMPTY; -} - -//========================================================= -// FIsSound - returns TRUE if the sound is an Audible sound -//========================================================= -BOOL CSound :: FIsSound ( void ) -{ - if ( m_iType & ( bits_SOUND_COMBAT | bits_SOUND_WORLD | bits_SOUND_PLAYER | bits_SOUND_DANGER ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// FIsScent - returns TRUE if the sound is actually a scent -//========================================================= -BOOL CSound :: FIsScent ( void ) -{ - if ( m_iType & ( bits_SOUND_CARCASS | bits_SOUND_MEAT | bits_SOUND_GARBAGE ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// Spawn -//========================================================= -void CSoundEnt :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - Initialize(); - - SetNextThink( 1 ); -} - -//========================================================= -// Think - at interval, the entire active sound list is checked -// for sounds that have ExpireTimes less than or equal -// to the current world time, and these sounds are deallocated. -//========================================================= -void CSoundEnt :: Think ( void ) -{ - int iSound; - int iPreviousSound; - - SetNextThink( 0.3 );// how often to check the sound list. - - iPreviousSound = SOUNDLIST_EMPTY; - iSound = m_iActiveSound; - - while ( iSound != SOUNDLIST_EMPTY ) - { - if ( m_SoundPool[ iSound ].m_flExpireTime <= gpGlobals->time && m_SoundPool[ iSound ].m_flExpireTime != SOUND_NEVER_EXPIRE ) - { - int iNext = m_SoundPool[ iSound ].m_iNext; - - // move this sound back into the free list - FreeSound( iSound, iPreviousSound ); - - iSound = iNext; - } - else - { - iPreviousSound = iSound; - iSound = m_SoundPool[ iSound ].m_iNext; - } - } - - if ( m_fShowReport ) - { - ALERT ( at_aiconsole, "Soundlist: %d / %d (%d)\n", ISoundsInList( SOUNDLISTTYPE_ACTIVE ),ISoundsInList( SOUNDLISTTYPE_FREE ), ISoundsInList( SOUNDLISTTYPE_ACTIVE ) - m_cLastActiveSounds ); - m_cLastActiveSounds = ISoundsInList ( SOUNDLISTTYPE_ACTIVE ); - } - -} - -//========================================================= -// Precache - dummy function -//========================================================= -void CSoundEnt :: Precache ( void ) -{ -} - -//========================================================= -// FreeSound - clears the passed active sound and moves it -// to the top of the free list. TAKE CARE to only call this -// function for sounds in the Active list!! -//========================================================= -void CSoundEnt :: FreeSound ( int iSound, int iPrevious ) -{ - if ( !pSoundEnt ) - { - // no sound ent! - return; - } - - if ( iPrevious != SOUNDLIST_EMPTY ) - { - // iSound is not the head of the active list, so - // must fix the index for the Previous sound -// pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = m_SoundPool[ iSound ].m_iNext; - pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = pSoundEnt->m_SoundPool[ iSound ].m_iNext; - } - else - { - // the sound we're freeing IS the head of the active list. - pSoundEnt->m_iActiveSound = pSoundEnt->m_SoundPool [ iSound ].m_iNext; - } - - // make iSound the head of the Free list. - pSoundEnt->m_SoundPool[ iSound ].m_iNext = pSoundEnt->m_iFreeSound; - pSoundEnt->m_iFreeSound = iSound; -} - -//========================================================= -// IAllocSound - moves a sound from the Free list to the -// Active list returns the index of the alloc'd sound -//========================================================= -int CSoundEnt :: IAllocSound( void ) -{ - int iNewSound; - - if ( m_iFreeSound == SOUNDLIST_EMPTY ) - { - // no free sound! - ALERT ( at_console, "Free Sound List is full!\n" ); - return SOUNDLIST_EMPTY; - } - - // there is at least one sound available, so move it to the - // Active sound list, and return its SoundPool index. - - iNewSound = m_iFreeSound;// copy the index of the next free sound - - m_iFreeSound = m_SoundPool[ m_iFreeSound ].m_iNext;// move the index down into the free list. - - m_SoundPool[ iNewSound ].m_iNext = m_iActiveSound;// point the new sound at the top of the active list. - - m_iActiveSound = iNewSound;// now make the new sound the top of the active list. You're done. - - return iNewSound; -} - -//========================================================= -// InsertSound - Allocates a free sound and fills it with -// sound info. -//========================================================= -void CSoundEnt :: InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) -{ - int iThisSound; - - if ( !pSoundEnt ) - { - // no sound ent! - return; - } - - iThisSound = pSoundEnt->IAllocSound(); - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - ALERT( at_console, "Could not AllocSound() for InsertSound() (DLL)\n" ); - return; - } - - pSoundEnt->m_SoundPool[ iThisSound ].m_vecOrigin = vecOrigin; - pSoundEnt->m_SoundPool[ iThisSound ].m_iType = iType; - pSoundEnt->m_SoundPool[ iThisSound ].m_iVolume = iVolume; - pSoundEnt->m_SoundPool[ iThisSound ].m_flExpireTime = gpGlobals->time + flDuration; -} - -//========================================================= -// Initialize - clears all sounds and moves them into the -// free sound list. -//========================================================= -void CSoundEnt :: Initialize ( void ) -{ - int i; - int iSound; - - m_cLastActiveSounds; - m_iFreeSound = 0; - m_iActiveSound = SOUNDLIST_EMPTY; - - for ( i = 0 ; i < MAX_WORLD_SOUNDS ; i++ ) - {// clear all sounds, and link them into the free sound list. - m_SoundPool[ i ].Clear(); - m_SoundPool[ i ].m_iNext = i + 1; - } - - m_SoundPool[ i - 1 ].m_iNext = SOUNDLIST_EMPTY;// terminate the list here. - - - // now reserve enough sounds for each client - for ( i = 0 ; i < gpGlobals->maxClients ; i++ ) - { - iSound = pSoundEnt->IAllocSound(); - - if ( iSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Could not AllocSound() for Client Reserve! (DLL)\n" ); - return; - } - - pSoundEnt->m_SoundPool[ iSound ].m_flExpireTime = SOUND_NEVER_EXPIRE; - } - - if ( CVAR_GET_FLOAT("displaysoundlist") == 1 ) - { - m_fShowReport = TRUE; - } - else - { - m_fShowReport = FALSE; - } -} - -//========================================================= -// ISoundsInList - returns the number of sounds in the desired -// sound list. -//========================================================= -int CSoundEnt :: ISoundsInList ( int iListType ) -{ - int i; - int iThisSound; - - if ( iListType == SOUNDLISTTYPE_FREE ) - { - iThisSound = m_iFreeSound; - } - else if ( iListType == SOUNDLISTTYPE_ACTIVE ) - { - iThisSound = m_iActiveSound; - } - else - { - ALERT( at_console, "Unknown Sound List Type!\n" ); - } - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - return 0; - } - - i = 0; - - while ( iThisSound != SOUNDLIST_EMPTY ) - { - i++; - - iThisSound = m_SoundPool[ iThisSound ].m_iNext; - } - - return i; -} - -//========================================================= -// ActiveList - returns the head of the active sound list -//========================================================= -int CSoundEnt :: ActiveList ( void ) -{ - if ( !pSoundEnt ) - { - return SOUNDLIST_EMPTY; - } - - return pSoundEnt->m_iActiveSound; -} - -//========================================================= -// FreeList - returns the head of the free sound list -//========================================================= -int CSoundEnt :: FreeList ( void ) -{ - if ( !pSoundEnt ) - { - return SOUNDLIST_EMPTY; - } - - return pSoundEnt->m_iFreeSound; -} - -//========================================================= -// SoundPointerForIndex - returns a pointer to the instance -// of CSound at index's position in the sound pool. -//========================================================= -CSound* CSoundEnt :: SoundPointerForIndex( int iIndex ) -{ - if ( !pSoundEnt ) - { - return NULL; - } - - if( iIndex > ( MAX_WORLD_SOUNDS - 1 )) - { - ALERT( at_console, "SoundPointerForIndex() - Index too large!\n" ); - return NULL; - } - - if ( iIndex < 0 ) - { - ALERT( at_console, "SoundPointerForIndex() - Index < 0!\n" ); - return NULL; - } - - return &pSoundEnt->m_SoundPool[ iIndex ]; -} - -//========================================================= -// Clients are numbered from 1 to MAXCLIENTS, but the client -// reserved sounds in the soundlist are from 0 to MAXCLIENTS - 1, -// so this function ensures that a client gets the proper index -// to his reserved sound in the soundlist. -//========================================================= -int CSoundEnt :: ClientSoundIndex ( edict_t *pClient ) -{ - int iReturn = ENTINDEX( pClient ) - 1; - -#ifdef _DEBUG - if ( iReturn < 0 || iReturn > gpGlobals->maxClients ) - { - ALERT( at_console, "** ClientSoundIndex returning a bogus value! **\n" ); - } -#endif // _DEBUG - - return iReturn; -} diff --git a/server/monsters/animating.cpp b/server/monsters/animating.cpp deleted file mode 100644 index f88eca5e..00000000 --- a/server/monsters/animating.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== monsters.cpp ======================================================== - - Monster-related utility code - -*/ - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "animation.h" -#include "saverestore.h" - -TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = -{ - DEFINE_FIELD( CBaseMonster, m_flFrameRate, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flGroundSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flLastEventCheck, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_fSequenceFinished, FIELD_BOOLEAN ), - DEFINE_FIELD( CBaseMonster, m_fSequenceLoops, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseLogic ); - - -//========================================================= -// StudioFrameAdvance - advance the animation frame up to the current time -// if an flInterval is passed in, only advance animation that number of seconds -//========================================================= -float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) -{ - if (flInterval == 0.0) - { - flInterval = (gpGlobals->time - pev->animtime); - if (flInterval <= 0.001) - { - pev->animtime = gpGlobals->time; - return 0.0; - } - } - if (! pev->animtime) - flInterval = 0.0; - - pev->frame += flInterval * m_flFrameRate * pev->framerate; - pev->animtime = gpGlobals->time; - - if (pev->frame < 0.0 || pev->frame >= 256.0) - { - if (m_fSequenceLoops) - pev->frame -= (int)(pev->frame / 256.0) * 256.0; - else - pev->frame = (pev->frame < 0.0) ? 0 : 255; - m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents - } - - return flInterval; -} - -float CBaseAnimating :: SequenceDuration( int iSequence ) -{ - dstudiohdr_t *pstudiohdr; - void *pmodel = GET_MODEL_PTR(ENT(pev)); - pstudiohdr = (dstudiohdr_t *)pmodel; - - if (!pstudiohdr) - return 0; - - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + iSequence; - return (float)pseqdesc->numframes/(float)pseqdesc->fps; -} - -//========================================================= -// LookupActivity -//========================================================= -int CBaseAnimating :: LookupActivity ( int activity ) -{ - ASSERT( activity != 0 ); - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupActivity( pmodel, pev, activity ); -} - -//========================================================= -// LookupActivityHeaviest -// -// Get activity with highest 'weight' -// -//========================================================= -int CBaseAnimating :: LookupActivityHeaviest ( int activity ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupActivityHeaviest( pmodel, pev, activity ); -} - -//========================================================= -//========================================================= -int CBaseAnimating :: LookupSequence ( const char *label ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupSequence( pmodel, label ); -} - - -//========================================================= -//========================================================= -void CBaseAnimating :: ResetSequenceInfo ( ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed ); - m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0); - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; - m_fSequenceFinished = FALSE; - m_flLastEventCheck = gpGlobals->time; -} - - - -//========================================================= -//========================================================= -BOOL CBaseAnimating :: GetSequenceFlags( ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::GetSequenceFlags( pmodel, pev ); -} - -//========================================================= -// DispatchAnimEvents -//========================================================= -void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) -{ - MonsterEvent_t event; - - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if ( !pmodel ) - { - ALERT( at_aiconsole, "Gibbed monster is thinking!\n" ); - return; - } - - // FIXME: I have to do this or some events get missed, and this is probably causing the problem below - flInterval = 0.1; - - // FIX: this still sometimes hits events twice - float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate; - float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate; - m_flLastEventCheck = pev->animtime + flInterval; - - m_fSequenceFinished = FALSE; - if (flEnd >= 256 || flEnd <= 0.0) - m_fSequenceFinished = TRUE; - - int index = 0; - - while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 ) - { - HandleAnimEvent( &event ); - } -} - - -//========================================================= -//========================================================= -float CBaseAnimating :: SetBoneController ( int iController, float flValue ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return SetController( pmodel, pev, iController, flValue ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: InitBoneControllers ( void ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - SetController( pmodel, pev, 0, 0.0 ); - SetController( pmodel, pev, 1, 0.0 ); - SetController( pmodel, pev, 2, 0.0 ); - SetController( pmodel, pev, 3, 0.0 ); -} - -//========================================================= -//========================================================= -float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::SetBlending( pmodel, pev, iBlender, flValue ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) -{ - GET_BONE_POSITION( ENT(pev), iBone, origin, angles ); -} - -//========================================================= -//========================================================= -BOOL CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) -{ - GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles ); - return TRUE; -} - -//========================================================= -//========================================================= -int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if (piDir == NULL) - { - int iDir; - int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir ); - if (iDir != 1) - return -1; - else - return sequence; - } - - return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) -{ - -} - -void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) -{ - ::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue ); -} - -int CBaseAnimating :: GetBodygroup( int iGroup ) -{ - return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup ); -} - -int CBaseAnimating :: GetBoneCount( void ) -{ - return ::GetBoneCount( GET_MODEL_PTR(ENT(pev)) ); -} - -void CBaseAnimating :: SetBones( float (*data)[3], int datasize ) -{ - ::SetBones( GET_MODEL_PTR( ENT(pev) ), data, datasize ); -} - -int CBaseAnimating :: ExtractBbox( int sequence, Vector &mins, Vector &maxs ) -{ - return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs ); -} - -//========================================================= -//========================================================= - -void CBaseAnimating :: SetSequenceBox( void ) -{ - Vector mins, maxs; - - // Get sequence bbox - if ( ExtractBbox( pev->sequence, mins, maxs ) ) - { - // expand box for rotation - // find min / max for rotations - float yaw = pev->angles.y * (M_PI / 180.0); - - Vector xvector, yvector; - xvector.x = cos(yaw); - xvector.y = sin(yaw); - yvector.x = -sin(yaw); - yvector.y = cos(yaw); - Vector bounds[2]; - - bounds[0] = mins; - bounds[1] = maxs; - - Vector rmin( 9999, 9999, 9999 ); - Vector rmax( -9999, -9999, -9999 ); - Vector base, transformed; - - for (int i = 0; i <= 1; i++ ) - { - base.x = bounds[i].x; - for ( int j = 0; j <= 1; j++ ) - { - base.y = bounds[j].y; - for ( int k = 0; k <= 1; k++ ) - { - base.z = bounds[k].z; - - // transform the point - transformed.x = xvector.x*base.x + yvector.x*base.y; - transformed.y = xvector.y*base.x + yvector.y*base.y; - transformed.z = base.z; - - if (transformed.x < rmin.x) - rmin.x = transformed.x; - if (transformed.x > rmax.x) - rmax.x = transformed.x; - if (transformed.y < rmin.y) - rmin.y = transformed.y; - if (transformed.y > rmax.y) - rmax.y = transformed.y; - if (transformed.z < rmin.z) - rmin.z = transformed.z; - if (transformed.z > rmax.z) - rmax.z = transformed.z; - } - } - } - rmin.z = 0; - rmax.z = rmin.z + 1; - UTIL_SetSize( pev, rmin, rmax ); - } -} - diff --git a/server/monsters/animation.cpp b/server/monsters/animation.cpp deleted file mode 100644 index 2e26387f..00000000 --- a/server/monsters/animation.cpp +++ /dev/null @@ -1,556 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include -#include -#include - -#include "extdll.h" -#include "utils.h" -#include "const.h" -#include "studio_ref.h" - -#ifndef ACTIVITY_H -#include "activity.h" -#endif - -#include "activitymap.h" - -#ifndef ANIMATION_H -#include "animation.h" -#endif - -#ifndef SCRIPTEVENT_H -#include "scriptevent.h" -#endif - -#ifndef ENGINECALLBACK_H -#include "enginecallback.h" -#endif - -int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - dstudioseqdesc_t *pseqdesc; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - mins[0] = pseqdesc[ sequence ].bbmin[0]; - mins[1] = pseqdesc[ sequence ].bbmin[1]; - mins[2] = pseqdesc[ sequence ].bbmin[2]; - - maxs[0] = pseqdesc[ sequence ].bbmax[0]; - maxs[1] = pseqdesc[ sequence ].bbmax[1]; - maxs[2] = pseqdesc[ sequence ].bbmax[2]; - - return 1; -} - - -int LookupActivity( void *pmodel, entvars_t *pev, int activity ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - dstudioseqdesc_t *pseqdesc; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - int weighttotal = 0; - int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].activity == activity) - { - weighttotal += pseqdesc[i].actweight; - if (!weighttotal || RANDOM_LONG(0,weighttotal-1) < pseqdesc[i].actweight) - seq = i; - } - } - - return seq; -} - - -int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if ( !pstudiohdr ) - return 0; - - dstudioseqdesc_t *pseqdesc; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - int weight = 0; - int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].activity == activity) - { - if ( pseqdesc[i].actweight > weight ) - { - weight = pseqdesc[i].actweight; - seq = i; - } - } - } - - return seq; -} - -void GetEyePosition ( void *pmodel, Vector &vecEyePosition ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - - if ( !pstudiohdr ) - { - ALERT ( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" ); - return; - } - - vecEyePosition = pstudiohdr->eyeposition; -} - -int LookupSequence( void *pmodel, const char *label ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - dstudioseqdesc_t *pseqdesc; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (stricmp( pseqdesc[i].label, label ) == 0) - return i; - } - - return -1; -} - - -int IsSoundEvent( int eventNumber ) -{ - if ( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE ) - return 1; - return 0; -} - - -void SequencePrecache( void *pmodel, const char *pSequenceName ) -{ - int index = LookupSequence( pmodel, pSequenceName ); - if ( index >= 0 ) - { - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if ( !pstudiohdr || index >= pstudiohdr->numseq ) - return; - - dstudioseqdesc_t *pseqdesc; - dstudioevent_t *pevent; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; - pevent = (dstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); - - for (int i = 0; i < pseqdesc->numevents; i++) - { - // Don't send client-side events to the server AI - if ( pevent[i].event >= EVENT_CLIENT ) - continue; - - // UNDONE: Add a callback to check to see if a sound is precached yet and don't allocate a copy - // of it's name if it is. - if ( IsSoundEvent( pevent[i].event ) ) - { - if ( !strlen(pevent[i].options) ) - { - ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options ); - } - - PRECACHE_SOUND( STRING( ALLOC_STRING(pevent[i].options)) ); - } - } - } -} - - - -void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return; - - dstudioseqdesc_t *pseqdesc; - - if (pev->sequence >= pstudiohdr->numseq) - { - *pflFrameRate = 0.0; - *pflGroundSpeed = 0.0; - return; - } - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if (pseqdesc->numframes > 1) - { - *pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1); - *pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] ); - *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); - } - else - { - *pflFrameRate = 256.0; - *pflGroundSpeed = 0.0; - } -} - - -int GetSequenceFlags( void *pmodel, entvars_t *pev ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) - return 0; - - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - return pseqdesc->flags; -} - - -int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) - return 0; - - int events = 0; - - dstudioseqdesc_t *pseqdesc; - dstudioevent_t *pevent; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - pevent = (dstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); - - if (pseqdesc->numevents == 0 || index > pseqdesc->numevents ) - return 0; - - if (pseqdesc->numframes > 1) - { - flStart *= (pseqdesc->numframes - 1) / 256.0; - flEnd *= (pseqdesc->numframes - 1) / 256.0; - } - else - { - flStart = 0; - flEnd = 1.0; - } - - for (; index < pseqdesc->numevents; index++) - { - // Don't send client-side events to the server AI - if ( pevent[index].event >= EVENT_CLIENT ) - continue; - - if ( (pevent[index].frame >= flStart && pevent[index].frame < flEnd) || - ((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1) ) - { - pMonsterEvent->event = pevent[index].event; - pMonsterEvent->options = pevent[index].options; - return index + 1; - } - } - return 0; -} - -float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return flValue; - - dstudiobonecontroller_t *pbonecontroller = (dstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); - - // find first controller that matches the index - int i = 0; - for (i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) - { - if (pbonecontroller->index == iController) - break; - } - if (i >= pstudiohdr->numbonecontrollers) - return flValue; - - // wrap 0..360 if it's a rotational controller - - if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if (pbonecontroller->end < pbonecontroller->start) - flValue = -flValue; - - // does the controller not wrap? - if (pbonecontroller->start + 359.0 >= pbonecontroller->end) - { - if (flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0) + 180) - flValue = flValue - 360; - if (flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0) - 180) - flValue = flValue + 360; - } - else - { - if (flValue > 360) - flValue = flValue - (int)(flValue / 360.0) * 360.0; - else if (flValue < 0) - flValue = flValue + (int)((flValue / -360.0) + 1) * 360.0; - } - } - - int setting = 255 * (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start); - - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; - pev->controller[iController] = setting; - - return setting * (1.0 / 255.0) * (pbonecontroller->end - pbonecontroller->start) + pbonecontroller->start; -} - - -float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return flValue; - - dstudioseqdesc_t *pseqdesc; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if (pseqdesc->blendtype[iBlender] == 0) - return flValue; - - if (pseqdesc->blendtype[iBlender] & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if (pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender]) - flValue = -flValue; - - // does the controller not wrap? - if (pseqdesc->blendstart[iBlender] + 359.0 >= pseqdesc->blendend[iBlender]) - { - if (flValue > ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) + 180) - flValue = flValue - 360; - if (flValue < ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) - 180) - flValue = flValue + 360; - } - } - - int setting = 255 * (flValue - pseqdesc->blendstart[iBlender]) / (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]); - - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; - - pev->blending[iBlender] = setting; - - return setting * (1.0 / 255.0) * (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]) + pseqdesc->blendstart[iBlender]; -} - - - - -int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return iGoalAnim; - - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - // bail if we're going to or from a node 0 - if (pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0) - { - return iGoalAnim; - } - - int iEndNode; - - // ALERT( at_console, "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode ); - - if (*piDir > 0) - { - iEndNode = pseqdesc[iEndingAnim].exitnode; - } - else - { - iEndNode = pseqdesc[iEndingAnim].entrynode; - } - - if (iEndNode == pseqdesc[iGoalAnim].entrynode) - { - *piDir = 1; - return iGoalAnim; - } - - byte *pTransition = ((byte *)pstudiohdr + pstudiohdr->transitionindex); - - int iInternNode = pTransition[(iEndNode-1)*pstudiohdr->numtransitions + (pseqdesc[iGoalAnim].entrynode-1)]; - - if (iInternNode == 0) - return iGoalAnim; - - int i; - - // look for someone going - for (i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode) - { - *piDir = 1; - return i; - } - if (pseqdesc[i].nodeflags) - { - if (pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode) - { - *piDir = -1; - return i; - } - } - } - - ALERT( at_console, "error in transition graph\n" ); - return iGoalAnim; -} - -void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return; - - if (iGroup > pstudiohdr->numbodyparts) - return; - - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; - - if (iValue >= pbodypart->nummodels) - return; - - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; - - pev->body = (pev->body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base)); -} - - -int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - if (iGroup > pstudiohdr->numbodyparts) - return 0; - - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; - - if (pbodypart->nummodels <= 1) - return 0; - - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; - - return iCurrent; -} - -//LRC -int GetBoneCount( void *pmodel ) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (!pstudiohdr) - { - ALERT(at_error, "Bad header in SetBones!\n"); - return 0; - } - - return pstudiohdr->numbones; -} - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -//LRC -void SetBones( void *pmodel, float (*data)[3], int datasize) -{ - dstudiohdr_t *pstudiohdr; - - pstudiohdr = (dstudiohdr_t *)pmodel; - if (!pstudiohdr) - { - ALERT(at_error, "Bad header in SetBones!\n"); - return; - } - - dstudiobone_t *pbone = (dstudiobone_t *)((byte *)pstudiohdr + pstudiohdr->boneindex); - -// ALERT(at_console, "List begins:\n"); - int j; - int limit = min(pstudiohdr->numbones, datasize); - // go through the bones - for (int i = 0; i < limit; i++, pbone++) - { -// ALERT(at_console, " %s\n", pbone->name); - for (j = 0; j < 3; j++) - pbone->value[j] = data[i][j]; - } -// ALERT(at_console, "List ends.\n"); -} diff --git a/server/monsters/animation.h b/server/monsters/animation.h deleted file mode 100644 index 3cf34b08..00000000 --- a/server/monsters/animation.h +++ /dev/null @@ -1,52 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ANIMATION_H -#define ANIMATION_H - -#define ACTIVITY_NOT_AVAILABLE -1 - -#ifndef MONSTEREVENT_H -#include "monsterevent.h" -#endif - -extern int IsSoundEvent( int eventNumber ); - -int LookupActivity( void *pmodel, entvars_t *pev, int activity ); -int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ); -int LookupSequence( void *pmodel, const char *label ); -void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ); -int GetSequenceFlags( void *pmodel, entvars_t *pev ); -int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd ); -float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ); -float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ); -void GetEyePosition( void *pmodel, Vector &vecEyePosition ); -void SequencePrecache( void *pmodel, const char *pSequenceName ); -int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ); -void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ); -int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ); - -//LRC -void SetBones( void *pmodel, float (*data)[3], int datasize ); -int GetBoneCount( void *pmodel ); -int GetSequenceFrames( void *pmodel, entvars_t *pev ); //LRC - -int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ); -int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ); - -// From /engine/studio.h -#define STUDIO_LOOPING 0x0001 - - -#endif //ANIMATION_H diff --git a/server/monsters/apache.cpp b/server/monsters/apache.cpp deleted file mode 100644 index d0161bdf..00000000 --- a/server/monsters/apache.cpp +++ /dev/null @@ -1,942 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef OEM_BUILD - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "monsters.h" -#include "baseweapon.h" -#include "nodes.h" -#include "basebeams.h" -#include "defaults.h" - -#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; - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - SET_MODEL(ENT(pev), "models/apache.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); - UTIL_SetOrigin( this, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - if (pev->health == 0) - pev->health = APACHE_HEALTH; - - m_flFieldOfView = -0.707; // 270 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - pev->frame = RANDOM_LONG(0, 0xFF); - - InitBoneControllers(); - - if (pev->spawnflags & SF_WAITFORTRIGGER) - { - SetUse(&CApache :: StartupUse ); - } - else - { - SetThink(&CApache :: HuntThink ); - SetTouch(&CApache :: FlyTouch ); - SetNextThink( 1.0 ); - } - - m_iRockets = 10; -} - - -void CApache::Precache( void ) -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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_PrecacheEntity( "hvr_rocket" ); -} - - - -void CApache::NullThink( void ) -{ - StudioFrameAdvance( ); - SetNextThink( 0.5 ); -} - - -void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink(&CApache:: HuntThink ); - SetTouch(&CApache:: FlyTouch ); - SetNextThink( 0.1 ); - SetUse( NULL ); -} - -void CApache :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - - STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink(&CApache :: DyingThink ); - SetTouch(&CApache :: CrashTouch ); - SetNextThink( 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( ); - SetNextThink( 0.1 ); - - pev->avelocity = pev->avelocity * 1.02; - - // still falling? - if (m_flNextRocket > gpGlobals->time ) - { - // random explosions - MESSAGE_BEGIN( MSG_PVS, gmsg.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, gmsg.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, gmsg.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; - SetNextThink( 0.2 ); - return; - } - else - { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - - /* - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.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, gmsg.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, gmsg.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, gmsg.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->flags & FL_ONGROUND) - { - CBaseEntity *pWreckage = Create( "smokeent", pev->origin, pev->angles ); - UTIL_SetModel( ENT(pWreckage->pev), pev->model ); - UTIL_SetSize( pWreckage->pev, Vector( -200, -200, -128 ), Vector( 200, 200, -32 ) ); - pWreckage->SetNextThink( 0.1 ); - pWreckage->pev->frame = pev->frame; - pWreckage->pev->sequence = pev->sequence; - pWreckage->pev->framerate = 0; - pWreckage->pev->impulse = 50; - pWreckage->pev->dmgtime = gpGlobals->time + 5; - } - - // gibs - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, gmsg.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( Remove ); - SetNextThink( 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; - SetNextThink( 0 ); - } -} - - - -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( ); - SetNextThink( 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; - } - - } - - 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, gmsg.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_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, gmsg.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 ); - } -} - -#endif diff --git a/server/monsters/barnacle.cpp b/server/monsters/barnacle.cpp deleted file mode 100644 index fe64f459..00000000 --- a/server/monsters/barnacle.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* 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 "utils.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 m_iClass?m_iClass: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( this, 1, 1 ); - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarnacle :: Spawn() -{ - Precache( ); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - SET_MODEL(ENT(pev), "models/barnacle.mdl"); - UTIL_SetSize( pev, Vector(-16, -16, -32), Vector(16, 16, 0) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_AIM; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = EF_INVLIGHT; // take light from the ceiling - pev->health = 25; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_flKillVictimTime = 0; - m_cGibs = 0; - m_fLiftingPrey = FALSE; - m_flTongueAdj = -100; - - InitBoneControllers(); - - SetActivity ( ACT_IDLE ); - - SetThink(&CBarnacle :: BarnacleThink ); - SetNextThink( 0.5 ); - - UTIL_SetOrigin ( this, 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; - - SetNextThink( 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, 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() ) ) && !HaveCamerasInPVS( edict() ) ) - SetNextThink( 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( this, 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 = pev->velocity; //LRC- make him come _with_ me - pTouchEnt->pev->basevelocity = pev->velocity; //LRC - 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 ); - - SetNextThink( 0.1 ); - SetThink(&CBarnacle :: WaitTillDead ); -} - -//========================================================= -//========================================================= -void CBarnacle :: WaitTillDead ( void ) -{ - SetNextThink( 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() -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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/server/monsters/barney.cpp b/server/monsters/barney.cpp deleted file mode 100644 index 40950966..00000000 --- a/server/monsters/barney.cpp +++ /dev/null @@ -1,926 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monster template -//========================================================= -// UNDONE: Holster weapon? - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "monsters.h" -#include "talkmonster.h" -#include "schedule.h" -#include "defaultai.h" -#include "scripted.h" -#include "baseweapon.h" -#include "soundent.h" -#include "defaults.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[]; - - int m_iBaseBody; //LRC - for barneys with different bodies - 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_iBaseBody, FIELD_INTEGER ), //LRC - 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 m_iClass?m_iClass:CLASS_PLAYER_ALLY; -} - -//========================================================= -// ALertSound - barney says "Freeze!" -//========================================================= -void CBarney :: AlertSound( void ) -{ - if ( m_hEnemy != NULL ) - { - if ( FOkToSpeak() ) - { - if (m_iszSpeakAs) - { - char szBuf[32]; - strcpy(szBuf,STRING(m_iszSpeakAs)); - strcat(szBuf,"_ATTACK"); - PlaySentence( szBuf, RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - } - else - { - 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; - - if (pev->frags) - { - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_357); - if (RANDOM_LONG(0, 1)) - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "weapons/357_shot1.wav", 1, ATTN_NORM, 0, 100 ); - else - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "weapons/357_shot2.wav", 1, ATTN_NORM, 0, 100 ); - } - else - { - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_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! - - // Teh_Freak: World Lighting! - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_DLIGHT ); - WRITE_COORD( vecShootOrigin.x ); // origin - WRITE_COORD( vecShootOrigin.y ); - WRITE_COORD( vecShootOrigin.z ); - WRITE_BYTE( 16 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 128 ); // B - WRITE_BYTE( 0 ); // life * 10 - WRITE_BYTE( 0 ); // decay - MESSAGE_END(); - // Teh_Freak: World Lighting! -} - -//========================================================= -// 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 = m_iBaseBody + BARNEY_BODY_GUNDRAWN; - m_fGunDrawn = TRUE; - break; - - case BARNEY_AE_HOLSTER: - // change bodygroup to replace gun in holster - pev->body = m_iBaseBody + BARNEY_BODY_GUNHOLSTERED; - m_fGunDrawn = FALSE; - break; - - default: - CTalkMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarney :: Spawn() -{ - Precache( ); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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; - if (pev->health == 0) //LRC - pev->health = BARNEY_HEALTH; - 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; - - m_iBaseBody = pev->body; //LRC - pev->body = m_iBaseBody + BARNEY_BODY_GUNHOLSTERED; // gun in holster - m_fGunDrawn = FALSE; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; - - MonsterInit(); - SetUse(&CBarney :: FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBarney :: Precache() -{ - UTIL_PrecacheModel( pev->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(); - - // barney speech group names (group names are in sentences.txt) - - if (!m_iszSpeakAs) - { - m_szGrp[TLK_ANSWER] = "BA_ANSWER"; - m_szGrp[TLK_QUESTION] = "BA_QUESTION"; - m_szGrp[TLK_IDLE] = "BA_IDLE"; - m_szGrp[TLK_STARE] = "BA_STARE"; - if (pev->spawnflags & SF_MONSTER_PREDISASTER) //LRC - m_szGrp[TLK_USE] = "BA_PFOLLOW"; - else - m_szGrp[TLK_USE] = "BA_OK"; - if (pev->spawnflags & SF_MONSTER_PREDISASTER) - m_szGrp[TLK_UNUSE] = "BA_PWAIT"; - else - m_szGrp[TLK_UNUSE] = "BA_WAIT"; - if (pev->spawnflags & SF_MONSTER_PREDISASTER) - m_szGrp[TLK_DECLINE] = "BA_POK"; - else - m_szGrp[TLK_DECLINE] = "BA_NOTOK"; - 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; -} - -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; - - // LRC - if my reaction to the player has been overridden, don't do this stuff - if (m_iPlayerReact) 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) || UTIL_IsFacing( pevAttacker, pev->origin )) - { - // Alright, now I'm pissed! - if (m_iszSpeakAs) - { - char szBuf[32]; - strcpy(szBuf,STRING(m_iszSpeakAs)); - strcat(szBuf,"_MAD"); - PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); - } - else - { - PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); - } - - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } - else - { - // Hey, be careful with that - if (m_iszSpeakAs) - { - char szBuf[32]; - strcpy(szBuf,STRING(m_iszSpeakAs)); - strcat(szBuf,"_SHOT"); - PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); - } - else - { - PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); - } - Remember( bits_MEMORY_SUSPICIOUS ); - } - } - else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) - { - if (m_iszSpeakAs) - { - char szBuf[32]; - strcpy(szBuf,STRING(m_iszSpeakAs)); - strcat(szBuf,"_SHOT"); - PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); - } - else - { - 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.0f ) - { - 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 < m_iBaseBody + BARNEY_BODY_GUNGONE && !(pev->spawnflags & SF_MONSTER_NO_WPN_DROP)) - { // drop the gun! - Vector vecGunPos; - Vector vecGunAngles; - - pev->body = m_iBaseBody + BARNEY_BODY_GUNGONE; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - CBaseEntity *pGun; - pGun = DropItem( "weapon_glock", 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() ) - { - // Hey, be careful with that - if (m_iszSpeakAs) - { - char szBuf[32]; - strcpy(szBuf,STRING(m_iszSpeakAs)); - strcat(szBuf,"_KILL"); - PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); - } - else - { - 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( m_szGrp[TLK_DECLINE], 2, VOL_NORM, ATTN_NORM ); //LRC -} - - - - - -//========================================================= -// 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 = DEAD_BARNEY_HEALTH; - - MonsterInitDead(); -} - - diff --git a/server/monsters/baseanimating.h b/server/monsters/baseanimating.h deleted file mode 100644 index b544d1e6..00000000 --- a/server/monsters/baseanimating.h +++ /dev/null @@ -1,50 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -#ifndef BASEANIMATING_H -#define BASEANIMATING_H - -class CBaseAnimating : public CBaseLogic -{ -public: - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // Basic Monster Animation functions - float StudioFrameAdvance( float flInterval = 0.0 ); - int GetSequenceFlags( void ); - int LookupActivity ( int activity ); - int LookupActivityHeaviest ( int activity ); - int LookupSequence ( const char *label ); - float SequenceDuration( int iSequence ); - void ResetSequenceInfo ( ); - void DispatchAnimEvents ( float flFutureInterval = 0.1 ); - virtual CBaseAnimating* GetBaseAnimating() { return this; } - virtual void HandleAnimEvent( MonsterEvent_t *pEvent ) { return; }; - float SetBoneController ( int iController, float flValue ); - void InitBoneControllers ( void ); - float SetBlending ( int iBlender, float flValue ); - void GetBonePosition ( int iBone, Vector &origin, Vector &angles ); - void GetAutomovement( Vector &origin, Vector &angles, float flInterval = 0.1 ); - int FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ); - BOOL GetAttachment ( int iAttachment, Vector &origin, Vector &angles ); - void SetBodygroup( int iGroup, int iValue ); - int GetBodygroup( int iGroup ); - int GetBoneCount( void ); - void SetBones( float (*data)[3], int datasize ); - - int ExtractBbox( int sequence, Vector &mins, Vector &maxs ); - void SetSequenceBox( void ); - - // animation needs - float m_flFrameRate; // computed FPS for current sequence - float m_flGroundSpeed; // computed linear movement rate for current sequence - float m_flLastEventCheck; // last time the event list was checked - BOOL m_fSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry - BOOL m_fSequenceLoops; // true if the sequence loops -}; - -#endif //BASEANIMATING_H \ No newline at end of file diff --git a/server/monsters/basemonster.cpp b/server/monsters/basemonster.cpp deleted file mode 100644 index 60fc46ac..00000000 --- a/server/monsters/basemonster.cpp +++ /dev/null @@ -1,6234 +0,0 @@ -/*** -* -* 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. -* 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 "utils.h" -#include "cbase.h" -#include "nodes.h" -#include "client.h" -#include "monsters.h" -#include "animation.h" -#include "saverestore.h" -#include "baseweapon.h" -#include "scripted.h" -#include "squadmonster.h" -#include "defaultai.h" -#include "decals.h" -#include "soundent.h" -#include "gamerules.h" -#include "game.h" - -#define MONSTER_CUT_CORNER_DIST 8 // 8 means the monster's bounding box is contained without the box of the node in WC -extern CGraph WorldGraph; - -Vector VecBModelOrigin( entvars_t* pevBModel ); -extern entvars_t *g_pevLastInflictor; -extern DLL_GLOBAL BOOL g_fDrawLines; -extern CGraph WorldGraph;// the world node graph -DLL_GLOBAL BOOL g_fDrawLines = FALSE; - - -// 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_iClass, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_iPlayerReact, FIELD_INTEGER ), - - 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, CBaseAnimating ); -int CBaseMonster::Save( CSave &save ) -{ - if ( !CBaseAnimating::Save(save) ) - return 0; - if ( pev->targetname ) - return save.WriteFields( STRING(pev->targetname), "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - else - return save.WriteFields( STRING(pev->classname), "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); -} - -int CBaseMonster::Restore( CRestore &restore ) -{ - if ( !CBaseAnimating::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; - } - return NULL; -} - - - -//========================================================= -// Monster Think - calls out to core AI functions and handles this -// monster's specific animation events -//========================================================= -void CBaseMonster :: MonsterThink ( void ) -{ - SetNextThink( 0.05 );// 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 ); -} - -//========================================================= -// 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 if 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->GetNext(); - - // 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, gmsg.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, gmsg.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( this, 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, gmsg.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( this, 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 = pcbeDoor->m_fNextThink - pevDoor->ltime; - - //ALERT(at_aiconsole, "Waiting %d ms\n", (int)(1000*flTravelTime)); - if ( pcbeDoor->pev->targetname ) - { - CBaseEntity *pTarget = NULL; - for (;;) - { - pTarget = UTIL_FindEntityByTargetname( pTarget, STRING(pcbeDoor->pev->targetname)); - if (!pTarget) - break; - - if ( VARS( pTarget->pev ) != pcbeDoor->pev && - FClassnameIs ( pTarget->pev, STRING(pcbeDoor->pev->classname) ) ) - { - pTarget->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->GetNext(); - - // 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, gmsg.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, gmsg.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, gmsg.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, gmsg.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, gmsg.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 - 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); - - ClearSchedule(); - RouteClear(); - InitBoneControllers( ); // FIX: should be done in Spawn - - m_iHintNode = NO_NODE; - - m_afMemory = MEMORY_CLEAR; - - m_hEnemy = NULL; - - m_flDistTooFar = 1024.0; - m_flDistLook = 2048.0; - - // set eye position - SetEyePosition(); - - SetThink(&CBaseMonster :: MonsterInitThink ); - SetNextThink( 0.1 ); - SetUse(&CBaseMonster :: MonsterUse ); -} - -//========================================================= -// MonsterInitThink - Calls StartMonster. Startmonster is -// virtual, but this function cannot be -//========================================================= -void CBaseMonster :: MonsterInitThink ( void ) -{ - StartMonster(); -} - - -void CBaseMonster :: StartPatrol ( CBaseEntity* path ) -{ - m_pGoalEnt = path; - - if ( !m_pGoalEnt ) - { - ALERT(at_error, "ReadyMonster()--%s couldn't find target \"%s\"\n", STRING(pev->classname), STRING(pev->target)); - } - else - { - // Monster will start turning towards his destination -// MakeIdealYaw ( m_pGoalEnt->pev->origin ); - - // 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 ) ); - } -} - -//========================================================= -// 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. - //LRC- there are perfectly good reasons for making a monster stuck, so it shouldn't always be an error. - if (!WALK_MOVE ( ENT(pev), 0, 0, WALKMOVE_NORMAL ) && !FBitSet( pev->spawnflags, SF_MONSTER_NO_YELLOW_BLOBS)) - { - Msg("%s \"%s\" stuck in wall--level design error\n", STRING(pev->classname), STRING(pev->targetname)); - pev->effects = EF_BRIGHTFIELD; - } - } - else - { - pev->flags &= ~FL_ONGROUND; - } - - if ( !FStringNull(pev->target) )// this monster has a target - { - StartPatrol(UTIL_FindEntityByTargetname( NULL, STRING( pev->target ))); - } - - //SetState ( m_IdealMonsterState ); - //SetActivity ( m_IdealActivity ); - - // Delay drop to floor to make sure each door in the level has had its chance to spawn - // Spread think times so that they don't all happen at the same time (Carmack) - SetThink(&CBaseMonster :: CallMonsterThink ); - AbsoluteNextThink( m_fNextThink + 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[17][17] = - { //NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN FACT_A FACT_B FACT_C - /*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, 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, 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, R_DL, 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, R_DL, R_DL, R_DL }, - /*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, R_DL, R_DL, R_DL }, - /*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, R_DL, R_DL, R_DL }, - /*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, R_DL, R_DL, R_DL }, - /*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, R_DL, R_DL, R_DL }, - /*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, R_DL, R_DL, R_DL }, - /*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, R_DL, R_DL, R_DL }, - /*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, R_FR, R_FR, R_FR }, - /*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, R_DL, R_DL, R_DL }, - /*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, R_DL, R_DL, 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, R_DL, R_DL, R_DL }, - /*FACTION_A*/ { R_NO, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_NO, R_DL, R_DL, R_DL, R_AL, R_DL, R_DL }, - /*FACTION_B*/ { R_NO, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_NO, R_DL, R_DL, R_DL, R_DL, R_AL, R_DL }, - /*FACTION_C*/ { R_NO, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_DL, R_NO, R_DL, R_DL, R_DL, R_DL, R_DL, R_AL } - }; - - int iTargClass = pTarget->Classify(); - - if (iTargClass == CLASS_PLAYER && m_iPlayerReact) //LRC - { - if (m_iPlayerReact == 1) // Ignore player - return R_NO; - else if (m_iPlayerReact == 4) - return R_HT; - else if (m_afMemory & bits_MEMORY_PROVOKED) - return R_HT; - else - return R_NO; - } - - return iEnemy[ Classify() ][ iTargClass ]; -} - -//========================================================= -// 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, gmsg.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 - if ( !(pev->spawnflags & SF_MONSTER_GAG) || m_MonsterState != MONSTERSTATE_IDLE) - EMIT_SOUND( edict(), CHAN_BODY, pEvent->options, 1.0, ATTN_IDLE ); - break; - - case SCRIPT_EVENT_SOUND_VOICE: - if ( !(pev->spawnflags & SF_MONSTER_GAG) || m_MonsterState != MONSTERSTATE_IDLE) - 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 - UTIL_FireTargets( pEvent->options, this, this, USE_TOGGLE ); - 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 if (FStrEq(pkvd->szKeyName, "m_iClass") ) //LRC - { - m_iClass = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iPlayerReact") ) - { - m_iPlayerReact = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "type") ) - { - pev->button = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CBaseAnimating::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" ); - UTIL_FireTargets( m_iszTriggerTarget , this, this, USE_TOGGLE ); - 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. -//========================================================= - -//LRC - to help debug when sequences won't play... -#define DEBUG_CANTPLAY - -int CBaseMonster :: CanPlaySequence( int interruptFlags ) -{ - if ( m_pCine ) - { - if ( interruptFlags & SS_INTERRUPT_SCRIPTS ) - { - return true; - } - else - { -#ifdef DEBUG_CANTPLAY - ALERT(at_console, "CANTPLAY: Already playing %s \"%s\"!\n", STRING(m_pCine->pev->classname), STRING(m_pCine->pev->targetname)); -#endif - return false; - } - } - else if ( !IsAlive() || m_MonsterState == MONSTERSTATE_PRONE ) - { -#ifdef DEBUG_CANTPLAY - ALERT(at_console, "CANTPLAY: Dead/Barnacled!\n"); -#endif - // monster is already running a scripted sequence or dead! - return FALSE; - } - - if ( interruptFlags & SS_INTERRUPT_ANYSTATE ) - { - // 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 && interruptFlags & SS_INTERRUPT_ALERT ) - return TRUE; - - // unknown situation -#ifdef DEBUG_CANTPLAY - ALERT(at_console, "CANTPLAY: non-interruptable state.\n"); -#endif - 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 ) -{ - if (m_pCine != NULL && m_hTargetEnt != NULL && (m_pCine->m_fTurnType == 1)) - { - Vector vecDest = ( m_hTargetEnt->pev->absmin + m_hTargetEnt->pev->absmax ) / 2; - return ( vecDest - shootOrigin ).Normalize(); - } - else if ( m_hEnemy ) - { - return ( (m_hEnemy->BodyTarget( shootOrigin ) - m_hEnemy->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( this, pev->origin );// link into world. - } - else - SetNextThink( 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( this, pev->origin ); - - // Setup health counters, etc. - BecomeDead(); - SetThink(&CBaseMonster :: CorpseFallThink ); - SetNextThink( 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 -} - -//========================================================= -// 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 ) || HaveCamerasInPVS( edict() )) - { - 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; -} - -//========================================================= -// 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. - 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 we're here, then either we're being told to do something (besides dying or playing a script) - // or our current schedule (besides dying) is invalid. -- LRC - 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())) || HaveCamerasInPVS( 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(); - UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); - 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(); - } - break; - } - case TASK_PLAY_SCRIPT: - { -// ALERT(at_console, "Play Script\n"); - if (m_fSequenceFinished) - { -// ALERT(at_console, "Anim Finished\n"); - if (m_pCine->m_iRepeatsLeft > 0) - { -// ALERT(at_console, "Frame %f; Repeat %d from %f\n", pev->frame, m_pCine->m_iRepeatsLeft, m_pCine->m_fRepeatFrame); - m_pCine->m_iRepeatsLeft--; - pev->frame = m_pCine->m_fRepeatFrame; - ResetSequenceInfo( ); - } - else - { - TaskComplete(); - } - } - 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_SCRIPT: - case TASK_WALK_TO_SCRIPT: - { - Activity newActivity; - - if ( !m_pGoalEnt || (m_pGoalEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - if ( pTask->iTask == TASK_WALK_TO_SCRIPT ) - newActivity = ACT_WALK; - else - newActivity = ACT_RUN; - // This monster can't do this! - if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) - TaskComplete(); - else - { - if ( m_pGoalEnt != NULL ) - { - Vector vecDest; - vecDest = m_pGoalEnt->pev->origin; - - if ( !MoveToLocation( newActivity, 2, vecDest ) ) - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to reach script!!!\n", STRING(pev->classname) ); - RouteClear(); - } - } - else - { - TaskFail(); - ALERT( at_aiconsole, "%s: MoveTarget is missing!?!\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 = UTIL_FindEntityByClassname( 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_SCRIPT: - { - RouteClear(); - if ( m_pCine != NULL && MoveToLocation( m_movementActivity, 1, m_pCine->pev->origin ) ) - { - 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_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) - { - TaskComplete(); //LRC - start playing immediately - } - else if (!m_pCine->IsAction() && 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: - { - if (m_pCine->IsAction()) - { - //ALERT(at_console,"PlayScript: setting idealactivity %d\n",m_pCine->m_fAction); - switch(m_pCine->m_fAction) - { - case 0: - m_IdealActivity = ACT_RANGE_ATTACK1; break; - case 1: - m_IdealActivity = ACT_RANGE_ATTACK2; break; - case 2: - m_IdealActivity = ACT_MELEE_ATTACK1; break; - case 3: - m_IdealActivity = ACT_MELEE_ATTACK2; break; - case 4: - m_IdealActivity = ACT_SPECIAL_ATTACK1; break; - case 5: - m_IdealActivity = ACT_SPECIAL_ATTACK2; break; - case 6: - m_IdealActivity = ACT_RELOAD; break; - case 7: - m_IdealActivity = ACT_HOP; break; - } - pev->framerate = 1.0; // shouldn't be needed, but just in case - pev->movetype = MOVETYPE_FLY; - ClearBits(pev->flags, FL_ONGROUND); - } - else - { - 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) ); - } - m_scriptState = SCRIPT_PLAYING; - break; - } - case TASK_ENABLE_SCRIPT: - { - m_pCine->DelayStart( 0 ); - TaskComplete(); - break; - } -//LRC - case TASK_END_SCRIPT: - { - m_pCine->SequenceDone( this ); - TaskComplete(); - break; - } - case TASK_PLANT_ON_SCRIPT: - { - if ( m_pCine != NULL ) - { - // Plant on script - // LRC - if it's a teleport script, do the turn too - if (m_pCine->m_fMoveTo == 4 || m_pCine->m_fMoveTo == 6) - { - if (m_pCine->m_fTurnType == 0) //LRC - pev->angles.y = m_hTargetEnt->pev->angles.y; - else if (m_pCine->m_fTurnType == 1) - pev->angles.y = UTIL_VecToYaw(m_hTargetEnt->pev->origin - pev->origin); - pev->ideal_yaw = pev->angles.y; - pev->avelocity = Vector( 0, 0, 0 ); - pev->velocity = Vector( 0, 0, 0 ); - pev->effects |= EF_NOINTERP; - } - - if (m_pCine->m_fMoveTo != 6) - pev->origin = m_pGoalEnt->pev->origin; - } - - TaskComplete(); - break; - } - case TASK_FACE_SCRIPT: - { - if ( m_pCine != NULL && m_pCine->m_fMoveTo != 0) // movetype "no move" makes us ignore turntype - { - switch (m_pCine->m_fTurnType) - { - case 0: - pev->ideal_yaw = UTIL_AngleMod( m_pCine->pev->angles.y ); - break; - case 1: - // yes, this is inconsistent- turn to face uses the "target" and turn to angle uses the "cine". - if (m_hTargetEnt) - MakeIdealYaw ( m_hTargetEnt->pev->origin ); - else - MakeIdealYaw ( m_pCine->pev->origin ); - break; - // default: don't turn - } - } - - 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) ); -// ALERT( at_console, "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 ]; -} - -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) -{ - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - int i; - - if ( !IsAlive() ) - { - // dealing with a dead monster. - if ( pev->max_health <= 0 ) - { - // no blood decal for a monster that has already decalled its limit. - return; - } - else - { - pev->max_health--; - } - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir; - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT(pev), &Bloodtr); - -/* - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_SHOWLINE); - WRITE_COORD( ptr->vecEndPos.x ); - WRITE_COORD( ptr->vecEndPos.y ); - WRITE_COORD( ptr->vecEndPos.z ); - - WRITE_COORD( Bloodtr.vecEndPos.x ); - WRITE_COORD( Bloodtr.vecEndPos.y ); - WRITE_COORD( Bloodtr.vecEndPos.z ); - MESSAGE_END(); -*/ - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} - -//========================================================= -// TraceAttack -//========================================================= -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= DMG_HEAD; - break; - case HITGROUP_CHEST: - flDamage *= DMG_CHEST; - break; - case HITGROUP_STOMACH: - flDamage *= DMG_STOMACH; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= DMG_ARM; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= DMG_LEG; - break; - default: - break; - } - - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -//========================================================= -// CheckTraceHullAttack - expects a length to trace, amount -// of damage to do, and damage type. Returns a pointer to -// the damaged entity in case the monster wishes to do -// other stuff to the victim (punchangle, etc) -// -// Used for many contact-range melee attacks. Bites, claws, etc. -//========================================================= -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) -{ - TraceResult tr; - - if (IsPlayer()) - UTIL_MakeVectors( pev->angles ); - else - UTIL_MakeAimVectors( pev->angles ); - - Vector vecStart = pev->origin; - vecStart.z += pev->size.z * 0.5; - Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist ); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if ( iDamage > 0 ) - { - pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); - } - - return pEntity; - } - - return NULL; -} - - -//========================================================= -// FInViewCone - returns true is the passed ent is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( pEntity->pev->origin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// FInViewCone - returns true is the passed vector is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( *pOrigin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - return TRUE; - return FALSE; -} - -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - - -void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - -/* -============ -TakeDamage - -The damage is coming from inflictor, but get mad at attacker -This should be the only function that ever reduces health. -bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK - -Time-based damage: only occurs while the monster is within the trigger_hurt. -When a monster is poisoned via an arrow etc it takes all the poison damage at once. -============ -*/ -int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - float flTake; - Vector vecDir; - - if (!pev->takedamage) - return 0; - - if ( !IsAlive() ) - { - return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - } - - if ( pev->deadflag == DEAD_NO ) - { - // no pain sound during death animation. - PainSound();// "Ouch!" - } - - //!!!LATER - make armor consideration here! - flTake = flDamage; - - // set damage type sustained - m_bitsDamageType |= bitsDamageType; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - - // add to the damage total for clients, which will be sent as a single - // message at the end of the frame - // todo: remove after combining shotgun blasts? - if ( IsPlayer() ) - { - if ( pevInflictor ) - pev->dmg_inflictor = ENT(pevInflictor); - - pev->dmg_take += flTake; - - // check for godmode or invincibility - if ( pev->flags & FL_GODMODE ) - { - return 0; - } - } - - // if this is a player, move him around! - if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) ) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - - // do the damage - pev->health -= flTake; - - - // HACKHACK Don't kill monsters in a script. Let them break their scripts first - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - SetConditions( bits_COND_LIGHT_DAMAGE ); - return 0; - } - - if ( pev->health <= 0 ) - { - g_pevLastInflictor = pevInflictor; - - if ( bitsDamageType & DMG_ALWAYSGIB ) - { - Killed( pevAttacker, GIB_ALWAYS ); - } - else if ( bitsDamageType & DMG_NEVERGIB ) - { - Killed( pevAttacker, GIB_NEVER ); - } - else - { - Killed( pevAttacker, GIB_NORMAL ); - } - - g_pevLastInflictor = NULL; - - return 0; - } - - // react to the damage (get mad) - if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) - { - //LRC - new behaviours, for m_iPlayerReact. - if (pevAttacker->flags & FL_CLIENT) - { - if (m_iPlayerReact == 2) - { - // just get angry. - Remember( bits_MEMORY_PROVOKED ); - } - else if (m_iPlayerReact == 3) - { - // try to decide whether it was deliberate... if I have an enemy, assume it was just crossfire. - if ( m_hEnemy == NULL ) - { - if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || UTIL_IsFacing( pevAttacker, pev->origin ) ) - Remember( bits_MEMORY_PROVOKED ); - else - Remember( bits_MEMORY_SUSPICIOUS ); - } - } - } - - if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) - {// only if the attack was a monster or client! - - // enemy's last known position is somewhere down the vector that the attack came from. - if (pevInflictor) - { - if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) - { - m_vecEnemyLKP = pevInflictor->origin; - } - } - else - { - m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); - } - - MakeIdealYaw( m_vecEnemyLKP ); - - // add pain to the conditions - // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and - // heavy damage per monster class? - if ( flDamage > 0 ) - { - SetConditions(bits_COND_LIGHT_DAMAGE); - } - - if ( flDamage >= 20 ) - { - SetConditions(bits_COND_HEAVY_DAMAGE); - } - } - } - - return 1; -} - -//========================================================= -// DeadTakeDamage - takedamage function called when a monster's -// corpse is damaged. -//========================================================= -int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecDir; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - -#if 0// turn this back on when the bounding box issues are resolved. - - pev->flags &= ~FL_ONGROUND; - pev->origin.z += 1; - - // let the damage scoot the corpse around a bit. - if ( !FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER) ) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - -#endif - - // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. - if ( bitsDamageType & DMG_GIB_CORPSE ) - { - if ( pev->health <= flDamage ) - { - pev->health = -50; - Killed( pevAttacker, GIB_ALWAYS ); - return 0; - } - // Accumulate corpse gibbing damage, so you can gib with multiple hits - pev->health -= flDamage * 0.1; - } - - return 1; -} - - -float CBaseMonster :: DamageForce( float damage ) -{ - float force = damage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; - - if ( force > 1000.0) - { - force = 1000.0; - } - - return force; -} - -// take health -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) -{ - if (!pev->takedamage) - return 0; - - // clear out any damage types we healed. - // UNDONE: generic health should not heal any - // UNDONE: time-based damage - - m_bitsDamageType &= ~(bitsDamageType & ~DMG_TIMEBASED); - return CBaseEntity::TakeHealth(flHealth, bitsDamageType); -} - -int CBaseMonster :: TakeArmor (float flArmor, int suit) -{ - if (!pev->takedamage) return 0; - return CBaseEntity::TakeArmor(flArmor, suit); -} - -BOOL CBaseMonster :: HasHumanGibs( void ) -{ - int myClass = Classify(); - - // these types of monster don't use gibs - if ( myClass == CLASS_NONE || myClass == CLASS_MACHINE || myClass == CLASS_PLAYER_BIOWEAPON && myClass == CLASS_ALIEN_BIOWEAPON) - { - return FALSE; - } - else - { - return (this->m_bloodColor == BLOOD_COLOR_RED); - } -} - - -BOOL CBaseMonster :: HasAlienGibs( void ) -{ - int myClass = Classify(); - - // these types of monster don't use gibs - if ( myClass == CLASS_NONE || myClass == CLASS_MACHINE || myClass == CLASS_PLAYER_BIOWEAPON && myClass == CLASS_ALIEN_BIOWEAPON) - { - return FALSE; - } - else - { - return (this->m_bloodColor == BLOOD_COLOR_GREEN); - } -} - - -//========================================================= -// GibMonster - create some gore and get rid of a monster's -// model. -//========================================================= -void CBaseMonster :: GibMonster( void ) -{ - TraceResult tr; - BOOL gibbed = FALSE; - int iszCustomGibs; - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM); - - if ( iszCustomGibs = HasCustomGibs() ) - { - CGib::SpawnHeadGib( this, iszCustomGibs ); - CGib::SpawnRandomGibs( this, 4, 1, iszCustomGibs ); - CGib::SpawnStickyGibs (this, 4, iszCustomGibs ); - gibbed = TRUE; - } - else if ( HasHumanGibs() ) - { - CGib::SpawnHeadGib( this ); - CGib::SpawnRandomGibs( this, 4, 1 ); // throw some human gibs. - CGib::SpawnStickyGibs (this, 4 ); - gibbed = TRUE; - } - else if ( HasAlienGibs() ) - { - CGib::SpawnRandomGibs( this, 4, 0 ); // Throw alien gibs - gibbed = TRUE; - } - if ( !IsPlayer() && gibbed ) UTIL_Remove (this); - else - { - StopAnimation(); - pev->velocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->avelocity = g_vecZero; - pev->animtime = gpGlobals->time; - pev->effects |= EF_NOINTERP; - } -} - -//========================================================= -// GetDeathActivity - determines the best type of death -// anim to play. -//========================================================= -Activity CBaseMonster :: GetDeathActivity ( void ) -{ - Activity deathActivity; - BOOL fTriedDirection; - float flDot; - TraceResult tr; - Vector vecSrc; - - if ( pev->deadflag != DEAD_NO ) - { - // don't run this while dying. - return m_IdealActivity; - } - - vecSrc = Center(); - - fTriedDirection = FALSE; - deathActivity = ACT_DIESIMPLE;// in case we can't find any special deaths to do. - - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // try to pick a region-specific death. - case HITGROUP_HEAD: - deathActivity = ACT_DIE_HEADSHOT; - break; - - case HITGROUP_STOMACH: - deathActivity = ACT_DIE_GUTSHOT; - break; - - case HITGROUP_GENERIC: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - - default: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - } - - - // can we perform the prescribed death? - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // no! did we fail to perform a directional death? - if ( fTriedDirection ) - { - // if yes, we're out of options. Go simple. - deathActivity = ACT_DIESIMPLE; - } - else - { - // cannot perform the ideal region-specific death, so try a direction. - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - } - } - - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // if we're still invalid, simple is our only option. - deathActivity = ACT_DIESIMPLE; - } - - if ( deathActivity == ACT_DIEFORWARD ) - { - // make sure there's room to fall forward - UTIL_TraceHull ( vecSrc, vecSrc + gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - if ( deathActivity == ACT_DIEBACKWARD ) - { - // make sure there's room to fall backward - UTIL_TraceHull ( vecSrc, vecSrc - gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - return deathActivity; -} - -//========================================================= -// GetSmallFlinchActivity - determines the best type of flinch -// anim to play. -//========================================================= -Activity CBaseMonster :: GetSmallFlinchActivity ( void ) -{ - Activity flinchActivity; - BOOL fTriedDirection; - float flDot; - - fTriedDirection = FALSE; - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // pick a region-specific flinch - case HITGROUP_HEAD: - flinchActivity = ACT_FLINCH_HEAD; - break; - case HITGROUP_STOMACH: - flinchActivity = ACT_FLINCH_STOMACH; - break; - case HITGROUP_LEFTARM: - flinchActivity = ACT_FLINCH_LEFTARM; - break; - case HITGROUP_RIGHTARM: - flinchActivity = ACT_FLINCH_RIGHTARM; - break; - case HITGROUP_LEFTLEG: - flinchActivity = ACT_FLINCH_LEFTLEG; - break; - case HITGROUP_RIGHTLEG: - flinchActivity = ACT_FLINCH_RIGHTLEG; - break; - case HITGROUP_GENERIC: - default: - // just get a generic flinch. - flinchActivity = ACT_SMALL_FLINCH; - break; - } - - - // do we have a sequence for the ideal activity? - if ( LookupActivity ( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - flinchActivity = ACT_SMALL_FLINCH; - } - - return flinchActivity; -} - - -void CBaseMonster::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. - - // make the corpse fly away from the attack vector - pev->movetype = MOVETYPE_TOSS; - //pev->flags &= ~FL_ONGROUND; - //pev->origin.z += 2; - //pev->velocity = g_vecAttackDir * -1; - //pev->velocity = pev->velocity * RANDOM_FLOAT( 300, 400 ); -} - - -BOOL CBaseMonster::ShouldGibMonster( int iGib ) -{ - if ( ( iGib == GIB_NORMAL && pev->health < -30 ) || ( iGib == GIB_ALWAYS ) ) - return TRUE; - - return FALSE; -} - - -void CBaseMonster::CallGibMonster( void ) -{ - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT;// do something with the body. while monster blows up - - StopAnimation(); - pev->velocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->avelocity = g_vecZero; - pev->animtime = gpGlobals->time; - pev->effects |= EF_NOINTERP; - - pev->effects = EF_NODRAW; // make the model invisible. - GibMonster(); - - pev->deadflag = DEAD_DEAD; - FCheckAITrigger(); - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) pev->health = 0; -} - - -/* -============ -Killed -============ -*/ -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - if ( HasMemory( bits_MEMORY_KILLED ) ) - { - if ( ShouldGibMonster( iGib ) ) - CallGibMonster(); - return; - } - - Remember( bits_MEMORY_KILLED ); - - // clear the deceased's sound channels.(may have been firing or reloading when killed) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/null.wav", 1, ATTN_NORM); - m_IdealMonsterState = MONSTERSTATE_DEAD; - // Make sure this condition is fired too (TakeDamage breaks out before this happens on death) - SetConditions( bits_COND_LIGHT_DAMAGE ); - - // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if ( pOwner ) - { - pOwner->DeathNotice( pev ); - } - if ( ShouldGibMonster( iGib ) ) - { - CallGibMonster(); - return; - } - else if ( pev->flags & FL_MONSTER ) - { - SetTouch( NULL ); - BecomeDead(); - } - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) pev->health = 0; - m_IdealMonsterState = MONSTERSTATE_DEAD; -} - -//========================================================= -// FBoxVisible - a more accurate ( and slower ) version -// of FVisible. -// -// !!!UNDONE - make this CBaseMonster? -//========================================================= -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize ) -{ - // don't look through water - if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3) - || (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0)) - return FALSE; - - TraceResult tr; - Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;//look through the monster's 'eyes' - for (int i = 0; i < 5; i++) - { - Vector vecTarget = pevTarget->origin; - vecTarget.x += RANDOM_FLOAT( pevTarget->mins.x + flSize, pevTarget->maxs.x - flSize); - vecTarget.y += RANDOM_FLOAT( pevTarget->mins.y + flSize, pevTarget->maxs.y - flSize); - vecTarget.z += RANDOM_FLOAT( pevTarget->mins.z + flSize, pevTarget->maxs.z - flSize); - - UTIL_TraceLine(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, ENT(pevLooker)/*pentIgnore*/, &tr); - - if (tr.flFraction == 1.0) - { - vecTargetOrigin = vecTarget; - return TRUE;// line of sight is valid. - } - } - return FALSE;// Line of sight is not established -} - -// -// VecCheckToss - returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2. -// returns g_vecZero if toss is not feasible. -// -Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj ) -{ - TraceResult tr; - Vector vecMidPoint;// halfway point between Spot1 and Spot2 - Vector vecApex;// highest point - Vector vecScale; - Vector vecGrenadeVel; - Vector vecTemp; - float flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj; - - if (vecSpot2.z - vecSpot1.z > 500) - { - // to high, fail - return g_vecZero; - } - - UTIL_MakeVectors (pev->angles); - - // toss a little bit to the left or right, not right down on the enemy's bean (head). - vecSpot2 = vecSpot2 + gpGlobals->v_right * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); - vecSpot2 = vecSpot2 + gpGlobals->v_forward * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); - - // calculate the midpoint and apex of the 'triangle' - // UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT - - // How much time does it take to get there? - - // get a rough idea of how high it can be thrown - vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, ENT(pev), &tr); - vecMidPoint = tr.vecEndPos; - // (subtract 15 so the grenade doesn't hit the ceiling) - vecMidPoint.z -= 15; - - if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z) - { - // to not enough space, fail - return g_vecZero; - } - - // How high should the grenade travel to reach the apex - float distance1 = (vecMidPoint.z - vecSpot1.z); - float distance2 = (vecMidPoint.z - vecSpot2.z); - - // How long will it take for the grenade to travel this distance - float time1 = sqrt( distance1 / (0.5 * flGravity) ); - float time2 = sqrt( distance2 / (0.5 * flGravity) ); - - if (time1 < 0.1) - { - // too close - return g_vecZero; - } - - // how hard to throw sideways to get there in time. - vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2); - // how hard upwards to reach the apex at the right time. - vecGrenadeVel.z = flGravity * time1; - - // find the apex - vecApex = vecSpot1 + vecGrenadeVel * time1; - vecApex.z = vecMidPoint.z; - - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - // UNDONE: either ignore monsters or change it to not care if we hit our enemy - UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - return vecGrenadeVel; -} - - -// -// VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2. -// returns g_vecZero if throw is not feasible. -// -Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj ) -{ - float flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj; - - Vector vecGrenadeVel = (vecSpot2 - vecSpot1); - - // throw at a constant time - float time = vecGrenadeVel.Length( ) / flSpeed; - vecGrenadeVel = vecGrenadeVel * (1.0 / time); - - // adjust upward toss to compensate for gravity loss - vecGrenadeVel.z += flGravity * time * 0.5; - - Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5); - - TraceResult tr; - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - return vecGrenadeVel; -} - - - -//========================================================= -// 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; - } - -} - -//LRC - an entity for monsters to shoot at. -#define SF_MONSTERTARGET_OFF 1 -class CMonsterTarget : public CBaseEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int Classify( void ) { return pev->frags; }; - STATE GetState( void ) - { - return pev->health?STATE_ON:STATE_OFF; - }; -}; -LINK_ENTITY_TO_CLASS( monster_target, CMonsterTarget ); - -void CMonsterTarget :: Spawn ( void ) -{ - if (pev->spawnflags & SF_MONSTERTARGET_OFF) - pev->health = 0; - else pev->health = 1; // Don't ignore me, I'm not dead. I'm quite well really. I think I'll go for a walk... - SetBits (pev->flags, FL_MONSTER); -} - -void CMonsterTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (useType == USE_TOGGLE) - { - if(pev->health) useType = USE_OFF; - else useType = USE_ON; - } - if (useType == USE_ON)pev->health = 1; - else if(useType == USE_OFF)pev->health = 0; -} \ No newline at end of file diff --git a/server/monsters/basemonster.h b/server/monsters/basemonster.h deleted file mode 100644 index fe103a6f..00000000 --- a/server/monsters/basemonster.h +++ /dev/null @@ -1,352 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ - -#ifndef BASEMONSTER_H -#define BASEMONSTER_H - -#define ROUTE_SIZE 8 // how many waypoints a monster can store at one time -#define MAX_OLD_ENEMIES 4 // how many old enemies to remember - -// -// generic Monster -// -class CBaseMonster : public CBaseAnimating -{ -private: - int m_afConditions; - -public: - typedef enum - { - SCRIPT_PLAYING = 0, // Playing the sequence - SCRIPT_WAIT, // Waiting on everyone in the script to be ready - SCRIPT_CLEANUP, // Cancelling the script / cleaning up - SCRIPT_WALK_TO_MARK, - SCRIPT_RUN_TO_MARK, - } SCRIPTSTATE; - - - - // these fields have been added in the process of reworking the state machine. (sjb) - EHANDLE m_hEnemy; // the entity that the monster is fighting. - EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach - EHANDLE m_hOldEnemy[ MAX_OLD_ENEMIES ]; - Vector m_vecOldEnemy[ MAX_OLD_ENEMIES ]; - - float m_flFieldOfView;// width of monster's field of view ( dot product ) - float m_flWaitFinished;// if we're told to wait, this is the time that the wait will be over. - float m_flMoveWaitFinished; - - Activity m_Activity;// what the monster is doing (animation) - Activity m_IdealActivity;// monster should switch to this activity - - int m_LastHitGroup; // the last body region that took damage - - MONSTERSTATE m_MonsterState;// monster's current state - MONSTERSTATE m_IdealMonsterState;// monster should change to this state - - int m_iTaskStatus; - Schedule_t *m_pSchedule; - int m_iScheduleIndex; - - WayPoint_t m_Route[ ROUTE_SIZE ]; // Positions of movement - int m_movementGoal; // Goal that defines route - int m_iRouteIndex; // index into m_Route[] - float m_moveWaitTime; // How long I should wait for something to move - - Vector m_vecMoveGoal; // kept around for node graph moves, so we know our ultimate goal - Activity m_movementActivity; // When moving, set this activity - - int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. - int m_afSoundTypes; - - Vector m_vecLastPosition;// monster sometimes wants to return to where it started after an operation. - - int m_iHintNode; // this is the hint node that the monster is moving towards or performing active idle on. - - int m_afMemory; - - int m_iMaxHealth;// keeps track of monster's maximum health value (for re-healing, etc) - - Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) - - int m_cAmmoLoaded; // how much ammo is in the weapon (used to trigger reload anim sequences) - - int m_afCapability;// tells us what a monster can/can't do. - - float m_flNextAttack; // cannot attack again until this time - - int m_bitsDamageType; // what types of damage has monster (player) taken - byte m_rgbTimeBasedDamage[CDMG_TIMEBASED]; - - int m_lastDamageAmount;// how much damage did monster (player) last take - // time based damage counters, decr. 1 per 2 seconds - int m_bloodColor; // color of blood particless - - int m_failSchedule; // Schedule type to choose if current schedule fails - - float m_flHungryTime;// set this is a future time to stop the monster from eating for a while. - - float m_flDistTooFar; // if enemy farther away than this, bits_COND_ENEMY_TOOFAR set in CheckEnemy - float m_flDistLook; // distance monster sees (Default 2048) - - int m_iTriggerCondition;// for scripted AI, this is the condition that will cause the activation of the monster's TriggerTarget - string_t m_iszTriggerTarget;// name of target that should be fired. - - Vector m_HackedGunPos; // HACK until we can query end of gun - -// Scripted sequence Info - SCRIPTSTATE m_scriptState; // internal cinematic state - CCineMonster *m_pCine; - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - virtual STATE GetState( void ) { return (pev->deadflag == DEAD_DEAD)?STATE_OFF:STATE_ON; }; - - static TYPEDESCRIPTION m_SaveData[]; - - void KeyValue( KeyValueData *pkvd ); - -// monster use function - void EXPORT MonsterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CorpseUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -// overrideable Monster member functions - - // LRC- to allow level-designers to change monster allegiances - int m_iClass; - int m_iPlayerReact; - virtual int Classify( void ) { return m_iClass?m_iClass:CLASS_NONE; } - - 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); } - -// Basic Monster AI functions - virtual float ChangeYaw ( int speed ); - float VecToYaw( Vector vecDir ); - float FlYawDiff ( void ); - - float DamageForce( float damage ); - -// stuff written for new state machine - virtual void MonsterThink( void ); - void EXPORT CallMonsterThink( void ) { this->MonsterThink(); } - virtual int IRelationship ( CBaseEntity *pTarget ); - virtual void MonsterInit ( void ); - virtual void MonsterInitDead( void ); // Call after animation/pose is set up - virtual void BecomeDead( void ); - void EXPORT CorpseFallThink( void ); - - void EXPORT MonsterInitThink ( void ); - virtual void StartMonster ( void ); - virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack - virtual BOOL FInViewCone ( CBaseEntity *pEntity );// see if pEntity is in monster's view cone - virtual BOOL FInViewCone ( Vector *pOrigin );// see if given location is in monster's view cone - virtual void HandleAnimEvent( MonsterEvent_t *pEvent ); - - virtual int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist );// check validity of a straight move through space - virtual void Move( float flInterval = 0.1 ); - virtual void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - virtual BOOL ShouldAdvanceRoute( float flWaypointDist ); - - virtual Activity GetStoppedActivity( void ) { return ACT_IDLE; } - virtual void Stop( void ) { m_IdealActivity = GetStoppedActivity(); } - - // This will stop animation until you call ResetSequenceInfo() at some point in the future - inline void StopAnimation( void ) { pev->framerate = 0; } - - // these functions will survey conditions and set appropriate conditions bits for attack types. - virtual BOOL CheckRangeAttack1( float flDot, float flDist ); - virtual BOOL CheckRangeAttack2( float flDot, float flDist ); - virtual BOOL CheckMeleeAttack1( float flDot, float flDist ); - virtual BOOL CheckMeleeAttack2( float flDot, float flDist ); - - BOOL FHaveSchedule( void ); - BOOL FScheduleValid ( void ); - void ClearSchedule( void ); - BOOL FScheduleDone ( void ); - void ChangeSchedule ( Schedule_t *pNewSchedule ); - void NextScheduledTask ( void ); - Schedule_t *ScheduleInList( const char *pName, Schedule_t **pList, int listCount ); - - virtual Schedule_t *ScheduleFromName( const char *pName ); - static Schedule_t *m_scheduleList[]; - - void MaintainSchedule ( void ); - virtual void StartTask ( Task_t *pTask ); - virtual void RunTask ( Task_t *pTask ); - virtual Schedule_t *GetScheduleOfType( int Type ); - virtual Schedule_t *GetSchedule( void ); - virtual void ScheduleChange( void ) {} -// virtual int CanPlaySequence( void ) { return ((m_pCine == NULL) && (m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE)); } - virtual int CanPlaySequence( int interruptFlags ); -// virtual int CanPlaySequence( BOOL fDisregardState, int interruptLevel ); - virtual int CanPlaySentence( BOOL fDisregardState ) { return IsAlive(); } - virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ); - virtual void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - - virtual void SentenceStop( void ); - - Task_t *GetTask ( void ); - virtual MONSTERSTATE GetIdealState ( void ); - virtual void SetActivity ( Activity NewActivity ); - void SetSequenceByName ( char *szSequence ); - void SetState ( MONSTERSTATE State ); - virtual void ReportAIState( void ); - - void CheckAttacks ( CBaseEntity *pTarget, float flDist ); - virtual int CheckEnemy ( CBaseEntity *pEnemy ); - void PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ); - BOOL PopEnemy( void ); - - BOOL FGetNodeRoute ( Vector vecDest ); - - inline void TaskComplete( void ) { if ( !HasConditions(bits_COND_TASK_FAILED) ) m_iTaskStatus = TASKSTATUS_COMPLETE; } - void MovementComplete( void ); - inline void TaskFail( void ) { SetConditions(bits_COND_TASK_FAILED); } - inline void TaskBegin( void ) { m_iTaskStatus = TASKSTATUS_RUNNING; } - int TaskIsRunning( void ); - inline int TaskIsComplete( void ) { return (m_iTaskStatus == TASKSTATUS_COMPLETE); } - inline int MovementIsComplete( void ) { return (m_movementGoal == MOVEGOAL_NONE); } - - int IScheduleFlags ( void ); - BOOL FRefreshRoute( void ); - BOOL FRouteClear ( void ); - void RouteSimplify( CBaseEntity *pTargetEnt ); - void AdvanceRoute ( float distance ); - virtual BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ); - void MakeIdealYaw( Vector vecTarget ); - virtual void SetYawSpeed ( void ) { return; };// allows different yaw_speeds for each activity - BOOL BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ); - virtual BOOL BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ); - int RouteClassify( int iMoveFlag ); - void InsertWaypoint ( Vector vecLocation, int afMoveFlags ); - - BOOL FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ); - virtual BOOL FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ); - virtual BOOL FValidateCover ( const Vector &vecCoverLocation ) { return TRUE; }; - virtual float CoverRadius( void ) { return 784; } // Default cover radius - - virtual BOOL FCanCheckAttacks ( void ); - virtual void CheckAmmo( void ) { return; }; - virtual int IgnoreConditions ( void ); - - inline void SetConditions( int iConditions ) { m_afConditions |= iConditions; } - inline void ClearConditions( int iConditions ) { m_afConditions &= ~iConditions; } - inline BOOL HasConditions( int iConditions ) { if ( m_afConditions & iConditions ) return TRUE; return FALSE; } - inline BOOL HasAllConditions( int iConditions ) { if ( (m_afConditions & iConditions) == iConditions ) return TRUE; return FALSE; } - - virtual BOOL FValidateHintType( short sHint ); - int FindHintNode ( void ); - virtual BOOL FCanActiveIdle ( void ); - void SetTurnActivity ( void ); - float FLSoundVolume ( CSound *pSound ); - - BOOL MoveToNode( Activity movementAct, float waitTime, const Vector &goal ); - BOOL MoveToTarget( Activity movementAct, float waitTime ); - BOOL MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ); - BOOL MoveToEnemy( Activity movementAct, float waitTime ); - - // Returns the time when the door will be open - float OpenDoorAndWait( entvars_t *pevDoor ); - - virtual int ISoundMask( void ); - virtual CSound* PBestSound ( void ); - virtual CSound* PBestScent ( void ); - virtual float HearingSensitivity( void ) { return 1.0; }; - - BOOL FBecomeProne ( void ); - virtual void BarnacleVictimBitten( entvars_t *pevBarnacle ); - virtual void BarnacleVictimReleased( void ); - - void SetEyePosition ( void ); - - BOOL FShouldEat( void );// see if a monster is 'hungry' - void Eat ( float flFullDuration );// make the monster 'full' for a while. - - CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); - BOOL FacingIdeal( void ); - - BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. - BOOL NoFriendlyFire( void ); - - BOOL BBoxFlat( void ); - - // PrescheduleThink - virtual void PrescheduleThink( void ) { return; }; - - BOOL GetEnemy ( void ); - void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - // combat functions - float UpdateTarget ( entvars_t *pevTarget ); - virtual Activity GetDeathActivity ( void ); - Activity GetSmallFlinchActivity( void ); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual void GibMonster( void ); - BOOL ShouldGibMonster( int iGib ); - void CallGibMonster( void ); - virtual int HasCustomGibs( void ) { return FALSE; } //LRC - virtual BOOL HasHumanGibs( void ); - virtual BOOL HasAlienGibs( void ); - - 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 TakeArmor( float flArmor, int suit = 0 ); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - int DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - void RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - virtual int IsMoving( void ) { return m_movementGoal != MOVEGOAL_NONE; } - - void RouteClear( void ); - void RouteNew( void ); - - virtual void DeathSound ( void ) { return; }; - virtual void AlertSound ( void ) { return; }; - virtual void IdleSound ( void ) { return; }; - virtual void PainSound ( void ) { return; }; - - virtual void StopFollowing( BOOL clearSchedule ) {} - - inline void Remember( int iMemory ) { m_afMemory |= iMemory; } - inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; } - inline BOOL HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; } - inline BOOL HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; } - - BOOL ExitScriptedSequence( ); - BOOL CineCleanup( ); - - void StartPatrol( CBaseEntity *path ); - - CBaseEntity* DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. -}; - - - -#endif // BASEMONSTER_H diff --git a/server/monsters/combat.cpp b/server/monsters/combat.cpp deleted file mode 100644 index 477bc2f5..00000000 --- a/server/monsters/combat.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== combat.cpp ======================================================== - - functions dealing with damage infliction & death - -*/ - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "monsters.h" -#include "soundent.h" -#include "decals.h" -#include "animation.h" -#include "baseweapon.h" -#include "basebrush.h" -#include "defaults.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -MULTIDAMAGE gMultiDamage; - - -/* -============================================================================== - -MULTI-DAMAGE - -Collects multiple small damages into a single damage - -============================================================================== -*/ - -// -// ClearMultiDamage - resets the global multi damage accumulator -// -void ClearMultiDamage(void) -{ - gMultiDamage.pEntity = NULL; - gMultiDamage.amount = 0; - gMultiDamage.type = 0; -} - - -// -// ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity -// -// GLOBALS USED: -// gMultiDamage - -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) -{ - Vector vecSpot1;//where blood comes from - Vector vecDir;//direction blood should go - TraceResult tr; - - if ( !gMultiDamage.pEntity ) - return; - - gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type ); -} - - -// GLOBALS USED: -// gMultiDamage - -void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) -{ - if ( !pEntity ) - return; - - gMultiDamage.type |= bitsDamageType; - - if ( pEntity != gMultiDamage.pEntity ) - { - ApplyMultiDamage(pevInflictor,pevInflictor); // UNDONE: wrong attacker! - gMultiDamage.pEntity = pEntity; - gMultiDamage.amount = 0; - } - - gMultiDamage.amount += flDamage; -} - -void DecalGunshot( TraceResult *pTrace, int iBulletType ) -{ - // Is the entity valid - if ( !UTIL_IsValidEntity( pTrace->pHit ) ) - return; - - if ( VARS(pTrace->pHit)->solid == SOLID_BSP || VARS(pTrace->pHit)->movetype == MOVETYPE_PUSHSTEP ) - { - CBaseEntity *pEntity = NULL; - // Decal the wall with a gunshot - if ( !FNullEnt(pTrace->pHit) ) - pEntity = CBaseEntity::Instance(pTrace->pHit); - - switch( iBulletType ) - { - case BULLET_9MM: - case BULLET_MP5: - case BULLET_BUCKSHOT: - case BULLET_357: - default: - // smoke and decal - UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); - break; - case BULLET_12MM: - // smoke and decal - UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); - break; - case BULLET_CROWBAR: - // wall decal - UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); - break; - } - } -} - -// -// EjectBrass - tosses a brass shell from passed origin at passed velocity -// -void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) -{ - // FIX: when the player shoots, their gun isn't in the same position as it is on the model other players see. - - MESSAGE_BEGIN( MSG_PVS, gmsg.TempEntity, vecOrigin ); - WRITE_BYTE( TE_MODEL); - WRITE_COORD( vecOrigin.x); - WRITE_COORD( vecOrigin.y); - WRITE_COORD( vecOrigin.z); - WRITE_COORD( vecVelocity.x); - WRITE_COORD( vecVelocity.y); - WRITE_COORD( vecVelocity.z); - WRITE_ANGLE( rotation ); - WRITE_SHORT( model ); - WRITE_BYTE ( soundtype); - WRITE_BYTE ( 25 );// 2.5 seconds - MESSAGE_END(); -} - -/* -================ -SpawnBlood -================ -*/ -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) -{ - UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage ); -} - - -int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) -{ - if ( !pEntity ) - return (DECAL_GUNSHOT1 + RANDOM_LONG(0,4)); - - return pEntity->DamageDecal( bitsDamageType ); -} - - -// -// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range. -// -// only damage ents that can clearly be seen by the explosion! - - -void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ) -{ - CBaseEntity *pEntity = NULL; - TraceResult tr; - float flAdjustedDamage, falloff; - Vector vecSpot; - - if ( flRadius ) - falloff = flDamage / flRadius; - else - falloff = 1.0; - - int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); - - vecSrc.z += 1;// in case grenade is lying on the ground - - if ( !pevAttacker ) - pevAttacker = pevInflictor; - - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) - { - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - // UNDONE: this should check a damage mask, not an ignore - if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) - {// houndeyes don't hurt other houndeyes with their attack - continue; - } - - // blast's don't tavel into or out of water - if (bInWater && pEntity->pev->waterlevel == 0) - continue; - if (!bInWater && pEntity->pev->waterlevel == 3) - continue; - - vecSpot = pEntity->BodyTarget( vecSrc ); - - UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr ); - - if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - {// the explosion can 'see' this entity, so hurt them! - if (tr.fStartSolid) - { - // if we're stuck inside them, fixup the position and distance - tr.vecEndPos = vecSrc; - tr.flFraction = 0.0; - } - - // decrease damage for an ent that's farther from the bomb. - flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff; - flAdjustedDamage = flDamage - flAdjustedDamage; - - if ( flAdjustedDamage < 0 ) - { - flAdjustedDamage = 0; - } - - // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); - if (tr.flFraction != 1.0) - { - ClearMultiDamage( ); - pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); - ApplyMultiDamage( pevInflictor, pevAttacker ); - } - else - { - pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); - } - } - } - } -} - - - - diff --git a/server/monsters/damage.h b/server/monsters/damage.h deleted file mode 100644 index 0761e7a1..00000000 --- a/server/monsters/damage.h +++ /dev/null @@ -1,21 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2006 -//======================================================================= - -extern void ClearMultiDamage(void); -extern void ApplyMultiDamage(entvars_t* pevInflictor, entvars_t* pevAttacker ); -extern void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType); - -extern void DecalGunshot( TraceResult *pTrace, int iBulletType ); -extern void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage); -extern int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ); -extern void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ); - -typedef struct -{ - CBaseEntity *pEntity; - float amount; - int type; -} MULTIDAMAGE; - -extern MULTIDAMAGE gMultiDamage; \ No newline at end of file diff --git a/server/monsters/defaultai.cpp b/server/monsters/defaultai.cpp deleted file mode 100644 index 2e17c687..00000000 --- a/server/monsters/defaultai.cpp +++ /dev/null @@ -1,1260 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Default behaviors. -//========================================================= -#include "extdll.h" -#include "utils.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" - }, -}; - -//LRC -Task_t tlScriptedTeleport[] = -{ - { TASK_PLANT_ON_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, - { TASK_END_SCRIPT, (float)0 }, -}; - -//LRC -Schedule_t slTeleportToScript[] = -{ - { - tlScriptedTeleport, - ARRAYSIZE ( tlScriptedTeleport ), - SCRIPT_BREAK_CONDITIONS, - 0, - "TeleportToScript" - }, -}; - -Task_t tlScriptedWalk[] = -{ - { TASK_WALK_TO_SCRIPT, (float)TARGET_MOVE_SCRIPTED }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLANT_ON_SCRIPT, (float)0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_ENABLE_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, - { TASK_END_SCRIPT, (float)0 }, -}; - -Schedule_t slWalkToScript[] = -{ - { - tlScriptedWalk, - ARRAYSIZE ( tlScriptedWalk ), - SCRIPT_BREAK_CONDITIONS, - 0, - "WalkToScript" - }, -}; - - -Task_t tlScriptedRun[] = -{ - { TASK_RUN_TO_SCRIPT, (float)TARGET_MOVE_SCRIPTED }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLANT_ON_SCRIPT, (float)0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_ENABLE_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, - { TASK_END_SCRIPT, (float)0 }, -}; - -Schedule_t slRunToScript[] = -{ - { - tlScriptedRun, - ARRAYSIZE ( tlScriptedRun ), - SCRIPT_BREAK_CONDITIONS, - 0, - "RunToScript" - }, -}; - -Task_t tlScriptedWait[] = -{ - { TASK_STOP_MOVING, 0 }, -// { TASK_ENABLE_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, - { TASK_END_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 }, - { TASK_END_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. // LRC- And scripted actions, too. - case SCHED_AISCRIPT: - { -// ALERT(at_console, "Doing AISCRIPT\n"); - 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: - return slWaitScript; - case 4: case 6: - return slTeleportToScript; - 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/server/monsters/defaultai.h b/server/monsters/defaultai.h deleted file mode 100644 index 652d1085..00000000 --- a/server/monsters/defaultai.h +++ /dev/null @@ -1,98 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#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/server/monsters/flyingmonster.cpp b/server/monsters/flyingmonster.cpp deleted file mode 100644 index c28906d3..00000000 --- a/server/monsters/flyingmonster.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "utils.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/server/monsters/flyingmonster.h b/server/monsters/flyingmonster.h deleted file mode 100644 index 616194db..00000000 --- a/server/monsters/flyingmonster.h +++ /dev/null @@ -1,53 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -// 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/server/monsters/generic.cpp b/server/monsters/generic.cpp deleted file mode 100644 index ea4373c7..00000000 --- a/server/monsters/generic.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Generic Monster - purely for scripted sequence work. -//========================================================= -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "talkmonster.h" -#include "basebeams.h" - -// For holograms, make them not solid so the player can walk through them -//LRC- this seems to interfere with SF_MONSTER_CLIP -#define SF_GENERICMONSTER_NOTSOLID 4 -#define SF_HEAD_CONTROLLER 8 -#define SF_GENERICMONSTER_INVULNERABLE 32 -#define SF_GENERICMONSTER_PLAYERMODEL 64 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -//G-Cont. This code - support for htorch model from Op4 ;) -#define HTORCH_AE_SHOWGUN ( 17) -#define HTORCH_AE_SHOWTORCH ( 18) -#define HTORCH_AE_HIDETORCH ( 19) -#define HTORCH_AE_ONGAS ( 20) -#define HTORCH_AE_OFFGAS ( 21) -#define GUN_DEAGLE 0 -#define GUN_TORCH 1 -#define GUN_NONE 2 - -class CGenericMonster : public CTalkMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); - void KeyValue( KeyValueData *pkvd ); - void Torch ( void ); - void MakeGas( void ); - void UpdateGas( void ); - void KillGas( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual int HasCustomGibs( void ) { return m_iszGibModel; } - - CBeam *m_pBeam; - int m_iszGibModel; -}; -LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ); - -TYPEDESCRIPTION CGenericMonster::m_SaveData[] = -{ - DEFINE_FIELD( CGenericMonster, m_iszGibModel, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CGenericMonster, CBaseMonster ); - -void CGenericMonster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_bloodColor")) - { - m_bloodColor = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszGibModel")) - { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGenericMonster :: Classify ( void ) -{ - return m_iClass?m_iClass: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 ) -{ - Vector vecShootDir; - Vector vecShootOrigin; - - switch( pEvent->event ) - { - case HTORCH_AE_SHOWTORCH: - pev->body = GUN_NONE; - pev->body = GUN_TORCH; - break; - - case HTORCH_AE_SHOWGUN: - pev->body = GUN_NONE; - pev->body = GUN_DEAGLE; - break; - - case HTORCH_AE_HIDETORCH: - pev->body = GUN_NONE; - break; - - case HTORCH_AE_ONGAS: - { - int gas = 1; - MakeGas(); - UpdateGas(); - }; - break; - - case HTORCH_AE_OFFGAS: - { - int gas = 0; - KillGas(); - }; - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// ISoundMask - generic monster can't hear. -//========================================================= -int CGenericMonster :: ISoundMask ( void ) -{ - return NULL; -} - -//========================================================= -// Spawn -//========================================================= -void CGenericMonster :: Spawn() -{ - Precache(); - - UTIL_SetModel( ENT(pev), STRING(pev->model) ); - - if ( FStrEq( STRING(pev->model), "models/player.mdl" ) || FStrEq( STRING(pev->model), "models/holo.mdl" )) - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - else UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - //UTIL_AutoSetSize(); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - //pev->weaponmodel = MAKE_STRING("materials/weapons/pulserifle/wp_prifle.mdl"); - if (!m_bloodColor) m_bloodColor = BLOOD_COLOR_RED; - if (!pev->health) 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(); - - m_afCapability = bits_CAP_TURN_HEAD; - - if ( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - } - else if ( pev->spawnflags & SF_GENERICMONSTER_INVULNERABLE ) - { - pev->takedamage = DAMAGE_NO; - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGenericMonster :: Precache() -{ - //PRECACHE_MODEL("materials/weapons/pulserifle/wp_prifle.mdl"); - CTalkMonster::Precache(); - TalkInit(); - UTIL_PrecacheModel((char *)STRING(pev->model) ); - if (m_iszGibModel) - PRECACHE_MODEL( (char*)STRING(m_iszGibModel) ); //LRC -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - TASK_TORCH_CHECK_FIRE = LAST_COMMON_SCHEDULE + 1, - TASK_GAS, -}; - -// ========================================================= -// TORCH SUPPORT -// ========================================================= -void CGenericMonster :: Torch ( void ) -{ - Vector vecGunPos; - Vector vecGunAngles; - Vector vecShootDir; - - GetAttachment( 4, vecGunPos, vecGunAngles ); - pev->effects |= EF_MUZZLEFLASH; - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -void CGenericMonster::UpdateGas( void ) { } - -void CGenericMonster::MakeGas( void ) -{ - Vector posGun, angleGun; - TraceResult tr; - UTIL_MakeVectors( pev->angles ); - { - KillGas(); - m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 7 ); - if ( m_pBeam ) - { - GetAttachment( 4, posGun, angleGun ); - GetAttachment( 3, posGun, angleGun ); - - Vector vecEnd = (gpGlobals->v_forward * 5) + posGun; - UTIL_TraceLine( posGun, vecEnd, dont_ignore_monsters, edict(), &tr ); - - m_pBeam->EntsInit( edict(), edict() ); - m_pBeam->SetColor( 24, 121, 239 ); - m_pBeam->SetBrightness( 190 ); - m_pBeam->SetScrollRate( 20 ); - m_pBeam->SetStartAttachment( 4 ); - m_pBeam->SetEndAttachment( 3 ); - m_pBeam->DamageDecal( 28 ); - m_pBeam->DoSparks( tr.vecEndPos, posGun ); - m_pBeam->SetFlags( FBEAM_SHADEIN ); - m_pBeam->RelinkBeam(); - - UTIL_Sparks( tr.vecEndPos ); - UTIL_DecalTrace(&tr, 28 + RANDOM_LONG(0,4)); - } - } - // m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 ); - if ( int gas = 1 ) - { - pev->nextthink = gpGlobals->time; - } -} - -void CGenericMonster :: KillGas( void ) -{ - if ( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } -} - -//========================================================= -// GENERIC DEAD MONSTER, PROP -//========================================================= -class CDeadGenericMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - int Classify ( void ) { return CLASS_PLAYER_ALLY; } - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual int HasCustomGibs( void ) { return m_iszGibModel; } - - int m_iszGibModel; -}; - -LINK_ENTITY_TO_CLASS( monster_generic_dead, CDeadGenericMonster ); - -TYPEDESCRIPTION CDeadGenericMonster::m_SaveData[] = -{ - DEFINE_FIELD( CDeadGenericMonster, m_iszGibModel, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CDeadGenericMonster, CBaseMonster ); - -void CDeadGenericMonster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_bloodColor")) - { - m_bloodColor = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszGibModel")) - { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -//========================================================= -// ********** DeadGenericMonster SPAWN ********** -//========================================================= -void CDeadGenericMonster :: Spawn( void ) -{ - Precache(); - SET_MODEL(ENT(pev), STRING(pev->model)); - - pev->effects = 0; - pev->yaw_speed = 8; //LRC -- what? - pev->sequence = 0; - - if( pev->netname ) - { - pev->sequence = LookupSequence( STRING( pev->netname )); - - if( pev->sequence == -1 ) - { - ALERT ( at_console, "Invalid sequence name \"%s\" in monster_generic_dead\n", STRING(pev->netname) ); - } - } - else - { - pev->sequence = LookupActivity( pev->frags ); -// if (pev->sequence == -1) -// { -// ALERT ( at_error, "monster_generic_dead - specify a sequence name or choose a different death type: model \"%s\" has no available death sequences.\n", STRING(pev->model) ); -// } - //...and if that doesn't work, forget it. - } - - // Corpses have less health - pev->health = 8; - - MonsterInitDead(); - - ResetSequenceInfo( ); - pev->frame = 255; // pose at the _end_ of its death sequence. -} - -void CDeadGenericMonster :: Precache() -{ - PRECACHE_MODEL( (char*)STRING(pev->model) ); - if (m_iszGibModel) - PRECACHE_MODEL( (char*)STRING(m_iszGibModel) ); //LRC -} diff --git a/server/monsters/gman.cpp b/server/monsters/gman.cpp deleted file mode 100644 index 98ebcace..00000000 --- a/server/monsters/gman.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// GMan - misunderstood servant of the people -//========================================================= -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "baseweapon.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 m_iClass?m_iClass: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(); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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() -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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/server/monsters/hassassin.cpp b/server/monsters/hassassin.cpp deleted file mode 100644 index c6c8cd4a..00000000 --- a/server/monsters/hassassin.cpp +++ /dev/null @@ -1,1068 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// hassassin - Human assassin, fast and stealthy -//========================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "squadmonster.h" -#include "baseweapon.h" -#include "soundent.h" -#include "scripted.h" -#include "game.h" -#include "defaults.h" - -//========================================================= -// 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 m_iClass?m_iClass: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 && !m_pCine) //LRC - { - 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_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: - { - Vector vecGunPosition = pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32); - UTIL_MakeVectors( pev->angles ); - //LRC - if (m_pCine && m_pCine->IsAction()) - { - Vector vecToss; - if (m_pCine->PreciseAttack() && m_hTargetEnt != NULL) - { - vecToss = VecCheckToss( pev, vecGunPosition, m_hTargetEnt->pev->origin, 0.5 ); - //if (vecToss != g_vecZero) - // ALERT(at_console,"Assassin %s throws precise grenade\n",STRING(pev->targetname)); - } - else - { - //ALERT(at_console,"Assassin %s throws nonprecise grenade\n",STRING(pev->targetname)); - // what speed would be best to use, here? Borrowing the hgrunt grenade speed seems silly... - vecToss = ((gpGlobals->v_forward*0.5)+(gpGlobals->v_up*0.5)).Normalize()*HGRUNT_GRENADE_SPEED; - } - CGrenade::ShootTimed( pev, vecGunPosition, vecToss, 2.0 ); - } - else - CGrenade::ShootTimed( pev, vecGunPosition, 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; - if (m_pCine) //LRC... - { - pev->velocity = g_vecZero; - if (m_pCine->PreciseAttack() && m_hTargetEnt != NULL) - { - Vector vecTemp = m_hTargetEnt->pev->origin; - vecTemp.y = vecTemp.y + 50; // put her feet on the target. - pev->velocity = VecCheckToss( pev, pev->origin, vecTemp, 0.5 ); - //if (pev->velocity != g_vecZero) - // ALERT(at_console,"Precise jump for assassin %s\n",STRING(pev->targetname)); - //else - // ALERT(at_console,"Precise jump failed. "); - } - if (pev->velocity == g_vecZero) - { // just jump, it doesn't matter where to. - //ALERT(at_console,"Nonprecise jump for assassin %s\n",STRING(pev->targetname)); - float flGravity = CVAR_GET_FLOAT( "sv_gravity" ); - float time = sqrt( 160 / (0.5 * flGravity)); - float speed = flGravity * time / 160; - UTIL_MakeVectors(pev->angles); - Vector vecDest = pev->origin + (gpGlobals->v_forward * 32); - vecDest.z += 160; // don't forget to jump into the air, now... - pev->velocity= (vecDest - pev->origin) * speed; - } - } - else - pev->velocity = m_vecJumpVelocity; - m_flNextJump = gpGlobals->time + 3.0; - } - return; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHAssassin :: Spawn() -{ - Precache( ); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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; - if (pev->health == 0) - pev->health = HASSASSIN_HEALTH; - 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() -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - PRECACHE_MODEL("models/hassassin.mdl"); - - PRECACHE_SOUND("weapons/pl_gun1.wav"); - PRECACHE_SOUND("weapons/pl_gun2.wav"); - - PRECACHE_SOUND("debris/beamstart1.wav"); - - m_iShell = UTIL_PrecacheModel ("models/gibs/shell556.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 = CVAR_GET_FLOAT( "sv_gravity" ); - - 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 (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 diff --git a/server/monsters/headcrab.cpp b/server/monsters/headcrab.cpp deleted file mode 100644 index c90cb7ac..00000000 --- a/server/monsters/headcrab.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// headcrab.cpp - tiny, jumpy alien parasite -//========================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "game.h" -#include "defaults.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 HEADCRAB_DMG_BITE; } - 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 m_iClass?m_iClass: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 (this, 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 = CVAR_GET_FLOAT( "sv_gravity" ); - 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( ); - - UTIL_SetModel( ENT( pev ), pev->model, "models/monsters/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; - if( pev->health == 0 ) pev->health = HEADCRAB_HEALTH; - 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); - - UTIL_PrecacheModel( pev->model, "models/monsters/headcrab.mdl" ); -} - - -//========================================================= -// RunTask -//========================================================= -void CHeadCrab :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - case TASK_RANGE_ATTACK2: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - SetTouch( NULL ); - m_IdealActivity = ACT_IDLE; - } - break; - } - default: - { - CBaseMonster :: RunTask(pTask); - } - } -} - -//========================================================= -// LeapTouch - this is the headcrab's touch function when it -// is in the air -//========================================================= -void CHeadCrab :: LeapTouch ( CBaseEntity *pOther ) -{ - if ( !pOther->pev->takedamage ) - { - return; - } - - if ( pOther->Classify() == Classify() ) - { - return; - } - - // Don't hit if back on ground - if ( !FBitSet( pev->flags, FL_ONGROUND ) ) - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - - pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH ); - } - - SetTouch( NULL ); -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CHeadCrab :: PrescheduleThink ( void ) -{ - // make the crab coo a little bit in combat state - if ( m_MonsterState == MONSTERSTATE_COMBAT && RANDOM_FLOAT( 0, 5 ) < 0.1 ) - { - IdleSound(); - } -} - -void CHeadCrab :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - m_IdealActivity = ACT_RANGE_ATTACK1; - SetTouch(&CHeadCrab :: LeapTouch ); - break; - } - default: - { - CBaseMonster :: StartTask( pTask ); - } - } -} - - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CHeadCrab :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist <= 256 && flDot >= 0.65 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 -//========================================================= -BOOL CHeadCrab :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - return FALSE; - // BUGBUG: Why is this code here? There is no ACT_RANGE_ATTACK2 animation. I've disabled it for now. -#if 0 - if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist > 64 && flDist <= 256 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -#endif -} - -int CHeadCrab :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Don't take any acid damage -- BigMomma's mortar is acid - if ( bitsDamageType & DMG_ACID ) - flDamage = 0; - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// IdleSound -//========================================================= -#define CRAB_ATTN_IDLE (float)1.5 -void CHeadCrab :: IdleSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab :: AlertSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab :: PainSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// DeathSound -//========================================================= -void CHeadCrab :: DeathSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -Schedule_t* CHeadCrab :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_RANGE_ATTACK1: - { - return &slHCRangeAttack1[ 0 ]; - } - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - - -class CBabyCrab : public CHeadCrab -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - float GetDamageAmount( void ) { return HEADCRAB_HEALTH * 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(); - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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 = HEADCRAB_HEALTH * 0.25; // less health than full grown -} - -void CBabyCrab :: Precache( void ) -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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/server/monsters/hgrunt.cpp b/server/monsters/hgrunt.cpp deleted file mode 100644 index a3155ec9..00000000 --- a/server/monsters/hgrunt.cpp +++ /dev/null @@ -1,2615 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// hgrunt -//========================================================= - -//========================================================= -// Hit groups! -//========================================================= -/* - - 1 - Head - 2 - Stomach - 3 - Gun - -*/ - - -#include "extdll.h" -#include "plane.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "squadmonster.h" -#include "baseweapon.h" -#include "talkmonster.h" -#include "soundent.h" -#include "basebeams.h" -#include "scripted.h" //LRC -#include "defaults.h" //LRC - -int g_fGruntQuestion; // true if an idle grunt asked a question. Cleared when someone answers. - -//========================================================= -// 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( 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 ) -{ - //LRC- only hate alien grunts if my behaviour hasn't been overridden - if (!m_iClass && 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 && !(pev->spawnflags & SF_MONSTER_NO_WPN_DROP)) - {// 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_mp5", 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 who are close enough, 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_hEnemy->pev->watertype == CONTENTS_FOG) && 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() / HGRUNT_GRENADE_SPEED) * 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; - return m_fThrowGrenade; //AJH need this or it is overridden later. - } - } - - 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, HGRUNT_GRENADE_SPEED, 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 m_iClass?m_iClass: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 && m_pCine == NULL) //LRC - scripts may fire when you have no enemy - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - if (m_cAmmoLoaded > 0) - { - 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_MP5 ); // shoot +-5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - } - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); - - // Teh_Freak: World Lighting! - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_DLIGHT ); - WRITE_COORD( vecShootOrigin.x ); // origin - WRITE_COORD( vecShootOrigin.y ); - WRITE_COORD( vecShootOrigin.z ); - WRITE_BYTE( 16 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 128 ); // B - WRITE_BYTE( 0 ); // life * 10 - WRITE_BYTE( 0 ); // decay - MESSAGE_END(); - // Teh_Freak: World Lighting! - -} - -//========================================================= -// Shoot -//========================================================= -void CHGrunt :: Shotgun ( void ) -{ - if (m_hEnemy == NULL && m_pCine == 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(HGRUNT_SHOTGUN_PELLETS, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_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 ); - - // Teh_Freak: World Lighting! - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); - WRITE_BYTE( TE_DLIGHT ); - WRITE_COORD( vecShootOrigin.x ); // origin - WRITE_COORD( vecShootOrigin.y ); - WRITE_COORD( vecShootOrigin.z ); - WRITE_BYTE( 16 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 128 ); // B - WRITE_BYTE( 0 ); // life * 10 - WRITE_BYTE( 0 ); // decay - MESSAGE_END(); - // Teh_Freak: World Lighting! - -} - -//========================================================= -// 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: - { - if (pev->spawnflags & SF_MONSTER_NO_WPN_DROP) break; //LRC - - 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_mp5", 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 ); - //LRC - a bit of a hack. Ideally the grunts would work out in advance whether it's ok to throw. - if (m_pCine) - { - Vector vecToss = g_vecZero; - if (m_hTargetEnt != NULL && m_pCine->PreciseAttack()) - { - vecToss = VecCheckToss( pev, GetGunPosition(), m_hTargetEnt->pev->origin, 0.5 ); - } - if (vecToss == g_vecZero) - { - vecToss = (gpGlobals->v_forward*0.5+gpGlobals->v_up*0.5).Normalize()*HGRUNT_GRENADE_SPEED; - } - CGrenade::ShootTimed( pev, GetGunPosition(), vecToss, 3.5 ); - } - else - 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/mp5/glauncher.wav", 0.8, ATTN_NORM); - //LRC: firing due to a script? - if (m_pCine) - { - Vector vecToss; - if (m_hTargetEnt != NULL && m_pCine->PreciseAttack()) - vecToss = VecCheckThrow( pev, GetGunPosition(), m_hTargetEnt->pev->origin, HGRUNT_GRENADE_SPEED, 0.5 ); - else - { - // just shoot diagonally up+forwards - UTIL_MakeVectors(pev->angles); - vecToss = (gpGlobals->v_forward*0.5 + gpGlobals->v_up*0.5).Normalize() * HGRUNT_GRENADE_SPEED; - } - CGrenade::ShootContact( pev, GetGunPosition(), vecToss ); - } - else - CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity ); - m_fThrowGrenade = FALSE; - m_flNextGrenadeCheck = gpGlobals->time + RANDOM_FLOAT( 4, 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 )) - { - // the first round of the three round burst plays the sound and puts a sound in the world sound list. - if (m_cAmmoLoaded > 0) - { - 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 - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "weapons/cock1.wav", 1, ATTN_NORM ); - } - - Shoot(); - } - else - { - Shotgun( ); - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shotgun/shotgun_single.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, HGRUNT_DMG_KICK, 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( ); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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; - if (pev->health == 0) - pev->health = HGRUNT_HEALTH; - 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() -{ - UTIL_PrecacheModel( pev->model, "models/hgrunt.mdl" ); - - PRECACHE_SOUND( "weapons/cock1.wav" ); - - 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/mp5/glauncher.wav" ); - - PRECACHE_SOUND( "weapons/shotgun/shotgun_single.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 = UTIL_PrecacheModel ("models/gibs/shell556.mdl");// brass shell - m_iShotgunShell = UTIL_PrecacheModel ("models/gibs/shellbuck.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" ); - } - // LRC: added a test to stop a marine without a launcher from firing. - else if ( pev->weapons & HGRUNT_GRENADELAUNCHER ) - { - // get launch anim - iSequence = LookupSequence( "launchgrenade" ); - } - else - { - ALERT( at_console, "No grenades available. "); // flow into the error message we get at the end... - } - 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 - { - ALERT(at_aiconsole,"leader spotted player!\n"); - //!!!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 (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 ( OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) && RANDOM_LONG(0,1) ) - { - return &slGruntGrenadeCover[ 0 ]; - } - else - { - return &slGruntTakeCover[ 0 ]; - } - } - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return &slGruntTakeCoverFromBestSound[ 0 ]; - } - case SCHED_GRUNT_TAKECOVER_FAILED: - { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType ( SCHED_FAIL ); - } - break; - case SCHED_GRUNT_ELOF_FAIL: - { - // human grunt is unable to move to a position that allows him to attack the enemy. - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE: - { - return &slGruntEstablishLineOfFire[ 0 ]; - } - break; - case SCHED_RANGE_ATTACK1: - { - // randomly stand or crouch - if (RANDOM_LONG(0,9) == 0) - m_fStanding = RANDOM_LONG(0,1); - - if (m_fStanding) - return &slGruntRangeAttack1B[ 0 ]; - else - return &slGruntRangeAttack1A[ 0 ]; - } - case SCHED_RANGE_ATTACK2: - { - return &slGruntRangeAttack2[ 0 ]; - } - case SCHED_COMBAT_FACE: - { - return &slGruntCombatFace[ 0 ]; - } - case SCHED_GRUNT_WAIT_FACE_ENEMY: - { - return &slGruntWaitInCover[ 0 ]; - } - case SCHED_GRUNT_SWEEP: - { - return &slGruntSweep[ 0 ]; - } - case SCHED_GRUNT_COVER_AND_RELOAD: - { - return &slGruntHideReload[ 0 ]; - } - case SCHED_GRUNT_FOUND_ENEMY: - { - return &slGruntFoundEnemy[ 0 ]; - } - case SCHED_VICTORY_DANCE: - { - if ( InSquad() ) - { - if ( !IsLeader() ) - { - return &slGruntFail[ 0 ]; - } - } - - return &slGruntVictoryDance[ 0 ]; - } - case SCHED_GRUNT_SUPPRESS: - { - if ( m_hEnemy->IsPlayer() && m_fFirstEncounter ) - { - m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy - return &slGruntSignalSuppress[ 0 ]; - } - else - { - return &slGruntSuppress[ 0 ]; - } - } - case SCHED_FAIL: - { - if ( m_hEnemy != NULL ) - { - // grunt has an enemy, so pick a different default fail schedule most likely to help recover. - return &slGruntCombatFail[ 0 ]; - } - - return &slGruntFail[ 0 ]; - } - case SCHED_GRUNT_REPEL: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slGruntRepel[ 0 ]; - } - case SCHED_GRUNT_REPEL_ATTACK: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slGruntRepelAttack[ 0 ]; - } - case SCHED_GRUNT_REPEL_LAND: - { - return &slGruntRepelLand[ 0 ]; - } - default: - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } -} - - -//========================================================= -// CHGruntRepel - when triggered, spawns a monster_human_grunt -// repelling down a line. -//========================================================= - -class CHGruntRepel : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int m_iSpriteTexture; // Don't save, precache -}; - -LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ); - -void CHGruntRepel::Spawn( void ) -{ - Precache( ); - pev->solid = SOLID_NOT; - - SetUse(&CHGruntRepel:: RepelUse ); -} - -void CHGruntRepel::Precache( void ) -{ - UTIL_PrecacheEntity( "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->edict() ); - pBeam->SetFlags( FBEAM_SOLID ); - pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( Remove ); - pBeam->SetNextThink( -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 ) -{ - int oldBody; - - 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; - - oldBody = pev->body; - pev->body = 0; - - if (oldBody >= 5 && oldBody <= 7) - pev->skin = 1; - else - pev->skin = 0; - - switch( pev->weapons ) - { - case 0: // MP5 - SetBodygroup( GUN_GROUP, GUN_MP5 ); - break; - case 1: // Shotgun - SetBodygroup( GUN_GROUP, GUN_SHOTGUN ); - break; - case 2: // No gun - SetBodygroup( GUN_GROUP, GUN_NONE ); - break; - } - - switch( oldBody ) - { - case 2: // Gasmask, no gun - SetBodygroup( GUN_GROUP, GUN_NONE ); //fall through - case 0: case 6: // Gasmask (white/black) - SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); - break; - case 3: // Commander, no gun - SetBodygroup( GUN_GROUP, GUN_NONE ); //fall through - case 1: // Commander - SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); - break; - case 4: case 7: // Skimask (white/black) - SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN ); - break; - case 5: // Commander - SetBodygroup( HEAD_GROUP, HEAD_M203 ); - break; - } - - MonsterInitDead(); -} diff --git a/server/monsters/leech.cpp b/server/monsters/leech.cpp deleted file mode 100644 index 73d87c48..00000000 --- a/server/monsters/leech.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// leech - basic little swimming monster -//========================================================= -// -// UNDONE: -// DONE:Steering force model for attack -// DONE:Attack animation control / damage -// DONE:Establish range of up/down motion and steer around vertical obstacles -// DONE:Re-evaluate height periodically -// DONE:Fall (MOVETYPE_TOSS) and play different anim if out of water -// Test in complex room (c2a3?) -// DONE:Sounds? - Kelly will fix -// Blood cloud? Hurt effect? -// Group behavior? -// DONE:Save/restore -// Flop animation - just bind to ACT_TWITCH -// Fix fatal push into wall case -// -// Try this on a bird -// Try this on a model with hulls/tracehull? -// - - -#include "float.h" -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "defaults.h" - - - -// Animation events -#define LEECH_AE_ATTACK 1 -#define LEECH_AE_FLOP 2 - - -// Movement constants - -#define LEECH_ACCELERATE 10 -#define LEECH_CHECK_DIST 45 -#define LEECH_SWIM_SPEED 50 -#define LEECH_SWIM_ACCEL 80 -#define LEECH_SWIM_DECEL 10 -#define LEECH_TURN_RATE 90 -#define LEECH_SIZEX 10 -#define LEECH_FRAMETIME 0.1 - - - -#define DEBUG_BEAMS 0 - -#if DEBUG_BEAMS -#include "basebeams.h" -#endif - - -class CLeech : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT SwimThink( void ); - void EXPORT DeadThink( void ); - void Touch( CBaseEntity *pOther ) - { - if ( pOther->IsPlayer() ) - { - // If the client is pushing me, give me some 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(); - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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 ); - if (pev->health == 0) - pev->health = LEECH_HEALTH; - - m_flFieldOfView = -0.5; // 180 degree FOV - m_flDistLook = 750; - MonsterInit(); - SetThink(&CLeech:: SwimThink ); - SetUse( NULL ); - SetTouch( NULL ); - pev->view_ofs = g_vecZero; - - m_flTurning = 0; - m_fPathBlocked = FALSE; - SetActivity( ACT_SWIM ); - SetState( MONSTERSTATE_IDLE ); - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 1, 5 ); -} - - -void CLeech::Activate( void ) -{ - RecalculateWaterlevel(); - CBaseMonster::Activate(); -} - - - -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 && pEnemy->pev->watertype != CONTENTS_FOG ) - { - 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"); - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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; - } - else if ( pev->movetype == MOVETYPE_TOSS ) - { - ALERT(at_console, "Waterlevel is out\n" ); -// if ( RANDOM_LONG( 0, 99 ) < 1 ) - pev->dmg += 2; - - - } - 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, LEECH_DMG_BITE, 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(); - SetNextThink( 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->watertype == CONTENTS_FOG ) - { - 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(); - ALERT(at_console, "Waterlevel is out\n" ); - if ( RANDOM_LONG( 0, 99 ) < 1 ) - { - pev->gravity = 0.02; - pev->takedamage += 2; - } - 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() ) ) && !HaveCamerasInPVS( edict() )) - { - SetNextThink( RANDOM_FLOAT(1,1.5) ); - pev->velocity = g_vecZero; - return; - } - else - SetNextThink( 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->watertype != CONTENTS_FOG ) - { - pev->angles.z = 0; - pev->angles.x = 0; - pev->origin.z += 1; - pev->avelocity = g_vecZero; - if ( RANDOM_LONG( 0, 99 ) < 70 ) - pev->avelocity.y = RANDOM_LONG( -720, 720 ); - - pev->gravity = 0.02; - ClearBits(pev->flags, FL_ONGROUND); - SetActivity( ACT_DIESIMPLE ); - } - else - SetActivity( ACT_DIEFORWARD ); - - pev->movetype = MOVETYPE_TOSS; - pev->takedamage = DAMAGE_NO; - SetThink(&CLeech:: DeadThink ); -} - - diff --git a/server/monsters/monsterevent.h b/server/monsters/monsterevent.h deleted file mode 100644 index b9639aca..00000000 --- a/server/monsters/monsterevent.h +++ /dev/null @@ -1,29 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef MONSTEREVENT_H -#define MONSTEREVENT_H - -typedef struct -{ - int event; - char *options; -} MonsterEvent_t; - -#define MONSTER_EVENT_BODYDROP_LIGHT 2001 -#define MONSTER_EVENT_BODYDROP_HEAVY 2002 - -#define MONSTER_EVENT_SWISHSOUND 2010 - -#endif // MONSTEREVENT_H diff --git a/server/monsters/monstermaker.cpp b/server/monsters/monstermaker.cpp deleted file mode 100644 index 3f7654bd..00000000 --- a/server/monsters/monstermaker.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Monster Maker - this is an entity that creates monsters -// in the game. -//========================================================= - -#include "extdll.h" -#include "utils.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 -#define SF_MONSTERMAKER_LEAVECORPSE 16 // Don't fade corpses. -#define SF_MONSTERMAKER_NO_WPN_DROP 1024 // Corpses don't drop weapons. - -//========================================================= -// 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 EXPORT MakeMonsterThink( void ); - void DeathNotice ( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died. - void TryMakeMonster( void ); //LRC - to allow for a spawndelay - CBaseMonster* MakeMonster( void ); //LRC - actually make a monster (and return the new creation) - - 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? - float m_fSpawnDelay;// LRC- delay between triggering targets and making a child (for env_warpball, mainly) -}; - -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 ), - DEFINE_FIELD( CMonsterMaker, m_fSpawnDelay, FIELD_FLOAT ), -}; - - -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 if ( FStrEq(pkvd->szKeyName, "spawndelay") ) - { - m_fSpawnDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CMonsterMaker :: Spawn( ) -{ - pev->solid = SOLID_NOT; - - m_cLiveChildren = 0; - Precache(); - if ( !FStringNull ( pev->targetname ) ) - { - if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) - { - SetUse(&CMonsterMaker :: CyclicUse );// drop one monster each time we fire - m_fActive = FALSE; - } - else - { - SetUse(&CMonsterMaker :: ToggleUse );// can be turned on/off - - if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) - { - // start making monsters as soon as monstermaker spawns - m_fActive = TRUE; - SetThink(&CMonsterMaker :: MakerThink ); - } - else - { - // wait to be activated. - m_fActive = FALSE; - DontThink(); - } - } - } - else - {// no targetname, just start. - SetNextThink( m_flDelay ); - m_fActive = TRUE; - SetThink(&CMonsterMaker :: MakerThink ); - } - - if ( m_cNumMonsters == 1 || (m_cNumMonsters != -1 && pev->spawnflags & SF_MONSTERMAKER_LEAVECORPSE )) - { - m_fFadeChildren = FALSE; - } - else - { - m_fFadeChildren = TRUE; - } - - m_flGround = 0; -} - -void CMonsterMaker :: Precache( void ) -{ - CBaseMonster::Precache(); - - UTIL_PrecacheEntity( STRING( m_iszMonsterClassname ) ); -} - -//========================================================= -// TryMakeMonster- check that it's ok to drop a monster. -//========================================================= -void CMonsterMaker::TryMakeMonster( void ) -{ - 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; - } - - if (m_fSpawnDelay) - { - // If I have a target, fire. (no locus) - if ( !FStringNull ( pev->target ) ) - { - // delay already overloaded for this entity, so can't call SUB_UseTargets() - UTIL_FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 ); - } - -// ALERT(at_console,"Making Monster in %f seconds\n",m_fSpawnDelay); - SetThink(&CMonsterMaker:: MakeMonsterThink ); - SetNextThink( m_fSpawnDelay ); - } - else - { -// ALERT(at_console,"No delay. Making monster.\n",m_fSpawnDelay); - CBaseMonster* pMonst = MakeMonster(); - - // If I have a target, fire! (the new monster is the locus) - if ( !FStringNull ( pev->target ) ) - { - UTIL_FireTargets( STRING(pev->target), pMonst, this, USE_TOGGLE, 0 ); - } - } -} - -//========================================================= -// MakeMonsterThink- a really trivial think function -//========================================================= -void CMonsterMaker::MakeMonsterThink( void ) -{ - MakeMonster(); -} - -//========================================================= -// MakeMonster- this is the code that drops the monster -//========================================================= -CBaseMonster* CMonsterMaker::MakeMonster( void ) -{ - edict_t *pent; - entvars_t *pevCreate; - -// ALERT(at_console,"Making Monster NOW\n"); - - pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); - - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in MonsterMaker!\n" ); - return NULL; - } - - pevCreate = VARS( pent ); - pevCreate->origin = pev->origin; - pevCreate->angles = pev->angles; - SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND ); - - if (pev->spawnflags & SF_MONSTERMAKER_NO_WPN_DROP) - SetBits( pevCreate->spawnflags, SF_MONSTER_NO_WPN_DROP); - - // Children hit monsterclip brushes - if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) - SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP ); - - DispatchSpawn( ENT( pevCreate ) ); - pevCreate->owner = edict(); - - //LRC - custom monster behaviour - CBaseEntity *pEntity = CBaseEntity::Instance( pevCreate ); - CBaseMonster *pMonst = NULL; - if (pEntity && (pMonst = pEntity->MyMonsterPointer()) != NULL) - { - pMonst->m_iClass = this->m_iClass; - pMonst->m_iPlayerReact = this->m_iPlayerReact; - } - - 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 ); - } - else if (m_fActive) - { - SetNextThink( m_flDelay ); - SetThink(&CMonsterMaker:: MakerThink ); - } - - return pMonst; -} - -//========================================================= -// CyclicUse - drops one monster from the monstermaker -// each time we call this. -//========================================================= -void CMonsterMaker::CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - TryMakeMonster(); -// ALERT(at_console,"CyclicUse complete\n"); -} - -//========================================================= -// ToggleUse - activates/deactivates the monster maker -//========================================================= -void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE ) - { - if ( !m_fActive ) - useType = USE_ON; - else useType = USE_OFF; - } - - if ( useType == USE_ON ) - { - m_fActive = TRUE; - SetThink(&CMonsterMaker :: MakerThink ); - } - else if ( useType == USE_OFF ) - { - m_fActive = FALSE; - SetThink ( NULL ); - } - SetNextThink( 0 ); -} - -//========================================================= -// MakerThink - creates a new monster every so often -//========================================================= -void CMonsterMaker :: MakerThink ( void ) -{ - SetNextThink( m_flDelay ); - - TryMakeMonster(); -} - - -//========================================================= -//========================================================= -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/server/monsters/monsters.h b/server/monsters/monsters.h deleted file mode 100644 index 16c3b5b4..00000000 --- a/server/monsters/monsters.h +++ /dev/null @@ -1,152 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef MONSTERS_H -#define MONSTERS_H - -/* - -===== monsters.h ======================================================== - - Header file for monster-related utility code - -*/ - -#define MAX_PATH_SIZE 10 // max number of nodes available for a path. - -// CHECKLOCALMOVE result types -#define LOCALMOVE_INVALID 0 // move is not possible -#define LOCALMOVE_INVALID_DONT_TRIANGULATE 1 // move is not possible, don't try to triangulate -#define LOCALMOVE_VALID 2 // move is possible - -// Hit Group standards -#define HITGROUP_GENERIC 0 -#define HITGROUP_HEAD 1 -#define HITGROUP_CHEST 2 -#define HITGROUP_STOMACH 3 -#define HITGROUP_LEFTARM 4 -#define HITGROUP_RIGHTARM 5 -#define HITGROUP_LEFTLEG 6 -#define HITGROUP_RIGHTLEG 7 - - -// Monster Spawnflags -#define SF_MONSTER_WAIT_TILL_SEEN 1// spawnflag that makes monsters wait until player can see them before attacking. -#define SF_MONSTER_GAG 2 // no idle noises from this monster -#define SF_MONSTER_HITMONSTERCLIP 4 -// 8 -#define SF_MONSTER_PRISONER 16 // monster won't attack anyone, no one will attacke him. -// 32 -// 64 -#define SF_MONSTER_NO_YELLOW_BLOBS 128 //LRC- if the monster is stuck, don't give errors or show yellow blobs. -//LRC- wasn't implemented. #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_NO_WPN_DROP 1024 //LRC- never drop your weapon (player can't pick it up.) -//LRC - this clashes with 'not in deathmatch'. Replaced with m_iPlayerReact. -//#define SF_MONSTER_INVERT_PLAYERREACT 2048 //LRC- if this monster would usually attack the player, don't attack unless provoked. If you would usually NOT attack the player, attack him. -#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 - -// spawn flags 256 and above are already taken by the engine -extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType ); - -Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 ); -Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 ); -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL CONSTANT float g_flMeleeRange; -extern DLL_GLOBAL CONSTANT float g_flMediumRange; -extern DLL_GLOBAL CONSTANT float g_flLongRange; -extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ); -extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ); - -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget ); -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 ); - -// monster to monster relationship types -#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable. -#define R_FR -1// (FEAR)will run -#define R_NO 0// (NO RELATIONSHIP) disregard -#define R_DL 1// (DISLIKE) will attack -#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters -#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what - - -// these bits represent the monster's memory -#define MEMORY_CLEAR 0 -#define bits_MEMORY_PROVOKED ( 1 << 0 )// right now only used for houndeyes. -#define bits_MEMORY_INCOVER ( 1 << 1 )// monster knows it is in a covered position. -#define bits_MEMORY_SUSPICIOUS ( 1 << 2 )// Ally is suspicious of the player, and will move to provoked more easily -#define bits_MEMORY_PATH_FINISHED ( 1 << 3 )// Finished monster path (just used by big momma for now) -#define bits_MEMORY_ON_PATH ( 1 << 4 )// Moving on a path -#define bits_MEMORY_MOVE_FAILED ( 1 << 5 )// Movement has already failed -#define bits_MEMORY_FLINCHED ( 1 << 6 )// Has already flinched -#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed() -#define bits_MEMORY_CUSTOM4 ( 1 << 28 ) // Monster-specific memory -#define bits_MEMORY_CUSTOM3 ( 1 << 29 ) // Monster-specific memory -#define bits_MEMORY_CUSTOM2 ( 1 << 30 ) // Monster-specific memory -#define bits_MEMORY_CUSTOM1 ( 1 << 31 ) // Monster-specific memory - -// trigger conditions for scripted AI -// these MUST match the CHOICES interface in halflife.fgd for the base monster -enum -{ - AITRIGGER_NONE = 0, - AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER, - AITRIGGER_TAKEDAMAGE, - AITRIGGER_HALFHEALTH, - AITRIGGER_DEATH, - AITRIGGER_SQUADMEMBERDIE, - AITRIGGER_SQUADLEADERDIE, - AITRIGGER_HEARWORLD, - AITRIGGER_HEARPLAYER, - AITRIGGER_HEARCOMBAT, - AITRIGGER_SEEPLAYER_UNCONDITIONAL, - AITRIGGER_SEEPLAYER_NOT_IN_COMBAT, -}; -/* - 0 : "No Trigger" - 1 : "See Player" - 2 : "Take Damage" - 3 : "50% Health Remaining" - 4 : "Death" - 5 : "Squad Member Dead" - 6 : "Squad Leader Dead" - 7 : "Hear World" - 8 : "Hear Player" - 9 : "Hear Combat" -*/ - -#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/server/monsters/nodes.cpp b/server/monsters/nodes.cpp deleted file mode 100644 index 20c16db0..00000000 --- a/server/monsters/nodes.cpp +++ /dev/null @@ -1,3654 +0,0 @@ -/*** -* -* 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. -* 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 -#include - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "client.h" -#include "monsters.h" -#include "nodes.h" -#include "animation.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 ) -{ - CBaseEntity *pSearch; - CBaseEntity *pTrigger; - entvars_t *pevTrigger; - entvars_t *pevLinkEnt; - TraceResult tr; - - pevLinkEnt = pLink->m_pLinkEnt; - if ( !pevLinkEnt ) - return NULL; - - pSearch = 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->team == 1 ) ) - {// door is use only, so the door is all the monster has to worry about - return pevLinkEnt; - } - - while ( 1 ) - { - pTrigger = UTIL_FindEntityByTarget ( pSearch, STRING( pevLinkEnt->targetname ) );// find the button or trigger - - if ( !pTrigger ) - {// 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; - } - - pSearch = pTrigger; - pevTrigger = pTrigger->pev; - - 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->team == 1 ) ) - {// 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->GetState() == STATE_ON && ( pevLinkEnt->impulse == 1 )) - { - 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->GetState() == STATE_ON && ( pevLinkEnt->impulse == 1 )) - { - return TRUE; - } - if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) - { - if ( 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, gmsg.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 && pEntity->pev->watertype != CONTENTS_FOG) - { - 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. - // - int i = 0; - for ( i = 0; i < m_cNodes; i++) - { - m_pNodes[ i ].m_flClosestSoFar = -1.0; - } - - m_pNodes[ iStart ].m_flClosestSoFar = 0.0; - m_pNodes[ iStart ].m_iPreviousNode = iStart;// tag this as the origin node - queue.Insert( iStart, 0.0 );// insert start node - - while ( !queue.Empty() ) - { - // now pull a node out of the queue - float flCurrentDistance; - iCurrentNode = queue.Remove(flCurrentDistance); - - // For straight-line weights, the following Shortcut works. For arbitrary weights, - // it doesn't. - // - if (iCurrentNode == iDest) break; - - CNode *pCurrentNode = &m_pNodes[ iCurrentNode ]; - - for ( i = 0 ; i < pCurrentNode->m_cNumLinks ; i++ ) - {// run through all of this node's neighbors - - iVisitNode = INodeLink ( iCurrentNode, i ); - if ( ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo & iHullMask ) != iHullMask ) - {// monster is too large to walk this connection - //ALERT ( at_aiconsole, "fat ass %d/%d\n",m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo, iMonsterHull ); - continue; - } - // check the connection from the current node to the node we're about to mark visited and push into the queue - if ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt != NULL ) - {// there's a brush ent in the way! Don't mark this node or put it into the queue unless the monster can negotiate it - - if ( !HandleLinkEnt ( iCurrentNode, m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt, afCapMask, NODEGRAPH_STATIC ) ) - {// monster should not try to go this way. - continue; - } - } - float flOurDistance = flCurrentDistance + m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i].m_flWeight; - if ( m_pNodes[ iVisitNode ].m_flClosestSoFar < -0.5 - || flOurDistance < m_pNodes[ iVisitNode ].m_flClosestSoFar - 0.001 ) - { - m_pNodes[iVisitNode].m_flClosestSoFar = flOurDistance; - m_pNodes[iVisitNode].m_iPreviousNode = iCurrentNode; - - queue.Insert ( iVisitNode, flOurDistance ); - } - } - } - if ( m_pNodes[iDest].m_flClosestSoFar < -0.5 ) - {// Destination is unreachable, no path found. - return 0; - } - - // the queue is not empty - - // now we must walk backwards through the m_iPreviousNode field, and count how many connections there are in the path - iCurrentNode = iDest; - iNumPathNodes = 1;// count the dest - - while ( iCurrentNode != iStart ) - { - iNumPathNodes++; - iCurrentNode = m_pNodes[ iCurrentNode ].m_iPreviousNode; - } - - iCurrentNode = iDest; - for ( i = iNumPathNodes - 1 ; i >= 0 ; i-- ) - { - piPath[ i ] = iCurrentNode; - iCurrentNode = m_pNodes [ iCurrentNode ].m_iPreviousNode; - } - } - -#if 0 - - if (m_fRoutingComplete) - { - // This will draw the entire path that was generated for the monster. - - for ( int i = 0 ; i < iNumPathNodes - 1 ; i++ ) - { - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.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, gmsg.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, gmsg.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( Remove ); - SetNextThink( 0 ); - } - else - { - SetThink(&CTestHull :: DropDelay ); - SetNextThink( 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 ( this, WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); - - SetThink(&CTestHull:: CallBuildNodeGraph ); - - SetNextThink( 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 ); - - SetNextThink( 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( Remove );// no matter what happens, the hull gets rid of itself. - SetNextThink( 0 ); - -// 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" ); - - //disable nrp files - file = fopen ( szNrpFilename, "w+" ); - - if ( !file ) - {// file error - ALERT ( at_aiconsole, "Couldn't create %s!\n", szNrpFilename ); - - if ( pTempPool ) - { - free ( pTempPool ); - } - - return; - } - - fprintf( file, "Node Graph Report for map: %s.bsp\n", STRING(gpGlobals->mapname) ); - fprintf ( file, "%d Total Nodes\n\n", WorldGraph.m_cNodes ); - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - {// print all node numbers and their locations to the file. - WorldGraph.m_pNodes[ i ].m_cNumLinks = 0; - WorldGraph.m_pNodes[ i ].m_iFirstLink = 0; - memset(WorldGraph.m_pNodes[ i ].m_pNextBestNode, 0, sizeof(WorldGraph.m_pNodes[ i ].m_pNextBestNode)); - - fprintf ( file, "Node# %4d\n", i ); - fprintf ( file, "Location %4d,%4d,%4d\n",(int)WorldGraph.m_pNodes[ i ].m_vecOrigin.x, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.y, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.z ); - fprintf ( file, "HintType: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintType ); - fprintf ( file, "HintActivity: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintActivity ); - fprintf ( file, "HintYaw: %4f\n", WorldGraph.m_pNodes[ i ].m_flHintYaw ); - fprintf ( file, "-------------------------------------------------------------------------------\n" ); - } - fprintf ( file, "\n\n" ); - - - // Automatically recognize WATER nodes and drop the LAND nodes to the floor. - // - for ( i = 0; i < WorldGraph.m_cNodes; i++) - { - if (WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_AIR) - { - // do nothing - } - else if (UTIL_PointContents(WorldGraph.m_pNodes[ i ].m_vecOrigin) == CONTENTS_WATER) - { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_WATER; - } - else - { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_LAND; - - // trace to the ground, then pop up 8 units and place node there to make it - // easier for them to connect (think stairs, chairs, and bumps in the floor). - // After the routing is done, push them back down. - // - TraceResult tr; - - UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, - WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), - ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &tr ); - - // This trace is ONLY used if we hit an entity flagged with FL_WORLDBRUSH - TraceResult trEnt; - UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, - WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), - dont_ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &trEnt ); - - - // Did we hit something closer than the floor? - if ( trEnt.flFraction < tr.flFraction ) - { - // If it was a world brush entity, copy the node location - if ( trEnt.pHit && (trEnt.pHit->v.flags & FL_WORLDBRUSH) ) - tr.vecEndPos = trEnt.vecEndPos; - } - - WorldGraph.m_pNodes[i].m_vecOriginPeek.z = - WorldGraph.m_pNodes[i].m_vecOrigin.z = tr.vecEndPos.z + NODE_HEIGHT; - } - } - - cPoolLinks = WorldGraph.LinkVisibleNodes( pTempPool, file, &iBadNode ); - - if ( !cPoolLinks ) - { - ALERT ( at_aiconsole, "**ConnectVisibleNodes FAILED!\n" ); - - SetThink(&CTestHull :: ShowBadNode );// send the hull off to show the offending node. - //pev->solid = SOLID_NOT; - pev->origin = WorldGraph.m_pNodes[ iBadNode ].m_vecOrigin; - - if ( pTempPool ) - { - free ( pTempPool ); - } - - if ( file ) - {// close the file - fclose ( file ); - } - - return; - } - -// send the walkhull to all of this node's connections now. We'll do this here since -// so much of it relies on being able to control the test hull. - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "Walk Rejection:\n"); - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - pSrcNode = &WorldGraph.m_pNodes[ i ]; - - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "Node %4d:\n\n", i ); - - for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) - { - // assume that all hulls can walk this link, then eliminate the ones that can't. - pTempPool [ pSrcNode->m_iFirstLink + j ].m_afLinkInfo = bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL | bits_LINK_FLY_HULL; - - - // do a check for each hull size. - - // if we can't fit a tiny hull through a connection, no other hulls with fit either, so we - // should just fall out of the loop. Do so by setting the SkipRemainingHulls flag. - fSkipRemainingHulls = FALSE; - for ( hull = 0 ; hull < MAX_NODE_HULLS; hull++ ) - { - if (fSkipRemainingHulls && (hull == NODE_HUMAN_HULL || hull == NODE_LARGE_HULL)) // skip the remaining walk hulls - continue; - - switch ( hull ) - { - case NODE_SMALL_HULL: - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); - break; - case NODE_HUMAN_HULL: - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - break; - case NODE_LARGE_HULL: - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - break; - case NODE_FLY_HULL: - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - // UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - break; - } - - UTIL_SetOrigin ( this, 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, gmsg.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 ( const 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(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 ( const 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; - CBaseEntity *pLinkEnt; - - 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; - pLinkEnt = UTIL_FindEntityByString( NULL, "model", name ); - - if ( !pLinkEnt ) - { - // 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 = pLinkEnt->pev; - - 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 ( const char *szMapName ) -{ - int retValue; - - char szBspFilename[MAX_PATH]; - char szGraphFilename[MAX_PATH]; - - - strcpy ( szBspFilename, "maps/" ); - strcat ( szBspFilename, szMapName ); - strcat ( szBspFilename, ".bsp" ); - - strcpy ( szGraphFilename, "maps/graphs/" ); - strcat ( szGraphFilename, szMapName ); - strcat ( szGraphFilename, ".nod" ); - - retValue = TRUE; - - int iCompare; - if (COMPARE_FILE_TIME(szBspFilename, szGraphFilename, &iCompare)) - { - if ( iCompare > 0 ) - {// BSP file is newer. - ALERT ( at_aiconsole, ".NOD File will be updated\n\n" ); - retValue = FALSE; - } - } - else - { - retValue = FALSE; - } - - return retValue; -} - -#define ENTRY_STATE_EMPTY -1 - -struct tagNodePair -{ - short iSrc; - short iDest; -}; - -void CGraph::HashInsert(int iSrcNode, int iDestNode, int iKey) -{ - struct tagNodePair np; - - np.iSrc = iSrcNode; - np.iDest = iDestNode; - CRC32_t dwHash; - CRC32_INIT(&dwHash); - CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); - dwHash = CRC32_FINAL(dwHash); - - int di = m_HashPrimes[dwHash&15]; - int i = (dwHash >> 4) % m_nHashLinks; - while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) - { - i += di; - if (i >= m_nHashLinks) i -= m_nHashLinks; - } - m_pHashLinks[i] = iKey; -} - -void CGraph::HashSearch(int iSrcNode, int iDestNode, int &iKey) -{ - struct tagNodePair np; - - np.iSrc = iSrcNode; - np.iDest = iDestNode; - CRC32_t dwHash; - CRC32_INIT(&dwHash); - CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); - dwHash = CRC32_FINAL(dwHash); - - int di = m_HashPrimes[dwHash&15]; - int i = (dwHash >> 4) % m_nHashLinks; - while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) - { - CLink &link = Link(m_pHashLinks[i]); - if (iSrcNode == link.m_iSrcNode && iDestNode == link.m_iDestNode) - { - break; - } - else - { - i += di; - if (i >= m_nHashLinks) i -= m_nHashLinks; - } - } - iKey = m_pHashLinks[i]; -} - -#define NUMBER_OF_PRIMES 177 - -int Primes[NUMBER_OF_PRIMES] = -{ 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, -71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, -157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, -241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, -347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, -439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, -547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, -643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, -751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, -859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, -977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 0 }; - -void CGraph::HashChoosePrimes(int TableSize) -{ - int LargestPrime = TableSize/2; - if (LargestPrime > Primes[NUMBER_OF_PRIMES-2]) - { - LargestPrime = Primes[NUMBER_OF_PRIMES-2]; - } - int Spacing = LargestPrime/16; - - // Pick a set primes that are evenly spaced from (0 to LargestPrime) - // We divide this interval into 16 equal sized zones. We want to find - // one prime number that best represents that zone. - // - int iZone = 0, iPrime = 0; - for (iZone = 1, iPrime = 0; iPrime < 16; iZone += Spacing) - { - // Search for a prime number that is less than the target zone - // number given by iZone. - // - int Lower = Primes[0]; - for (int jPrime = 0; Primes[jPrime] != 0; jPrime++) - { - if (jPrime != 0 && TableSize % Primes[jPrime] == 0) continue; - int Upper = Primes[jPrime]; - if (Lower <= iZone && iZone <= Upper) - { - // Choose the closest lower prime number. - // - if (iZone - Lower <= Upper - iZone) - { - m_HashPrimes[iPrime++] = Lower; - } - else - { - m_HashPrimes[iPrime++] = Upper; - } - break; - } - Lower = Upper; - } - } - - // Alternate negative and positive numbers - // - for (iPrime = 0; iPrime < 16; iPrime += 2) - { - m_HashPrimes[iPrime] = TableSize-m_HashPrimes[iPrime]; - } - - // Shuffle the set of primes to reduce correlation with bits in - // hash key. - // - for (iPrime = 0; iPrime < 16-1; iPrime++) - { - int Pick = RANDOM_LONG(0, 15-iPrime); - int Temp = m_HashPrimes[Pick]; - m_HashPrimes[Pick] = m_HashPrimes[15-iPrime]; - m_HashPrimes[15-iPrime] = Temp; - } -} - -// Renumber nodes so that nodes that link together are together. -// -#define UNNUMBERED_NODE -1 -void CGraph::SortNodes(void) -{ - // We are using m_iPreviousNode to be the new node number. - // After assigning new node numbers to everything, we move - // things and patchup the links. - // - int iNodeCnt = 0; - m_pNodes[0].m_iPreviousNode = iNodeCnt++; - int i = 0; - for (i = 1; i < m_cNodes; i++) - { - m_pNodes[i].m_iPreviousNode = UNNUMBERED_NODE; - } - - for (i = 0; i < m_cNodes; i++) - { - // Run through all of this node's neighbors - // - for (int j = 0 ; j < m_pNodes[i].m_cNumLinks; j++ ) - { - int iDestNode = INodeLink(i, j); - if (m_pNodes[iDestNode].m_iPreviousNode == UNNUMBERED_NODE) - { - m_pNodes[iDestNode].m_iPreviousNode = iNodeCnt++; - } - } - } - - // Assign remaining node numbers to unlinked nodes. - // - for (i = 0; i < m_cNodes; i++) - { - if (m_pNodes[i].m_iPreviousNode == UNNUMBERED_NODE) - { - m_pNodes[i].m_iPreviousNode = iNodeCnt++; - } - } - - // Alter links to reflect new node numbers. - // - for (i = 0; i < m_cLinks; i++) - { - m_pLinkPool[i].m_iSrcNode = m_pNodes[m_pLinkPool[i].m_iSrcNode].m_iPreviousNode; - m_pLinkPool[i].m_iDestNode = m_pNodes[m_pLinkPool[i].m_iDestNode].m_iPreviousNode; - } - - // Rearrange nodes to reflect new node numbering. - // - for (i = 0; i < m_cNodes; i++) - { - while (m_pNodes[i].m_iPreviousNode != i) - { - // Move current node off to where it should be, and bring - // that other node back into the current slot. - // - int iDestNode = m_pNodes[i].m_iPreviousNode; - CNode TempNode = m_pNodes[iDestNode]; - m_pNodes[iDestNode] = m_pNodes[i]; - m_pNodes[i] = TempNode; - } - } -} - -void CGraph::BuildLinkLookups(void) -{ - m_nHashLinks = 3*m_cLinks/2 + 3; - - HashChoosePrimes(m_nHashLinks); - m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); - if (!m_pHashLinks) - { - ALERT(at_aiconsole, "Couldn't allocated Link Lookup Table.\n"); - return; - } - int i = 0; - for (i = 0; i < m_nHashLinks; i++) - { - m_pHashLinks[i] = ENTRY_STATE_EMPTY; - } - - for (i = 0; i < m_cLinks; i++) - { - CLink &link = Link(i); - HashInsert(link.m_iSrcNode, link.m_iDestNode, i); - } -#if 0 - for (i = 0; i < m_cLinks; i++) - { - CLink &link = Link(i); - int iKey; - HashSearch(link.m_iSrcNode, link.m_iDestNode, iKey); - if (iKey != i) - { - ALERT(at_aiconsole, "HashLinks don't match (%d versus %d)\n", i, iKey); - } - } -#endif -} - -void CGraph::BuildRegionTables(void) -{ - if (m_di) free(m_di); - - // Go ahead and setup for range searching the nodes for FindNearestNodes - // - m_di = (DIST_INFO *)calloc(sizeof(DIST_INFO), m_cNodes); - if (!m_di) - { - ALERT(at_aiconsole, "Couldn't allocated node ordering array.\n"); - return; - } - - // Calculate regions for all the nodes. - // - // - int i = 0; - for (i = 0; i < 3; i++) - { - m_RegionMin[i] = 999999999.0; // just a big number out there; - m_RegionMax[i] = -999999999.0; // just a big number out there; - } - for (i = 0; i < m_cNodes; i++) - { - if (m_pNodes[i].m_vecOrigin.x < m_RegionMin[0]) - m_RegionMin[0] = m_pNodes[i].m_vecOrigin.x; - if (m_pNodes[i].m_vecOrigin.y < m_RegionMin[1]) - m_RegionMin[1] = m_pNodes[i].m_vecOrigin.y; - if (m_pNodes[i].m_vecOrigin.z < m_RegionMin[2]) - m_RegionMin[2] = m_pNodes[i].m_vecOrigin.z; - - if (m_pNodes[i].m_vecOrigin.x > m_RegionMax[0]) - m_RegionMax[0] = m_pNodes[i].m_vecOrigin.x; - if (m_pNodes[i].m_vecOrigin.y > m_RegionMax[1]) - m_RegionMax[1] = m_pNodes[i].m_vecOrigin.y; - if (m_pNodes[i].m_vecOrigin.z > m_RegionMax[2]) - m_RegionMax[2] = m_pNodes[i].m_vecOrigin.z; - } - for (i = 0; i < m_cNodes; i++) - { - m_pNodes[i].m_Region[0] = CALC_RANGE(m_pNodes[i].m_vecOrigin.x, m_RegionMin[0], m_RegionMax[0]); - m_pNodes[i].m_Region[1] = CALC_RANGE(m_pNodes[i].m_vecOrigin.y, m_RegionMin[1], m_RegionMax[1]); - m_pNodes[i].m_Region[2] = CALC_RANGE(m_pNodes[i].m_vecOrigin.z, m_RegionMin[2], m_RegionMax[2]); - } - - for (i = 0; i < 3; i++) - { - int j = 0; - for ( j = 0; j < NUM_RANGES; j++) - { - m_RangeStart[i][j] = 255; - m_RangeEnd[i][j] = 0; - } - for (j = 0; j < m_cNodes; j++) - { - m_di[j].m_SortedBy[i] = j; - } - - for (j = 0; j < m_cNodes - 1; j++) - { - int jNode = m_di[j].m_SortedBy[i]; - int jCodeX = m_pNodes[jNode].m_Region[0]; - int jCodeY = m_pNodes[jNode].m_Region[1]; - int jCodeZ = m_pNodes[jNode].m_Region[2]; - int jCode; - switch (i) - { - case 0: - jCode = (jCodeX << 16) + (jCodeY << 8) + jCodeZ; - break; - case 1: - jCode = (jCodeY << 16) + (jCodeZ << 8) + jCodeX; - break; - case 2: - jCode = (jCodeZ << 16) + (jCodeX << 8) + jCodeY; - break; - } - - for (int k = j+1; k < m_cNodes; k++) - { - int kNode = m_di[k].m_SortedBy[i]; - int kCodeX = m_pNodes[kNode].m_Region[0]; - int kCodeY = m_pNodes[kNode].m_Region[1]; - int kCodeZ = m_pNodes[kNode].m_Region[2]; - int kCode; - switch (i) - { - case 0: - kCode = (kCodeX << 16) + (kCodeY << 8) + kCodeZ; - break; - case 1: - kCode = (kCodeY << 16) + (kCodeZ << 8) + kCodeX; - break; - case 2: - kCode = (kCodeZ << 16) + (kCodeX << 8) + kCodeY; - break; - } - - if (kCode < jCode) - { - // Swap j and k entries. - // - int Tmp = m_di[j].m_SortedBy[i]; - m_di[j].m_SortedBy[i] = m_di[k].m_SortedBy[i]; - m_di[k].m_SortedBy[i] = Tmp; - } - } - } - } - - // Generate lookup tables. - // - for (i = 0; i < m_cNodes; i++) - { - int CodeX = m_pNodes[m_di[i].m_SortedBy[0]].m_Region[0]; - int CodeY = m_pNodes[m_di[i].m_SortedBy[1]].m_Region[1]; - int CodeZ = m_pNodes[m_di[i].m_SortedBy[2]].m_Region[2]; - - if (i < m_RangeStart[0][CodeX]) - { - m_RangeStart[0][CodeX] = i; - } - if (i < m_RangeStart[1][CodeY]) - { - m_RangeStart[1][CodeY] = i; - } - if (i < m_RangeStart[2][CodeZ]) - { - m_RangeStart[2][CodeZ] = i; - } - if (m_RangeEnd[0][CodeX] < i) - { - m_RangeEnd[0][CodeX] = i; - } - if (m_RangeEnd[1][CodeY] < i) - { - m_RangeEnd[1][CodeY] = i; - } - if (m_RangeEnd[2][CodeZ] < i) - { - m_RangeEnd[2][CodeZ] = i; - } - } - - // Initialize the cache. - // - memset(m_Cache, 0, sizeof(m_Cache)); -} - -void CGraph :: ComputeStaticRoutingTables( void ) -{ - int nRoutes = m_cNodes*m_cNodes; -#define FROM_TO(x,y) ((x)*m_cNodes+(y)) - short *Routes = new short[nRoutes]; - - int *pMyPath = new int[m_cNodes]; - unsigned short *BestNextNodes = new unsigned short[m_cNodes]; - char *pRoute = new char[m_cNodes*2]; - - - if (Routes && pMyPath && BestNextNodes && pRoute) - { - int nTotalCompressedSize = 0; - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) - { - for (int iCap = 0; iCap < 2; iCap++) - { - int iCapMask; - switch (iCap) - { - case 0: - iCapMask = 0; - break; - - case 1: - iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - break; - } - - - // Initialize Routing table to uncalculated. - // - int iFrom = 0; - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - Routes[FROM_TO(iFrom, iTo)] = -1; - } - } - - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = m_cNodes-1; iTo >= 0; iTo--) - { - if (Routes[FROM_TO(iFrom, iTo)] != -1) continue; - - int cPathSize = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - - // Use the computed path to update the routing table. - // - if (cPathSize > 1) - { - for (int iNode = 0; iNode < cPathSize-1; iNode++) - { - int iStart = pMyPath[iNode]; - int iNext = pMyPath[iNode+1]; - for (int iNode1 = iNode+1; iNode1 < cPathSize; iNode1++) - { - int iEnd = pMyPath[iNode1]; - Routes[FROM_TO(iStart, iEnd)] = iNext; - } - } -#if 0 - // Well, at first glance, this should work, but actually it's safer - // to be told explictly that you can take a series of node in a - // particular direction. Some links don't appear to have links in - // the opposite direction. - // - for (iNode = cPathSize-1; iNode >= 1; iNode--) - { - int iStart = pMyPath[iNode]; - int iNext = pMyPath[iNode-1]; - for (int iNode1 = iNode-1; iNode1 >= 0; iNode1--) - { - int iEnd = pMyPath[iNode1]; - Routes[FROM_TO(iStart, iEnd)] = iNext; - } - } -#endif - } - else - { - Routes[FROM_TO(iFrom, iTo)] = iFrom; - Routes[FROM_TO(iTo, iFrom)] = iTo; - } - } - } - - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - BestNextNodes[iTo] = Routes[FROM_TO(iFrom, iTo)]; - } - - // Compress this node's routing table. - // - int iLastNode = 9999999; // just really big. - int cSequence = 0; - int cRepeats = 0; - int CompressedSize = 0; - char *p = pRoute; - for (int i = 0; i < m_cNodes; i++) - { - BOOL CanRepeat = ((BestNextNodes[i] == iLastNode) && cRepeats < 127); - BOOL CanSequence = (BestNextNodes[i] == i && cSequence < 128); - - if (cRepeats) - { - if (CanRepeat) - { - cRepeats++; - } - else - { - // Emit the repeat phrase. - // - CompressedSize += 2; // (count-1, iLastNode-i) - *p++ = cRepeats - 1; - int a = iLastNode - iFrom; - int b = iLastNode - iFrom + m_cNodes; - int c = iLastNode - iFrom - m_cNodes; - if (-128 <= a && a <= 127) - { - *p++ = a; - } - else if (-128 <= b && b <= 127) - { - *p++ = b; - } - else if (-128 <= c && c <= 127) - { - *p++ = c; - } - else - { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); - } - cRepeats = 0; - - if (CanSequence) - { - // Start a sequence. - // - cSequence++; - } - else - { - // Start another repeat. - // - cRepeats++; - } - } - } - else if (cSequence) - { - if (CanSequence) - { - cSequence++; - } - else - { - // It may be advantageous to combine - // a single-entry sequence phrase with the - // next repeat phrase. - // - if (cSequence == 1 && CanRepeat) - { - // Combine with repeat phrase. - // - cRepeats = 2; - cSequence = 0; - } - else - { - // Emit the sequence phrase. - // - CompressedSize += 1; // (-count) - *p++ = -cSequence; - cSequence = 0; - - // Start a repeat sequence. - // - cRepeats++; - } - } - } - else - { - if (CanSequence) - { - // Start a sequence phrase. - // - cSequence++; - } - else - { - // Start a repeat sequence. - // - cRepeats++; - } - } - iLastNode = BestNextNodes[i]; - } - if (cRepeats) - { - // Emit the repeat phrase. - // - CompressedSize += 2; - *p++ = cRepeats - 1; -#if 0 - iLastNode = iFrom + *pRoute; - if (iLastNode >= m_cNodes) iLastNode -= m_cNodes; - else if (iLastNode < 0) iLastNode += m_cNodes; -#endif - int a = iLastNode - iFrom; - int b = iLastNode - iFrom + m_cNodes; - int c = iLastNode - iFrom - m_cNodes; - if (-128 <= a && a <= 127) - { - *p++ = a; - } - else if (-128 <= b && b <= 127) - { - *p++ = b; - } - else if (-128 <= c && c <= 127) - { - *p++ = c; - } - else - { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); - } - } - if (cSequence) - { - // Emit the Sequence phrase. - // - CompressedSize += 1; - *p++ = -cSequence; - } - - // Go find a place to store this thing and point to it. - // - int nRoute = p - pRoute; - if (m_pRouteInfo) - { - int i = 0; - for (i = 0; i < m_nRouteInfo - nRoute; i++) - { - if (memcmp(m_pRouteInfo + i, pRoute, nRoute) == 0) - { - break; - } - } - if (i < m_nRouteInfo - nRoute) - { - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = i; - } - else - { - char *Tmp = (char *)calloc(sizeof(char), (m_nRouteInfo + nRoute)); - memcpy(Tmp, m_pRouteInfo, m_nRouteInfo); - free(m_pRouteInfo); - m_pRouteInfo = Tmp; - memcpy(m_pRouteInfo + m_nRouteInfo, pRoute, nRoute); - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = m_nRouteInfo; - m_nRouteInfo += nRoute; - nTotalCompressedSize += CompressedSize; - } - } - else - { - m_nRouteInfo = nRoute; - m_pRouteInfo = (char *)calloc(sizeof(char), nRoute); - memcpy(m_pRouteInfo, pRoute, nRoute); - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = 0; - nTotalCompressedSize += CompressedSize; - } - } - } - } - ALERT( at_aiconsole, "Size of Routes = %d\n", nTotalCompressedSize); - } - if (Routes) delete Routes; - if (BestNextNodes) delete BestNextNodes; - if (pRoute) delete pRoute; - if (pMyPath) delete pMyPath; - Routes = 0; - BestNextNodes = 0; - pRoute = 0; - pMyPath = 0; - -#if 0 - TestRoutingTables(); -#endif - m_fRoutingComplete = TRUE; -} - -// Test those routing tables. Doesn't really work, yet. -// -void CGraph :: TestRoutingTables( void ) -{ - int *pMyPath = new int[m_cNodes]; - int *pMyPath2 = new int[m_cNodes]; - if (pMyPath && pMyPath2) - { - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) - { - for (int iCap = 0; iCap < 2; iCap++) - { - int iCapMask; - switch (iCap) - { - case 0: - iCapMask = 0; - break; - - case 1: - iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - break; - } - - for (int iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - m_fRoutingComplete = FALSE; - int cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - m_fRoutingComplete = TRUE; - int cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); - - // Unless we can look at the entire path, we can verify that it's correct. - // - if (cPathSize2 == MAX_PATH_SIZE) continue; - - // Compare distances. - // -#if 1 - float flDistance1 = 0.0; - int i = 0; - for (i = 0; i < cPathSize1-1; i++) - { - // Find the link from pMyPath[i] to pMyPath[i+1] - // - if (pMyPath[i] == pMyPath[i+1]) continue; - int iVisitNode; - BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath[i]].m_cNumLinks; iLink++) - { - iVisitNode = INodeLink ( pMyPath[i], iLink ); - if (iVisitNode == pMyPath[i+1]) - { - flDistance1 += m_pLinkPool[ m_pNodes[ pMyPath[i] ].m_iFirstLink + iLink].m_flWeight; - bFound = TRUE; - break; - } - } - if (!bFound) - { - ALERT(at_aiconsole, "No link.\n"); - } - } - - float flDistance2 = 0.0; - for (i = 0; i < cPathSize2-1; i++) - { - // Find the link from pMyPath2[i] to pMyPath2[i+1] - // - if (pMyPath2[i] == pMyPath2[i+1]) continue; - int iVisitNode; - BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath2[i]].m_cNumLinks; iLink++) - { - iVisitNode = INodeLink ( pMyPath2[i], iLink ); - if (iVisitNode == pMyPath2[i+1]) - { - flDistance2 += m_pLinkPool[ m_pNodes[ pMyPath2[i] ].m_iFirstLink + iLink].m_flWeight; - bFound = TRUE; - break; - } - } - if (!bFound) - { - ALERT(at_aiconsole, "No link.\n"); - } - } - if (fabs(flDistance1 - flDistance2) > 0.10) - { -#else - if (cPathSize1 != cPathSize2 || memcmp(pMyPath, pMyPath2, sizeof(int)*cPathSize1) != 0) - { -#endif - ALERT(at_aiconsole, "Routing is inconsistent!!!\n"); - ALERT(at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap); - int i = 0; - for (i = 0; i < cPathSize1; i++) - { - ALERT(at_aiconsole, "%d ", pMyPath[i]); - } - ALERT(at_aiconsole, "\n(%d to %d |%d/%d)2:", iFrom, iTo, iHull, iCap); - for (i = 0; i < cPathSize2; i++) - { - ALERT(at_aiconsole, "%d ", pMyPath2[i]); - } - ALERT(at_aiconsole, "\n"); - m_fRoutingComplete = FALSE; - cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - m_fRoutingComplete = TRUE; - cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); - goto EnoughSaid; - } - } - } - } - } - } - -EnoughSaid: - - if (pMyPath) delete pMyPath; - if (pMyPath2) delete pMyPath2; - pMyPath = 0; - pMyPath2 = 0; -} - - - - - - - - - -//========================================================= -// CNodeViewer - Draws a graph of the shorted path from all nodes -// to current location (typically the player). It then draws -// as many connects as it can per frame, trying not to overflow the buffer -//========================================================= -class CNodeViewer : public CBaseEntity -{ -public: - void Spawn( void ); - - int m_iBaseNode; - int m_iDraw; - int m_nVisited; - int m_aFrom[128]; - int m_aTo[128]; - int m_iHull; - int m_afNodeType; - Vector m_vecColor; - - void FindNodeConnections( int iNode ); - void AddNode( int iFrom, int iTo ); - void EXPORT DrawThink( void ); - -}; -LINK_ENTITY_TO_CLASS( node_viewer, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_human, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_fly, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_large, CNodeViewer ); - -void CNodeViewer::Spawn( ) -{ - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_console, "Graph not ready!\n" ); - UTIL_Remove( this ); - return; - } - - - if (FClassnameIs( pev, "node_viewer_fly")) - { - m_iHull = NODE_FLY_HULL; - m_afNodeType = bits_NODE_AIR; - m_vecColor = Vector( 160, 100, 255 ); - } - else if (FClassnameIs( pev, "node_viewer_large")) - { - m_iHull = NODE_LARGE_HULL; - m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; - m_vecColor = Vector( 100, 255, 160 ); - } - else - { - m_iHull = NODE_HUMAN_HULL; - m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; - m_vecColor = Vector( 255, 160, 100 ); - } - - - m_iBaseNode = WorldGraph.FindNearestNode ( pev->origin, m_afNodeType ); - - if ( m_iBaseNode < 0 ) - { - ALERT( at_console, "No nearby node\n" ); - return; - } - - m_nVisited = 0; - - ALERT( at_aiconsole, "basenode %d\n", m_iBaseNode ); - - if (WorldGraph.m_cNodes < 128) - { - for (int i = 0; i < WorldGraph.m_cNodes; i++) - { - AddNode( i, WorldGraph.NextNodeInRoute( i, m_iBaseNode, m_iHull, 0 )); - } - } - else - { - // do a depth traversal - FindNodeConnections( m_iBaseNode ); - - int start = 0; - int end; - do { - end = m_nVisited; - // ALERT( at_console, "%d :", m_nVisited ); - for (end = m_nVisited; start < end; start++) - { - FindNodeConnections( m_aFrom[start] ); - FindNodeConnections( m_aTo[start] ); - } - } while (end != m_nVisited); - } - - ALERT( at_aiconsole, "%d nodes\n", m_nVisited ); - - m_iDraw = 0; - SetThink(&CNodeViewer:: DrawThink ); - SetNextThink( 0 ); -} - - -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 ) -{ - SetNextThink( 0 ); - - for (int i = 0; i < 10; i++) - { - if (m_iDraw == m_nVisited) - { - UTIL_Remove( this ); - return; - } - - extern short g_sModelIndexLaser; - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.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/server/monsters/nodes.h b/server/monsters/nodes.h deleted file mode 100644 index 692546de..00000000 --- a/server/monsters/nodes.h +++ /dev/null @@ -1,374 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// nodes.h -//========================================================= - -//========================================================= -// DEFINE -//========================================================= -#define MAX_STACK_NODES 100 -#define NO_NODE -1 -#define MAX_NODE_HULLS 4 - -#define bits_NODE_LAND ( 1 << 0 ) // Land node, so nudge if necessary. -#define bits_NODE_AIR ( 1 << 1 ) // Air node, don't nudge. -#define bits_NODE_WATER ( 1 << 2 ) // Water node, don't nudge. -#define bits_NODE_GROUP_REALM (bits_NODE_LAND | bits_NODE_AIR | bits_NODE_WATER) - -//========================================================= -// Instance of a node. -//========================================================= -class CNode -{ -public: - Vector m_vecOrigin;// location of this node in space - Vector m_vecOriginPeek; // location of this node (LAND nodes are NODE_HEIGHT higher). - byte m_Region[3]; // Which of 256 regions do each of the coordinate belong? - int m_afNodeInfo;// bits that tell us more about this location - - int m_cNumLinks; // how many links this node has - int m_iFirstLink;// index of this node's first link in the link pool. - - // Where to start looking in the compressed routing table (offset into m_pRouteInfo). - // (4 hull sizes -- smallest to largest + fly/swim), and secondly, door capability. - // - int m_pNextBestNode[MAX_NODE_HULLS][2]; - - // Used in finding the shortest path. m_fClosestSoFar is -1 if not visited. - // Then it is the distance to the source. If another path uses this node - // and has a closer distance, then m_iPreviousNode is also updated. - // - float m_flClosestSoFar; // Used in finding the shortest path. - int m_iPreviousNode; - - short m_sHintType;// there is something interesting in the world at this node's position - short m_sHintActivity;// there is something interesting in the world at this node's position - float m_flHintYaw;// monster on this node should face this yaw to face the hint. -}; - -//========================================================= -// CLink - A link between 2 nodes -//========================================================= -#define bits_LINK_SMALL_HULL ( 1 << 0 )// headcrab box can fit through this connection -#define bits_LINK_HUMAN_HULL ( 1 << 1 )// player box can fit through this connection -#define bits_LINK_LARGE_HULL ( 1 << 2 )// big box can fit through this connection -#define bits_LINK_FLY_HULL ( 1 << 3 )// a flying big box can fit through this connection -#define bits_LINK_DISABLED ( 1 << 4 )// link is not valid when the set - -#define NODE_SMALL_HULL 0 -#define NODE_HUMAN_HULL 1 -#define NODE_LARGE_HULL 2 -#define NODE_FLY_HULL 3 - -class CLink -{ -public: - int m_iSrcNode;// the node that 'owns' this link ( keeps us from having to make reverse lookups ) - int m_iDestNode;// the node on the other end of the link. - - entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc) - - // m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes) - char m_szLinkEntModelname[ 4 ];// the unique name of the brush model that blocks the connection (this is kept for save/restore) - - int m_afLinkInfo;// information about this link - float m_flWeight;// length of the link line segment -}; - - -typedef struct -{ - int m_SortedBy[3]; - int m_CheckedEvent; -} DIST_INFO; - -typedef struct -{ - Vector v; - short n; // Nearest node or -1 if no node found. -} CACHE_ENTRY; - -//========================================================= -// CGraph -//========================================================= -#define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files. -class CGraph -{ -public: - -// the graph has two flags, and should not be accessed unless both flags are TRUE! - BOOL m_fGraphPresent;// is the graph in memory? - BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set? - BOOL m_fRoutingComplete; // are the optimal routes computed, yet? - - CNode *m_pNodes;// pointer to the memory block that contains all node info - CLink *m_pLinkPool;// big list of all node connections - char *m_pRouteInfo; // compressed routing information the nodes use. - - int m_cNodes;// total number of nodes - int m_cLinks;// total number of links - int m_nRouteInfo; // size of m_pRouteInfo in bytes. - - // Tables for making nearest node lookup faster. SortedBy provided nodes in a - // order of a particular coordinate. Instead of doing a binary search, RangeStart - // and RangeEnd let you get to the part of SortedBy that you are interested in. - // - // Once you have a point of interest, the only way you'll find a closer point is - // if at least one of the coordinates is closer than the ones you have now. So we - // search each range. After the search is exhausted, we know we have the closest - // node. - // -#define CACHE_SIZE 128 -#define NUM_RANGES 256 - DIST_INFO *m_di; // This is m_cNodes long, but the entries don't correspond to CNode entries. - int m_RangeStart[3][NUM_RANGES]; - int m_RangeEnd[3][NUM_RANGES]; - float m_flShortest; - int m_iNearest; - int m_minX, m_minY, m_minZ, m_maxX, m_maxY, m_maxZ; - int m_minBoxX, m_minBoxY, m_minBoxZ, m_maxBoxX, m_maxBoxY, m_maxBoxZ; - int m_CheckedCounter; - float m_RegionMin[3], m_RegionMax[3]; // The range of nodes. - CACHE_ENTRY m_Cache[CACHE_SIZE]; - - - int m_HashPrimes[16]; - short *m_pHashLinks; - int m_nHashLinks; - - - // kinda sleazy. In order to allow variety in active idles for monster groups in a room with more than one node, - // we keep track of the last node we searched from and store it here. Subsequent searches by other monsters will pick - // up where the last search stopped. - int m_iLastActiveIdleSearch; - - // another such system used to track the search for cover nodes, helps greatly with two monsters trying to get to the same node. - int m_iLastCoverSearch; - - // functions to create the graph - int LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ); - int RejectInlineLinks ( CLink *pLinkPool, FILE *file ); - int FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask); - int FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ); - int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ); - //int FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine ); - float PathLength( int iStart, int iDest, int iHull, int afCapMask ); - int NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ); - - enum NODEQUERY { NODEGRAPH_DYNAMIC, NODEGRAPH_STATIC }; - // A static query means we're asking about the possiblity of handling this entity at ANY time - // A dynamic query means we're asking about it RIGHT NOW. So we should query the current state - int HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ); - entvars_t* LinkEntForLink ( CLink *pLink, CNode *pNode ); - void ShowNodeConnections ( int iNode ); - void InitGraph( void ); - int AllocNodes( void ); - - int CheckNODFile( const char *szMapName ); - int FLoadGraph( const char *szMapName ); - int FSaveGraph( const char *szMapName ); - int FSetGraphPointers( void ); - void CheckNode( Vector vecOrigin, int iNode ); - - void BuildRegionTables(void); - void ComputeStaticRoutingTables(void); - void TestRoutingTables(void); - - void HashInsert(int iSrcNode, int iDestNode, int iKey); - void HashSearch(int iSrcNode, int iDestNode, int &iKey); - void HashChoosePrimes(int TableSize); - void BuildLinkLookups(void); - - void SortNodes(void); - - int HullIndex( const CBaseEntity *pEntity ); // what hull the monster uses - int NodeType( const CBaseEntity *pEntity ); // what node type the monster uses - inline int CapIndex( int afCapMask ) - { - if (afCapMask & (bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE)) - return 1; - return 0; - } - - - inline CNode &Node( int i ) - { -#ifdef _DEBUG - if ( !m_pNodes || i < 0 || i > m_cNodes ) - ALERT( at_error, "Bad Node!\n" ); -#endif - return m_pNodes[i]; - } - - inline CLink &Link( int i ) - { -#ifdef _DEBUG - if ( !m_pLinkPool || i < 0 || i > m_cLinks ) - ALERT( at_error, "Bad link!\n" ); -#endif - return m_pLinkPool[i]; - } - - inline CLink &NodeLink( int iNode, int iLink ) - { - return Link( Node( iNode ).m_iFirstLink + iLink ); - } - - inline CLink &NodeLink( const CNode &node, int iLink ) - { - return Link( node.m_iFirstLink + iLink ); - } - - inline int INodeLink ( int iNode, int iLink ) - { - return NodeLink( iNode, iLink ).m_iDestNode; - } - -#if 0 - inline CNode &SourceNode( int iNode, int iLink ) - { - return Node( NodeLink( iNode, iLink ).m_iSrcNode ); - } - - inline CNode &DestNode( int iNode, int iLink ) - { - return Node( NodeLink( iNode, iLink ).m_iDestNode ); - } - - inline CNode *PNodeLink ( int iNode, int iLink ) - { - return &DestNode( iNode, iLink ); - } -#endif -}; - -//========================================================= -// Nodes start out as ents in the level. The node graph -// is built, then these ents are discarded. -//========================================================= -class CNodeEnt : public CBaseEntity -{ - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - short m_sHintType; - short m_sHintActivity; -}; - - -//========================================================= -// CStack - last in, first out. -//========================================================= -class CStack -{ -public: - CStack( void ); - void Push( int value ); - int Pop( void ); - int Top( void ); - int Empty( void ) { return m_level==0; } - int Size( void ) { return m_level; } - void CopyToArray ( int *piArray ); - -private: - int m_stack[ MAX_STACK_NODES ]; - int m_level; -}; - - -//========================================================= -// CQueue - first in, first out. -//========================================================= -class CQueue -{ -public: - - CQueue( void );// constructor - inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); } - inline int Empty ( void ) { return ( m_cSize == 0 ); } - //inline int Tail ( void ) { return ( m_queue[ m_tail ] ); } - inline int Size ( void ) { return ( m_cSize ); } - void Insert( int, float ); - int Remove( float & ); - -private: - int m_cSize; - struct tag_QUEUE_NODE - { - int Id; - float Priority; - } m_queue[ MAX_STACK_NODES ]; - int m_head; - int m_tail; -}; - -//========================================================= -// CQueuePriority - Priority queue (smallest item out first). -// -//========================================================= -class CQueuePriority -{ -public: - - CQueuePriority( void );// constructor - inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); } - inline int Empty ( void ) { return ( m_cSize == 0 ); } - //inline int Tail ( float & ) { return ( m_queue[ m_tail ].Id ); } - inline int Size ( void ) { return ( m_cSize ); } - void Insert( int, float ); - int Remove( float &); - -private: - int m_cSize; - struct tag_HEAP_NODE - { - int Id; - float Priority; - } m_heap[ MAX_STACK_NODES ]; - void Heap_SiftDown(int); - void Heap_SiftUp(void); - -}; - -//========================================================= -// hints - these MUST coincide with the HINTS listed under -// info_node in the FGD file! -//========================================================= -enum -{ - HINT_NONE = 0, - HINT_WORLD_DOOR, - HINT_WORLD_WINDOW, - HINT_WORLD_BUTTON, - HINT_WORLD_MACHINERY, - HINT_WORLD_LEDGE, - HINT_WORLD_LIGHT_SOURCE, - HINT_WORLD_HEAT_SOURCE, - HINT_WORLD_BLINKING_LIGHT, - HINT_WORLD_BRIGHT_COLORS, - HINT_WORLD_HUMAN_BLOOD, - HINT_WORLD_ALIEN_BLOOD, - - HINT_TACTICAL_EXIT = 100, - HINT_TACTICAL_VANTAGE, - HINT_TACTICAL_AMBUSH, - - HINT_STUKA_PERCH = 300, - HINT_STUKA_LANDING, -}; - -extern CGraph WorldGraph; diff --git a/server/monsters/osprey.cpp b/server/monsters/osprey.cpp deleted file mode 100644 index 97325fee..00000000 --- a/server/monsters/osprey.cpp +++ /dev/null @@ -1,823 +0,0 @@ -/*** -* -* 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. -* 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 "utils.h" -#include "cbase.h" -#include "client.h" -#include "monsters.h" -#include "baseweapon.h" -#include "nodes.h" -#include "soundent.h" -#include "basebeams.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; - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - SET_MODEL(ENT(pev), "models/osprey.mdl"); - UTIL_SetSize(pev, Vector( -400, -400, -100), Vector(400, 400, 32)); - UTIL_SetOrigin( this, pev->origin ); - - // ALERT( at_console, "Osprey origin %f %f %f\n", pev->origin.x, pev->origin.y, pev->origin.z); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_YES; - m_flRightHealth = 200; - m_flLeftHealth = 200; - pev->health = 400; - - pev->speed = 80; //LRC - default speed, in case path corners don't give a speed. - - m_flFieldOfView = 0; // 180 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - pev->frame = RANDOM_LONG(0,0xFF); - - InitBoneControllers(); - - SetThink(&COsprey :: FindAllThink ); - SetUse(&COsprey :: CommandUse ); - - if (!(pev->spawnflags & SF_WAITFORTRIGGER)) - { - SetNextThink( 1.0 ); - } - - m_pos2 = pev->origin; - m_ang2 = pev->angles; - m_vel2 = pev->velocity; -} - - -void COsprey::Precache( void ) -{ - UTIL_PrecacheEntity( "monster_human_grunt" ); - - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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 ) -{ - SetNextThink( 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) - { - m_iUnits = 4; //LRC - stop whining, just make the damn grunts... - -// ALERT( at_console, "osprey error: no grunts to resupply\n"); -// UTIL_Remove( this ); -// return; - } - SetThink(&COsprey :: FlyThink ); - SetNextThink( 0.1 ); - m_startTime = gpGlobals->time; -} - - -void COsprey :: DeployThink( void ) -{ - UTIL_MakeAimVectors( pev->angles ); - - Vector vecForward = gpGlobals->v_forward; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - Vector vecSrc; - - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0), ignore_monsters, ENT(pev), &tr); - CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * 100 + vecUp * -96; - m_hRepel[0] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * 100 + vecUp * -96; - m_hRepel[1] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * -100 + vecUp * -96; - m_hRepel[2] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96; - m_hRepel[3] = MakeGrunt( vecSrc ); - - SetThink(&COsprey :: HoverThink ); - SetNextThink( 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()) - { - 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->edict() ); - pBeam->SetFlags( FBEAM_SOLID ); - pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( Remove ); - pBeam->SetNextThink( -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5 ); - - // ALERT( at_console, "%d at %.0f %.0f %.0f\n", i, m_vecOrigin[i].x, m_vecOrigin[i].y, m_vecOrigin[i].z ); - pGrunt->m_vecLastPosition = m_vecOrigin[i]; - m_hGrunt[i] = pGrunt; - return pGrunt; - } - } - // ALERT( at_console, "none dead\n"); - return NULL; -} - - -void COsprey :: HoverThink( void ) -{ - int i; - for (i = 0; i < 4; i++) - { - if (m_hRepel[i] != NULL && m_hRepel[i]->pev->health > 0 && !(m_hRepel[i]->pev->flags & FL_ONGROUND)) - { - break; - } - } - - if (i == 4) - { - m_startTime = gpGlobals->time; - SetThink(&COsprey :: FlyThink ); - } - - SetNextThink( 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 ) ); - - //LRC - ugh. we shouldn't require our path corners to specify a speed! - if (m_pGoalEnt->pev->speed) - pev->speed = m_pGoalEnt->pev->speed; - - m_vel2 = gpGlobals->v_forward * pev->speed; //LRC - - m_startTime = m_startTime + m_dTime; - m_dTime = 2.0 * (m_pos1 - m_pos2).Length() / (m_vel1.Length() + pev->speed); - - // ALERT(at_console, "osprey m_dTime = %f / %f + %f\n", (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 (pev->speed < 400) - m_flIdealtilt = 0; - else - m_flIdealtilt = -90; - } - else - { - ALERT( at_console, "osprey missing target"); - } -} - - -void COsprey::FlyThink( void ) -{ - StudioFrameAdvance( ); - SetNextThink( 0.1 ); - - if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target - { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); - UpdateGoal( ); - } - - if (gpGlobals->time > m_startTime + m_dTime) - { - if (m_pGoalEnt->pev->speed == 0) - { - SetThink(&COsprey:: DeployThink ); - } - int loopbreaker = 100; //LRC - don't loop indefinitely! - do { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_pGoalEnt->pev->target ) ); - loopbreaker--; //LRC - } while (m_pGoalEnt->pev->speed < 400 && !HasDead() && loopbreaker > 0); - 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 ); - -// ALERT(at_console, "Osprey setorigin m_pos1 %f, m_vel1 %f, m_pos2 %f, m_vel2 %f, m_dTime %f, t %f, f %f\n", m_pos1.x, m_vel1.x, m_pos2.x, m_vel2.x, m_dTime, t, f); - - Vector pos = (m_pos1 + m_vel1 * t) * (1.0 - f) + (m_pos2 - m_vel2 * (m_dTime - t)) * f; - Vector ang = (m_ang1) * (1.0 - f) + (m_ang2) * f; - m_velocity = m_vel1 * (1.0 - f) + m_vel2 * f; - - UTIL_SetOrigin( this, 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 ) -{ - SetNextThink( 2.0 ); -} - - -/* -int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if (m_flRotortilt <= -90) - { - m_flRotortilt = 0; - } - else - { - m_flRotortilt -= 45; - } - SetBoneController( 0, m_flRotortilt ); - return 0; -} -*/ - - - -void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - pev->velocity = m_velocity; - pev->avelocity = Vector( RANDOM_FLOAT( -20, 20 ), 0, RANDOM_FLOAT( -50, 50 ) ); - STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink(&COsprey :: DyingThink ); - SetTouch(&COsprey :: CrashTouch ); - SetNextThink( 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; - SetNextThink( 0 ); - m_velocity = pev->velocity; - } -} - - -void COsprey :: DyingThink( void ) -{ - StudioFrameAdvance( ); - SetNextThink( 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, gmsg.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, gmsg.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, gmsg.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; - SetNextThink( 0.2 ); - return; - } - else - { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - - /* - MESSAGE_BEGIN( MSG_BROADCAST, gmsg.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, gmsg.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, gmsg.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, gmsg.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, gmsg.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, gmsg.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, gmsg.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/server/monsters/player.cpp b/server/monsters/player.cpp deleted file mode 100644 index 80754246..00000000 --- a/server/monsters/player.cpp +++ /dev/null @@ -1,4777 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== player.cpp ======================================================== - - functions dealing with the player - -*/ - -#include "extdll.h" -#include "utils.h" - -#include "cbase.h" -#include "client.h" -#include "player.h" -#include "nodes.h" -#include "baseweapon.h" -#include "soundent.h" -#include "monsters.h" -#include "shake.h" -#include "decals.h" -#include "gamerules.h" -#include "game.h" -#include "basebeams.h" -#include "defaults.h" - - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL BOOL g_fDrawLines; -float g_flWeaponCheat; -int gEvilImpulse101; -BOOL GiveOnlyAmmo; -BOOL g_markFrameBounds = 0; -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 ); -extern void LinkUserMessages( void ); - -// 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 -#define TRAIN_NEUTRAL 0x01 -#define TRAIN_SLOW 0x02 -#define TRAIN_MEDIUM 0x03 -#define TRAIN_FAST 0x04 -#define TRAIN_BACK 0x05 - -#define FLASH_DRAIN_TIME 1.2 // 100 units / 3 minutes -#define FLASH_CHARGE_TIME 0.2 // 100 units / 20 seconds (seconds per unit) - -// Global Savedata for player -TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = -{ - DEFINE_FIELD( CBasePlayer, m_flFlashLightTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_iFlashBattery, FIELD_INTEGER ), - - DEFINE_FIELD( CBasePlayer, m_afButtonLast, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonPressed, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonReleased, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgItems, FIELD_INTEGER, MAX_ITEMS ), - DEFINE_FIELD( CBasePlayer, m_afPhysicsFlags, FIELD_INTEGER ), - - DEFINE_FIELD( CBasePlayer, m_flTimeStepSound, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flTimeWeaponIdle, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flSwimTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flDuckTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flWallJumpTime, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_fAirFinished, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_fPainFinished, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flSuitUpdate, FIELD_TIME ), - DEFINE_ARRAY( CBasePlayer, m_rgSuitPlayList, FIELD_INTEGER, CSUITPLAYLIST ), - DEFINE_FIELD( CBasePlayer, m_iSuitPlayNext, FIELD_INTEGER ), - DEFINE_ARRAY( CBasePlayer, m_rgiSuitNoRepeat, FIELD_INTEGER, CSUITNOREPEAT ), - DEFINE_ARRAY( CBasePlayer, m_rgflSuitNoRepeatTime, FIELD_TIME, CSUITNOREPEAT ), - DEFINE_ARRAY( CBasePlayer, m_szAnimExtention, FIELD_CHARACTER, 32), - DEFINE_FIELD( CBasePlayer, m_lastDamageAmount, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CBasePlayer, m_pActiveItem, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayer, m_pLastItem, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayer, m_pNextItem, FIELD_CLASSPTR ), - - DEFINE_ARRAY( CBasePlayer, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_FIELD( CBasePlayer, m_idrowndmg, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_idrownrestored, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_tSneaking, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_iTrain, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_bitsHUDDamage, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_flFallVelocity, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, m_iTargetVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iExtraSoundTypes, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponFlash, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_fLongJump, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_fInitHUD, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_tbdPrev, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_pTank, FIELD_EHANDLE ), // NB: this points to a CFuncTank*Controls* now. --LRC - DEFINE_FIELD( CBasePlayer, m_pMonitor, FIELD_EHANDLE ), - DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, pViewEnt, FIELD_CLASSPTR), - DEFINE_FIELD( CBasePlayer, viewFlags, FIELD_INTEGER), - DEFINE_FIELD( CBasePlayer, m_iSndRoomtype, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iFogStartDist, FIELD_INTEGER), - DEFINE_FIELD( CBasePlayer, m_iFogEndDist, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iFogFinalEndDist, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_FogColor, FIELD_VECTOR ), - DEFINE_FIELD( CBasePlayer, m_FogFadeTime, FIELD_INTEGER), - DEFINE_FIELD( CBasePlayer, m_iWarHUD, FIELD_INTEGER), - - DEFINE_FIELD( CBasePlayer, m_FadeColor, FIELD_VECTOR ), - DEFINE_FIELD( CBasePlayer, m_FadeAlpha, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iFadeFlags, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_flFadeHold, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flFadeTime, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_flStartTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flNextNuclearDamage, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, Rain_dripsPerSecond, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, Rain_windX, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, Rain_windY, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, Rain_randX, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, Rain_randY, FIELD_FLOAT ), - - DEFINE_FIELD( CBasePlayer, Rain_ideal_dripsPerSecond, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, Rain_ideal_windX, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, Rain_ideal_windY, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, Rain_ideal_randX, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, Rain_ideal_randY, FIELD_FLOAT ), - - DEFINE_FIELD( CBasePlayer, Rain_endFade, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, Rain_nextFadeUpdate, FIELD_TIME ), - - //LRC - //DEFINE_FIELD( CBasePlayer, m_iFogStartDist, FIELD_INTEGER ), - //DEFINE_FIELD( CBasePlayer, m_iFogEndDist, FIELD_INTEGER ), - //DEFINE_FIELD( CBasePlayer, m_vecFogColor, FIELD_VECTOR ), - - //DEFINE_FIELD( CBasePlayer, m_fDeadTime, FIELD_FLOAT ), // only used in multiplayer games - //DEFINE_FIELD( CBasePlayer, m_fGameHUDInitialized, FIELD_INTEGER ), // only used in multiplayer games - //DEFINE_FIELD( CBasePlayer, m_flStopExtraSoundTime, FIELD_TIME ), - //DEFINE_FIELD( CBasePlayer, m_fKnownItem, FIELD_INTEGER ), // reset to zero on load - //DEFINE_FIELD( CBasePlayer, m_iPlayerSound, FIELD_INTEGER ), // Don't restore, set in Precache() - //DEFINE_FIELD( CBasePlayer, m_pentSndLast, FIELD_EDICT ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_flSndRange, FIELD_FLOAT ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_fNewAmmo, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_flgeigerRange, FIELD_FLOAT ), // Don't restore, reset in Precache() - //DEFINE_FIELD( CBasePlayer, m_flgeigerDelay, FIELD_FLOAT ), // Don't restore, reset in Precache() - //DEFINE_FIELD( CBasePlayer, m_igeigerRangePrev, FIELD_FLOAT ), // Don't restore, reset in Precache() - //DEFINE_FIELD( CBasePlayer, m_iStepLeft, FIELD_INTEGER ), // Don't need to restore - //DEFINE_ARRAY( CBasePlayer, m_szTextureName, FIELD_CHARACTER, CBTEXTURENAMEMAX ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_chTextureType, FIELD_CHARACTER ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_fNoPlayerSound, FIELD_BOOLEAN ), // Don't need to restore, debug - //DEFINE_FIELD( CBasePlayer, m_iUpdateTime, FIELD_INTEGER ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_iClientHealth, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_iClientBattery, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_iClientHideHUD, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_fWeapon, FIELD_BOOLEAN ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't restore, depends on server message after spawning and only matters in multiplayer - //DEFINE_FIELD( CBasePlayer, m_vecAutoAim, FIELD_VECTOR ), // Don't save/restore - this is recomputed - //DEFINE_ARRAY( CBasePlayer, m_rgAmmoLast, FIELD_INTEGER, MAX_AMMO_SLOTS ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_fOnTarget, FIELD_BOOLEAN ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't need to restore - -}; -LINK_ENTITY_TO_CLASS( player, CBasePlayer ); - - - -void CBasePlayer :: Pain( void ) -{ - float flRndSound;//sound randomizer - - flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); -} - -/* - * - */ -Vector VecVelocityForDamage(float flDamage) -{ - Vector vec(RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - - if (flDamage > -50) - vec = vec * 0.7; - else if (flDamage > -200) - vec = vec * 2; - else - vec = vec * 10; - - return vec; -} - -#if 0 /* -static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage) -{ - edict_t *pentNew = CREATE_ENTITY(); - entvars_t *pevNew = VARS(pentNew); - - pevNew->origin = pev->origin; - SET_MODEL(ENT(pevNew), szGibModel); - UTIL_SetSize(pevNew, g_vecZero, g_vecZero); - - pevNew->velocity = VecVelocityForDamage(flDamage); - pevNew->movetype = MOVETYPE_BOUNCE; - pevNew->solid = SOLID_NOT; - pevNew->avelocity.x = RANDOM_FLOAT(0,600); - pevNew->avelocity.y = RANDOM_FLOAT(0,600); - pevNew->avelocity.z = RANDOM_FLOAT(0,600); - CHANGE_METHOD(ENT(pevNew), em_think, Remove); - pevNew->ltime = gpGlobals->time; - pevNew->nextthink = gpGlobals->time + RANDOM_FLOAT(10,20); - pevNew->frame = 0; - pevNew->flags = 0; -} - - -static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage) -{ - SET_MODEL(ENT(pev), szGibModel); - pev->frame = 0; - pev->nextthink = -1; - pev->movetype = MOVETYPE_BOUNCE; - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT; - pev->view_ofs = Vector(0,0,8); - UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,56)); - pev->velocity = VecVelocityForDamage(flDamage); - pev->avelocity = RANDOM_FLOAT(-1,1) * Vector(0,600,0); - pev->origin.z -= 24; - ClearBits(pev->flags, FL_ONGROUND); -} - - -*/ -#endif - -int TrainSpeed(int iSpeed, int iMax) -{ - float fSpeed, fMax; - int iRet = 0; - - fMax = (float)iMax; - fSpeed = iSpeed; - - fSpeed = fSpeed/fMax; - - if (iSpeed < 0) - iRet = TRAIN_BACK; - else if (iSpeed == 0) - iRet = TRAIN_NEUTRAL; - else if (fSpeed < 0.33) - iRet = TRAIN_SLOW; - else if (fSpeed < 0.66) - iRet = TRAIN_MEDIUM; - else - iRet = TRAIN_FAST; - - return iRet; -} - -void CBasePlayer :: DeathSound( void ) -{ - // water death sounds - /* - if (pev->waterlevel == 3) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE); - return; - } - */ - - // temporarily using pain sounds for death sounds - switch (RANDOM_LONG(1,5)) - { - case 1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - break; - case 2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - break; - case 3: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); - break; - } - - // play one of the suit death alarms - //LRC- if no suit, then no flatline sound. (unless it's a deathmatch.) - if(!( pev->weapons & ITEM_SUIT ) && !g_pGameRules->IsDeathmatch( )) - return; - EMIT_GROUPNAME_SUIT(ENT(pev), "HEV_DEAD"); -} - -// override takehealth -// bitsDamageType indicates type of damage healed. - -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) -{ - return CBaseMonster::TakeHealth (flHealth, bitsDamageType); -} - -int CBasePlayer :: TakeArmor( float flArmor, int suit ) -{ - if(!( pev->weapons & ITEM_SUIT )) return 0; - - if(CBaseMonster::TakeArmor(flArmor )) - { - if( !suit ) return 1; //silent take armor - - int pct; - char szcharge[64]; - - // Suit reports new power level - pct = (int)( (float)(pev->armorvalue * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5); - pct = (pct / 5); - if( pct > 0 ) pct--; - - sprintf( szcharge,"!HEV_%1dP", pct ); - SetSuitUpdate( szcharge, FALSE, SUIT_NEXT_IN_30SEC ); - - return 1; - } - return 0; -} - -int CBasePlayer :: TakeItem( int iItem ) -{ - if ( m_iHideHUD & iItem ) - return 0; - return 1; -} - -Vector CBasePlayer :: GetGunPosition( ) -{ - return pev->origin + pev->view_ofs; -} - -//========================================================= -// TraceAttack -//========================================================= -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= DMG_HEAD; - break; - case HITGROUP_CHEST: - flDamage *= DMG_CHEST; - break; - case HITGROUP_STOMACH: - flDamage *= DMG_STOMACH; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= DMG_ARM; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= DMG_LEG; - break; - default: - break; - } - - if( bitsDamageType & DMG_NUCLEAR && m_flNextNuclearDamage < gpGlobals->time ) - { - m_FadeColor = Vector( 255, 255, 255 ); - m_FadeAlpha = 240; - m_iFadeFlags = FFADE_IN|FFADE_MODULATE; - m_flFadeTime = 25.0f; - m_flFadeHold = 0.0f; - fadeNeedsUpdate = TRUE; - m_flNextNuclearDamage = gpGlobals->time + 1.0f; - } - else SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -/* - Take some damage. - NOTE: each call to TakeDamage with bitsDamageType set to a time-based damage - type will cause the damage time countdown to be reset. Thus the ongoing effects of poison, radiation - etc are implemented with subsequent calls to TakeDamage using DMG_GENERIC. -*/ - -#define ARMOR_RATIO 0.2 // Armor Takes 80% of the damage -#define ARMOR_BONUS 0.5 // Each Point of Armor is work 1/x points of health - -int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // have suit diagnose the problem - ie: report damage type - int bitsDamage = bitsDamageType; - int ffound = TRUE; - int fmajor; - int fcritical; - int fTookDamage; - int ftrivial; - float flRatio; - float flBonus; - float flHealthPrev = pev->health; - - flBonus = ARMOR_BONUS; - flRatio = ARMOR_RATIO; - - if ( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() ) - { - // blasts damage armor more. - flBonus *= 2; - } - - // Already dead - if ( !IsAlive() ) - return 0; - // go take the damage first - - - CBaseEntity *pAttacker = CBaseEntity::Instance(pevAttacker); - - if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) - { - // Refuse the damage - return 0; - } - - // keep track of amount of damage last sustained - m_lastDamageAmount = flDamage; - - // Armor. - if (pev->armorvalue && !(bitsDamageType & (DMG_FALL | DMG_DROWN)) )// armor doesn't protect against fall or drown damage! - { - float flNew = flDamage * flRatio; - - float flArmor; - - flArmor = (flDamage - flNew) * flBonus; - - // Does this use more armor than we have? - if (flArmor > pev->armorvalue) - { - flArmor = pev->armorvalue; - flArmor *= (1/flBonus); - flNew = flDamage - flArmor; - pev->armorvalue = 0; - } - else - pev->armorvalue -= flArmor; - - flDamage = flNew; - } - - // this cast to INT is critical!!! If a player ends up with 0.5 health, the engine will get that - // as an int (zero) and think the player is dead! (this will incite a clientside screentilt, etc) - fTookDamage = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, (int)flDamage, bitsDamageType); - - // reset damage time countdown for each type of time based damage player just sustained - - { - for (int i = 0; i < CDMG_TIMEBASED; i++) - if (bitsDamageType & (DMG_PARALYZE << i)) - m_rgbTimeBasedDamage[i] = 0; - } - - - // how bad is it, doc? - - ftrivial = (pev->health > 75 || m_lastDamageAmount < 5); - fmajor = (m_lastDamageAmount > 25); - fcritical = (pev->health < 30); - - // handle all bits set in this damage message, - // let the suit give player the diagnosis - - // UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash ) - - // UNDONE: still need to record damage and heal messages for the following types - - // DMG_BURN - // DMG_FREEZE - // DMG_BLAST - // DMG_SHOCK - - m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client - m_bitsHUDDamage = -1; // make sure the damage bits get resent - - while (fTookDamage && (!ftrivial || (bitsDamage & DMG_TIMEBASED)) && ffound && bitsDamage) - { - ffound = FALSE; - - if (bitsDamage & DMG_CLUB) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - bitsDamage &= ~DMG_CLUB; - ffound = TRUE; - } - if (bitsDamage & (DMG_FALL | DMG_CRUSH)) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC); // major fracture - else - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - - bitsDamage &= ~(DMG_FALL | DMG_CRUSH); - ffound = TRUE; - } - - if (bitsDamage & DMG_BULLET) - { - if (m_lastDamageAmount > 5) - SetSuitUpdate("!HEV_DMG6", FALSE, SUIT_NEXT_IN_30SEC); // blood loss detected - //else - // SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_BULLET; - ffound = TRUE; - } - - if (bitsDamage & DMG_SLASH) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC); // major laceration - else - SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_SLASH; - ffound = TRUE; - } - if (bitsDamage & DMG_SONIC) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN); // internal bleeding - bitsDamage &= ~DMG_SONIC; - ffound = TRUE; - } - - if (bitsDamage & (DMG_POISON | DMG_PARALYZE)) - { - SetSuitUpdate("!HEV_DMG3", FALSE, SUIT_NEXT_IN_1MIN); // blood toxins detected - bitsDamage &= ~(DMG_POISON | DMG_PARALYZE); - ffound = TRUE; - } - - if (bitsDamage & DMG_ACID) - { - SetSuitUpdate("!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected - bitsDamage &= ~DMG_ACID; - ffound = TRUE; - } - - if (bitsDamage & DMG_NERVEGAS) - { - SetSuitUpdate("!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN); // biohazard detected - bitsDamage &= ~DMG_NERVEGAS; - ffound = TRUE; - } - - if (bitsDamage & DMG_RADIATION) - { - SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN); // radiation detected - bitsDamage &= ~DMG_RADIATION; - ffound = TRUE; - } - if (bitsDamage & DMG_NUCLEAR) - { - SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN); // radiation detected - bitsDamage &= ~DMG_NUCLEAR; - ffound = TRUE; - } - if (bitsDamage & DMG_SHOCK) - { - bitsDamage &= ~DMG_SHOCK; - ffound = TRUE; - } - } - - pev->punchangle.x = -2; - - if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75) - { - // first time we take major damage... - // turn automedic on if not on - SetSuitUpdate("!HEV_MED1", FALSE, SUIT_NEXT_IN_30MIN); // automedic on - - // give morphine shot if not given recently - SetSuitUpdate("!HEV_HEAL7", FALSE, SUIT_NEXT_IN_30MIN); // morphine shot - } - - if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75) - { - - // already took major damage, now it's critical... - if (pev->health < 6) - SetSuitUpdate("!HEV_HLTH3", FALSE, SUIT_NEXT_IN_10MIN); // near death - else if (pev->health < 20) - SetSuitUpdate("!HEV_HLTH2", FALSE, SUIT_NEXT_IN_10MIN); // health critical - - // give critical health warnings - if (!RANDOM_LONG(0,3) && flHealthPrev < 50) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - - // if we're taking time based damage, warn about its continuing effects - if (fTookDamage && (bitsDamageType & DMG_TIMEBASED) && flHealthPrev < 75) - { - if (flHealthPrev < 50) - { - if (!RANDOM_LONG(0,3)) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - else - SetSuitUpdate("!HEV_HLTH1", FALSE, SUIT_NEXT_IN_10MIN); // health dropping - } - - return fTookDamage; -} - -//========================================================= -// PackDeadPlayerItems - call this when a player dies to -// pack up the appropriate weapons and ammo items, and to -// destroy anything that shouldn't be packed. -// -// This is pretty brute force :( -//========================================================= -void CBasePlayer::PackDeadPlayerItems( void ) -{ - int iWeaponRules; - int iAmmoRules; - int i; - CBasePlayerWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have? - int iPackAmmo[ MAX_AMMO_SLOTS + 1]; - int iPW = 0;// index into packweapons array - int iPA = 0;// index into packammo array - - memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons) ); - memset(iPackAmmo, -1, sizeof(iPackAmmo) ); - - // get the game rules - iWeaponRules = g_pGameRules->DeadPlayerWeapons( this ); - iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); - - if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO ) - { - // nothing to pack. Remove the weapons and return. Don't call create on the box! - RemoveAllItems( TRUE ); - return; - } - -// go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerWeapon *pPlayerItem = m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - switch( iWeaponRules ) - { - case GR_PLR_DROP_GUN_ACTIVE: - if ( m_pActiveItem && pPlayerItem == m_pActiveItem ) - { - // this is the active item. Pack it. - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - } - break; - - case GR_PLR_DROP_GUN_ALL: - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - break; - - default: - break; - } - - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - -// now go through ammo and make a list of which types to pack. - if ( iAmmoRules != GR_PLR_DROP_AMMO_NO ) - { - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( m_rgAmmo[ i ] > 0 ) - { - // player has some ammo of this type. - switch ( iAmmoRules ) - { - case GR_PLR_DROP_AMMO_ALL: - iPackAmmo[ iPA++ ] = i; - break; - - case GR_PLR_DROP_AMMO_ACTIVE: - if ( m_pActiveItem && i == m_pActiveItem->m_iPrimaryAmmoType ) - { - // this is the primary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - else if ( m_pActiveItem && i == m_pActiveItem->m_iSecondaryAmmoType ) - { - // this is the secondary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - break; - - default: - break; - } - } - } - } - -// create a box to pack the stuff into. - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "item_weaponbox", pev->origin, pev->angles, edict() ); - - pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. - pWeaponBox->pev->angles.z = 0; - - pWeaponBox->SetThink(& CWeaponBox::Kill ); - pWeaponBox->SetNextThink( 120 ); - - // back these two lists up to their first elements - iPA = 0; - iPW = 0; - - // pack the ammo - while( iPackAmmo[ iPA ] != -1 ) - { - pWeaponBox->PackAmmo( CBasePlayerWeapon::AmmoInfoArray[ iPackAmmo[ iPA ] ].iszName, m_rgAmmo[iPackAmmo[iPA]] ); - iPA++; - } - - // now pack all of the items in the lists - while( rgpPackWeapons[ iPW ] ) - { - // weapon unhooked from the player. Pack it into der box. - pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] ); - - iPW++; - } - - pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. - - RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. -} - -void CBasePlayer::RemoveAllItems( BOOL removeSuit ) -{ - if (m_pActiveItem) - { - ResetAutoaim( ); - m_pActiveItem->Holster( ); - m_pActiveItem = NULL; - } - - m_pLastItem = NULL; - - int i; - CBasePlayerWeapon *pPendingItem; - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - m_pActiveItem = m_rgpPlayerItems[i]; - while (m_pActiveItem) - { - pPendingItem = m_pActiveItem->m_pNext; - m_pActiveItem->Drop( ); - m_pActiveItem = pPendingItem; - } - m_rgpPlayerItems[i] = NULL; - } - m_pActiveItem = NULL; - - pev->viewmodel = 0; - pev->weaponmodel = 0; - pev->weapons = ITEM_SUIT; - - if ( removeSuit ) pev->weapons &= ~ITEM_SUIT; - - for ( i = 0; i < MAX_AMMO_SLOTS; i++) - m_rgAmmo[i] = 0; - - UpdateClientData(); - - // send Selected Weapon Message to our client - MESSAGE_BEGIN( MSG_ONE, gmsg.CurWeapon, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(0); - WRITE_BYTE(0); - MESSAGE_END(); -} - -/* - * GLOBALS ASSUMED SET: g_ulModelIndexPlayer - * - * ENTITY_METHOD(PlayerDie) - */ -entvars_t *g_pevLastInflictor; // Set in combat.cpp. Used to pass the damage inflictor for death messages. - // Better solution: Add as parameter to all Killed() functions. - -void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) -{ - CSound *pSound; - - // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); - - m_pNextItem = NULL; - - g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); - - if ( m_pTank != NULL ) - { - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - - if( m_pMonitor != NULL ) - { - m_pMonitor->Use( this, this, USE_SET, 1 ); - m_pMonitor = NULL; - } - // this client isn't going to be thinking for a while, so reset the sound until they respawn - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) ); - { - if ( pSound ) - { - pSound->Reset(); - } - } - - SetAnimation( PLAYER_DIE ); - - m_iRespawnFrames = 0; - - pev->modelindex = g_ulModelIndexPlayer; // don't use eyes - - pev->deadflag = DEAD_DYING; - pev->movetype = MOVETYPE_TOSS; - ClearBits( pev->flags, FL_ONGROUND ); - if (pev->velocity.z < 10) - pev->velocity.z += RANDOM_FLOAT(0,300); - - // clear out the suit message cache so we don't keep chattering - SetSuitUpdate(NULL, FALSE, 0); - - // send "health" update message to zero - m_iClientHealth = 0; - MESSAGE_BEGIN( MSG_ONE, gmsg.Health, NULL, pev ); - WRITE_BYTE( m_iClientHealth ); - MESSAGE_END(); - - // Tell Ammo Hud that the player is dead - MESSAGE_BEGIN( MSG_ONE, gmsg.CurWeapon, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(0xFF); - WRITE_BYTE(0xFF); - MESSAGE_END(); - - // reset FOV - pev->fov = 90.0f; - - pViewEnt = 0; - viewFlags = 0; - viewNeedsUpdate = 1; - - // death fading - m_FadeColor = Vector( 128, 0, 0 ); - m_FadeAlpha = 254; - m_iFadeFlags = FFADE_OUT|FFADE_MODULATE; - m_flFadeTime = 6.0f; - m_flFadeHold = 9999.0f; - fadeNeedsUpdate = TRUE; - - // death sound fading - g_engfuncs.pfnFadeClientVolume( edict(), 99, 6.0f, 999999.0f, 0.0f ); - - m_iSndRoomtype = 15; - hearNeedsUpdate = 1; - - if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) - { - pev->solid = SOLID_NOT; - GibMonster(); // This clears pev->model - pev->effects |= EF_NODRAW; - return; - } - - DeathSound(); - - pev->angles.x = 0; - pev->angles.z = 0; - - SetThink(PlayerDeathThink); - SetNextThink( 0.1 ); -} - - -// Set the activity based on an event or current state -void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) -{ - int animDesired; - float speed; - char szAnim[64]; - - speed = pev->velocity.Length2D(); - - if( pev->flags & FL_FROZEN ) - { - speed = 0; - playerAnim = PLAYER_IDLE; - } - - switch( playerAnim ) - { - case PLAYER_JUMP: - m_IdealActivity = ACT_HOP; - break; - - case PLAYER_SUPERJUMP: - m_IdealActivity = ACT_LEAP; - break; - - case PLAYER_DIE: - m_IdealActivity = ACT_DIESIMPLE; - m_IdealActivity = GetDeathActivity( ); - break; - - case PLAYER_ATTACK1: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - break; - case PLAYER_IDLE: - case PLAYER_WALK: - if ( !FBitSet( pev->flags, FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) ) // Still jumping - { - m_IdealActivity = m_Activity; - } - else if ( pev->waterlevel > 1 && pev->watertype != CONTENTS_FOG ) - { - if ( speed == 0 ) - m_IdealActivity = ACT_HOVER; - else - m_IdealActivity = ACT_SWIM; - } - else - { - m_IdealActivity = ACT_WALK; - } - break; - } - - switch (m_IdealActivity) - { - case ACT_HOVER: - case ACT_LEAP: - case ACT_SWIM: - case ACT_HOP: - case ACT_DIESIMPLE: - default: - if ( m_Activity == m_IdealActivity) - return; - m_Activity = m_IdealActivity; - - animDesired = LookupActivity( m_Activity ); - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - pev->gaitsequence = 0; - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); - return; - - case ACT_RANGE_ATTACK1: - if ( FBitSet( pev->flags, FL_DUCKING ) ) // crouching - strcpy( szAnim, "crouch_shoot_" ); - else - strcpy( szAnim, "ref_shoot_" ); - strcat( szAnim, m_szAnimExtention ); - animDesired = LookupSequence( szAnim ); - if (animDesired == -1) - animDesired = 0; - - if ( pev->sequence != animDesired || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - if (!m_fSequenceLoops) - { - pev->effects |= EF_NOINTERP; - } - - m_Activity = m_IdealActivity; - - pev->sequence = animDesired; - ResetSequenceInfo( ); - break; - - case ACT_WALK: - if (m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished) - { - if ( FBitSet( pev->flags, FL_DUCKING ) ) // crouching - strcpy( szAnim, "crouch_aim_" ); - else - strcpy( szAnim, "ref_aim_" ); - strcat( szAnim, m_szAnimExtention ); - animDesired = LookupSequence( szAnim ); - if (animDesired == -1) - animDesired = 0; - m_Activity = ACT_WALK; - } - else - { - animDesired = pev->sequence; - } - } - - if ( FBitSet( pev->flags, FL_DUCKING ) ) - { - if ( speed == 0) - { - pev->gaitsequence = LookupActivity( ACT_CROUCHIDLE ); - // pev->gaitsequence = LookupActivity( ACT_CROUCH ); - } - else - { - pev->gaitsequence = LookupActivity( ACT_CROUCH ); - } - } - else if ( speed > 220 ) - { - pev->gaitsequence = LookupActivity( ACT_RUN ); - } - else if (speed > 0) - { - pev->gaitsequence = LookupActivity( ACT_WALK ); - } - else - { - // pev->gaitsequence = LookupActivity( ACT_WALK ); - pev->gaitsequence = LookupSequence( "deep_idle" ); - } - - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - //ALERT( at_console, "Set animation to %d\n", animDesired ); - // Reset to first frame of desired animation - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); -} - - -/* -=========== -WaterMove -============ -*/ -#define AIRTIME 12 // lung full of air lasts this many seconds - -void CBasePlayer::WaterMove() -{ - int air; - - if (pev->movetype == MOVETYPE_NOCLIP) - return; - - if (pev->health < 0) - return; - - // waterlevel 0 - not in water - // waterlevel 1 - feet in water - // waterlevel 2 - waist in water - // waterlevel 3 - head in water - - if (pev->waterlevel != 3 || pev->watertype <= CONTENTS_FLYFIELD ) - { - // not underwater - - // play 'up for air' sound - if (m_fAirFinished < gpGlobals->time) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", 1, ATTN_NORM); - else if (m_fAirFinished < gpGlobals->time + 9) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", 1, ATTN_NORM); - - m_fAirFinished = gpGlobals->time + AIRTIME; - pev->dmg = 2; - - // if we took drowning damage, give it back slowly - if (m_idrowndmg > m_idrownrestored) - { - // set drowning damage bit. hack - dmg_drownrecover actually - // makes the time based damage code 'give back' health over time. - // make sure counter is cleared so we start count correctly. - - // NOTE: this actually causes the count to continue restarting - // until all drowning damage is healed. - - m_bitsDamageType |= DMG_DROWNRECOVER; - m_bitsDamageType &= ~DMG_DROWN; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - } - - } - else if (pev->watertype > CONTENTS_FLYFIELD) // FLYFIELD, FLYFIELD_GRAVITY & FOG aren't really water... - { // fully under water - // stop restoring damage while underwater - m_bitsDamageType &= ~DMG_DROWNRECOVER; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - - if (m_fAirFinished < gpGlobals->time) // drown! - { - if (m_fPainFinished < gpGlobals->time) - { - // take drowning damage - pev->dmg += 1; - if (pev->dmg > 5) - pev->dmg = 5; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), pev->dmg, DMG_DROWN); - m_fPainFinished = gpGlobals->time + 1; - - // track drowning damage, give it back when - // player finally takes a breath - - m_idrowndmg += pev->dmg; - } - } - else - { - m_bitsDamageType &= ~DMG_DROWN; - } - } - - if (!pev->waterlevel || pev->watertype <= CONTENTS_FLYFIELD ) - { - if (FBitSet(pev->flags, FL_INWATER)) - { - ClearBits(pev->flags, FL_INWATER); - } - return; - } - - // make bubbles - - air = (int)(m_fAirFinished - gpGlobals->time); - if (!RANDOM_LONG(0,0x1f) && RANDOM_LONG(0,AIRTIME-1) >= air) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim1.wav", 0.8, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 0.8, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim3.wav", 0.8, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim4.wav", 0.8, ATTN_NORM); break; - } - } - - if( pev->watertype == CONTENTS_LAVA ) // do damage - { - if (pev->dmgtime < gpGlobals->time) - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 10 * pev->waterlevel, DMG_BURN); - } - else if( pev->watertype == CONTENTS_SLIME ) // do damage - { - pev->dmgtime = gpGlobals->time + 1; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 4 * pev->waterlevel, DMG_ACID); - } - - if (!FBitSet( pev->flags, FL_INWATER )) - { - SetBits( pev->flags, FL_INWATER ); - pev->dmgtime = 0; - } -} - -// TRUE if the player is attached to a ladder -BOOL CBasePlayer::IsOnLadder( void ) -{ - return ( pev->movetype == MOVETYPE_FLY ); -} - -void CBasePlayer::PlayerDeathThink(void) -{ - float flForward; - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - flForward = pev->velocity.Length() - 20; - if (flForward <= 0) - pev->velocity = g_vecZero; - else - pev->velocity = flForward * pev->velocity.Normalize(); - } - - if ( HasWeapons() ) - { - // we drop the guns here because weapons that have an area effect and can kill their user - // will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the - // player class sometimes is freed. It's safer to manipulate the weapons once we know - // we aren't calling into any of their code anymore through the player pointer. - PackDeadPlayerItems(); - } - - // disable redeemer HUD - MESSAGE_BEGIN( MSG_ONE, gmsg.WarHUD, NULL, pev ); - WRITE_BYTE( 0 ); - MESSAGE_END(); - - if( pev->modelindex && (!m_fSequenceFinished) && ( pev->deadflag == DEAD_DYING )) - { - StudioFrameAdvance( ); - - m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands - if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this - return; - } - - // once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore - // this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn - if ( pev->movetype != MOVETYPE_NONE && FBitSet( pev->flags, FL_ONGROUND )) - pev->movetype = MOVETYPE_NONE; - - if ( pev->deadflag == DEAD_DYING ) - pev->deadflag = DEAD_DEAD; - - StopAnimation(); - - pev->effects |= EF_NOINTERP; - pev->framerate = 0.0; - - BOOL fAnyButtonDown = (pev->button & ~IN_SCORE ); - - // wait for all buttons released - if (pev->deadflag == DEAD_DEAD) - { - if (fAnyButtonDown) - return; - - if ( g_pGameRules->FPlayerCanRespawn( this ) ) - { - m_fDeadTime = gpGlobals->time; - pev->deadflag = DEAD_RESPAWNABLE; - } - - return; - } - -// if the player has been dead for one second longer than allowed by forcerespawn, -// forcerespawn isn't on. Send the player off to an intermission camera until they -// choose to respawn. - if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) ) - { - // go to dead camera. - StartDeathCam(); - } - -// wait for any button down, or mp_forcerespawn is set and the respawn time is up - if (!fAnyButtonDown - && !( g_pGameRules->IsMultiplayer() && CVAR_GET_FLOAT( "mp_forcerespawn" ) > 0 && (gpGlobals->time > (m_fDeadTime + 5))) ) - return; - - pev->button = 0; - m_iRespawnFrames = 0; - - //ALERT(at_console, "Respawn\n"); - - respawn(pev, !(m_afPhysicsFlags & PFLAG_OBSERVER) ); // don't copy a corpse if we're in deathcam. - DontThink(); -} - -//========================================================= -// StartDeathCam - find an intermission spot and send the -// player off into observer mode -//========================================================= -void CBasePlayer::StartDeathCam( void ) -{ - CBaseEntity *pSpot, *pNewSpot; - int iRand; - - if ( pev->view_ofs == g_vecZero ) - { - // don't accept subsequent attempts to StartDeathCam() - return; - } - - pSpot = UTIL_FindEntityByClassname( NULL, "info_intermission"); - - if ( pSpot ) - { - // at least one intermission spot in the world. - iRand = RANDOM_LONG( 0, 3 ); - - while ( iRand > 0 ) - { - pNewSpot = UTIL_FindEntityByTargetname( pSpot, "info_intermission"); - - if ( pNewSpot ) - { - pSpot = pNewSpot; - } - - iRand--; - } - - CopyToBodyQue( pev ); - StartObserver( pSpot->pev->origin, pSpot->pev->v_angle ); - } - else - { - // no intermission spot. Push them up in the air, looking down at their corpse - TraceResult tr; - CopyToBodyQue( pev ); - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); - StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); - return; - } -} - -void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) -{ - m_afPhysicsFlags |= PFLAG_OBSERVER; - - pev->view_ofs = g_vecZero; - pev->angles = pev->v_angle = vecViewAngle; - pev->fixangle = TRUE; - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - pev->movetype = MOVETYPE_NONE; - pev->modelindex = 0; - UTIL_SetOrigin( this, vecPosition ); -} - -// -// PlayerUse - handles USE keypress -// -#define PLAYER_SEARCH_RADIUS (float)64 - -void CBasePlayer::PlayerUse ( void ) -{ - // Was use pressed or released? - if ( ! ((pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) - return; - - // Hit Use on a train? - if ( m_afButtonPressed & IN_USE ) - { - if ( m_pTank != NULL ) - { - // Stop controlling the tank - // TODO: Send HUD Update - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - return; - } - else if (m_pMonitor != NULL ) - { - m_pMonitor->Use( this, this, USE_SET, 1 ); - m_pMonitor = NULL; - return; - } - else - { - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - else - { // Start controlling the train! - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - - if ( pTrain && !(pev->button & IN_JUMP) && FBitSet(pev->flags, FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(pev) ) - { - m_afPhysicsFlags |= PFLAG_ONTRAIN; - m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); - m_iTrain |= TRAIN_NEW; - EMIT_SOUND( ENT(pev), CHAN_ITEM, "trains/train_use1.wav", 0.8, ATTN_NORM); - return; - } - } - } - } - - CBaseEntity *pObject = NULL; - CBaseEntity *pClosest = NULL; - Vector vecLOS; - float flMaxDot = VIEW_FIELD_NARROW; - float flDot; - TraceResult tr; - int caps; - - UTIL_MakeVectors ( pev->v_angle );// so we know which way we are facing - - //LRC- try to get an exact entity to use. - // (is this causing "use-buttons-through-walls" problems? Surely not!) - UTIL_TraceLine( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + (gpGlobals->v_forward * PLAYER_SEARCH_RADIUS), dont_ignore_monsters, ENT(pev), &tr ); - if (tr.pHit) - { - pObject = CBaseEntity::Instance(tr.pHit); - if (!pObject || !(pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE))) - { - pObject = NULL; - } - } - - if (!pObject) //LRC- couldn't find a direct solid object to use, try the normal method - { - while ((pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS )) != NULL) - { - caps = pObject->ObjectCaps(); - if (caps & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE) && !(caps & FCAP_ONLYDIRECT_USE)) //LRC - we can't see 'direct use' entities in this section - { - // !!!PERFORMANCE- should this check be done on a per case basis AFTER we've determined that - // this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS - // when player hits the use key. How many objects can be in that area, anyway? (sjb) - vecLOS = (VecBModelOrigin( pObject->pev ) - (pev->origin + pev->view_ofs)); - -// ALERT(at_console, "absmin %f %f %f, absmax %f %f %f, mins %f %f %f, maxs %f %f %f, size %f %f %f\n", pObject->pev->absmin.x, pObject->pev->absmin.y, pObject->pev->absmin.z, pObject->pev->absmax.x, pObject->pev->absmax.y, pObject->pev->absmax.z, pObject->pev->mins.x, pObject->pev->mins.y, pObject->pev->mins.z, pObject->pev->maxs.x, pObject->pev->maxs.y, pObject->pev->maxs.z, pObject->pev->size.x, pObject->pev->size.y, pObject->pev->size.z);//LRCTEMP - // This essentially moves the origin of the target to the corner nearest the player to test to see - // if it's "hull" is in the view cone - vecLOS = UTIL_ClampVectorToBox( vecLOS, pObject->pev->size * 0.5 ); - - flDot = DotProduct (vecLOS , gpGlobals->v_forward); - if (flDot > flMaxDot || vecLOS == g_vecZero ) // LRC - if the player is standing inside this entity, it's also ok to use it. - {// only if the item is in front of the user - pClosest = pObject; - flMaxDot = flDot; -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } - } - pObject = pClosest; - } - - // Found an object - if (pObject ) - { - //!!!UNDONE: traceline here to prevent USEing buttons through walls - caps = pObject->ObjectCaps(); - - if ( m_afButtonPressed & IN_USE ) - EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM); - - if ( ( (pev->button & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || - ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) - { - if ( caps & FCAP_CONTINUOUS_USE ) - m_afPhysicsFlags |= PFLAG_USING; - - pObject->Use( this, this, USE_SET, 1 ); - } - // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away - // (actually, nothing uses on/off. They're either continuous - rechargers and momentary - // buttons - or they're impulse - buttons, doors, tanks, trains, etc.) --LRC - else if ( (m_afButtonReleased & IN_USE) && (pObject->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use - { - pObject->Use( this, this, USE_SET, 0 ); - } - } - else - { - if ( m_afButtonPressed & IN_USE ) - EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_denyselect.wav", 0.4, ATTN_NORM); - } -} - - - -void CBasePlayer :: Jump( void ) -{ - Vector vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping - Vector vecAdjustedVelocity; - Vector vecSpot; - TraceResult tr; - - if( FBitSet( pev->flags, FL_WATERJUMP )) - return; - - if( pev->waterlevel >= 2 && pev->watertype != CONTENTS_FOG ) - { - return; - } - - // jump velocity is sqrt( height * gravity * 2) - - // If this isn't the first frame pressing the jump button, break out. - if ( !FBitSet( m_afButtonPressed, IN_JUMP ) ) - return; // don't pogo stick - - if ( !(pev->flags & FL_ONGROUND) || !pev->groundentity ) - { - return; - } - - // many features in this function use v_forward, so makevectors now. - UTIL_MakeVectors (pev->angles); - - // ClearBits(pev->flags, FL_ONGROUND);// don't stairwalk - - SetAnimation( PLAYER_JUMP ); - - if( m_fLongJump && ( pev->button & IN_DUCK ) && ( pev->flDuckTime > 0 ) && pev->velocity.Length() > 50 ) - { - SetAnimation( PLAYER_SUPERJUMP ); - } - - // If you're standing on a conveyor, add its velocity to yours (for momentum) - entvars_t *pevGround = VARS(pev->groundentity); - if ( pevGround && (pevGround->flags & FL_CONVEYOR) ) - { - pev->velocity = pev->velocity + pev->basevelocity; - } -} - - - -// This is a glorious hack to find free space when you've crouched into some solid space -// Our crouching collisions do not work correctly for some reason and this is easier -// than fixing the problem :( -void FixPlayerCrouchStuck( edict_t *pPlayer ) -{ - TraceResult trace; - - // Move up as many as 18 pixels if the player is stuck. - for ( int i = 0; i < 18; i++ ) - { - UTIL_TraceHull( pPlayer->v.origin, pPlayer->v.origin, dont_ignore_monsters, head_hull, pPlayer, &trace ); - if ( trace.fStartSolid ) - pPlayer->v.origin.z ++; - else - break; - } -} - -void CBasePlayer::Duck( ) -{ - if (pev->button & IN_DUCK) - { - if ( m_IdealActivity != ACT_LEAP ) - { - SetAnimation( PLAYER_WALK ); - } - } -} - - -// -// ID's player as such. -// -int CBasePlayer::Classify ( void ) -{ - return CLASS_PLAYER; -} - - -void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) -{ - // Positive score always adds - if ( score < 0 ) - { - if ( !bAllowNegativeScore ) - { - if ( pev->frags < 0 ) // Can't go more negative - return; - - if ( -score > pev->frags ) // Will this go negative? - { - score = -pev->frags; // Sum will be 0 - } - } - } - - pev->frags += score; - - MESSAGE_BEGIN( MSG_ALL, gmsg.ScoreInfo ); - WRITE_BYTE( ENTINDEX(edict()) ); - WRITE_SHORT( pev->frags ); - WRITE_SHORT( m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 ); - MESSAGE_END(); -} - - -void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) -{ - int index = entindex(); - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( pPlayer && i != index ) - { - if ( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE ) - { - pPlayer->AddPoints( score, bAllowNegativeScore ); - } - } - } -} - -//Player ID -void CBasePlayer::InitStatusBar() -{ - m_flStatusBarDisappearDelay = 0; - m_SbarString1[0] = m_SbarString0[0] = 0; -} - -void CBasePlayer::UpdateStatusBar() -{ - int newSBarState[ SBAR_END ]; - char sbuf0[ SBAR_STRING_SIZE ]; - char sbuf1[ SBAR_STRING_SIZE ]; - - memset( newSBarState, 0, sizeof(newSBarState) ); - strcpy( sbuf0, m_SbarString0 ); - strcpy( sbuf1, m_SbarString1 ); - - // Find an ID Target - TraceResult tr; - UTIL_MakeVectors( pev->v_angle + pev->punchangle ); - Vector vecSrc = EyePosition(); - Vector vecEnd = vecSrc + (gpGlobals->v_forward * MAX_ID_RANGE); - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr); - - if (tr.flFraction != 1.0) - { - if ( !FNullEnt( tr.pHit ) ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if (pEntity->Classify() == CLASS_PLAYER ) - { - newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); - strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" ); - - // allies and medics get to see the targets health - if ( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE ) - { - newSBarState[ SBAR_ID_TARGETHEALTH ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); - newSBarState[ SBAR_ID_TARGETARMOR ] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max. - } - - m_flStatusBarDisappearDelay = gpGlobals->time + 1.0; - } - } - else if ( m_flStatusBarDisappearDelay > gpGlobals->time ) - { - // hold the values for a short amount of time after viewing the object - newSBarState[ SBAR_ID_TARGETNAME ] = m_izSBarState[ SBAR_ID_TARGETNAME ]; - newSBarState[ SBAR_ID_TARGETHEALTH ] = m_izSBarState[ SBAR_ID_TARGETHEALTH ]; - newSBarState[ SBAR_ID_TARGETARMOR ] = m_izSBarState[ SBAR_ID_TARGETARMOR ]; - } - } - - BOOL bForceResend = FALSE; - - if ( strcmp( sbuf0, m_SbarString0 ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.StatusText, NULL, pev ); - WRITE_BYTE( 0 ); - WRITE_STRING( sbuf0 ); - MESSAGE_END(); - - strcpy( m_SbarString0, sbuf0 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - if ( strcmp( sbuf1, m_SbarString1 ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.StatusText, NULL, pev ); - WRITE_BYTE( 1 ); - WRITE_STRING( sbuf1 ); - MESSAGE_END(); - - strcpy( m_SbarString1, sbuf1 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - // Check values and send if they don't match - for (int i = 1; i < SBAR_END; i++) - { - if ( newSBarState[i] != m_izSBarState[i] || bForceResend ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.StatusValue, NULL, pev ); - WRITE_BYTE( i ); - WRITE_SHORT( newSBarState[i] ); - MESSAGE_END(); - - m_izSBarState[i] = newSBarState[i]; - } - } -} - - - - - - - - - -#define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing -#define MAX_CLIMB_SPEED 200 // fastest vertical climbing speed possible -#define CLIMB_SPEED_DEC 15 // climbing deceleration rate -#define CLIMB_PUNCH_X -7 // how far to 'punch' client X axis when climbing -#define CLIMB_PUNCH_Z 7 // how far to 'punch' client Z axis when climbing - -void CBasePlayer::PreThink(void) -{ - int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame - - // Debounced button codes for pressed/released - // UNDONE: Do we need auto-repeat? - m_afButtonPressed = buttonsChanged & pev->button; // The ones that changed and are now down are "pressed" - m_afButtonReleased = buttonsChanged & (~pev->button); // The ones that changed and aren't down are "released" - - g_pGameRules->PlayerThink( this ); - - if ( g_fGameOver ) - return; // intermission or finale - - UTIL_MakeVectors(pev->v_angle); // is this still used? - - ItemPreFrame( ); - WaterMove(); - - if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) - m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; - else - m_iHideHUD |= HIDEHUD_FLASHLIGHT; - - - // JOHN: checks if new client data (for HUD and view control) needs to be sent to the client - UpdateClientData(); - - CheckTimeBasedDamage(); - - CheckSuitUpdate(); - - if (pev->deadflag >= DEAD_DYING) - { - PlayerDeathThink(); - return; - } - - // So the correct flags get sent to client asap. - // - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - pev->flags |= FL_ONTRAIN; - else - pev->flags &= ~FL_ONTRAIN; - - // Train speed control - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - float vel; - - if ( !pTrain ) - { - TraceResult trainTrace; - // Maybe this is on the other side of a level transition - UTIL_TraceLine( pev->origin, pev->origin + Vector(0,0,-38), ignore_monsters, ENT(pev), &trainTrace ); - - // HACKHACK - Just look for the func_tracktrain classname - if ( trainTrace.flFraction != 1.0 && trainTrace.pHit ) - pTrain = CBaseEntity::Instance( trainTrace.pHit ); - - - if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(pev) ) - { - //ALERT( at_error, "In train mode with no train!\n" ); - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - } - else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, 0x2 ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) ) - { - // Turn off the train if you jump, strafe, or the train controls go dead - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - - pev->velocity = g_vecZero; - vel = 0; - if ( m_afButtonPressed & IN_FORWARD ) - { - vel = 1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - else if ( m_afButtonPressed & IN_BACK ) - { - vel = -1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - - if (vel) - { - m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); - m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; - } - - } else if (m_iTrain & TRAIN_ACTIVE) - m_iTrain = TRAIN_NEW; // turn off train - - if( pev->button & IN_JUMP ) - { - // If on a ladder, jump off the ladder - // else Jump - Jump(); - } - - - // If trying to duck, already ducked, or in the process of ducking - if ((pev->button & IN_DUCK) || FBitSet( pev->flags, FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) ) - Duck(); - - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) - { - m_flFallVelocity = -pev->velocity.z; - } - - // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? - - // Clear out ladder pointer - m_hEnemy = NULL; - - if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) - { - pev->velocity = g_vecZero; - } -} -/* Time based Damage works as follows: - 1) There are several types of timebased damage: - - #define DMG_PARALYZE (1 << 14) // slows affected creature down - #define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad - #define DMG_POISON (1 << 16) // blood poisioning - #define DMG_RADIATION (1 << 17) // radiation exposure - #define DMG_DROWNRECOVER (1 << 18) // drown recovery - #define DMG_ACID (1 << 19) // toxic chemicals or acid burns - #define DMG_SLOWBURN (1 << 20) // in an oven - #define DMG_SLOWFREEZE (1 << 21) // in a subzero freezer - #define DMG_NUCLEAR (1 << 24) - - 2) A new hit inflicting tbd restarts the tbd counter - each monster has an 8bit counter, - per damage type. The counter is decremented every second, so the maximum time - an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius - of a damaging effect like fire, nervegas, radiation will continually reset the counter to max. - - 3) Every second that a tbd counter is running, the player takes damage. The damage - is determined by the type of tdb. - Paralyze - 1/2 movement rate, 30 second duration. - Nervegas - 5 points per second, 16 second duration = 80 points max dose. - Poison - 2 points per second, 25 second duration = 50 points max dose. - Radiation - 1 point per second, 50 second duration = 50 points max dose. - Drown - 5 points per second, 2 second duration. - Acid/Chemical - 5 points per second, 10 second duration = 50 points max. - Burn - 10 points per second, 2 second duration. - Freeze - 3 points per second, 10 second duration = 30 points max. - - 4) Certain actions or countermeasures counteract the damaging effects of tbds: - - Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body - - recharged by suit recharger - Air In Lungs - drowning damage is done to air in lungs first, then to body - - recharged by poking head out of water - - 10 seconds if swiming fast - Air In SCUBA - drowning damage is done to air in tanks first, then to body - - 2 minutes in tanks. Need new tank once empty. - Radiation Syringe - Each syringe full provides protection vs one radiation dosage - Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison). - Health kit - Immediate stop to acid/chemical, fire or freeze damage. - Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage. - - -*/ - -// If player is taking time based damage, continue doing damage to player - -// this simulates the effect of being poisoned, gassed, dosed with radiation etc - -// anything that continues to do damage even after the initial contact stops. -// Update all time based damage counters, and shut off any that are done. - -// The m_bitsDamageType bit MUST be set if any damage is to be taken. -// This routine will detect the initial on value of the m_bitsDamageType -// and init the appropriate counter. Only processes damage every second. - -//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage -//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval - -//#define NERVEGAS_DURATION 16 -//#define NERVEGAS_DAMAGE 5.0 - -//#define POISON_DURATION 25 -//#define POISON_DAMAGE 2.0 - -//#define RADIATION_DURATION 50 -//#define RADIATION_DAMAGE 1.0 - -//#define ACID_DURATION 10 -//#define ACID_DAMAGE 5.0 - -//#define SLOWBURN_DURATION 2 -//#define SLOWBURN_DAMAGE 1.0 - -//#define SLOWFREEZE_DURATION 1.0 -//#define SLOWFREEZE_DAMAGE 3.0 - -/* */ - - -void CBasePlayer::CheckTimeBasedDamage() -{ - int i; - byte bDuration = 0; - - static float gtbdPrev = 0.0; - - if (!(m_bitsDamageType & DMG_TIMEBASED)) - return; - - // only check for time based damage approx. every 2 seconds - if (abs(gpGlobals->time - m_tbdPrev) < 2.0) - return; - - m_tbdPrev = gpGlobals->time; - - for (i = 0; i < CDMG_TIMEBASED; i++) - { - // make sure bit is set for damage type - if (m_bitsDamageType & (DMG_PARALYZE << i)) - { - switch (i) - { - case itbd_Paralyze: - // UNDONE - flag movement as half-speed - bDuration = PARALYZE_DURATION; - break; - case itbd_NerveGas: -// TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC); - bDuration = NERVEGAS_DURATION; - break; - case itbd_Poison: - TakeDamage(pev, pev, POISON_DAMAGE, DMG_GENERIC); - bDuration = POISON_DURATION; - break; - case itbd_Radiation: -// TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); - bDuration = RADIATION_DURATION; - break; - case itbd_DrownRecover: - // NOTE: this hack is actually used to RESTORE health - // after the player has been drowning and finally takes a breath - if (m_idrowndmg > m_idrownrestored) - { - int idif = min(m_idrowndmg - m_idrownrestored, 10); - - TakeHealth(idif, DMG_GENERIC); - m_idrownrestored += idif; - } - bDuration = 4; // get up to 5*10 = 50 points back - break; - case itbd_Acid: -// TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC); - bDuration = ACID_DURATION; - break; - case itbd_SlowBurn: -// TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); - bDuration = SLOWBURN_DURATION; - break; - case itbd_SlowFreeze: -// TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); - bDuration = SLOWFREEZE_DURATION; - break; - default: - bDuration = 0; - } - - if (m_rgbTimeBasedDamage[i]) - { - // decrement damage duration, detect when done. - if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0) - { - m_rgbTimeBasedDamage[i] = 0; - // if we're done, clear damage bits - m_bitsDamageType &= ~(DMG_PARALYZE << i); - } - } - else - // first time taking this damage type - init damage duration - m_rgbTimeBasedDamage[i] = bDuration; - } - } -} - -/* -THE POWER SUIT - -The Suit provides 3 main functions: Protection, Notification and Augmentation. -Some functions are automatic, some require power. -The player gets the suit shortly after getting off the train in C1A0 and it stays -with him for the entire game. - -Protection - - Heat/Cold - When the player enters a hot/cold area, the heating/cooling indicator on the suit - will come on and the battery will drain while the player stays in the area. - After the battery is dead, the player starts to take damage. - This feature is built into the suit and is automatically engaged. - Radiation Syringe - This will cause the player to be immune from the effects of radiation for N seconds. Single use item. - Anti-Toxin Syringe - This will cure the player from being poisoned. Single use item. - Health - Small (1st aid kits, food, etc.) - Large (boxes on walls) - Armor - The armor works using energy to create a protective field that deflects a - percentage of damage projectile and explosive attacks. After the armor has been deployed, - it will attempt to recharge itself to full capacity with the energy reserves from the battery. - It takes the armor N seconds to fully charge. - -Notification (via the HUD) - -x Health -x Ammo -x Automatic Health Care - Notifies the player when automatic healing has been engaged. -x Geiger counter - Classic Geiger counter sound and status bar at top of HUD - alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal. -x Poison - Armor - Displays the current level of armor. - -Augmentation - - Reanimation (w/adrenaline) - Causes the player to come back to life after he has been dead for 3 seconds. - Will not work if player was gibbed. Single use. - Long Jump - Used by hitting the ??? key(s). Caused the player to further than normal. - SCUBA - Used automatically after picked up and after player enters the water. - Works for N seconds. Single use. - -Things powered by the battery - - Armor - Uses N watts for every M units of damage. - Heat/Cool - Uses N watts for every second in hot/cold area. - Long Jump - Uses N watts for every jump. - Alien Cloak - Uses N watts for each use. Each use lasts M seconds. - Alien Shield - Augments armor. Reduces Armor drain by one half - -*/ - -// if in range of radiation source, ping geiger counter - -#define GEIGERDELAY 0.25 - -void CBasePlayer :: UpdateGeigerCounter( void ) -{ - byte range; - - // delay per update ie: don't flood net with these msgs - if (gpGlobals->time < m_flgeigerDelay) - return; - - m_flgeigerDelay = gpGlobals->time + GEIGERDELAY; - - // send range to radition source to client - - range = (byte) (m_flgeigerRange / 4); - - if (range != m_igeigerRangePrev) - { - m_igeigerRangePrev = range; - - MESSAGE_BEGIN( MSG_ONE, gmsg.GeigerRange, NULL, pev ); - WRITE_BYTE( range ); - MESSAGE_END(); - } - - // reset counter and semaphore - if (!RANDOM_LONG(0,3)) - m_flgeigerRange = 1000; - -} - -/* -================ -CheckSuitUpdate - -Play suit update if it's time -================ -*/ - -#define SUITUPDATETIME 3.5 -#define SUITFIRSTUPDATETIME 0.1 - -void CBasePlayer::CheckSuitUpdate() -{ - int i; - int isentence = 0; - int isearch = m_iSuitPlayNext; - - // Ignore suit updates if no suit - if (!(pev->weapons & ITEM_SUIT)) - return; - - // if in range of radiation source, ping geiger counter - UpdateGeigerCounter(); - - if ( g_pGameRules->IsMultiplayer() ) - { - // don't bother updating HEV voice in multiplayer. - return; - } - - if ( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0) - { - // play a sentence off of the end of the queue - for (i = 0; i < CSUITPLAYLIST; i++) - { - if (isentence = m_rgSuitPlayList[isearch]) - break; - - if (++isearch == CSUITPLAYLIST) - isearch = 0; - } - - if (isentence) - { - m_rgSuitPlayList[isearch] = 0; - if (isentence > 0) - { - // play sentence number - - char sentence[CBSENTENCENAME_MAX+1]; - strcpy(sentence, "!"); - strcat(sentence, gszallsentencenames[isentence]); - EMIT_SOUND_SUIT(ENT(pev), sentence); - } - else - { - // play sentence group - EMIT_GROUPID_SUIT(ENT(pev), -isentence); - } - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - else - // queue is empty, don't check - m_flSuitUpdate = 0; - } -} - -// add sentence to suit playlist queue. if fgroup is true, then -// name is a sentence group (HEV_AA), otherwise name is a specific -// sentence name ie: !HEV_AA0. If iNoRepeat is specified in -// seconds, then we won't repeat playback of this word or sentence -// for at least that number of seconds. - -void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) -{ - int i; - int isentence; - int iempty = -1; - - - // Ignore suit updates if no suit - if (!(pev->weapons & ITEM_SUIT)) - return; - - if ( g_pGameRules->IsMultiplayer() ) - { - // due to static channel design, etc. We don't play HEV sounds in multiplayer right now. - return; - } - - // if name == NULL, then clear out the queue - - if (!name) - { - for (i = 0; i < CSUITPLAYLIST; i++) - m_rgSuitPlayList[i] = 0; - return; - } - // get sentence or group number - if (!fgroup) - { - isentence = SENTENCEG_Lookup( name, NULL ); - if( isentence < 0 ) - { - ALERT( at_console, "HEV couldn't find sentence %s\n", name ); - return; - } - } - else - // mark group number as negative - isentence = -SENTENCEG_GetIndex(name); - - // check norepeat list - this list lets us cancel - // the playback of words or sentences that have already - // been played within a certain time. - - for (i = 0; i < CSUITNOREPEAT; i++) - { - if (isentence == m_rgiSuitNoRepeat[i]) - { - // this sentence or group is already in - // the norepeat list - - if (m_rgflSuitNoRepeatTime[i] < gpGlobals->time) - { - // norepeat time has expired, clear it out - m_rgiSuitNoRepeat[i] = 0; - m_rgflSuitNoRepeatTime[i] = 0.0; - iempty = i; - break; - } - else - { - // don't play, still marked as norepeat - return; - } - } - // keep track of empty slot - if (!m_rgiSuitNoRepeat[i]) - iempty = i; - } - - // sentence is not in norepeat list, save if norepeat time was given - - if (iNoRepeatTime) - { - if (iempty < 0) - iempty = RANDOM_LONG(0, CSUITNOREPEAT-1); // pick random slot to take over - m_rgiSuitNoRepeat[iempty] = isentence; - m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->time; - } - - // find empty spot in queue, or overwrite last spot - - m_rgSuitPlayList[m_iSuitPlayNext++] = isentence; - if (m_iSuitPlayNext == CSUITPLAYLIST) - m_iSuitPlayNext = 0; - - if (m_flSuitUpdate <= gpGlobals->time) - { - if (m_flSuitUpdate == 0) - // play queue is empty, don't delay too long before playback - m_flSuitUpdate = gpGlobals->time + SUITFIRSTUPDATETIME; - else - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - -} - -/* -================ -CheckPowerups - -Check for turning off powerups - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -================ -*/ -static void CheckPowerups( entvars_t *pev ) -{ - if( pev->health <= 0 ) - return; - pev->modelindex = g_ulModelIndexPlayer; // don't use eyes -} - - -//========================================================= -// UpdatePlayerSound - updates the position of the player's -// reserved sound slot in the sound list. -//========================================================= -void CBasePlayer :: UpdatePlayerSound ( void ) -{ - int iBodyVolume; - int iVolume; - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt :: ClientSoundIndex( edict() ) ); - - if( !pSound ) - { - ALERT ( at_console, "Client lost reserved sound!\n" ); - return; - } - - pSound->m_iType = bits_SOUND_NONE; - - // now calculate the best target volume for the sound. If the player's weapon - // is louder than his body/movement, use the weapon volume, else, use the body volume. - - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - iBodyVolume = pev->velocity.Length(); - - // clamp the noise that can be made by the body, in case a push trigger, - // weapon recoil, or anything shoves the player abnormally fast. - if ( iBodyVolume > 512 ) - { - iBodyVolume = 512; - } - } - else - { - iBodyVolume = 0; - } - - if ( pev->button & IN_JUMP ) - { - iBodyVolume += 100; - } - -// convert player move speed and actions into sound audible by monsters. - if ( m_iWeaponVolume > iBodyVolume ) - { - m_iTargetVolume = m_iWeaponVolume; - - // OR in the bits for COMBAT sound if the weapon is being louder than the player. - pSound->m_iType |= bits_SOUND_COMBAT; - } - else - { - m_iTargetVolume = iBodyVolume; - } - - // decay weapon volume over time so bits_SOUND_COMBAT stays set for a while - m_iWeaponVolume -= 250 * gpGlobals->frametime; - if ( m_iWeaponVolume < 0 ) - { - iVolume = 0; - } - - - // if target volume is greater than the player sound's current volume, we paste the new volume in - // immediately. If target is less than the current volume, current volume is not set immediately to the - // lower volume, rather works itself towards target volume over time. This gives monsters a much better chance - // to hear a sound, especially if they don't listen every frame. - iVolume = pSound->m_iVolume; - - if ( m_iTargetVolume > iVolume ) - { - iVolume = m_iTargetVolume; - } - else if ( iVolume > m_iTargetVolume ) - { - iVolume -= 250 * gpGlobals->frametime; - - if ( iVolume < m_iTargetVolume ) - { - iVolume = 0; - } - } - - if ( m_fNoPlayerSound ) - { - // debugging flag, lets players move around and shoot without monsters hearing. - iVolume = 0; - } - - if ( gpGlobals->time > m_flStopExtraSoundTime ) - { - // since the extra sound that a weapon emits only lasts for one client frame, we keep that sound around for a server frame or two - // after actual emission to make sure it gets heard. - m_iExtraSoundTypes = 0; - } - - if ( pSound ) - { - pSound->m_vecOrigin = pev->origin; - pSound->m_iType |= ( bits_SOUND_PLAYER | m_iExtraSoundTypes ); - pSound->m_iVolume = iVolume; - } - - // keep track of virtual muzzle flash - m_iWeaponFlash -= 256 * gpGlobals->frametime; - if (m_iWeaponFlash < 0) - m_iWeaponFlash = 0; - - //UTIL_MakeVectors ( pev->angles ); - //gpGlobals->v_forward.z = 0; - - // Below are a couple of useful little bits that make it easier to determine just how much noise the - // player is making. - // UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * iVolume, g_vecZero, 255, 25 ); - //ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume ); -} - - -void CBasePlayer::PostThink() -{ - if ( g_fGameOver ) return; // intermission or finale - if ( !IsAlive () ) return; - - if ( m_pTank != NULL ) - { - if ( m_pTank->OnControls( pev ) && !pev->weaponmodel ); - else - { // they've moved off the platform - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - } - - if ( m_pMonitor != NULL ) - { - if ( !m_pMonitor->OnControls( pev ) ) - { // they've moved off the platform - m_pMonitor->Use( this, this, USE_SET, 1 ); - m_pMonitor = NULL; - } - } - - // do weapon stuff - ItemPostFrame( ); - -// check to see if player landed hard enough to make a sound -// falling farther than half of the maximum safe distance, but not as far a max safe distance will -// play a bootscrape sound, and no damage will be inflicted. Fallling a distance shorter than half -// of maximum safe distance will make no sound. Falling farther than max safe distance will play a -// fallpain sound, and damage will be inflicted based on how far the player fell - - if ( (FBitSet(pev->flags, FL_ONGROUND)) && (pev->health > 0) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) - { - // ALERT ( at_console, "%f\n", m_flFallVelocity ); - - if (pev->watertype == CONTENTS_WATER) - { - // Did he hit the world or a non-moving entity? - // BUG - this happens all the time in water, especially when - // BUG - water has current force - // if ( !pev->groundentity || VARS(pev->groundentity)->velocity.z == 0 ) - // EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); - } - else if ( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED ) - {// after this point, we start doing damage - - float flFallDamage = g_pGameRules->FlPlayerFallDamage( this ); - - if ( flFallDamage > pev->health ) - {//splat - // note: play on item channel because we play footstep landing on body channel - EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM); - } - - if ( flFallDamage > 0 ) - { - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); - pev->punchangle.x = 0; - } - } - - if ( IsAlive() ) - { - SetAnimation( PLAYER_WALK ); - } - } - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - if (m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer()) - { - CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, m_flFallVelocity, 0.2 ); - // ALERT( at_console, "fall %f\n", m_flFallVelocity ); - } - m_flFallVelocity = 0; - } - - // select the proper animation for the player character - if ( IsAlive() ) - { - if (!pev->velocity.x && !pev->velocity.y) - SetAnimation( PLAYER_IDLE ); - else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND))) - SetAnimation( PLAYER_WALK ); - else if (pev->waterlevel > 1) - SetAnimation( PLAYER_WALK ); - } - - StudioFrameAdvance( ); - CheckPowerups(pev); - - UpdatePlayerSound(); - - // Track button info so we can detect 'pressed' and 'released' buttons next frame - m_afButtonLast = pev->button; -} - - -// checks if the spot is clear of players -BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) -{ - CBaseEntity *ent = NULL; - - if ( pSpot->GetState( pPlayer ) != STATE_ON ) - { - return FALSE; - } - - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) - { - // if ent is a client, don't spawn on 'em - if ( ent->IsPlayer() && ent != pPlayer ) - return FALSE; - } - - return TRUE; -} - - -DLL_GLOBAL CBaseEntity *g_pLastSpawn; - -/* -============ -EntSelectSpawnPoint - -Returns the entity to spawn at - -USES AND SETS GLOBAL g_pLastSpawn -============ -*/ -edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) -{ - CBaseEntity *pSpot; - edict_t *player; - - player = pPlayer->edict(); - -// choose a info_player_deathmatch point - if (g_pGameRules->IsCoOp()) - { - pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_coop"); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_start"); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - } - else if ( g_pGameRules->IsDeathmatch() ) - { - pSpot = g_pLastSpawn; - // Randomize the start spot - for ( int i = RANDOM_LONG(1,5); i > 0; i-- ) - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - if ( FNullEnt( pSpot ) ) // skip over the null point - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - - CBaseEntity *pFirstSpot = pSpot; - - do - { - if ( pSpot ) - { - // check if pSpot is valid - if ( IsSpawnPointValid( pPlayer, pSpot ) ) - { - if ( pSpot->pev->origin == Vector( 0, 0, 0 ) ) - { - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - continue; - } - - // if so, go to pSpot - goto ReturnSpot; - } - } - // increment pSpot - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - } while ( pSpot != pFirstSpot ); // loop if we're not back to the start - - // we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there - if ( !FNullEnt( pSpot ) ) - { - CBaseEntity *ent = NULL; - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) - { - // if ent is a client, kill em (unless they are ourselves) - if ( ent->IsPlayer() && !(ent->edict() == player) ) - ent->TakeDamage( VARS(INDEXENT(0)), VARS(INDEXENT(0)), 300, DMG_GENERIC ); - } - goto ReturnSpot; - } - } - - // If startspot is set, (re)spawn there. - if ( FStringNull( gpGlobals->startspot ) || !strlen(STRING(gpGlobals->startspot))) - { - pSpot = UTIL_FindEntityByClassname(NULL, "info_player_start"); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - - // q3a maps doesn't contain info_player_start - pSpot = UTIL_FindEntityByClassname(NULL, "info_player_deathmatch"); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - } - else - { - pSpot = UTIL_FindEntityByTargetname( NULL, STRING(gpGlobals->startspot) ); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - } - -ReturnSpot: - if ( FNullEnt( pSpot ) ) - { - ALERT( at_error, "PutClientInServer: no info_player_start on level\n" ); - return INDEXENT(0); - } - - g_pLastSpawn = pSpot; - return pSpot->edict(); -} - -void CBasePlayer::Spawn( void ) -{ -// ALERT(at_console, "PLAYER spawns at time %f\n", gpGlobals->time); - - pev->classname = MAKE_STRING( "player" ); - pev->health = 100; - pev->armorvalue = 0; - pev->takedamage = DAMAGE_AIM; - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_WALK; - pev->max_health = pev->health; - pev->flags &= FL_PROXY; // keep proxy flag sey by engine - pev->flags |= FL_CLIENT; - m_fAirFinished = gpGlobals->time + 12; - pev->dmg = 2; // initial water damage - pev->effects = 0; - pev->deadflag = DEAD_NO; - pev->dmg_take = 0; - pev->dmg_save = 0; - pev->skin = atoi(g_engfuncs.pfnInfoKeyValue(g_engfuncs.pfnGetInfoKeyBuffer(edict()), "skin"));// XWider - pev->friction = 1.0; - pev->gravity = 1.0; - pev->renderfx = 0; - pev->rendercolor = g_vecZero; - pev->v_angle.z = 0; // cut off any camera rolling - pev->view_ofs = VEC_VIEW; - - m_bitsHUDDamage = -1; - m_bitsDamageType = 0; - m_afPhysicsFlags = 0; - m_fLongJump = FALSE; // no longjump module. - Rain_dripsPerSecond = 0; - Rain_windX = 0; - Rain_windY = 0; - Rain_randX = 0; - Rain_randY = 0; - Rain_ideal_dripsPerSecond = 0; - Rain_ideal_windX = 0; - Rain_ideal_windY = 0; - Rain_ideal_randX = 0; - Rain_ideal_randY = 0; - Rain_endFade = 0; - Rain_nextFadeUpdate = 0; - GiveOnlyAmmo = FALSE; - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - pev->fov = 90.0f; // init field of view. - //m_iAcessLevel = 2; - - m_flNextDecalTime = 0; // let this player decal as soon as he spawns. - m_flNextNuclearDamage = 0; - - m_flgeigerDelay = gpGlobals->time + 2.0; // wait a few seconds until user-defined message registrations - // are recieved by all clients - - m_flTimeStepSound = 0; - m_iStepLeft = 0; - m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them. - - m_bloodColor = BLOOD_COLOR_RED; - m_flNextAttack = UTIL_WeaponTimeBase(); - StartSneaking(); - - m_iFlashBattery = 0; - m_flFlashLightTime = 1; // force first message - -// dont let uninitialized value here hurt the player - m_flFallVelocity = 0; - - g_pGameRules->SetDefaultPlayerTeam( this ); - g_pGameRules->GetPlayerSpawnSpot( this ); - - SetObjectClass( ED_CLIENT ); - UTIL_SetModel( ENT( pev ), "models/player.mdl" ); - g_ulModelIndexPlayer = pev->modelindex; - pev->sequence = LookupActivity( ACT_IDLE ); - - if( FBitSet( pev->flags, FL_DUCKING )) - UTIL_SetSize( pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); - else UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX ); - - pViewEnt = 0; - viewFlags = 0; - Precache(); - m_HackedGunPos = Vector( 0, 32, 0 ); - - if( m_iPlayerSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Couldn't alloc player sound slot!\n" ); - } - - m_fNoPlayerSound = FALSE;// normal sound behavior. - - m_pLastItem = NULL; - m_fInitHUD = TRUE; - m_iClientHideHUD = -1; // force this to be recalculated - m_fWeapon = FALSE; - m_pClientActiveItem = NULL; - m_iClientBattery = -1; - - // reset all ammo values to 0 - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - m_rgAmmo[i] = 0; - m_rgAmmoLast[i] = 0; // client ammo values also have to be reset (the death hud clear messages does on the client side) - } - - m_lastx = m_lasty = 0; - - m_flNextChatTime = gpGlobals->time; - - g_pGameRules->PlayerSpawn( this ); -} - - -void CBasePlayer :: Precache( void ) -{ - // in the event that the player JUST spawned, and the level node graph - // was loaded, fix all of the node graph pointers before the game starts. - - // SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific) - // because they need to precache before any clients have connected - - // init geiger counter vars during spawn and each time - // we cross a level transition - - m_flgeigerRange = 1000; - m_igeigerRangePrev = 1000; - - m_bitsDamageType = 0; - m_bitsHUDDamage = -1; - GiveOnlyAmmo = FALSE; - - m_iClientBattery = -1; - - m_iTrain = TRAIN_NEW; - - // Make sure any necessary user messages have been registered - LinkUserMessages(); - viewNeedsUpdate = 1; - hearNeedsUpdate = 1; - fogNeedsUpdate = 1; - fadeNeedsUpdate = 1; - m_iClientWarHUD = -1; - - m_iUpdateTime = 5; // won't update for 1/2 a second - - if ( gInitHUD ) m_fInitHUD = TRUE; - rainNeedsUpdate = 1; - - // clear fade effects - if( IsMultiplayer( )) - { - m_FadeColor = Vector( 255, 255, 255 ); - m_FadeAlpha = 0; - m_iFadeFlags = 0; - m_flFadeTime = 0.0f; - m_flFadeHold = 0.0f; - fadeNeedsUpdate = TRUE; - } -} - - -int CBasePlayer::Save( CSave &save ) -{ - if ( !CBaseMonster::Save(save) ) - return 0; - - return save.WriteFields( "cPLAYER", "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); -} - - -// -// Marks everything as new so the player will resend this to the hud. -// -void CBasePlayer::RenewItems(void) -{ - -} - -int CBasePlayer::Restore( CRestore &restore ) -{ - if ( !CBaseMonster::Restore(restore) ) - return 0; - - int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); - - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - // landmark isn't present. - if( !pSaveData->fUseLandmark ) - { - ALERT( at_error, "No Landmark:%s\n", pSaveData->szLandmarkName ); - - // default to normal spawn - edict_t* pentSpawnSpot = EntSelectSpawnPoint( this ); - pev->origin = VARS( pentSpawnSpot )->origin + Vector( 0, 0, 1 ); - pev->v_angle = pev->angles = VARS( pentSpawnSpot )->angles; - } - - pev->v_angle.z = 0; // clear out roll - pev->angles = pev->v_angle; - pev->fixangle = TRUE; // turn this way immediately - - // Copied from spawn() for now - m_bloodColor = BLOOD_COLOR_RED; - - g_ulModelIndexPlayer = pev->modelindex; - - if( FBitSet( pev->flags, FL_DUCKING )) - { - // Use the crouch HACK - //FixPlayerCrouchStuck( edict() ); - // Don't need to do this with new player prediction code. - UTIL_SetSize( pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); - } - else - { - UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX ); - } - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - if ( m_fLongJump ) - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "1" ); - } - else - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - } - - RenewItems(); - - return status; -} - - - -void CBasePlayer::SelectNextItem( int iItem ) -{ - CBasePlayerWeapon *pItem; - - pItem = m_rgpPlayerItems[ iItem ]; - - if (!pItem) - return; - - if (pItem == m_pActiveItem) - { - // select the next one in the chain - pItem = m_pActiveItem->m_pNext; - if (! pItem) - { - return; - } - - CBasePlayerWeapon *pLast; - pLast = pItem; - while (pLast->m_pNext) - pLast = pLast->m_pNext; - - // relink chain - pLast->m_pNext = m_pActiveItem; - m_pActiveItem->m_pNext = NULL; - m_rgpPlayerItems[ iItem ] = pItem; - } - - ResetAutoaim( ); - - if (m_pActiveItem) m_pActiveItem->Holster( ); - QueueItem(pItem); - if (m_pActiveItem) m_pActiveItem->Deploy( ); -} - -void CBasePlayer::QueueItem(CBasePlayerWeapon *pItem) -{ - if(!m_pActiveItem)// no active weapon - { - m_pActiveItem = pItem; - return;// just set this item as active - } - else - { - m_pLastItem = m_pActiveItem; - m_pActiveItem = NULL;// clear current - } - m_pNextItem = pItem;// add item to queue -} - -void CBasePlayer::SelectItem(const char *pstr) -{ - if (!pstr) return; - - CBasePlayerWeapon *pItem = NULL; - for (int i = 0; i < MAX_ITEM_TYPES; i++) - { - if (m_rgpPlayerItems[i]) - { - pItem = m_rgpPlayerItems[i]; - - while (pItem) - { - if(FStrEq( STRING( pItem->pev->netname), pstr )) - break; - pItem = pItem->m_pNext; - } - } - - if (pItem) - break; - } - - if (!pItem) - return; - - - if (pItem == m_pActiveItem) - return; - - ResetAutoaim( ); - - if (m_pActiveItem) m_pActiveItem->Holster( ); - QueueItem(pItem); - if (m_pActiveItem) m_pActiveItem->Deploy( ); -} - - -void CBasePlayer::SelectLastItem(void) -{ - if (!m_pLastItem) - { - return; - } - - if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) - { - return; - } - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) m_pActiveItem->Holster( ); - QueueItem(m_pLastItem); - if (m_pActiveItem) m_pActiveItem->Deploy( ); -} - -//============================================== -// HasWeapons - do I have any weapons at all? -//============================================== -BOOL CBasePlayer::HasWeapons( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - return TRUE; - } - } - - return FALSE; -} - -void CBasePlayer::SelectPrevItem( int iItem ) -{ -} - - -const char *CBasePlayer::TeamID( void ) -{ - if ( pev == NULL ) // Not fully connected yet - return ""; - - // return their team name - return m_szTeamName; -} - -//========================================================= -// remove all items -//========================================================= -#define SF_REMOVE_SUIT 1 - -class CStripWeapons : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - CBasePlayer *pPlayer = NULL; - - if ( pActivator && pActivator->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pActivator; - } - else if ( !IsMultiplayer() ) - { - pPlayer = (CBasePlayer *)UTIL_PlayerByIndex( 1 ); - } - else - { - ALERT( at_warning, "%s: %s activator not player. Ignored.\n", STRING( pev->classname ), STRING( pev->targetname )); - return; - } - - if ( pPlayer ) pPlayer->RemoveAllItems( pev->spawnflags & SF_REMOVE_SUIT ); - if ( pev->spawnflags & SF_FIREONCE ) UTIL_Remove( this ); - } -}; -LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons ); - -class CRevertSaved : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MessageThink( void ); - void EXPORT LoadThink( void ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline float Duration( void ) { return pev->dmg_take; } - inline float HoldTime( void ) { return pev->dmg_save; } - inline float MessageTime( void ) { return m_messageTime; } - inline float LoadTime( void ) { return m_loadTime; } - - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } - inline void SetMessageTime( float time ) { m_messageTime = time; } - inline void SetLoadTime( float time ) { m_loadTime = time; } - -private: - float m_messageTime; - float m_loadTime; -}; - -LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ); - -TYPEDESCRIPTION CRevertSaved::m_SaveData[] = -{ - DEFINE_FIELD( CRevertSaved, m_messageTime, FIELD_FLOAT ), // These are not actual times, but durations, so save as floats - DEFINE_FIELD( CRevertSaved, m_loadTime, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity ); - -void CRevertSaved :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - SetHoldTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messagetime")) - { - SetMessageTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "loadtime")) - { - SetLoadTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); - SetNextThink( MessageTime() ); - SetThink(&CRevertSaved :: MessageThink ); -} - - -void CRevertSaved :: MessageThink( void ) -{ - UTIL_ShowMessageAll( STRING(pev->message) ); - float nextThink = LoadTime() - MessageTime(); - if ( nextThink > 0 ) - { - SetNextThink( nextThink ); - SetThink(&CRevertSaved :: LoadThink ); - } - else - LoadThink(); -} - - -void CRevertSaved :: LoadThink( void ) -{ - if ( !gpGlobals->deathmatch ) - { - SERVER_COMMAND("reload\n"); - } -} - -//============================================== -// !!!UNDONE:ultra temporary SprayCan entity to apply -// decal frame at a time. For PreAlpha CD -//============================================== -class CSprayCan : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Think( void ); - - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -void CSprayCan::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - pev->frame = 0; - - SetNextThink( 0.1 ); - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM); -} - -void CSprayCan::Think( void ) -{ - TraceResult tr; - int playernum; - int nFrames; - CBasePlayer *pPlayer; - - pPlayer = (CBasePlayer *)GET_PRIVATE(pev->owner); - - if (pPlayer) - nFrames = pPlayer->GetCustomDecalFrames(); - else - nFrames = -1; - - playernum = ENTINDEX(pev->owner); - - // ALERT(at_console, "Spray by player %i, %i of %i\n", playernum, (int)(pev->frame + 1), nFrames); - - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - // No customization present. - if (nFrames == -1) - { - UTIL_DecalTrace( &tr, DECAL_LAMBDA6 ); - UTIL_Remove( this ); - } - else - { - UTIL_PlayerDecalTrace( &tr, playernum, pev->frame, TRUE ); - // Just painted last custom frame. - if ( pev->frame++ >= (nFrames - 1)) - UTIL_Remove( this ); - } - - SetNextThink( 0.1 ); -} - -class CBloodSplat : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Spray ( void ); -}; - -void CBloodSplat::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - - SetThink(&CBloodSplat:: Spray ); - SetNextThink( 0.1 ); -} - -void CBloodSplat::Spray ( void ) -{ - TraceResult tr; - - if ( g_Language != LANGUAGE_GERMAN ) - { - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); - } - SetThink( Remove ); - SetNextThink( 0.1 ); -} - -//============================================== - -void CBasePlayer::GiveNamedItem( const char *pszName ) -{ - edict_t *pent; - CBaseEntity *pEntity; - string_t istr = MAKE_STRING( pszName ); - - pent = CREATE_NAMED_ENTITY( istr ); - if( FNullEnt( pent )) return; - - VARS( pent )->origin = pev->origin; - pent->v.spawnflags |= SF_NORESPAWN; - - DispatchSpawn( pent ); - - pEntity = CBaseEntity::Instance( pent ); - - if( pEntity && ( pEntity->IsItem() || pEntity->IsWeapon() || pEntity->IsAmmo() )) - { - ALERT( at_aiconsole, "Give %s\n", STRING( pent->v.classname )); - DispatchTouch( pEntity->edict(), ENT( pev )); - - if(( pEntity->IsItem() || pEntity->IsAmmo()) && !FBitSet( pEntity->pev->flags, FL_KILLME )) - { - // player can't got this item for some reasons, delete it from map - REMOVE_ENTITY( pent ); - } - } - else - { - // player won't give monsters or like stuff - ALERT( at_aiconsole, "Can't give %s\n", STRING( pent->v.classname )); - REMOVE_ENTITY( pent ); - } -} - -BOOL CBasePlayer :: FlashlightIsOn( void ) -{ - return FBitSet( pev->effects, EF_DIMLIGHT ); -} - - -void CBasePlayer :: FlashlightTurnOn( void ) -{ - if ( !g_pGameRules->FAllowFlashlight()) return; - - if (m_iFlashBattery == 0) - { - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_ON, 1.0, ATTN_NORM, 0, PITCH_NORM ); - return; - } - - if( pev->weapons & ITEM_SUIT ) - { - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_ON, 1.0, ATTN_NORM, 0, PITCH_NORM ); - SetBits(pev->effects, EF_DIMLIGHT); - MESSAGE_BEGIN( MSG_ONE, gmsg.Flashlight, NULL, pev ); - WRITE_BYTE(1); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; - } -} - - -void CBasePlayer :: FlashlightTurnOff( void ) -{ - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, 1.0, ATTN_NORM, 0, PITCH_NORM ); - - ClearBits(pev->effects, EF_DIMLIGHT); - MESSAGE_BEGIN( MSG_ONE, gmsg.Flashlight, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time; - -} - -/* -=============== -ForceClientDllUpdate - -When recording a demo, we need to have the server tell us the entire client state -so that the client side .dll can behave correctly. -Reset stuff so that the state is transmitted. -=============== -*/ -void CBasePlayer :: ForceClientDllUpdate( void ) -{ - m_iClientHealth = -1; - m_iClientBattery = -1; - m_iTrain |= TRAIN_NEW; // Force new train message. - m_fWeapon = FALSE; // Force weapon send - m_fKnownItem = FALSE; // Force weaponinit messages. - m_fInitHUD = TRUE; // Force HUD gmsg.ResetHUD message - m_flFlashLightTime = 1; // Force to update flashlight - rainNeedsUpdate = 1; - fogNeedsUpdate = 1; - m_iStartMessage = 1; - fadeNeedsUpdate = 1; - hearNeedsUpdate = 1; - viewNeedsUpdate = 1; - - // Now force all the necessary messages to be sent. - UpdateClientData(); - g_pGameRules->InitHUD( this ); - - if( m_pActiveItem ) - m_pActiveItem->SendWeaponAnim( m_pActiveItem->m_iSequence ); -} - -/* -============ -ImpulseCommands -============ -*/ -void CBasePlayer::ImpulseCommands( void ) -{ - TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs - - // Handle use events - PlayerUse(); - - int iImpulse = (int)pev->impulse; - switch (iImpulse) - { - case 100: //enable flashlight - if ( FlashlightIsOn()) FlashlightTurnOff(); - else FlashlightTurnOn(); - break; - case 201: // paint decal - if( gpGlobals->time < m_flNextDecalTime ) break; - - UTIL_MakeVectors(pev->v_angle); - UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr); - - if ( tr.flFraction != 1.0 ) - { - // line hit something, so paint a decal - m_flNextDecalTime = gpGlobals->time + CVAR_GET_FLOAT( "decalfrequency" ); - CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL); - pCan->Spawn( pev ); - } - break; - case 204: //Demo recording, update client dll specific data again. - ForceClientDllUpdate(); - break; - default: - // check all of the cheat impulse commands now - CheatImpulseCommands( iImpulse ); - break; - } - - pev->impulse = 0; -} - -//========================================================= -//========================================================= -void CBasePlayer::CheatImpulseCommands( int iImpulse ) -{ - if ( !g_flWeaponCheat) return; - - - CBaseEntity *pEntity; - TraceResult tr; - - switch ( iImpulse ) - { - - case 101: - { - if( GiveOnlyAmmo ) - { - gEvilImpulse101 = TRUE; - GiveNamedItem( "item_suit" ); //player may don't give suit at first time - GiveNamedItem("weapon_handgrenade"); - GiveNamedItem( "ammo_buckshot" ); - GiveNamedItem( "ammo_9mmclip" ); - GiveNamedItem( "ammo_357" ); - GiveNamedItem( "ammo_556" ); - GiveNamedItem( "ammo_762" ); - GiveNamedItem( "ammo_9mmAR" ); - GiveNamedItem( "ammo_m203" ); - GiveNamedItem( "ammo_rpgclip" ); - gEvilImpulse101 = FALSE; - } - else - { - char *afile = (char *)LOAD_FILE( "scripts/impulse101.txt", NULL ); - const char *pfile = afile; - int ItemName[256]; - int count = 0; - char *token; - - token = COM_ParseToken( &pfile ); - - while( token ) - { - // parsing impulse101.txt - if( strlen( token )) - { - ItemName[count] = ALLOC_STRING( token ); - count++; - } - token = COM_ParseToken( &pfile ); - } - - COM_FreeFile( afile ); - - gEvilImpulse101 = TRUE; - - for( int i = 0; i < count; i++ ) - { - GiveNamedItem( (char *)STRING( ItemName[i]) ); - } - - gEvilImpulse101 = FALSE; - GiveOnlyAmmo = TRUE; // no need to give all weapons again - } - } - break; - - case 102: - { - pEntity = UTIL_FindEntityForward( this ); - if (pEntity) pEntity->Use( this, this, USE_TOGGLE, 0); - break; - } - case 103: // print global info about current entity or texture - { - TraceResult tr; - edict_t *pWorld = g_engfuncs.pfnPEntityOfEntIndex( 0 ); - Vector start = pev->origin + pev->view_ofs; - Vector end = start + gpGlobals->v_forward * 1024; - UTIL_TraceLine( start, end, dont_ignore_monsters, edict(), &tr ); - if ( tr.pHit ) pWorld = tr.pHit; - const char *pTextureName = TRACE_TEXTURE( pWorld, start, end ); - pEntity = UTIL_FindEntityForward( this ); - if ( pEntity ) - { - CBaseMonster *pMonster = pEntity->MyMonsterPointer(); - if ( pMonster ) pMonster->ReportAIState(); - else pEntity->Use( this, this, USE_SHOWINFO, 0 ); - } - if ( pTextureName ) ALERT( at_console, "Texture: %s\n", pTextureName ); - } - break; - case 104: - // Dump all of the global state varaibles (and global entity names) - gGlobalState.DumpGlobals(); - break; - case 105:// remove any solid entity. - pEntity = UTIL_FindEntityForward( this ); - if ( pEntity ) UTIL_Remove (pEntity); - break; - case 106://give weapon_debug - GiveNamedItem( "weapon_debug" ); - break; - case 107:// show shortest paths for entire level to nearest node - Create("node_viewer_fly", pev->origin, pev->angles); - Create("node_viewer_human", pev->origin, pev->angles); - break; - } -} - -// -// Add a weapon to the player (Item == Weapon == Selectable Object) -// -int CBasePlayer::AddPlayerItem( CBasePlayerWeapon *pItem ) -{ - CBasePlayerWeapon *pInsert; - - pInsert = m_rgpPlayerItems[pItem->iItemSlot()]; - - while (pInsert) - { - if (FClassnameIs( pInsert->pev, STRING( pItem->pev->netname))) - { - if (pItem->AddDuplicate( pInsert )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - pItem->Drop( ); - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Drop(); - } - return FALSE; - } - pInsert = pInsert->m_pNext; - } - - if (pItem->AddToPlayer( this )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - - pItem->m_pNext = m_rgpPlayerItems[pItem->iItemSlot()]; - m_rgpPlayerItems[pItem->iItemSlot()] = pItem; - - // should we switch to this item? - if ( g_pGameRules->FShouldSwitchWeapon( this, pItem ) ) - { - SwitchWeapon( pItem ); - } - - return TRUE; - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Drop(); - } - - return FALSE; -} - - - -int CBasePlayer::RemovePlayerItem( CBasePlayerWeapon *pItem ) -{ - if (m_pActiveItem == pItem) - { - ResetAutoaim( ); - pItem->Holster( ); - pItem->DontThink();// crowbar may be trying to swing again, etc. - pItem->SetThink( NULL ); - m_pActiveItem = NULL; - pev->viewmodel = 0; - pev->weaponmodel = 0; - } - else if ( m_pLastItem == pItem ) - m_pLastItem = NULL; - - CBasePlayerWeapon *pPrev = m_rgpPlayerItems[pItem->iItemSlot()]; - - if (pPrev == pItem) - { - m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext; - return TRUE; - } - else - { - while (pPrev && pPrev->m_pNext != pItem) - { - pPrev = pPrev->m_pNext; - } - if (pPrev) - { - pPrev->m_pNext = pItem->m_pNext; - return TRUE; - } - } - return FALSE; -} - - -// -// Returns the unique ID for the ammo, or -1 if error -// -int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) -{ - if ( !szName ) return -1; - - if ( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) ) - { - // game rules say I can't have any more of this ammo type. - return -1; - } - - int i = 0; - - i = GetAmmoIndex( szName ); - - if ( i < 0 || i >= MAX_AMMO_SLOTS ) return -1; - - int iAdd = min( iCount, iMax - m_rgAmmo[i] ); - if ( iAdd < 1 ) return i; - - m_rgAmmo[ i ] += iAdd; - - - if ( gmsg.AmmoPickup )// make sure the ammo messages have been linked first - { - // Send the message that ammo has been picked up - MESSAGE_BEGIN( MSG_ONE, gmsg.AmmoPickup, NULL, pev ); - WRITE_BYTE( GetAmmoIndex(szName) ); - WRITE_BYTE( iAdd ); - MESSAGE_END(); - } - - return i; -} - - -/* -============ -ItemPreFrame - -Called every frame by the player PreThink -============ -*/ -void CBasePlayer::ItemPreFrame() -{ - if ( gpGlobals->time < m_flNextAttack ) - { - return; - } - - if (!m_pActiveItem)// XWider - { - if(m_pNextItem) - { - m_pActiveItem = m_pNextItem; - m_pActiveItem->Deploy(); - m_pNextItem = NULL; - } - } - - if (!m_pActiveItem) - return; - - m_pActiveItem->ItemPreFrame( ); -} - - -/* -============ -ItemPostFrame - -Called every frame by the player PostThink -============ -*/ -void CBasePlayer::ItemPostFrame() -{ - static int fInSelect = FALSE; - - // check if the player is using a tank - if ( m_pTank != NULL || m_pMonitor != NULL)return; - - if ( gpGlobals->time < m_flNextAttack ) - { - return; - } - - ImpulseCommands(); - - if (!m_pActiveItem) - return; - m_pActiveItem->ItemPostFrame( ); -} - -int CBasePlayer::AmmoInventory( int iAmmoIndex ) -{ - if (iAmmoIndex == -1) - { - return -1; - } - - return m_rgAmmo[ iAmmoIndex ]; -} - -int CBasePlayer :: GetAmmoIndex( const char *psz ) -{ - int i; - - if( !psz || !stricmp( psz, "none" )) return -1; - - for( i = 1; i < MAX_AMMO_SLOTS; i++ ) - { - if( !CBasePlayerWeapon::AmmoInfoArray[i].iszName ) - continue; - - if( !stricmp( psz, STRING( CBasePlayerWeapon::AmmoInfoArray[i].iszName ))) - return i; - } - return -1; -} - -const char *CBasePlayer::GetAmmoName( int index ) -{ - return STRING( CBasePlayerWeapon::AmmoInfoArray[index].iszName ); -} - -// Called from UpdateClientData -// makes sure the client has all the necessary ammo info, if values have changed -void CBasePlayer::SendAmmoUpdate(void) -{ - for (int i=0; i < MAX_AMMO_SLOTS;i++) - { - if (m_rgAmmo[i] != m_rgAmmoLast[i]) - { - m_rgAmmoLast[i] = m_rgAmmo[i]; - - ASSERT( m_rgAmmo[i] >= 0 ); - ASSERT( m_rgAmmo[i] < 255 ); - - // send "Ammo" update message - MESSAGE_BEGIN( MSG_ONE, gmsg.AmmoX, NULL, pev ); - WRITE_BYTE( i ); - WRITE_BYTE( max( min( m_rgAmmo[i], 254 ), 0 ) ); // clamp the value to one byte - MESSAGE_END(); - } - } -} - -/* -========================================================= - UpdateClientData - -resends any changed player HUD info to the client. -Called every frame by Player::PreThink -Also called at start of demo recording and playback by -ForceClientDllUpdate to ensure the demo gets messages -reflecting all of the HUD state info. -========================================================= -*/ - -void CBasePlayer :: UpdateClientData( void ) -{ - // check for cheats here - g_flWeaponCheat = CVAR_GET_FLOAT( "sv_cheats" ); // Is the impulse 101 command allowed? - - if (m_fInitHUD) - { - m_fInitHUD = FALSE; - gInitHUD = FALSE; - - MESSAGE_BEGIN( MSG_ONE, gmsg.ResetHUD, NULL, pev ); - WRITE_BYTE( 0 ); - MESSAGE_END(); - - if ( !m_fGameHUDInitialized ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.InitHUD, NULL, pev ); - MESSAGE_END(); - - g_pGameRules->InitHUD( this ); - m_fGameHUDInitialized = TRUE; - if ( g_pGameRules->IsMultiplayer() ) - { - UTIL_FireTargets( "game_playerjoin", this, this, USE_TOGGLE ); - } - m_iStartMessage = 1; //send player init messages - } - - UTIL_FireTargets( "game_playerspawn", this, this, USE_TOGGLE ); - InitStatusBar(); - } - - if ( m_iHideHUD != m_iClientHideHUD ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.HideWeapon, NULL, pev ); - WRITE_BYTE( m_iHideHUD ); - MESSAGE_END(); - - m_iClientHideHUD = m_iHideHUD; - } - - if( viewNeedsUpdate != 0 ) - { - int indexToSend; - - // we can entity to look at - if( pViewEnt && ( viewFlags & CAMERA_ON )) - { - indexToSend = pViewEnt->entindex(); - } - else - { - // just reset camera - indexToSend = 0; - viewFlags = 0; //clear possibly ACTIVE flag - } - - MESSAGE_BEGIN( MSG_ONE, gmsg.CamData, NULL, pev ); - WRITE_SHORT( indexToSend ); - WRITE_SHORT( viewFlags ); - MESSAGE_END(); - - viewNeedsUpdate = 0; - } - - if( hearNeedsUpdate != 0 ) - { - // update dsp sound - MESSAGE_BEGIN( MSG_ONE, gmsg.RoomType, NULL, pev ); - WRITE_BYTE( m_iSndRoomtype ); - MESSAGE_END(); - hearNeedsUpdate = 0; - } - - if( fadeNeedsUpdate != 0 ) - { - // update screenfade - MESSAGE_BEGIN( MSG_ONE, gmsg.Fade, NULL, pev ); - WRITE_SHORT( FixedUnsigned16( m_flFadeTime, 1<<12 )); - WRITE_SHORT( FixedUnsigned16( m_flFadeHold, 1<<12 )); - WRITE_SHORT( m_iFadeFlags ); // fade flags - WRITE_BYTE( (byte)m_FadeColor.x ); // fade red - WRITE_BYTE( (byte)m_FadeColor.y ); // fade green - WRITE_BYTE( (byte)m_FadeColor.z ); // fade blue - WRITE_BYTE( (byte)m_FadeAlpha ); // fade alpha - MESSAGE_END(); - fadeNeedsUpdate = 0; - } - - if (m_iStartMessage != 0) - { - SendStartMessages(); - m_iStartMessage = 0; - } - - if(m_FogFadeTime != 0) - { - float flDegree = (gpGlobals->time - m_flStartTime) / m_FogFadeTime; - m_iFogEndDist -= (FOG_LIMIT - m_iFogFinalEndDist)*(flDegree / m_iFogFinalEndDist); - - // cap it - if (m_iFogEndDist > FOG_LIMIT) - { - m_iFogEndDist = FOG_LIMIT; - m_FogFadeTime = 0; - } - if (m_iFogEndDist < m_iFogFinalEndDist) - { - m_iFogEndDist = m_iFogFinalEndDist; - m_FogFadeTime = 0; - } - fogNeedsUpdate = TRUE; - } - - if(fogNeedsUpdate != 0) - { - //update fog - MESSAGE_BEGIN( MSG_ONE, gmsg.SetFog, NULL, pev ); - WRITE_BYTE ( m_FogColor.x ); - WRITE_BYTE ( m_FogColor.y ); - WRITE_BYTE ( m_FogColor.z ); - WRITE_SHORT ( m_iFogStartDist ); - WRITE_SHORT ( m_iFogEndDist ); - MESSAGE_END(); - fogNeedsUpdate = 0; - } - - if( m_iWarHUD != m_iClientWarHUD ) - { - MESSAGE_BEGIN( MSG_ONE, gmsg.WarHUD, NULL, pev ); - WRITE_BYTE( m_iWarHUD );//make static screen - MESSAGE_END(); - m_iClientWarHUD = m_iWarHUD; - } - - if (pev->health != m_iClientHealth) - { - int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent - - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsg.Health, NULL, pev ); - WRITE_BYTE( iHealth ); - MESSAGE_END(); - - m_iClientHealth = pev->health; - } - - - if (pev->armorvalue != m_iClientBattery) - { - m_iClientBattery = pev->armorvalue; - - ASSERT( gmsg.Battery > 0 ); - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsg.Battery, NULL, pev ); - WRITE_SHORT( (int)pev->armorvalue); - MESSAGE_END(); - } - - if (pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType) - { - // Comes from inside me if not set - Vector damageOrigin = pev->origin; - // send "damage" message - // causes screen to flash, and pain compass to show direction of damage - edict_t *other = pev->dmg_inflictor; - if ( other ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(other); - if ( pEntity ) - damageOrigin = pEntity->Center(); - } - - // only send down damage type that have hud art - int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD; - - MESSAGE_BEGIN( MSG_ONE, gmsg.Damage, NULL, pev ); - WRITE_BYTE( pev->dmg_save ); - WRITE_BYTE( pev->dmg_take ); - WRITE_LONG( visibleDamageBits ); - WRITE_COORD( damageOrigin.x ); - WRITE_COORD( damageOrigin.y ); - WRITE_COORD( damageOrigin.z ); - MESSAGE_END(); - - pev->dmg_take = 0; - pev->dmg_save = 0; - m_bitsHUDDamage = m_bitsDamageType; - - // Clear off non-time-based damage indicators - m_bitsDamageType &= DMG_TIMEBASED; - } - - // Update Flashlight - if ((m_flFlashLightTime) && (m_flFlashLightTime <= gpGlobals->time)) - { - if (FlashlightIsOn()) - { - if (m_iFlashBattery) - { - m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; - m_iFlashBattery--; - - if (!m_iFlashBattery) FlashlightTurnOff(); - } - } - else - { - if (m_iFlashBattery < 100) - { - m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time; - m_iFlashBattery++; - } - else m_flFlashLightTime = 0; - } - - MESSAGE_BEGIN( MSG_ONE, gmsg.FlashBattery, NULL, pev ); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - } - - // calculate and update rain fading - if (Rain_endFade > 0) - { - if (gpGlobals->time < Rain_endFade) - { // we're in fading process - if (Rain_nextFadeUpdate <= gpGlobals->time) - { - int secondsLeft = Rain_endFade - gpGlobals->time + 1; - - Rain_dripsPerSecond += (Rain_ideal_dripsPerSecond - Rain_dripsPerSecond) / secondsLeft; - Rain_windX += (Rain_ideal_windX - Rain_windX) / (float)secondsLeft; - Rain_windY += (Rain_ideal_windY - Rain_windY) / (float)secondsLeft; - Rain_randX += (Rain_ideal_randX - Rain_randX) / (float)secondsLeft; - Rain_randY += (Rain_ideal_randY - Rain_randY) / (float)secondsLeft; - - Rain_nextFadeUpdate = gpGlobals->time + 1; // update once per second - rainNeedsUpdate = 1; - - ALERT(at_aiconsole, "Rain fading: curdrips: %i, idealdrips %i\n", Rain_dripsPerSecond, Rain_ideal_dripsPerSecond); - } - } - else - { // finish fading process - Rain_nextFadeUpdate = 0; - Rain_endFade = 0; - - Rain_dripsPerSecond = Rain_ideal_dripsPerSecond; - Rain_windX = Rain_ideal_windX; - Rain_windY = Rain_ideal_windY; - Rain_randX = Rain_ideal_randX; - Rain_randY = Rain_ideal_randY; - rainNeedsUpdate = 1; - - ALERT(at_aiconsole, "Rain fading finished at %i drips\n", Rain_dripsPerSecond); - } - } - - // send rain message - if (rainNeedsUpdate) - { - //search for rain_settings entity - CBaseEntity *pFind; - pFind = UTIL_FindEntityByClassname( NULL, "env_rain" ); - if (!FNullEnt( pFind )) - { - // rain allowed on this map - CBaseEntity *pEnt = CBaseEntity::Instance( pFind->edict() ); - - float raindistance = pEnt->pev->armorvalue; - float rainheight = pEnt->pev->origin[2]; - int rainmode = pEnt->pev->button; - - // search for constant rain_modifies - pFind = UTIL_FindEntityByClassname( NULL, "env_rainmodify" ); - while ( !FNullEnt( pFind ) ) - { - if ( pFind->pev->spawnflags & 1 ) - { - // copy settings to player's data and clear fading - CBaseEntity *pEnt = CBaseEntity::Instance( pFind->edict() ); - CEnvRainModify *pRainModify = (CEnvRainModify *)pEnt; - - Rain_dripsPerSecond = pRainModify->pev->button; - Rain_windX = pRainModify->windXY[1]; - Rain_windY = pRainModify->windXY[0]; - Rain_randX = pRainModify->randXY[1]; - Rain_randY = pRainModify->randXY[0]; - - Rain_endFade = 0; - break; - } - pFind = UTIL_FindEntityByClassname( pFind, "util_rainmodify" ); - } - - MESSAGE_BEGIN(MSG_ONE, gmsg.RainData, NULL, pev); - WRITE_SHORT(Rain_dripsPerSecond); - WRITE_COORD(raindistance); - WRITE_COORD(Rain_windX); - WRITE_COORD(Rain_windY); - WRITE_COORD(Rain_randX); - WRITE_COORD(Rain_randY); - WRITE_SHORT(rainmode); - WRITE_COORD(rainheight); - MESSAGE_END(); - - if (Rain_dripsPerSecond) - ALERT(at_aiconsole, "Sending enabling rain message\n"); - else - ALERT(at_aiconsole, "Sending disabling rain message\n"); - } - else - { - // no rain on this map - Rain_dripsPerSecond = 0; - Rain_windX = 0; - Rain_windY = 0; - Rain_randX = 0; - Rain_randY = 0; - Rain_ideal_dripsPerSecond = 0; - Rain_ideal_windX = 0; - Rain_ideal_windY = 0; - Rain_ideal_randX = 0; - Rain_ideal_randY = 0; - Rain_endFade = 0; - Rain_nextFadeUpdate = 0; - } - rainNeedsUpdate = 0; - } - - // Update Flashlight - if ((m_flFlashLightTime) && (m_flFlashLightTime <= gpGlobals->time)) - { - if (FlashlightIsOn()) - { - if (m_iFlashBattery) - { - m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; - m_iFlashBattery--; - - if (!m_iFlashBattery) - FlashlightTurnOff(); - } - } - else m_flFlashLightTime = 0; - - MESSAGE_BEGIN( MSG_ONE, gmsg.FlashBattery, NULL, pev ); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - } - - if (m_iTrain & TRAIN_NEW) - { - ASSERT( gmsg.Train > 0 ); - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsg.Train, NULL, pev ); - WRITE_BYTE(m_iTrain & 0xF); - MESSAGE_END(); - - m_iTrain &= ~TRAIN_NEW; - } - - // - // New Weapon? - // - if (!m_fKnownItem) - { - m_fKnownItem = TRUE; - - // WeaponInit Message - // byte = # of weapons - // - // for each weapon: - // byte name str length (not including null) - // bytes... name - // byte Ammo Type - // byte Ammo2 Type - // byte bucket - // byte bucket pos - // byte flags - // ???? Icons - - // Send ALL the weapon info now - int i; - - for (i = 0; i < MAX_WEAPONS; i++) - { - ItemInfo& II = CBasePlayerWeapon::ItemInfoArray[i]; - - if( !II.iId ) continue; - - const char *pszName; - if( !II.iszName ) - pszName = "Empty"; - else pszName = STRING( II.iszName ); - - MESSAGE_BEGIN( MSG_ONE, gmsg.WeaponList, NULL, pev ); - WRITE_STRING( pszName ); // string weapon name - WRITE_BYTE( GetAmmoIndex( STRING( II.iszAmmo1 ))); // byte Ammo Type - WRITE_BYTE( II.iMaxAmmo1 ); // byte Max Ammo 1 - WRITE_BYTE( GetAmmoIndex(STRING( II.iszAmmo2 ))); // byte Ammo2 Type - WRITE_BYTE( II.iMaxAmmo2 ); // byte Max Ammo 2 - WRITE_BYTE( II.iSlot ); // byte bucket - WRITE_BYTE( II.iPosition ); // byte bucket pos - WRITE_BYTE( II.iId ); // byte id (bit index into pev->weapons) - WRITE_BYTE( II.iFlags ); // byte Flags - MESSAGE_END(); - } - } - - SendAmmoUpdate(); - - // Update all the items - for ( int i = 0; i < MAX_ITEM_TYPES; i++ ) - { - if ( m_rgpPlayerItems[i] ) // each item updates it's successors - m_rgpPlayerItems[i]->UpdateClientData( this ); - } - - // Cache and client weapon change - m_pClientActiveItem = m_pActiveItem; - - // update Status Bar - if( m_flNextSBarUpdateTime < gpGlobals->time ) - { - UpdateStatusBar(); - m_flNextSBarUpdateTime = gpGlobals->time + 0.2; - } -} - -void CBasePlayer :: SendStartMessages( void ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - - if ( !pEdict ) return; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) continue;// Not in use - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) continue; - - pEntity->StartMessage( this ); - } -} - -//========================================================= -// FBecomeProne - Overridden for the player to set the proper -// physics flags when a barnacle grabs player. -//========================================================= -BOOL CBasePlayer :: FBecomeProne ( void ) -{ - m_afPhysicsFlags |= PFLAG_ONBARNACLE; - return TRUE; -} - -//========================================================= -// BarnacleVictimBitten - bad name for a function that is called -// by Barnacle victims when the barnacle pulls their head -// into its mouth. For the player, just die. -//========================================================= -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) -{ - TakeDamage ( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB ); -} - -//========================================================= -// BarnacleVictimReleased - overridden for player who has -// physics flags concerns. -//========================================================= -void CBasePlayer :: BarnacleVictimReleased ( void ) -{ - m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; -} - - -//========================================================= -// Illumination -// return player light level plus virtual muzzle flash -//========================================================= -int CBasePlayer :: Illumination( void ) -{ - int iIllum = CBaseEntity::Illumination( ); - - iIllum += m_iWeaponFlash; - if (iIllum > 255) - return 255; - return iIllum; -} - - -void CBasePlayer :: EnableControl(BOOL fControl) -{ - if( !fControl ) - { - pev->flags |= FL_FROZEN; - pev->velocity = g_vecZero; //LRC - stop view bobbing - } - else pev->flags &= ~FL_FROZEN; -} - - -#define DOT_1DEGREE 0.9998476951564 -#define DOT_2DEGREE 0.9993908270191 -#define DOT_3DEGREE 0.9986295347546 -#define DOT_4DEGREE 0.9975640502598 -#define DOT_5DEGREE 0.9961946980917 -#define DOT_6DEGREE 0.9945218953683 -#define DOT_7DEGREE 0.9925461516413 -#define DOT_8DEGREE 0.9902680687416 -#define DOT_9DEGREE 0.9876883405951 -#define DOT_10DEGREE 0.9848077530122 -#define DOT_15DEGREE 0.9659258262891 -#define DOT_20DEGREE 0.9396926207859 -#define DOT_25DEGREE 0.9063077870367 - -//========================================================= -// Autoaim -// set crosshair position to point to enemey -//========================================================= -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) -{ - Vector vecSrc = GetGunPosition( ); - float flDist = 8192; - - m_vecAutoAim = Vector( 0, 0, 0 ); - - BOOL m_fOldTargeting = m_fOnTarget; - Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta ); - - // update ontarget if changed - if ( !g_pGameRules->AllowAutoTargetCrosshair() ) - m_fOnTarget = 0; - - if (angles.x > 180) - angles.x -= 360; - if (angles.x < -180) - angles.x += 360; - if (angles.y > 180) - angles.y -= 360; - if (angles.y < -180) - angles.y += 360; - - if (angles.x > 25) - angles.x = 25; - if (angles.x < -25) - angles.x = -25; - if (angles.y > 12) - angles.y = 12; - if (angles.y < -12) - angles.y = -12; - - - m_vecAutoAim = angles * 0.9; - - // Don't send across network if sv_aim is 0 - if( !IsMultiplayer() && CVAR_GET_FLOAT( "sv_aim" ) != 0 ) - { - if ( m_vecAutoAim.x != m_lastx || m_vecAutoAim.y != m_lasty ) - { - SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y ); - - m_lastx = m_vecAutoAim.x; - m_lasty = m_vecAutoAim.y; - } - } - - // ALERT( at_console, "%f %f\n", angles.x, angles.y ); - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - return gpGlobals->v_forward; -} - - -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - float bestdot; - Vector bestdir; - edict_t *bestent; - TraceResult tr; - - if( IsMultiplayer() || CVAR_GET_FLOAT( "sv_aim" ) == 0 ) - { - m_fOnTarget = FALSE; - return g_vecZero; - } - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - - // try all possible entities - bestdir = gpGlobals->v_forward; - bestdot = flDelta; // +- 10 degrees - bestent = NULL; - - m_fOnTarget = FALSE; - - UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr ); - - - if ( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO) - { - // don't look through water - if (!((pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3) - || (pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0))) - { - if (tr.pHit->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return m_vecAutoAim; - } - } - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - Vector center; - Vector dir; - float dot; - - if ( pEdict->free ) // Not in use - continue; - - if (pEdict->v.takedamage != DAMAGE_AIM) - continue; - if (pEdict == edict()) - continue; - if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) - continue; - - pEntity = Instance( pEdict ); - if (pEntity == NULL) - continue; - - if (!pEntity->IsAlive()) - continue; - - // don't look through water - if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) - continue; - - center = pEntity->BodyTarget( vecSrc ); - - dir = (center - vecSrc).Normalize( ); - - // make sure it's in front of the player - if (DotProduct (dir, gpGlobals->v_forward ) < 0) - continue; - - dot = fabs( DotProduct (dir, gpGlobals->v_right ) ) - + fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5; - - // tweek for distance - dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist); - - if (dot > bestdot) - continue; // to far to turn - - UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr ); - if (tr.flFraction != 1.0 && tr.pHit != pEdict) - { - // ALERT( at_console, "hit %s, can't see %s\n", STRING( tr.pHit->v.classname ), STRING( pEdict->v.classname ) ); - continue; - } - - // don't shoot at friends - if (IRelationship( pEntity ) < 0) - { - if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch()) - // ALERT( at_console, "friend\n"); - continue; - } - - // can shoot at this one - bestdot = dot; - bestent = pEdict; - bestdir = dir; - } - - if (bestent) - { - bestdir = UTIL_VecToAngles (bestdir); - bestdir.x = -bestdir.x; - bestdir = bestdir - pev->v_angle - pev->punchangle; - - if (bestent->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return bestdir; - } - - return Vector( 0, 0, 0 ); -} - - -void CBasePlayer :: ResetAutoaim( ) -{ - if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) - { - m_vecAutoAim = Vector( 0, 0, 0 ); - SET_CROSSHAIRANGLE( edict(), 0, 0 ); - } - m_fOnTarget = FALSE; -} - -/* -============= -SetCustomDecalFrames - - UNDONE: Determine real frame limit, 8 is a placeholder. - Note: -1 means no custom frames present. -============= -*/ -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) -{ - if (nFrames > 0 && - nFrames < 8) - m_nCustomSprayFrames = nFrames; - else - m_nCustomSprayFrames = -1; -} - -/* -============= -GetCustomDecalFrames - - Returns the # of custom frames this player's custom clan logo contains. -============= -*/ -int CBasePlayer :: GetCustomDecalFrames( void ) -{ - return m_nCustomSprayFrames; -} - - -//========================================================= -// DropPlayerItem - drop the named item, or if no name, -// the active item. -//========================================================= -void CBasePlayer::DropPlayerItem ( char *pszItemName ) -{ - if( !g_pGameRules->IsMultiplayer() || (CVAR_GET_FLOAT( "mp_weaponstay" ) > 0 )) - { - // no dropping in single player. - //return; - } - - if ( !strlen( pszItemName ) ) - { - // if this string has no length, the client didn't type a name! - // assume player wants to drop the active item. - // make the string null to make future operations in this function easier - pszItemName = NULL; - } - - CBasePlayerWeapon *pWeapon; - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - if ( pszItemName ) - { - // try to match by name. - if ( !strcmp( pszItemName, STRING( pWeapon->pev->netname ) ) ) - { - // match! - break; - } - } - else - { - // trying to drop active item - if ( pWeapon == m_pActiveItem ) - { - // active item! - break; - } - } - - pWeapon = pWeapon->m_pNext; - } - - - // if we land here with a valid pWeapon pointer, that's because we found the - // item we want to drop and hit a BREAK; pWeapon is the item. - if ( pWeapon ) - { - g_pGameRules->GetNextBestWeapon( this, pWeapon ); - - UTIL_MakeVectors ( pev->angles ); - - pev->weapons &= ~(1<m_iId);// take item off hud - - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "item_weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() ); - pWeaponBox->pev->angles.x = 0; - pWeaponBox->pev->angles.z = 0; - pWeaponBox->PackWeapon( pWeapon ); - pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; - - // drop half of the ammo for this weapon. - int iAmmoIndex; - - iAmmoIndex = GetAmmoIndex ( pWeapon->pszAmmo1() ); // ??? - - if ( iAmmoIndex != -1 ) - { - // this weapon weapon uses ammo, so pack an appropriate amount. - if ( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE ) - { - // pack up all the ammo, this weapon is its own ammo type - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] ); - m_rgAmmo[ iAmmoIndex ] = 0; - - } - else - { - // pack half of the ammo - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] / 2 ); - m_rgAmmo[ iAmmoIndex ] /= 2; - } - - } - - return;// we're done, so stop searching with the FOR loop. - } - } -} - -//========================================================= -// HasPlayerItem Does the player already have this item? -//========================================================= -BOOL CBasePlayer::HasPlayerItem( CBasePlayerWeapon *pCheckItem ) -{ - CBasePlayerWeapon *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while (pItem) - { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->netname) )) - return TRUE; - pItem = pItem->m_pNext; - } - - return FALSE; -} - -//========================================================= -// HasNamedPlayerItem Does the player already have this item? -//========================================================= -BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) -{ - CBasePlayerWeapon *pItem; - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pItem = m_rgpPlayerItems[ i ]; - - while (pItem) - { - if ( !strcmp( pszItemName, STRING( pItem->pev->netname ))) - return TRUE; - pItem = pItem->m_pNext; - } - } - - return FALSE; -} - -//========================================================= -// -//========================================================= -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerWeapon *pWeapon ) -{ - if ( !pWeapon->CanDeploy() ) return FALSE; - ResetAutoaim( ); - - if (m_pActiveItem) m_pActiveItem->Holster( ); - QueueItem(pWeapon); - if (m_pActiveItem) m_pActiveItem->Deploy( ); - - return TRUE; -} - -//========================================================= -// Body queue class here.... It's really just CBaseEntity -//========================================================= -class CCorpse : public CBaseEntity -{ - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; -LINK_ENTITY_TO_CLASS( bodyque, CCorpse ); - -//========================================================= -// Dead HEV suit prop -// LRC- i.e. the dead blokes you see in Xen. -//========================================================= -class CDeadHEV : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[4]; -}; - -char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", "deadstomach", "deadtable" }; - -void CDeadHEV::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ); - -//========================================================= -// ********** DeadHEV SPAWN ********** -//========================================================= -void CDeadHEV :: Spawn( void ) -{ - PRECACHE_MODEL("models/player.mdl"); - SET_MODEL(ENT(pev), "models/player.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - pev->body = 1; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - - if( pev->sequence == -1 ) - { - ALERT ( at_console, "Dead hevsuit with bad pose\n" ); - pev->sequence = 0; - pev->effects = EF_BRIGHTFIELD; - } - - // Corpses have less health - pev->health = 8; - - MonsterInitDead(); -} \ No newline at end of file diff --git a/server/monsters/player.h b/server/monsters/player.h deleted file mode 100644 index 9cb77bc4..00000000 --- a/server/monsters/player.h +++ /dev/null @@ -1,363 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PLAYER_H -#define PLAYER_H - - -#include "pm_materials.h" - -#define PLAYER_FATAL_FALL_SPEED 1024 // approx 60 feet -#define PLAYER_MAX_SAFE_FALL_SPEED 580 // approx 20 feet -#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. -#define PLAYER_MIN_BOUNCE_SPEED 200 -#define PLAYER_FALL_PUNCH_THRESHHOLD (float) 350 // won't punch player's screen/make scrape noise unless player falling at least this fast. - -// -// Player PHYSICS FLAGS bits -// -#define PFLAG_ONLADDER ( 1<<0 ) -#define PFLAG_ONSWING ( 1<<0 ) -#define PFLAG_ONTRAIN ( 1<<1 ) -#define PFLAG_ONBARNACLE ( 1<<2 ) -#define PFLAG_DUCKING ( 1<<3 ) // In the process of ducking, but totally squatted yet -#define PFLAG_USING ( 1<<4 ) // Using a continuous entity -#define PFLAG_OBSERVER ( 1<<5 ) // player is locked in stationary cam mode. Spectators can move, observers can't. - -// -// generic player -// -//----------------------------------------------------- -//This is Half-Life player entity -//----------------------------------------------------- -#define CSUITPLAYLIST 4 // max of 4 suit sentences queued up at any time - -#define SUIT_GROUP TRUE -#define SUIT_SENTENCE FALSE - -#define SUIT_REPEAT_OK 0 -#define SUIT_NEXT_IN_30SEC 30 -#define SUIT_NEXT_IN_1MIN 60 -#define SUIT_NEXT_IN_5MIN 300 -#define SUIT_NEXT_IN_10MIN 600 -#define SUIT_NEXT_IN_30MIN 1800 -#define SUIT_NEXT_IN_1HOUR 3600 - -#define CSUITNOREPEAT 32 - -#define SOUND_FLASHLIGHT_ON "items/flashlight1.wav" -#define SOUND_FLASHLIGHT_OFF "items/flashlight1.wav" - -#define TEAM_NAME_LENGTH 16 - -typedef enum -{ - PLAYER_IDLE, - PLAYER_WALK, - PLAYER_JUMP, - PLAYER_SUPERJUMP, - PLAYER_DIE, - PLAYER_ATTACK1, -} PLAYER_ANIM; - - -//NB: changing this structure will cause problems! --LRC - -#define MAX_ID_RANGE 2048 -#define SBAR_STRING_SIZE 128 - -enum sbar_data -{ - SBAR_ID_TARGETNAME = 1, - SBAR_ID_TARGETHEALTH, - SBAR_ID_TARGETARMOR, - SBAR_END, -}; - -#define CHAT_INTERVAL 1.0f - -class CBasePlayer : public CBaseMonster -{ -public: - int random_seed; // See that is shared between client & server for shared weapons code - - int m_iPlayerSound;// the index of the sound list slot reserved for this player - int m_iTargetVolume;// ideal sound volume. - int m_iWeaponVolume;// how loud the player's weapon is right now. - int m_iExtraSoundTypes;// additional classification for this weapon's sound - int m_iWeaponFlash;// brightness of the weapon flash - float m_flStopExtraSoundTime; - float m_flNextNuclearDamage; - - float m_flFlashLightTime; // Time until next battery draw/Recharge - int m_iFlashBattery; // Flashlight Battery Draw - - int m_afButtonLast; - int m_afButtonPressed; - int m_afButtonReleased; - - float m_flFallVelocity; - - int m_rgItems[MAX_ITEMS]; - int m_fKnownItem; // True when a new item needs to be added - int m_fNewAmmo; // True when a new item has been added - - unsigned int m_afPhysicsFlags; // physics flags - set when 'normal' physics should be revisited or overriden - float m_fNextSuicideTime; // the time after which the player can next use the suicide command - - -// these are time-sensitive things that we keep track of - float m_flTimeStepSound; // when the last stepping sound was made - float m_flTimeWeaponIdle; // when to play another weapon idle animation. - float m_flSwimTime; // how long player has been underwater - float m_flDuckTime; // how long we've been ducking - float m_flWallJumpTime; // how long until next walljump - - float m_flSuitUpdate; // when to play next suit update - int m_rgSuitPlayList[CSUITPLAYLIST];// next sentencenum to play for suit update - int m_iSuitPlayNext; // next sentence slot for queue storage; - int m_rgiSuitNoRepeat[CSUITNOREPEAT]; // suit sentence no repeat list - float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; // how long to wait before allowing repeat - int m_lastDamageAmount; // Last damage taken - float m_tbdPrev; // Time-based damage timer - - float m_flgeigerRange; // range to nearest radiation source - float m_flgeigerDelay; // delay per update of range msg to client - int m_igeigerRangePrev; - int m_iStepLeft; // alternate left/right foot stepping sound - char m_szTextureName[CBTEXTURENAMEMAX]; // current texture name we're standing on - char m_chTextureType; // current texture type - - int m_idrowndmg; // track drowning damage taken - int m_idrownrestored; // track drowning damage restored - - int m_bitsHUDDamage; // Damage bits for the current fame. These get sent to - // the hude via the DAMAGE message - BOOL m_fInitHUD; // True when deferred HUD restart msg needs to be sent - BOOL m_fGameHUDInitialized; - int m_iTrain; // Train control position - BOOL m_fWeapon; // Set this to FALSE to force a reset of the current weapon HUD info - - EHANDLE m_pTank; // the tank which the player is currently controlling, NULL if no tank - EHANDLE m_pMonitor; - float m_fDeadTime; // the time at which the player died (used in PlayerDeathThink()) - float m_fAirFinished; // moved here from progdefs.h - float m_fPainFinished; // moved here from progdefs.h - - BOOL m_fNoPlayerSound; // a debugging feature. Player makes no sound if this is true. - BOOL m_fLongJump; // does this player have the longjump module? - - float m_tSneaking; - int m_iUpdateTime; // stores the number of frame ticks before sending HUD update messages - int m_iClientHealth; // the health currently known by the client. If this changes, send a new - int m_iClientBattery; // the Battery currently known by the client. If this changes, send a new - int m_iHideHUD; // the players hud weapon info is to be hidden - int m_iClientHideHUD; - - // usable player items - CBasePlayerWeapon *m_rgpPlayerItems[MAX_ITEM_TYPES]; - CBasePlayerWeapon *m_pActiveItem; - CBasePlayerWeapon *m_pClientActiveItem; // client version of the active item - CBasePlayerWeapon *m_pLastItem; - CBasePlayerWeapon *m_pNextItem; - // shared ammo slots - int m_rgAmmo[MAX_AMMO_SLOTS]; - int m_rgAmmoLast[MAX_AMMO_SLOTS]; - - Vector m_vecAutoAim; - BOOL m_fOnTarget; - int m_iDeaths; - float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn - - int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE - - int m_nCustomSprayFrames;// Custom clan logo frames for this player - float m_flNextDecalTime;// next time this player can spray a decal - - char m_szTeamName[TEAM_NAME_LENGTH]; - - virtual void Spawn( void ); - void Pain( void ); - - virtual void Jump( void ); - virtual void Duck( void ); - virtual void PreThink( void ); - virtual void PostThink( void ); - virtual Vector GetGunPosition( void ); - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual int TakeArmor( float flArmor, int suit = 0 ); - virtual int TakeItem( int iItem ); - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) + pev->view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); }; // position to shoot at - virtual void StartSneaking( void ) { m_tSneaking = gpGlobals->time - 1; } - virtual void StopSneaking( void ) { m_tSneaking = gpGlobals->time + 30; } - virtual BOOL IsSneaking( void ) { return m_tSneaking <= gpGlobals->time; } - virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; } - virtual BOOL IsPlayer( void ) { return TRUE; } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned - - virtual BOOL IsNetClient( void ) { return TRUE; } // Bots should return FALSE for this, they can't receive NET messages - // Spectators should return TRUE for this - virtual const char *TeamID( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - void RenewItems(void); - void PackDeadPlayerItems( void ); - void RemoveAllItems( BOOL removeSuit ); - BOOL SwitchWeapon( CBasePlayerWeapon *pWeapon ); - - // JOHN: sends custom messages if player HUD data has changed (eg health, ammo) - virtual void UpdateClientData( void ); - - static TYPEDESCRIPTION m_playerSaveData[]; - - // Player is moved across the transition by other means - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual void Precache( void ); - BOOL IsOnLadder( void ); - BOOL FlashlightIsOn( void ); - void FlashlightTurnOn( void ); - void FlashlightTurnOff( void ); - - void UpdatePlayerSound ( void ); - void DeathSound ( void ); - - int Classify ( void ); - void SetAnimation( PLAYER_ANIM playerAnim ); - void SetWeaponAnimType( const char *szExtention ); - char m_szAnimExtention[32]; - - // custom player functions - virtual void ImpulseCommands( void ); - void CheatImpulseCommands( int iImpulse ); - - void StartDeathCam( void ); - void StartObserver( Vector vecPosition, Vector vecViewAngle ); - - void AddPoints( int score, BOOL bAllowNegativeScore ); - void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); - BOOL AddPlayerItem( CBasePlayerWeapon *pItem ); - BOOL RemovePlayerItem( CBasePlayerWeapon *pItem ); - void DropPlayerItem ( char *pszItemName ); - BOOL HasPlayerItem( CBasePlayerWeapon *pCheckItem ); - BOOL HasNamedPlayerItem( const char *pszItemName ); - BOOL HasWeapons( void );// do I have ANY weapons? - void SelectPrevItem( int iItem ); - void SelectNextItem( int iItem ); - void SelectLastItem(void); - void SelectItem(const char *pstr); - void QueueItem(CBasePlayerWeapon *pItem); - void ItemPreFrame( void ); - void ItemPostFrame( void ); - void GiveNamedItem( const char *szName ); - void EnableControl(BOOL fControl); - - int GiveAmmo( int iAmount, char *szName, int iMax ); - void SendAmmoUpdate(void); - - void WaterMove( void ); - void EXPORT PlayerDeathThink( void ); - void PlayerUse( void ); - - void CheckSuitUpdate(); - void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); - void UpdateGeigerCounter( void ); - void CheckTimeBasedDamage( void ); - - BOOL FBecomeProne ( void ); - void BarnacleVictimBitten ( entvars_t *pevBarnacle ); - void BarnacleVictimReleased ( void ); - static int GetAmmoIndex(const char *psz); - const char *GetAmmoName(int index ); - int AmmoInventory( int iAmmoIndex ); - int Illumination( void ); - - void ResetAutoaim( void ); - Vector GetAutoaimVector( float flDelta ); - Vector AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ); - - void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client. - - void DeathMessage( entvars_t *pevKiller ); - void SendStartMessages( void ); - - void SetCustomDecalFrames( int nFrames ); - int GetCustomDecalFrames( void ); - - //Player ID - void InitStatusBar( void ); - void UpdateStatusBar( void ); - int m_izSBarState[ SBAR_END ]; - float m_flNextSBarUpdateTime; - float m_flStatusBarDisappearDelay; - char m_SbarString0[ SBAR_STRING_SIZE ]; - char m_SbarString1[ SBAR_STRING_SIZE ]; - // for trigger_viewset - CBaseEntity *pViewEnt; // entity to look at - int viewFlags; // 1-active, 2-draw hud, 4 - inverse x, 8 - monster look - int viewNeedsUpdate; // precache sets to 1, UpdateClientData() sets to 0 - - // for trigger_sound - byte m_iSndRoomtype; // last roomtype set by sound entity - int hearNeedsUpdate; // update DSP contents - - //warhud message - int m_iWarHUD; - int m_iClientWarHUD; - - //fog variables - int m_iFogStartDist; - int m_iFogEndDist; - int m_iFogFinalEndDist; - int m_FogFadeTime; - Vector m_FogColor; - int fogNeedsUpdate; - - //fade fariables - Vector m_FadeColor; - int m_FadeAlpha; - int m_iFadeFlags; - float m_flFadeTime; - float m_flFadeHold; - int fadeNeedsUpdate; - int m_iStartMessage; - - float m_flStartTime; //start time - - float m_flNextChatTime; - int Rain_dripsPerSecond; - float Rain_windX, Rain_windY; - float Rain_randX, Rain_randY; - - int Rain_ideal_dripsPerSecond; - float Rain_ideal_windX, Rain_ideal_windY; - float Rain_ideal_randX, Rain_ideal_randY; - - float Rain_endFade; // 0 means off - float Rain_nextFadeUpdate; - - int rainNeedsUpdate; - Vector v_LastAngles; -}; - -#define AUTOAIM_2DEGREES 0.0348994967025 -#define AUTOAIM_5DEGREES 0.08715574274766 -#define AUTOAIM_8DEGREES 0.1391731009601 -#define AUTOAIM_10DEGREES 0.1736481776669 - -extern BOOL gInitHUD; - -#endif // PLAYER_H diff --git a/server/monsters/rat.cpp b/server/monsters/rat.cpp deleted file mode 100644 index 9eef8202..00000000 --- a/server/monsters/rat.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// rat - environmental monster -//========================================================= - -#include "extdll.h" -#include "utils.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 m_iClass?m_iClass:CLASS_INSECT; //LRC- maybe someone needs to give them a basic biology lesson... -} - -//========================================================= -// 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( ); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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() -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - PRECACHE_MODEL("models/bigrat.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/server/monsters/roach.cpp b/server/monsters/roach.cpp deleted file mode 100644 index 97fca488..00000000 --- a/server/monsters/roach.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// cockroach -//========================================================= - -#include "extdll.h" -#include "utils.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 m_iClass?m_iClass: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( ); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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() -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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() ) ) && !HaveCamerasInPVS( edict() )) - SetNextThink( RANDOM_FLOAT(1,1.5) ); - else - SetNextThink( 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. - SetNextThink( 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() ) ) && !HaveCamerasInPVS( 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 assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); - break; - } - } - } - } - SetConditions( iSighted ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - diff --git a/server/monsters/schedule.h b/server/monsters/schedule.h deleted file mode 100644 index 59e4079d..00000000 --- a/server/monsters/schedule.h +++ /dev/null @@ -1,292 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// 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_SCRIPT, - TASK_RUN_TO_SCRIPT, - 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_SCRIPT, - 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_END_SCRIPT, //LRC - 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/server/monsters/scientist.cpp b/server/monsters/scientist.cpp deleted file mode 100644 index 15647566..00000000 --- a/server/monsters/scientist.cpp +++ /dev/null @@ -1,1458 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// human scientist (passive lab worker) -//========================================================= - -#include "extdll.h" -#include "utils.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" -#include "defaults.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( m_szGrp[TLK_DECLINE], 2, VOL_NORM, ATTN_NORM ); //LRC -} - - -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 m_iClass?m_iClass: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( ); - - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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; - if (pev->health == 0) - pev->health = SCIENTIST_HEALTH; - pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - -// m_flDistTooFar = 256.0; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - - // White hands - pev->skin = 0; - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - MonsterInit(); - SetUse(&CScientist :: FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CScientist :: Precache( void ) -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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) - - if (!m_iszSpeakAs) - { - m_szGrp[TLK_ANSWER] = "SC_ANSWER"; - m_szGrp[TLK_QUESTION] = "SC_QUESTION"; - m_szGrp[TLK_IDLE] = "SC_IDLE"; - m_szGrp[TLK_STARE] = "SC_STARE"; - if (pev->spawnflags & SF_MONSTER_PREDISASTER) - m_szGrp[TLK_USE] = "SC_PFOLLOW"; - else - m_szGrp[TLK_USE] = "SC_OK"; - if (pev->spawnflags & SF_MONSTER_PREDISASTER) - m_szGrp[TLK_UNUSE] = "SC_PWAIT"; - else - m_szGrp[TLK_UNUSE] = "SC_WAIT"; - if (pev->spawnflags & SF_MONSTER_PREDISASTER) - m_szGrp[TLK_DECLINE] = "SC_POK"; - else - m_szGrp[TLK_DECLINE] = "SC_NOTOK"; - 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( SCIENTIST_HEAL, 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( void ) -{ - 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; - - -#define SF_SITTINGSCI_POSTDISASTER 1024 - -// -// ********** Scientist SPAWN ********** -// -void CSittingScientist :: Spawn( ) -{ - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - PRECACHE_MODEL("models/scientist.mdl"); - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - 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; - - if (!FBitSet(pev->spawnflags, SF_SITTINGSCI_POSTDISASTER)) //LRC- allow a sitter to be postdisaster. - SetBits(pev->spawnflags, SF_MONSTER_PREDISASTER); // predisaster only! - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - m_baseSequence = LookupSequence( "sitlookleft" ); - pev->sequence = m_baseSequence + RANDOM_LONG(0,4); - ResetSequenceInfo( ); - - SetThink(&CSittingScientist ::SittingThink); - SetNextThink( 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 m_iClass?m_iClass: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 ); - } - SetNextThink( 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/server/monsters/scripted.cpp b/server/monsters/scripted.cpp deleted file mode 100644 index a2198551..00000000 --- a/server/monsters/scripted.cpp +++ /dev/null @@ -1,1246 +0,0 @@ -/*** -* -* 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. -* 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 "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "player.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_iszAttack")) - { - m_iszAttack = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszMoveTarget")) - { - m_iszMoveTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszFireOnBegin")) - { - m_iszFireOnBegin = 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_fTurnType")) - { - m_fTurnType = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_fAction")) - { - m_fAction = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } -// LRC 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_iRepeats")) - { - m_iRepeats = atoi( pkvd->szValue ); - m_iRepeatsLeft = m_iRepeats; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_fRepeatFrame")) - { - m_fRepeatFrame = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iFinishSchedule")) - { - m_iFinishSchedule = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iPriority")) - { - m_iPriority = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CBaseMonster::KeyValue( pkvd ); - } -} - -TYPEDESCRIPTION CCineMonster::m_SaveData[] = -{ - DEFINE_FIELD( CCineMonster, m_iState, FIELD_INTEGER ), //LRC - 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_iszAttack, FIELD_STRING ), //LRC - DEFINE_FIELD( CCineMonster, m_iszMoveTarget, FIELD_STRING ), //LRC - DEFINE_FIELD( CCineMonster, m_iszFireOnBegin, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_fMoveTo, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_fTurnType, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_fAction, FIELD_INTEGER ), -//LRC- this is unused 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 ), - - //LRC - DEFINE_FIELD( CCineMonster, m_iRepeats, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_iRepeatsLeft, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_fRepeatFrame, FIELD_FLOAT ), - DEFINE_FIELD( CCineMonster, m_iPriority, FIELD_INTEGER ), -}; - - -IMPLEMENT_SAVERESTORE( CCineMonster, CBaseMonster ); - -LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ); -LINK_ENTITY_TO_CLASS( scripted_action, CCineMonster ); //LRC - -void CCineMonster :: Spawn( void ) -{ - // pev->solid = SOLID_TRIGGER; - // UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - pev->solid = SOLID_NOT; - - m_iState = STATE_OFF; //LRC - - if ( FStringNull(m_iszIdle) && FStringNull(pev->targetname) ) // if no targetname, start now - { - SetThink(&CCineMonster :: CineThink ); - SetNextThink( 1.0 ); - } - else if ( m_iszIdle ) - { - SetThink(&CCineMonster :: InitIdleThink ); - SetNextThink( 1.0 ); - } - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - m_interruptable = FALSE; - else - m_interruptable = TRUE; - - //LRC - the only difference between AI and normal sequences - if ( pev->spawnflags & SF_SCRIPT_OVERRIDESTATE ) - { - m_iPriority |= SS_INTERRUPT_ANYSTATE; - } -} - -// -// 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 ) - { -// ALERT(at_console, "Sequence \"%s\" triggered, already has a target.\n", STRING(pev->targetname)); - // am I already playing the script? - if ( pTarget->m_scriptState == SCRIPT_PLAYING ) - return; - - m_startTime = gpGlobals->time + 0.05; //why the delay? -- LRC - } - else - { -// ALERT(at_console, "Sequence \"%s\" triggered, can't find target; searching\n", STRING(pev->targetname)); - m_hActivator = pActivator; - // if not, try finding them - SetThink(&CCineMonster :: CineThink ); -// SetNextThink( 0 ); - CineThink(); //LRC - } -} - - -// This doesn't really make sense since only MOVETYPE_PUSH get 'Blocked' events -void CCineMonster :: Blocked( CBaseEntity *pOther ) -{ - -} - -void CCineMonster :: Touch( CBaseEntity *pOther ) -{ -} - -// -// ********** Cinematic DIE ********** -// -void CCineMonster :: Die( void ) -{ - SetThink( Remove ); -} - -// -// ********** Cinematic PAIN ********** -// -void CCineMonster :: Pain( void ) -{ - -} - -// -// ********** Cinematic Think ********** -// - -//LRC: now redefined... find a viable entity with the given name, and return it (or NULL if not found). -CBaseMonster* CCineMonster :: FindEntity( const char* sName, CBaseEntity *pActivator ) -{ - CBaseEntity *pEntity; - - pEntity = UTIL_FindEntityByTargetname(NULL, sName, pActivator); - //m_hTargetEnt = NULL; - CBaseMonster *pMonster = NULL; - - while (pEntity) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pMonster = pEntity->MyMonsterPointer( ); - if ( pMonster && pMonster->CanPlaySequence( m_iPriority | SS_INTERRUPT_ALERT ) ) - { - return pMonster; - } - ALERT( at_console, "Found %s, but can't play!\n", sName ); - } - pEntity = UTIL_FindEntityByTargetname( pEntity, sName, pActivator ); - pMonster = NULL; - } - - // couldn't find something with the given targetname; assume it's a classname instead. - if ( !pMonster ) - { - pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pEntity->pev, sName)) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pMonster = pEntity->MyMonsterPointer( ); - if ( pMonster && pMonster->CanPlaySequence( m_iPriority ) ) - { - return pMonster; - } - } - } - } - } - return NULL; -} - -// make the entity enter a scripted sequence -void CCineMonster :: PossessEntity( void ) -{ - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - -// ALERT( at_console, "Possess: pEntity %s, pTarget %s\n", STRING(pEntity->pev->targetname), STRING(pTarget->pev->targetname)); - - if ( pTarget ) - { - if (pTarget->m_pCine) - { - pTarget->m_pCine->CancelScript(); - } - - pTarget->m_pCine = this; - if (m_iszAttack) - { - // anything with that name? - pTarget->m_hTargetEnt = UTIL_FindEntityByTargetname(NULL, STRING(m_iszAttack), m_hActivator); - if ( pTarget->m_hTargetEnt == NULL ) - { // nothing. Anything with that classname? - while ((pTarget->m_hTargetEnt = UTIL_FindEntityInSphere( pTarget->m_hTargetEnt, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pTarget->m_hTargetEnt->pev, STRING(m_iszAttack))) break; - } - } - - if( pTarget->m_hTargetEnt == NULL ) - { - // nothing. Oh well. - ALERT( at_console, "%s %s has a missing \"turn target\": %s\n",STRING(pev->classname),STRING(pev->targetname),STRING(m_iszAttack)); - pTarget->m_hTargetEnt = this; - } - } - else - { - pTarget->m_hTargetEnt = this; - } - - if( m_iszMoveTarget ) - { - // anything with that name? - pTarget->m_pGoalEnt = UTIL_FindEntityByTargetname(NULL, STRING(m_iszMoveTarget), m_hActivator); - if( pTarget->m_pGoalEnt == NULL ) - { - // nothing. Oh well. - ALERT( at_console, "%s %s has a missing \"move target\": %s\n",STRING(pev->classname),STRING(pev->targetname),STRING(m_iszMoveTarget)); - pTarget->m_pGoalEnt = this; - } - } - else - { - pTarget->m_pGoalEnt = this; - } -// if (IsAction()) -// pTarget->PushEnemy(this,pev->origin); - - m_saved_movetype = pTarget->pev->movetype; - m_saved_solid = pTarget->pev->solid; - m_saved_effects = pTarget->pev->effects; - pTarget->pev->effects |= pev->effects; - -// ALERT(at_console, "script. IsAction = %d",IsAction()); - - m_iState = STATE_ON; // LRC: assume we'll set it to 'on', unless proven otherwise... - switch (m_fMoveTo) - { - case 1: - case 2: - DelayStart( 1 ); - m_iState = STATE_TURN_ON; - // fall through... - case 0: - case 4: - //G-Cont. this is a not a better way :( - //in my new project this bug will be removed - //in Spirit... as is. Sorry about that. - //If we interesting - decomment UTIL_AssignOrigin - //and run c1a4i with tentacle script - no comments - //UTIL_AssignOrigin( pTarget, 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; - break; - case 5: - case 6: - pTarget->m_scriptState = SCRIPT_WAIT; - 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) -// { -// ALERT(at_console, "Possess: Play idle sequence\n"); -// StartSequence( pTarget, m_iszIdle, FALSE ); -// if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) -// { -// pTarget->pev->framerate = 0; -// } -// } -// ALERT(at_console, "Finished PossessEntity, ms %d, ims %d\n", pTarget->m_MonsterState, pTarget->m_IdealMonsterState); - } - -} - - -// at the beginning of the level, set up the idle animation. --LRC -void CCineMonster :: InitIdleThink( void ) -{ - if ((m_hTargetEnt = FindEntity(STRING(m_iszEntity), NULL)) != NULL) - { - PossessEntity( ); - m_startTime = gpGlobals->time + 1E6; - 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 ) ); - SetNextThink( 1.0 ); - } -} - -void CCineMonster :: CineThink( void ) -{ -// ALERT(at_console, "Sequence think, activator %s\n", STRING(m_hActivator->pev->targetname)); - if ((m_hTargetEnt = FindEntity(STRING(m_iszEntity),m_hActivator)) != NULL) - { -// ALERT(at_console, "Sequence found %s \"%s\"\n", STRING(m_hTargetEnt->pev->classname), STRING(m_hTargetEnt->pev->targetname)); - PossessEntity( ); - ALERT( at_aiconsole, "script \"%s\" using monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - } - else - { -// ALERT(at_console, "Sequence found nothing called %s\n", STRING(m_iszEntity)); - CancelScript( ); - ALERT( at_aiconsole, "script \"%s\" can't find monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - SetNextThink( 1.0 ); - } -} - - -// lookup a sequence name and setup the target monster to play it -BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) -{ -// ALERT( at_console, "StartSequence %s \"%s\"\n", STRING(pev->classname), STRING(pev->targetname)); - - 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; -} - -//========================================================= -// 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 ) -{ - m_iRepeatsLeft = m_iRepeats; //LRC - reset the repeater count - m_iState = STATE_OFF; // we've finished. -// ALERT( at_console, "Sequence %s finished\n", STRING(pev->targetname));//STRING( m_pCine->m_iszPlay ) ); - - if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) - { - SetThink( Remove ); - SetNextThink( 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 - UTIL_FireTargets( pev->target, NULL, this, USE_TOGGLE ); -} - -//========================================================= -// 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. -// -// or select a specific AMBUSH schedule, regardless of state. //LRC -//========================================================= -void CCineMonster :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) -{ - if ( pMonster->m_IdealMonsterState != MONSTERSTATE_DEAD ) pMonster->m_IdealMonsterState = MONSTERSTATE_IDLE; -// pMonster->ClearSchedule(); - - 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; - - // Big fat BUG: This is an IgnoreConditions function - we need to return the conditions - // that _shouldn't_ be able to break the script, instead of the conditions that _should_!! - return SCRIPT_BREAK_CONDITIONS; -} - - -void ScriptEntityCancel( edict_t *pentCine ) -{ - // make sure they are a scripted_sequence - if (FClassnameIs( pentCine, "scripted_sequence" ) || FClassnameIs( pentCine, "scripted_action" )) - { - GetClassPtr((CCineMonster *)VARS(pentCine))->m_iState = STATE_OFF; - 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( ); - //LRC - clean up so that if another script is starting immediately, the monster will notice it. - pTarget->ClearSchedule( ); - } - } - } -} - - -// 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; - } - - CBaseEntity *pCineTarget = UTIL_FindEntityByTargetname(NULL, STRING(pev->targetname)); - - while (pCineTarget) - { - ScriptEntityCancel( ENT(pCineTarget->pev) ); - pCineTarget = UTIL_FindEntityByTargetname(pCineTarget, STRING(pev->targetname)); - } -} - - -// find all the cinematic entities with my targetname and tell them whether to wait before starting -void CCineMonster :: DelayStart( int state ) -{ - CBaseEntity *pCine = UTIL_FindEntityByTargetname(NULL, STRING(pev->targetname)); - - while ( pCine ) - { - if (FClassnameIs( pCine->pev, "scripted_sequence" ) || FClassnameIs( pCine->pev, "scripted_action" )) - { - CCineMonster *pTarget = GetClassPtr((CCineMonster *)(pCine->pev)); - if (state) - { -// ALERT(at_console, "Delaying start\n"); - pTarget->m_iDelay++; - } - else - { -// ALERT(at_console, "Undelaying start\n"); - pTarget->m_iDelay--; - if (pTarget->m_iDelay <= 0) - { - pTarget->m_iState = STATE_ON; //LRC - UTIL_FireTargets( m_iszFireOnBegin, this, this, USE_TOGGLE ); //LRC - pTarget->m_startTime = gpGlobals->time + 0.05; // why the delay? -- LRC - } - } - } - pCine = UTIL_FindEntityByTargetname(pCine, 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 ) -{ - CBaseEntity *pEntity; - CBaseMonster *pTarget; - - // The entity name could be a target name or a classname - // Check the targetname - pEntity = UTIL_FindEntityByTargetname(NULL, STRING(m_iszEntity)); - pTarget = NULL; - - while (!pTarget && pEntity) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pTarget = pEntity->MyMonsterPointer( ); - } - pEntity = UTIL_FindEntityByTargetname(pEntity, STRING(m_iszEntity)); - } - - // If no entity with that targetname, check the classname - if ( !pTarget ) - { - pEntity = UTIL_FindEntityByClassname(NULL, STRING(m_iszEntity)); - while (!pTarget && pEntity) - { - pTarget = pEntity->MyMonsterPointer( ); - pEntity = UTIL_FindEntityByClassname(pEntity, 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 ) ); - } - } - - CBaseMonster::Activate(); -} - - -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; - - if (m_pCine->pev->spawnflags & SF_SCRIPT_STAYDEAD) - pev->deadflag = DEAD_DYING; - } - 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 ) - { - SetUse( NULL ); // BUGBUG -- This doesn't call Killed() - SetThink( NULL ); // This will probably break some stuff - SetTouch( NULL ); - } - // 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( this, 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 ); - //LRC- removed, was never implemented. ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); - - return TRUE; -} - - - - -class CScriptedSentence : public CBaseAnimating -{ -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 ); - void EXPORT DurationThink( void ); - int ObjectCaps( void ) { return (CBaseAnimating :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - STATE GetState() { return m_playing?STATE_ON:STATE_OFF; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - CBaseMonster *FindEntity( CBaseEntity *pActivator ); - 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; // maximum repeat rate - float m_flAttenuation; - float m_flVolume; - BOOL m_active; // is the sentence enabled? (for m_flRepeat) - BOOL m_playing; //LRC- is the sentence playing? (for GetState) - 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_playing, FIELD_BOOLEAN ), - DEFINE_FIELD( CScriptedSentence, m_iszListener, FIELD_STRING ), -}; - - -IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseAnimating ); - -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 - CBaseAnimating::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) ); - m_hActivator = pActivator; - SetThink(&CScriptedSentence :: FindThink ); - SetNextThink( 0 ); -} - - -void CScriptedSentence :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - - m_active = TRUE; - m_playing = FALSE; //LRC - // if no targetname, start now - if ( !pev->targetname ) - { - SetThink(&CScriptedSentence :: FindThink ); - SetNextThink( 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 ) -{ - if (!m_iszEntity) //LRC- no target monster given: speak through HEV - { - CBasePlayer* pPlayer = (CBasePlayer*)UTIL_FindEntityByClassname( NULL, "player" ); - if (pPlayer) - { - m_playing = TRUE; - if ((STRING(m_iszSentence))[0] == '!') - pPlayer->SetSuitUpdate((char*)STRING(m_iszSentence),FALSE,0); - else - pPlayer->SetSuitUpdate((char*)STRING(m_iszSentence),TRUE,0); - if ( pev->spawnflags & SF_SENTENCE_ONCE ) - UTIL_Remove( this ); - SetThink(&CScriptedSentence :: DurationThink ); - SetNextThink( m_flDuration ); - m_active = FALSE; - } - else - ALERT( at_console, "ScriptedSentence: can't find \"player\" to play HEV sentence!?\n" ); - return; - } - - CBaseMonster *pMonster = FindEntity( m_hActivator ); - if ( pMonster ) - { - m_playing = TRUE; - StartSentence( pMonster ); - if ( pev->spawnflags & SF_SENTENCE_ONCE ) - UTIL_Remove( this ); - SetThink(&CScriptedSentence :: DurationThink ); - SetNextThink( m_flDuration ); - 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) ); - SetNextThink( m_flRepeat + 0.5 ); - } -} - -//LRC -void CScriptedSentence :: DurationThink( void ) -{ - m_playing = FALSE; - SetNextThink( m_flRepeat ); - SetThink(&CScriptedSentence :: DelayThink ); -} - -void CScriptedSentence :: DelayThink( void ) -{ - m_active = TRUE; - if ( !pev->targetname ) - SetNextThink( 0.1 ); - SetThink(&CScriptedSentence :: FindThink ); -} - - -BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) -{ - if ( pMonster ) - { - if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) - { - if ( pMonster->m_hTargetEnt == NULL || !FClassnameIs(pMonster->m_hTargetEnt->pev, "player") ) - return FALSE; - } - BOOL override; - if ( pev->spawnflags & SF_SENTENCE_INTERRUPT ) - override = TRUE; - else - override = FALSE; - if ( pMonster->CanPlaySentence( override ) ) - return TRUE; - } - return FALSE; -} - - -CBaseMonster *CScriptedSentence :: FindEntity( CBaseEntity *pActivator ) -{ - CBaseEntity *pTarget; - CBaseMonster *pMonster; - - pTarget = UTIL_FindEntityByTargetname(NULL, STRING(m_iszEntity), pActivator); - pMonster = NULL; - - while ( pTarget ) - { - pMonster = pTarget->MyMonsterPointer( ); - if ( pMonster != NULL ) - { - if ( AcceptableSpeaker( pMonster ) ) - return pMonster; -// ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) ); - } - pTarget = UTIL_FindEntityByTargetname(pTarget, STRING(m_iszEntity), pActivator); - } - - pTarget = NULL; - while ((pTarget = UTIL_FindEntityInSphere( pTarget, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pTarget->pev, STRING(m_iszEntity))) - { - if ( FBitSet( pTarget->pev->flags, FL_MONSTER )) - { - pMonster = pTarget->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; - //LRC: Er... if the "concurrent" flag is NOT set, we make bConcurrent true!? - 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 ); - UTIL_FireTargets( pev->target, NULL, this, USE_TOGGLE ); - 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( Remove ); - SetNextThink( 0 ); -} - -//========================================================= -// 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 m_iClass?m_iClass:CLASS_NONE; -} - - diff --git a/server/monsters/scripted.h b/server/monsters/scripted.h deleted file mode 100644 index 9f5cb94e..00000000 --- a/server/monsters/scripted.h +++ /dev/null @@ -1,128 +0,0 @@ -/*** -* -* 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. -* 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 SF_SCRIPT_STAYDEAD 256 // LRC- signifies that the animation kills the monster - // (needed because the monster animations don't use AnimEvent 1000 properly) - -#define SCRIPT_BREAK_CONDITIONS (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) - -//LRC - rearranged into flags -#define SS_INTERRUPT_IDLE 0x0 -#define SS_INTERRUPT_ALERT 0x1 -#define SS_INTERRUPT_ANYSTATE 0x2 -#define SS_INTERRUPT_SCRIPTS 0x4 - -// 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[]; - - //LRC: states for script entities - virtual STATE GetState( void ) { return m_iState; }; - STATE m_iState; - - // void EXPORT CineSpawnThink( void ); - void EXPORT CineThink( void ); - void EXPORT InitIdleThink( void ); //LRC - void Pain( void ); - void Die( void ); - void DelayStart( int state ); - CBaseMonster* FindEntity( const char* sName, CBaseEntity *pActivator ); - virtual void PossessEntity( void ); - - inline BOOL IsAction( void ) { return FClassnameIs(pev,"scripted_action"); }; //LRC - - //LRC: Should the monster do a precise attack for this scripted_action? - // (Do a precise attack if we'll be turning to face the target, but we haven't just walked to the target.) - BOOL PreciseAttack( void ) - { - // if (m_fTurnType != 1) { ALERT(at_console,"preciseattack fails check 1\n"); return FALSE; } - // if (m_fMoveTo == 0) { ALERT(at_console,"preciseattack fails check 2\n"); return FALSE; } - // if (m_fMoveTo != 5 && m_iszAttack == 0) { ALERT(at_console,"preciseattack fails check 3\n"); return FALSE; } - // ALERT(at_console,"preciseattack passes!\n"); - // return TRUE; - return m_fTurnType == 1 && ( m_fMoveTo == 5 || (m_fMoveTo != 0 && !FStrEq(STRING(m_iszAttack), STRING(m_iszMoveTarget)) )); - }; - - void ReleaseEntity( CBaseMonster *pEntity ); - void CancelScript( void ); - virtual BOOL StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ); - 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_iszAttack; // entity to attack - int m_iszMoveTarget; // entity to move to - int m_iszFireOnBegin; // entity to fire when the sequence _starts_. - int m_fMoveTo; - int m_fTurnType; - int m_fAction; - int m_iFinishSchedule; - float m_flRadius; // range to search -//LRC- this does nothing!! float m_flRepeat; // repeat rate - int m_iRepeats; //LRC - number of times to repeat the animation - int m_iRepeatsLeft; //LRC - float m_fRepeatFrame; //LRC - int m_iPriority; //LRC - - int m_iDelay; - float m_startTime; - - int m_saved_movetype; - int m_saved_solid; - int m_saved_effects; -// Vector m_vecOrigOrigin; - BOOL m_interruptable; -}; - -//LRC - removed CCineAI, obsolete - -#endif //SCRIPTED_H diff --git a/server/monsters/scriptevent.h b/server/monsters/scriptevent.h deleted file mode 100644 index 9a02bd64..00000000 --- a/server/monsters/scriptevent.h +++ /dev/null @@ -1,29 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef SCRIPTEVENT_H -#define SCRIPTEVENT_H - -#define SCRIPT_EVENT_DEAD 1000 // character is now dead -#define SCRIPT_EVENT_NOINTERRUPT 1001 // does not allow interrupt -#define SCRIPT_EVENT_CANINTERRUPT 1002 // will allow interrupt -#define SCRIPT_EVENT_FIREEVENT 1003 // event now fires -#define SCRIPT_EVENT_SOUND 1004 // Play named wave file (on CHAN_BODY) -#define SCRIPT_EVENT_SENTENCE 1005 // Play named sentence -#define SCRIPT_EVENT_INAIR 1006 // Leave the character in air at the end of the sequence (don't find the floor) -#define SCRIPT_EVENT_ENDANIMATION 1007 // Set the animation by name after the sequence completes -#define SCRIPT_EVENT_SOUND_VOICE 1008 // Play named wave file (on CHAN_VOICE) -#define SCRIPT_EVENT_SENTENCE_RND1 1009 // Play sentence group 25% of the time -#define SCRIPT_EVENT_NOT_DEAD 1010 // Bring back to life (for life/death sequences) -#endif //SCRIPTEVENT_H diff --git a/server/monsters/squad.h b/server/monsters/squad.h deleted file mode 100644 index 9acfccb2..00000000 --- a/server/monsters/squad.h +++ /dev/null @@ -1,20 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: New version of the slider bar -// -// $NoKeywords: $ -//============================================================================= - -//========================================================= -// squad.h -//========================================================= - -// these are special group roles that are assigned to members when the group is formed. -// the reason these are explicitly assigned and tasks like throwing grenades to flush out -// enemies is that it's bad to have two members trying to flank left at the same time, but -// ok to have two throwing grenades at the same time. When a squad member cannot attack the -// enemy, it will choose to execute its special role. -#define bits_SQUAD_FLANK_LEFT ( 1 << 0 ) -#define bits_SQUAD_FLANK_RIGHT ( 1 << 1 ) -#define bits_SQUAD_ADVANCE ( 1 << 2 ) -#define bits_SQUAD_FLUSH_ATTACK ( 1 << 3 ) \ No newline at end of file diff --git a/server/monsters/squadmonster.cpp b/server/monsters/squadmonster.cpp deleted file mode 100644 index 59a9aaf3..00000000 --- a/server/monsters/squadmonster.cpp +++ /dev/null @@ -1,642 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Squadmonster functions -//========================================================= -#include "extdll.h" -#include "utils.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_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; - } - - } -} - -BOOL CSquadMonster :: NoFriendlyFire( void ) -{ - return NoFriendlyFire( FALSE ); //default: don't like the player -} - -//========================================================= -// 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. -// -// Can now, also, check whether the player is in the box. LRC -//========================================================= -BOOL CSquadMonster :: NoFriendlyFire( BOOL playerAlly ) -{ - if ( !playerAlly && !InSquad() ) - { - return TRUE; - } - - VPlane backPlane; - VPlane leftPlane; - VPlane 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.Init ( gpGlobals->v_right, vecLeftSide ); - rightPlane.Init ( v_left, vecRightSide ); - backPlane.Init ( 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.GetPointSide ( pMember->pev->origin ) && - leftPlane.GetPointSide ( pMember->pev->origin ) && - rightPlane.GetPointSide ( pMember->pev->origin) ) - { - // this guy is in the check volume! Don't shoot! - return FALSE; - } - } - } - - if (playerAlly) - { - edict_t *pentPlayer = FIND_CLIENT_IN_PVS( edict() ); - if (!FNullEnt(pentPlayer) && - backPlane.GetPointSide ( pentPlayer->v.origin ) && - leftPlane.GetPointSide ( pentPlayer->v.origin ) && - rightPlane.GetPointSide ( pentPlayer->v.origin ) ) - { - // the player 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/server/monsters/squadmonster.h b/server/monsters/squadmonster.h deleted file mode 100644 index 8519bdd7..00000000 --- a/server/monsters/squadmonster.h +++ /dev/null @@ -1,121 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// 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 ); - BOOL NoFriendlyFire( BOOL playerAlly ); - - // 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/server/monsters/talkmonster.cpp b/server/monsters/talkmonster.cpp deleted file mode 100644 index 472684da..00000000 --- a/server/monsters/talkmonster.cpp +++ /dev/null @@ -1,1557 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "utils.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_iszDecline, FIELD_STRING ), //LRC - DEFINE_FIELD( CTalkMonster, m_iszSpeakAs, FIELD_STRING ), //LRC - 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; - - if (m_iszSpeakAs) //LRC: changing voice groups for monsters - { - char szBuf[64]; - strcpy(szBuf,STRING(m_iszSpeakAs)); - strcat(szBuf,"_"); - char *szAssign = &(szBuf[strlen(szBuf)]); - - //LRC - this is pretty dodgy; test with save/restore. - strcpy(szAssign,"ANSWER"); - m_szGrp[TLK_ANSWER] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"QUESTION"); - m_szGrp[TLK_QUESTION] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"IDLE"); - m_szGrp[TLK_IDLE] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"STARE"); - m_szGrp[TLK_STARE] = STRING(ALLOC_STRING(szBuf)); - if (pev->spawnflags & SF_MONSTER_PREDISASTER) //LRC - strcpy(szAssign,"PFOLLOW"); - else - strcpy(szAssign,"OK"); - m_szGrp[TLK_USE] = STRING(ALLOC_STRING(szBuf)); - if (pev->spawnflags & SF_MONSTER_PREDISASTER) //LRC - strcpy(szAssign,"PWAIT"); - else - strcpy(szAssign,"WAIT"); - m_szGrp[TLK_UNUSE] = STRING(ALLOC_STRING(szBuf)); - if (pev->spawnflags & SF_MONSTER_PREDISASTER) //LRC - strcpy(szAssign,"POK"); - else - strcpy(szAssign,"NOTOK"); - m_szGrp[TLK_DECLINE] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"STOP"); - m_szGrp[TLK_STOP] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"NOSHOOT"); - m_szGrp[TLK_NOSHOOT] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"HELLO"); - m_szGrp[TLK_HELLO] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"PLHURT1"); - m_szGrp[TLK_PLHURT1] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"PLHURT2"); - m_szGrp[TLK_PLHURT2] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"PLHURT3"); - m_szGrp[TLK_PLHURT3] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"PHELLO"); - m_szGrp[TLK_PHELLO] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"PIDLE"); - m_szGrp[TLK_PIDLE] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"PQUESTION"); - m_szGrp[TLK_PQUESTION] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"SMELL"); - m_szGrp[TLK_SMELL] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"WOUND"); - m_szGrp[TLK_WOUND] = STRING(ALLOC_STRING(szBuf)); - strcpy(szAssign,"MORTAL"); - m_szGrp[TLK_MORTAL] = STRING(ALLOC_STRING(szBuf)); - } - - 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; - - //monster generic can speak always - if ( pev->spawnflags & SF_MONSTER_GAG && !FClassnameIs(pev, "monster_generic") ) - 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())) && !HaveCamerasInPVS( 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(); -} - -//LRC- redefined, now returns true if following would be physically possible -BOOL CTalkMonster::CanFollow( void ) -{ - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - if ( !m_pCine->CanInterrupt() ) - return FALSE; - } - - if ( !IsAlive() ) - return FALSE; - - return TRUE; -} - - -//LRC- rewritten -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; - - //ALERT(at_console,"Talkmonster was Used: "); - - // CanFollow is now true if the monster could physically follow anyone - if ( pCaller != NULL && pCaller->IsPlayer() && CanFollow() ) - { - if ( !IsFollowing() ) - { - // Pre-disaster followers can't be used unless they've got a master to override their behaviour... - if (IsLockedByMaster() || (pev->spawnflags & SF_MONSTER_PREDISASTER && !m_sMaster)) - { - //ALERT(at_console,"Decline\n"); - DeclineFollowing(); - } - else - { - LimitFollowers( pCaller , 1 ); - if ( m_afMemory & bits_MEMORY_PROVOKED ) - { - //ALERT(at_console,"Fail\n"); - ALERT( at_aiconsole, "I'm not following you, you evil person!\n" ); - } - else - { - //ALERT(at_console,"Start\n"); - StartFollowing( pCaller ); - SetBits(m_bitsSaid, bit_saidHelloPlayer); // Don't say hi after you've started following - } - } - } - else - { - //ALERT(at_console,"Stop\n"); - 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 if (FStrEq(pkvd->szKeyName, "RefusalSentence")) //LRC - { - m_iszDecline = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "SpeakAs")) //LRC - { - m_iszSpeakAs = 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 ); - if ( m_iszDecline ) //LRC - m_szGrp[TLK_DECLINE] = STRING( m_iszDecline ); -} - diff --git a/server/monsters/talkmonster.h b/server/monsters/talkmonster.h deleted file mode 100644 index a6736868..00000000 --- a/server/monsters/talkmonster.h +++ /dev/null @@ -1,186 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#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_DECLINE, //LRC- refuse to accompany - TLK_STOP, - TLK_NOSHOOT, - TLK_HELLO, - TLK_PHELLO, - TLK_PIDLE, - TLK_PQUESTION, - TLK_PLHURT1, - TLK_PLHURT2, - TLK_PLHURT3, - TLK_SMELL, - TLK_WOUND, - TLK_MORTAL, - - TLK_CGROUPS, // MUST be last entry -} TALKGROUPNAMES; - - -enum -{ - SCHED_CANT_FOLLOW = LAST_COMMON_SCHEDULE + 1, - SCHED_MOVE_AWAY, // Try to get out of the player's way - SCHED_MOVE_AWAY_FOLLOW, // same, but follow afterward - SCHED_MOVE_AWAY_FAIL, // Turn back toward player - - LAST_TALKMONSTER_SCHEDULE, // MUST be last -}; - -enum -{ - TASK_CANT_FOLLOW = LAST_COMMON_TASK + 1, - TASK_MOVE_AWAY_PATH, - TASK_WALK_PATH_FOR_UNITS, - - TASK_TLK_RESPOND, // say my response - TASK_TLK_SPEAK, // question or remark - TASK_TLK_HELLO, // Try to say hello to player - TASK_TLK_HEADRESET, // reset head position - TASK_TLK_STOPSHOOTING, // tell player to stop shooting friend - TASK_TLK_STARE, // let the player know I know he's staring at me. - TASK_TLK_LOOK_AT_CLIENT,// faces player if not moving and not talking and in idle. - TASK_TLK_CLIENT_STARE, // same as look at client, but says something if the player stares. - TASK_TLK_EYECONTACT, // maintain eyecontact with person who I'm talking to - TASK_TLK_IDEALYAW, // set ideal yaw to face who I'm talking to - TASK_FACE_PLAYER, // Face the player - - LAST_TALKMONSTER_TASK, // MUST be last -}; - -class CTalkMonster : public CBaseMonster -{ -public: - void TalkInit( void ); - CBaseEntity *FindNearestFriend(BOOL fPlayer); - float TargetDistance( void ); - void StopTalking( void ) { SentenceStop(); } - - // Base Monster functions - void Precache( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); - void Touch( CBaseEntity *pOther ); - void Killed( entvars_t *pevAttacker, int iGib ); - int IRelationship ( CBaseEntity *pTarget ); - virtual int CanPlaySentence( BOOL fDisregardState ); - virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ); - void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - void KeyValue( KeyValueData *pkvd ); - - // AI functions - void SetActivity ( Activity newActivity ); - Schedule_t *GetScheduleOfType ( int Type ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void PrescheduleThink( void ); - - - // Conversations / communication - int GetVoicePitch( void ); - void IdleRespond( void ); - int FIdleSpeak( void ); - int FIdleStare( void ); - int FIdleHello( void ); - void IdleHeadTurn( Vector &vecFriend ); - int FOkToSpeak( void ); - void TrySmellTalk( void ); - CBaseEntity *EnumFriends( CBaseEntity *pentPrevious, int listNumber, BOOL bTrace ); - void AlertFriends( void ); - void ShutUpFriends( void ); - BOOL IsTalking( void ); - void Talk( float flDuration ); - // For following - BOOL CanFollow( void ); - BOOL IsFollowing( void ) { return m_hTargetEnt != NULL && m_hTargetEnt->IsPlayer(); } - void StopFollowing( BOOL clearSchedule ); - void StartFollowing( CBaseEntity *pLeader ); - virtual void DeclineFollowing( void ) {} - void LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ); - - void EXPORT FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual void SetAnswerQuestion( CTalkMonster *pSpeaker ); - virtual int FriendNumber( int arrayNumber ) { return arrayNumber; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - - static char *m_szFriends[TLK_CFRIENDS]; // array of friend names - static float g_talkWaitTime; - - int m_bitsSaid; // set bits for sentences we don't want repeated - int m_nSpeak; // number of times initiated talking - int m_voicePitch; // pitch of voice for this head - const char *m_szGrp[TLK_CGROUPS]; // sentence group names - float m_useTime; // Don't allow +USE until this time - int m_iszUse; // Custom +USE sentence group (follow) - int m_iszUnUse; // Custom +USE sentence group (stop following) - int m_iszDecline; // Custom +USE sentence group (refuse to follow) LRC - int m_iszSpeakAs; // Change the prefix for all this monster's speeches LRC - - 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/server/monsters/turret.cpp b/server/monsters/turret.cpp deleted file mode 100644 index c1c0437b..00000000 --- a/server/monsters/turret.cpp +++ /dev/null @@ -1,1343 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== 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 "utils.h" -#include "cbase.h" -#include "client.h" -#include "monsters.h" -#include "baseweapon.h" -#include "basebeams.h" -#include "defaults.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; - virtual STATE getState() { if (m_iOn) { return STATE_ON; } else { return STATE_OFF; } } - - 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( ); - SetNextThink( 1 ); - pev->movetype = MOVETYPE_FLY; - pev->sequence = 0; - pev->frame = 0; - pev->solid = SOLID_SLIDEBOX; - pev->takedamage = DAMAGE_AIM; - - SetBits (pev->flags, FL_MONSTER); - SetUse(&CBaseTurret:: TurretUse ); - - if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) - { - m_iAutoStart = TRUE; - } - - if (m_iOrientation == 1) - { - pev->idealpitch = 180; - pev->angles.x = 180; - } - - 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( ); - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - SET_MODEL(ENT(pev), "models/turret.mdl"); - if (!pev->health) - pev->health = TURRET_HEALTH; - m_HackedGunPos = Vector( 0, 0, 12.75 ); - m_flMaxSpin = TURRET_MAXSPIN; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); - - SetThink(&CTurret::Initialize); - - m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); - m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); - m_pEyeGlow->SetParent( this, 2 ); - m_eyeBrightness = 0; - - SetNextThink( 0.3 ); -} - -void CTurret::Precache() -{ - CBaseTurret::Precache( ); - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - PRECACHE_MODEL ("models/turret.mdl"); - PRECACHE_MODEL (TURRET_GLOW_SPRITE); -} - -void CMiniTurret::Spawn() -{ - Precache( ); - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - SET_MODEL(ENT(pev), "models/miniturret.mdl"); - if (!pev->health) - pev->health = MINITURRET_HEALTH; - m_HackedGunPos = Vector( 0, 0, 12.75 ); - m_flMaxSpin = 0; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - - SetThink(&CMiniTurret::Initialize); - SetNextThink( 0.3 ); -} - - -void CMiniTurret::Precache() -{ - CBaseTurret::Precache( ); - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - 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; //This is moved to CBaseTurret::Spawn for fix old bug in original HL. G-Cont. -// pev->angles.x = 180; - pev->view_ofs.z = -pev->view_ofs.z; - pev->effects |= EF_INVLIGHT; - pev->angles.y = pev->angles.y + 180; - if (pev->angles.y > 360) - pev->angles.y = pev->angles.y - 360; - } - - m_vecGoalAngles.x = 0; - - if (m_iAutoStart) - { - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::AutoSearchThink); - SetNextThink( 0.1 ); - } - else - SetThink( NULL ); -} - -void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType == USE_TOGGLE ) - { - if ( m_iOn ) - useType = USE_OFF; - else useType = USE_ON; - } - if ( useType == USE_ON ) - { - SetNextThink( 0.1 ); // turn on delay - - if ( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - m_iAutoStart = TRUE; - SetThink( Deploy ); - } - else if ( useType == USE_OFF ) - { - m_hEnemy = NULL; - SetNextThink( 0.1 ); - m_iAutoStart = FALSE; // switching off a turret disables autostart - SetThink( Retire ); - } - else if( USE_SHOWINFO ) - { - DEBUGHEAD; - } -} - - -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( void ) -{ - if( m_pEyeGlow ) - { - if( m_eyeBrightness != 255 ) - { - m_eyeBrightness = 255; - pev->skin = 1; // enable glow - } - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - } -} - - -void CBaseTurret :: EyeOff( void ) -{ - if( m_pEyeGlow ) - { - if( m_eyeBrightness > 0 ) - { - m_eyeBrightness = max( 0, m_eyeBrightness - 30 ); - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - if( m_eyeBrightness < 50 ) pev->skin = 0; - } - } -} - - -void CBaseTurret::ActiveThink(void) -{ - int fAttack = 0; - Vector vecDirToEnemy; - - SetNextThink( 0.1 ); - StudioFrameAdvance( ); - - if ((!m_iOn) || (m_hEnemy == NULL)) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - - // if it's dead, look for something new - if ( !m_hEnemy->IsAlive() ) - { - if (!m_flLastSight) - { - m_flLastSight = gpGlobals->time + 0.5; // continue-shooting timeout - } - else - { - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - } - - Vector vecMid = pev->origin + pev->view_ofs; - Vector vecMidEnemy = m_hEnemy->BodyTarget( vecMid ); - - // Look for our current enemy - int fEnemyVisible = FBoxVisible(pev, m_hEnemy->pev, vecMidEnemy ); - - vecDirToEnemy = vecMidEnemy - vecMid; // calculate dir and dist to enemy - float flDistToEnemy = vecDirToEnemy.Length(); - - Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid); - - // Current enmey is not visible. - if (!fEnemyVisible || (flDistToEnemy > TURRET_RANGE)) - { - if (!m_flLastSight) - m_flLastSight = gpGlobals->time + 0.5; - else - { - // Should we look for a new target? - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - fEnemyVisible = 0; - } - else - { - m_vecLastSight = vecMidEnemy; - } - - UTIL_MakeAimVectors(m_vecCurAngles); - - /* - ALERT( at_console, "%.0f %.0f : %.2f %.2f %.2f\n", - m_vecCurAngles.x, m_vecCurAngles.y, - gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_forward.z ); - */ - - Vector vecLOS = vecDirToEnemy; //vecMid - m_vecLastSight; - vecLOS = vecLOS.Normalize(); - - // Is the Gun looking at the target - if (DotProduct(vecLOS, gpGlobals->v_forward) <= 0.866) // 30 degree slop - fAttack = FALSE; - else - fAttack = TRUE; - - // fire the gun - if (m_iSpin && ((fAttack) || (m_fBeserk))) - { - Vector vecSrc, vecAng; - GetAttachment( 0, vecSrc, vecAng ); - SetTurretAnim(TURRET_ANIM_FIRE); - Shoot(vecSrc, gpGlobals->v_forward ); - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - } - - //move the gun - if (m_fBeserk) - { - if (RANDOM_LONG(0,9) == 0) - { - m_vecGoalAngles.y = RANDOM_FLOAT(0,360); - m_vecGoalAngles.x = RANDOM_FLOAT(0,90) - 90 * m_iOrientation; - TakeDamage(pev,pev,1, DMG_GENERIC); // don't beserk forever - return; - } - } - else if (fEnemyVisible) - { - if (vec.y > 360) - vec.y -= 360; - - if (vec.y < 0) - vec.y += 360; - - //ALERT(at_console, "[%.2f]", vec.x); - - if (vec.x < -180) - vec.x += 360; - - if (vec.x > 180) - vec.x -= 360; - - // now all numbers should be in [1...360] - // pin to turret limitations to [-90...15] - - if (m_iOrientation == 0) - { - if (vec.x > 90) - vec.x = 90; - else if (vec.x < m_iMinPitch) - vec.x = m_iMinPitch; - } - else - { - if (vec.x < -90) - vec.x = -90; - else if (vec.x > -m_iMinPitch) - vec.x = -m_iMinPitch; - } - - // ALERT(at_console, "->[%.2f]\n", vec.x); - - m_vecGoalAngles.y = vec.y; - m_vecGoalAngles.x = vec.x; - - } - - SpinUpCall(); - MoveTurret(); -} - - -void CTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_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_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) -{ - SetNextThink( 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); - UTIL_FireTargets( pev->target, this, this, USE_ON ); - } - - if (m_fSequenceFinished) - { - pev->maxs.z = m_iDeployHeight; - pev->mins.z = -m_iDeployHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - - m_vecCurAngles.x = 0; - - if (m_iOrientation == 1) - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y + 180 ); - } - else - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y ); - } - - SetTurretAnim(TURRET_ANIM_SPIN); - pev->framerate = 0; - SetThink(&CBaseTurret::SearchThink); - } - - m_flLastSight = gpGlobals->time + m_flMaxWait; -} - -void CBaseTurret::Retire(void) -{ - // make the turret level - m_vecGoalAngles.x = 0; - m_vecGoalAngles.y = m_flStartYaw; - - SetNextThink( 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); - UTIL_FireTargets( pev->target, this, this, USE_OFF ); - } - else if (m_fSequenceFinished) - { - m_iOn = 0; - m_flLastSight = 0; - SetTurretAnim(TURRET_ANIM_NONE); - pev->maxs.z = m_iRetractHeight; - pev->mins.z = -m_iRetractHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - if (m_iAutoStart) - { - SetThink(&CBaseTurret::AutoSearchThink); - SetNextThink( 0.1 ); - } - else - SetThink( NULL ); - } - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - } -} - - -void CTurret::SpinUpCall(void) -{ - StudioFrameAdvance( ); - SetNextThink( 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) - { - SetNextThink( 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) - { - SetNextThink( 0.1 ); // retarget delay - EMIT_SOUND(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - SetThink(&CTurret::ActiveThink); - m_iStartSpin = 0; - m_iSpin = 1; - } - else - { - pev->framerate += 0.075; - } - } - - if (m_iSpin) - { - SetThink(&CTurret::ActiveThink); - } -} - - -void CTurret::SpinDownCall(void) -{ - if (m_iSpin) - { - SetTurretAnim( TURRET_ANIM_SPIN ); - if (pev->framerate == 1.0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - EMIT_SOUND(ENT(pev), CHAN_ITEM, "turret/tu_spindown.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - } - pev->framerate -= 0.02; - if (pev->framerate <= 0) - { - pev->framerate = 0; - m_iSpin = 0; - } - } -} - - -void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) -{ - if (pev->sequence != anim) - { - switch(anim) - { - case TURRET_ANIM_FIRE: - case TURRET_ANIM_SPIN: - if (pev->sequence != TURRET_ANIM_FIRE && pev->sequence != TURRET_ANIM_SPIN) - { - pev->frame = 0; - } - break; - default: - pev->frame = 0; - break; - } - - pev->sequence = anim; - ResetSequenceInfo( ); - - switch(anim) - { - case TURRET_ANIM_RETIRE: - pev->frame = 255; - pev->framerate = -1.0; - break; - case TURRET_ANIM_DIE: - pev->framerate = 1.0; - break; - } - //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( ); - SetNextThink( 0.1 ); - - if (m_flSpinUpTime == 0 && m_flMaxSpin) - m_flSpinUpTime = gpGlobals->time + m_flMaxSpin; - - Ping( ); - - // If we have a target and we're still healthy - if (m_hEnemy != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - - // Acquire Target - if (m_hEnemy == NULL) - { - Look(TURRET_RANGE); - m_hEnemy = BestVisibleEnemy(); - } - - // If we've found a target, spin up the barrel and start to attack - if (m_hEnemy != NULL) - { - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::ActiveThink); - } - else - { - // Are we out of time, do we need to retract? - if (gpGlobals->time > m_flLastSight) - { - //Before we retrace, make sure that we are spun down. - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::Retire); - } - // should we stop the spin? - else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) - { - SpinDownCall(); - } - - // generic hunt for new victims - m_vecGoalAngles.y = (m_vecGoalAngles.y + 0.1 * m_fTurnRate); - if (m_vecGoalAngles.y >= 360) - m_vecGoalAngles.y -= 360; - MoveTurret(); - } -} - - -// -// This think function will deploy the turret when something comes into range. This is for -// automatically activated turrets. -// -void CBaseTurret::AutoSearchThink(void) -{ - // ensure rethink - StudioFrameAdvance( ); - SetNextThink( 0.3 ); - - // If we have a target and we're still healthy - - if (m_hEnemy != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - // Acquire Target - - if (m_hEnemy == NULL) - { - Look( TURRET_RANGE ); - m_hEnemy = BestVisibleEnemy(); - } - - if (m_hEnemy != NULL) - { - SetThink(&CBaseTurret::Deploy); - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - } -} - - -void CBaseTurret :: TurretDeath( void ) -{ - BOOL iActive = FALSE; - - StudioFrameAdvance( ); - SetNextThink( 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, gmsg.TempEntity ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ) ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ) ); - WRITE_COORD( pev->origin.z - m_iOrientation * 64 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 25 ); // scale * 10 - WRITE_BYTE( 10 - m_iOrientation * 5); // framerate - MESSAGE_END(); - } - - if (pev->dmgtime + RANDOM_FLOAT( 0, 5 ) > gpGlobals->time) - { - Vector vecSrc = Vector( RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ), RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ), 0 ); - if (m_iOrientation == 0) - vecSrc = vecSrc + Vector( 0, 0, RANDOM_FLOAT( pev->origin.z, pev->absmax.z ) ); - else - vecSrc = vecSrc + Vector( 0, 0, RANDOM_FLOAT( pev->absmin.z, pev->origin.z ) ); - - UTIL_Sparks( vecSrc ); - } - - if (m_fSequenceFinished && !MoveTurret( ) && pev->dmgtime + 5 < gpGlobals->time) - { - pev->framerate = 0; - SetThink( NULL ); - } -} - - - -void CBaseTurret :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( ptr->iHitgroup == 10 ) - { - // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - - if ( !pev->takedamage ) - return; - - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -// take damage. bitsDamageType indicates type of damage sustained, ie: DMG_BULLET - -int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - - if (!m_iOn) - flDamage /= 10.0; - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink(&CBaseTurret::TurretDeath); - UTIL_FireTargets( pev->target, this, this, USE_ON ); - SetNextThink( 0.1 ); - - return 0; - } - - if (pev->health <= 10) - { - if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) - { - m_fBeserk = 1; - SetThink(&CBaseTurret::SearchThink); - } - } - - return 1; -} - -int CBaseTurret::MoveTurret(void) -{ - int state = 0; - // any x movement? - - if (m_vecCurAngles.x != m_vecGoalAngles.x) - { - float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; - - m_vecCurAngles.x += 0.1 * m_fTurnRate * flDir; - - // if we started below the goal, and now we're past, peg to goal - if (flDir == 1) - { - if (m_vecCurAngles.x > m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - else - { - if (m_vecCurAngles.x < m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - - if (m_iOrientation == 0) - SetBoneController(1, -m_vecCurAngles.x); - else - SetBoneController(1, m_vecCurAngles.x); - state = 1; - } - - if (m_vecCurAngles.y != m_vecGoalAngles.y) - { - float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; - float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); - - if (flDist > 180) - { - flDist = 360 - flDist; - flDir = -flDir; - } - if (flDist > 30) - { - if (m_fTurnRate < m_iBaseTurnRate * 10) - { - m_fTurnRate += m_iBaseTurnRate; - } - } - else if (m_fTurnRate > 45) - { - m_fTurnRate -= m_iBaseTurnRate; - } - else - { - m_fTurnRate += m_iBaseTurnRate; - } - - m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; - - if (m_vecCurAngles.y < 0) - m_vecCurAngles.y += 360; - else if (m_vecCurAngles.y >= 360) - m_vecCurAngles.y -= 360; - - if (flDist < (0.05 * m_iBaseTurnRate)) - m_vecCurAngles.y = m_vecGoalAngles.y; - - //ALERT(at_console, "%.2f -> %.2f\n", m_vecCurAngles.y, y); - if (m_iOrientation == 0) - SetBoneController(0, m_vecCurAngles.y - pev->angles.y ); - else - SetBoneController(0, pev->angles.y - 180 - m_vecCurAngles.y ); - state = 1; - } - - if (!state) - m_fTurnRate = m_iBaseTurnRate; - - //ALERT(at_console, "(%.2f, %.2f)->(%.2f, %.2f)\n", m_vecCurAngles.x, - // m_vecCurAngles.y, m_vecGoalAngles.x, m_vecGoalAngles.y); - return state; -} - -// -// ID as a machine -// -int CBaseTurret::Classify ( void ) -{ - if (m_iClass) return m_iClass; - 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( ); - if (pev->model) - PRECACHE_MODEL((char*)STRING(pev->model)); //LRC - else - PRECACHE_MODEL ("models/sentry.mdl"); -} - -void CSentry::Spawn() -{ - Precache( ); - if (pev->model) - SET_MODEL(ENT(pev), STRING(pev->model)); //LRC - else - SET_MODEL(ENT(pev), "models/sentry.mdl"); - if (!pev->health) //LRC - pev->health = SENTRY_HEALTH; - m_HackedGunPos = Vector( 0, 0, 48 ); - pev->view_ofs.z = 48; - //m_flMaxWait = 1E6; - if (m_flMaxWait == 0) m_flMaxWait = TURRET_MAXWAIT;//G-Cont. now sentry can deployed - 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)); - DROP_TO_FLOOR ( ENT(pev) ); - - SetTouch(&CSentry::SentryTouch); - SetThink(&CSentry::Initialize); - SetNextThink( 0.3 ); -} - -void CSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MP5, 1 ); - - switch(RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - -int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - - if (!m_iOn) - { - SetThink(&CSentry:: Deploy ); - SetUse( NULL ); - SetNextThink( 0.1 ); - } - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink(&CSentry::SentryDeath); - UTIL_FireTargets( pev->target, this, this, USE_ON ); - SetNextThink( 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( ); - SetNextThink( 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, gmsg.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/server/monsters/zombie.cpp b/server/monsters/zombie.cpp deleted file mode 100644 index 9d2658f3..00000000 --- a/server/monsters/zombie.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Zombie -//========================================================= - -// UNDONE: Don't flinch every time you get hit - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "defaults.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_AE_CRAB1 0x04 -#define ZOMBIE_AE_CRAB2 0x05 -#define ZOMBIE_AE_CRAB3 0x06 - -#define ZOMBIE_FLINCH_DELAY 2 // at most one flinch every n secs -#define ZOMBIE_CRAB "monster_headcrab" // headcrab jumps from zombie - - -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 ); - void SpawnCrab( 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 m_iClass?m_iClass:CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CZombie :: SetYawSpeed ( void ) -{ - pev->yaw_speed = 120; -} - -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. - CBaseEntity *pHurt = CheckTraceHullAttack( 70, ZOMBIE_ONE_SLASH, 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. - CBaseEntity *pHurt = CheckTraceHullAttack( 70, ZOMBIE_ONE_SLASH, 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, ZOMBIE_BOTH_SLASH, 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; - - case ZOMBIE_AE_CRAB1: - { - pev->body = 1; // set the head to a skull - SpawnCrab(); - } - break; - - case ZOMBIE_AE_CRAB2: - { - pev->body = 1; // set the head to a skull - SpawnCrab(); - } - break; - - case ZOMBIE_AE_CRAB3: - { - pev->body = 1; // set the head to a skull - SpawnCrab(); - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CZombie :: Spawn() -{ - Precache(); - - if (pev->model) UTIL_SetModel(ENT(pev), pev->model); - else - { - if(pev->button == 0) UTIL_SetModel(ENT(pev), "models/monsters/zombie_sci.mdl"); - else if(pev->button == 1) UTIL_SetModel(ENT(pev), "models/monsters/zombie_bar.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; - if (pev->health == 0) - pev->health = ZOMBIE_HEALTH; - 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; - - if (pev->model) UTIL_PrecacheModel(pev->model); //LRC - else - { - if(pev->button) UTIL_PrecacheModel("models/monsters/zombie_bar.mdl"); - else UTIL_PrecacheModel("models/monsters/zombie_sci.mdl"); - } - UTIL_PrecacheEntity( ZOMBIE_CRAB ); - 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 (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; - -} - -//========================================================= -// Spawn Headcrab - headcrab jumps from zombie -//========================================================= -void CZombie :: SpawnCrab( void ) -{ - vec3_t vecSrc, vecAng; - GetAttachment( 0, vecSrc, vecAng ); - CBaseEntity *pCrab = CBaseEntity::Create( ZOMBIE_CRAB, vecSrc, vecAng, edict() ); // create the crab - pCrab->pev->spawnflags |= SF_MONSTER_FALL_TO_GROUND; // make the crab fall - pCrab->pev->velocity = pev->movedir * 30; - pCrab->pev->velocity.z += 30; -} diff --git a/server/server.def b/server/server.def deleted file mode 100644 index a2eccc63..00000000 --- a/server/server.def +++ /dev/null @@ -1,5 +0,0 @@ -LIBRARY server -EXPORTS - GiveFnptrsToDll @1 -SECTIONS - .data READ WRITE diff --git a/server/server.dsp b/server/server.dsp deleted file mode 100644 index 3d224f5a..00000000 --- a/server/server.dsp +++ /dev/null @@ -1,576 +0,0 @@ -# Microsoft Developer Studio Project File - Name="server" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=server - 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 "server.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 "server.mak" CFG="server - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "server - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "server - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName ""$/GoldSrc/server", ELEBAAAA" -# PROP Scc_LocalPath "." -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "server - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\Release" -# PROP BASE Intermediate_Dir ".\Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\server\!release" -# PROP Intermediate_Dir "..\temp\server\!release" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "ents" /I "game" /I "global" /I "monsters" /I "../common" /I "../game_shared" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /Fr /YX -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 msvcrt.lib /nologo /subsystem:windows /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /def:".\server.def" /libpath:"..\common\libs" -# SUBTRACT LINK32 /profile /map /debug /nodefaultlib -# Begin Custom Build - Performing Custom Build Step on $(InputPath) -TargetDir=\Xash3D\src_main\temp\server\!release -InputPath=\Xash3D\src_main\temp\server\!release\server.dll -SOURCE="$(InputPath)" - -"D:\Xash3D\xash\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\server.dll "D:\Xash3D\xash\bin\server.dll" - -# End Custom Build - -!ELSEIF "$(CFG)" == "server - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "server___Win32_Debug" -# PROP BASE Intermediate_Dir "server___Win32_Debug" -# PROP BASE Ignore_Export_Lib 1 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\server\!debug" -# PROP Intermediate_Dir "..\temp\server\!debug" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /G5 /MT /W3 /O2 /I "..\server" /I "..\common" /I "..\server\ents" /I "..\server\global" /I "..\server\weapons" /I "..\server\game" /I "..\server\monsters" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# SUBTRACT BASE CPP /Fr -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "ents" /I "game" /I "global" /I "monsters" /I "../common" /I "../game_shared" /D "DEBUG" /D "WIN32" /D "_WINDOWS" /FR /FD /c -# SUBTRACT CPP /u /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# 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 /nologo /subsystem:windows /dll /incremental:yes /machine:I386 /nodefaultlib:"libc" /def:".\server.def" /libpath:"..\common\libs" -# SUBTRACT BASE LINK32 /profile /map /debug -# ADD LINK32 msvcrtd.lib /nologo /subsystem:windows /dll /incremental:yes /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\server.def" /pdbtype:sept -# SUBTRACT LINK32 /profile /map -# Begin Custom Build - Performing Custom Build Step on $(InputPath) -TargetDir=\Xash3D\src_main\temp\server\!debug -InputPath=\Xash3D\src_main\temp\server\!debug\server.dll -SOURCE="$(InputPath)" - -"D:\Xash3D\xash\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\server.dll "D:\Xash3D\xash\bin\server.dll" - -# End Custom Build - -!ENDIF - -# Begin Target - -# Name "server - Win32 Release" -# Name "server - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def" -# Begin Source File - -SOURCE=.\monsters\ai_sound.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\animating.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\animation.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\apache.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\barnacle.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\barney.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basebrush.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baseentity.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basefunc.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basefx.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baseinfo.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baseitem.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baselogic.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\basemonster.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basemover.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baseother.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basephys.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baserockets.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basetank.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basetrain.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\basetrigger.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baseweapon.cpp -# End Source File -# Begin Source File - -SOURCE=.\ents\baseworld.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\client.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\combat.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\decals.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\defaultai.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\dll_int.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\flyingmonster.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\game.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\gamerules.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\generic.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\globals.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\gman.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\hassassin.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\headcrab.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\hgrunt.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\leech.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\lights.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\maprules.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\monstermaker.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\multiplay_gamerules.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\nodes.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\osprey.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\parent.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\player.cpp -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_shared.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\rat.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\roach.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\saverestore.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\scientist.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\scripted.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\sfx.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\singleplay_gamerules.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\sound.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\spectator.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\squadmonster.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\talkmonster.cpp -# End Source File -# Begin Source File - -SOURCE=.\game\teamplay_gamerules.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\turret.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\utils.cpp -# End Source File -# Begin Source File - -SOURCE=.\weapon_generic.cpp -# End Source File -# Begin Source File - -SOURCE=.\monsters\zombie.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp" -# Begin Source File - -SOURCE=.\monsters\activity.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\activitymap.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\animation.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\baseanimating.h -# End Source File -# Begin Source File - -SOURCE=.\ents\basebeams.h -# End Source File -# Begin Source File - -SOURCE=.\ents\basebrush.h -# End Source File -# Begin Source File - -SOURCE=.\ents\baseentity.h -# End Source File -# Begin Source File - -SOURCE=.\ents\baseinfo.h -# End Source File -# Begin Source File - -SOURCE=.\ents\baseitem.h -# End Source File -# Begin Source File - -SOURCE=.\ents\baselogic.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\basemonster.h -# End Source File -# Begin Source File - -SOURCE=.\ents\basemover.h -# End Source File -# Begin Source File - -SOURCE=.\ents\baserockets.h -# End Source File -# Begin Source File - -SOURCE=.\ents\basesprite.h -# End Source File -# Begin Source File - -SOURCE=.\ents\basetank.h -# End Source File -# Begin Source File - -SOURCE=.\ents\baseweapon.h -# End Source File -# Begin Source File - -SOURCE=.\ents\baseworld.h -# End Source File -# Begin Source File - -SOURCE=.\cbase.h -# End Source File -# Begin Source File - -SOURCE=.\global\cdll_dll.h -# End Source File -# Begin Source File - -SOURCE=.\global\client.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\damage.h -# End Source File -# Begin Source File - -SOURCE=.\global\decals.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\defaultai.h -# End Source File -# Begin Source File - -SOURCE=.\global\defaults.h -# End Source File -# Begin Source File - -SOURCE=.\global\enginecallback.h -# End Source File -# Begin Source File - -SOURCE=.\global\extdll.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\flyingmonster.h -# End Source File -# Begin Source File - -SOURCE=.\game\game.h -# End Source File -# Begin Source File - -SOURCE=.\game\gamerules.h -# End Source File -# Begin Source File - -SOURCE=.\global\globals.h -# End Source File -# Begin Source File - -SOURCE=.\global\hierarchy.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\monsterevent.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\monsters.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\nodes.h -# End Source File -# Begin Source File - -SOURCE=.\global\plane.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\player.h -# End Source File -# Begin Source File - -SOURCE=.\global\saverestore.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\schedule.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\scripted.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\scriptevent.h -# End Source File -# Begin Source File - -SOURCE=.\global\sfx.h -# End Source File -# Begin Source File - -SOURCE=.\global\shake.h -# End Source File -# Begin Source File - -SOURCE=.\global\soundent.h -# End Source File -# Begin Source File - -SOURCE=.\game\spectator.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\squad.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\squadmonster.h -# End Source File -# Begin Source File - -SOURCE=.\monsters\talkmonster.h -# End Source File -# Begin Source File - -SOURCE=.\game\teamplay_gamerules.h -# End Source File -# Begin Source File - -SOURCE=.\global\utils.h -# End Source File -# Begin Source File - -SOURCE=.\global\vector.h -# End Source File -# End Group -# End Target -# End Project diff --git a/server/weapon_generic.cpp b/server/weapon_generic.cpp deleted file mode 100644 index bcad6cfb..00000000 --- a/server/weapon_generic.cpp +++ /dev/null @@ -1,67 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2006 -// weapons.cpp - player weapon baseclass -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "cbase.h" -#include "baseweapon.h" - -LINK_ENTITY_TO_CLASS( weapon_m249, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_crowbar, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_redeemer, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_eagle, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_glock, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_mp5, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_shotgun, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_m40a1, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_handgrenade, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_debug, CBasePlayerWeapon ); -LINK_ENTITY_TO_CLASS( weapon_rpg, CBasePlayerWeapon ); - -//*********************************************************** -// world_items -//*********************************************************** -class CWorldItem : public CBaseEntity -{ -public: - void KeyValue(KeyValueData *pkvd ); - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS(world_items, CWorldItem); - -void CWorldItem::KeyValue(KeyValueData *pkvd) -{ - if (FStrEq(pkvd->szKeyName, "type")) - { - pev->impulse = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CWorldItem::Spawn( void ) -{ - CBaseEntity *pEntity = NULL; - - switch (pev->impulse) - { - case 44: //ITEM_BATTERY: - pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles ); - break; - case 45: //ITEM_SUIT: - pEntity = CBaseEntity::Create( "item_suit", pev->origin, pev->angles ); - break; - } - - if (!pEntity) Msg( "unable to create world_item %d\n", pev->impulse ); - else - { - pEntity->pev->target = pev->target; - pEntity->pev->targetname = pev->targetname; - pEntity->pev->spawnflags = pev->spawnflags; - } - REMOVE_ENTITY(edict()); -} diff --git a/snd_al/s_export.c b/snd_al/s_export.c deleted file mode 100644 index 0cb2c884..00000000 --- a/snd_al/s_export.c +++ /dev/null @@ -1,54 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// s_export.c - sound library main -//======================================================================= - -#include "sound.h" - -vsound_imp_t si; -stdlib_api_t com; -byte *sndpool; - -vsound_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, vsound_imp_t *engfuncs ) -{ - static vsound_exp_t snd; - - com = *input; - - // Sys_LoadLibrary can create fake instance, to check - // api version and api size, but second argument will be 0 - // and always make exception, run simply check for avoid it - if( engfuncs ) si = *engfuncs; - - // generic functions - snd.api_size = sizeof( vsound_exp_t ); - snd.com_size = sizeof( stdlib_api_t ); - - snd.Init = S_Init; - snd.Shutdown = S_Shutdown; - - // sound manager - snd.BeginRegistration = S_BeginRegistration; - snd.RegisterSound = S_RegisterSound; - snd.EndRegistration = S_EndRegistration; - - snd.FadeClientVolume = S_FadeClientVolume; - snd.StartSound = S_StartSound; - snd.StaticSound = S_StaticSound; - snd.StreamRawSamples = S_StreamRawSamples; - snd.StartLocalSound = S_StartLocalSound; - snd.StartBackgroundTrack = S_StartBackgroundTrack; - snd.StopBackgroundTrack = S_StopBackgroundTrack; - - snd.StartStreaming = S_StartStreaming; - snd.StopStreaming = S_StopStreaming; - - snd.BeginFrame = S_BeginFrame; - snd.RenderFrame = S_Update; - snd.StopSound = S_StopSound; - snd.StopAllSounds = S_StopAllSounds; - - snd.Activate = S_Activate; - - return &snd; -} \ No newline at end of file diff --git a/snd_al/s_load.c b/snd_al/s_load.c deleted file mode 100644 index d418d85c..00000000 --- a/snd_al/s_load.c +++ /dev/null @@ -1,397 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// s_load.c - sound managment -//======================================================================= - -#include "sound.h" - -// during registration it is possible to have more sounds -// than could actually be referenced during gameplay, -// because we don't want to free anything until we are -// sure we won't need it. -#define MAX_SFX 8192 -#define MAX_SFX_HASH (MAX_SFX/4) - -static int s_numSfx = 0; -static sfx_t s_knownSfx[MAX_SFX]; -static sfx_t *s_sfxHashList[MAX_SFX_HASH]; -static string s_sentenceImmediateName; // keep dummy sentence name -bool s_registering = false; -int s_registration_sequence = 0; - -/* -================= -S_SoundList_f -================= -*/ -void S_SoundList_f( void ) -{ - sfx_t *sfx; - int i, samples = 0; - int totalSfx = 0; - - Msg( "\n" ); - Msg( " -samples -hz-- -format- -name--------\n" ); - - for( i = 0; i < s_numSfx; i++ ) - { - sfx = &s_knownSfx[i]; - if( sfx->loaded ) - { - samples += sfx->samples; - if( sfx->loopStart >= 0 ) Msg( "L" ); - else Msg( " " ); - Msg( "%8i ", sfx->samples ); - Msg( "%5i ", sfx->rate ); - - switch( sfx->format ) - { - case AL_FORMAT_STEREO16: Msg( "STEREO16 " ); break; - case AL_FORMAT_STEREO8: Msg( "STEREO8 " ); break; - case AL_FORMAT_MONO16: Msg( "MONO16 " ); break; - case AL_FORMAT_MONO8: Msg( "MONO8 " ); break; - default: Msg( "???????? " ); break; - } - - Msg( "sound/%s", sfx->name ); - Msg( "\n" ); - totalSfx++; - } - } - - Msg( "-------------------------------------------\n" ); - Msg( "%i total samples\n", samples ); - Msg( "%i total sounds\n", totalSfx ); - Msg( "\n" ); -} - -// return true if char 'c' is one of 1st 2 characters in pch -bool S_TestSoundChar( const char *pch, char c ) -{ - int i; - char *pcht = (char *)pch; - - // check first 2 characters - for( i = 0; i < 2; i++ ) - { - if( *pcht == c ) - return true; - pcht++; - } - return false; -} - -// return pointer to first valid character in file name -char *S_SkipSoundChar( const char *pch ) -{ - char *pcht = (char *)pch; - - // check first character - if( *pcht == '!' ) - pcht++; - return pcht; -} - -uint S_GetFormat( int width, int channels ) -{ - uint format = AL_FORMAT_MONO16; - - // work out format - if( width == 1 ) - { - if( channels == 1 ) - format = AL_FORMAT_MONO8; - else if( channels == 2 ) - format = AL_FORMAT_STEREO8; - } - else if( width == 2 ) - { - if( channels == 1 ) - format = AL_FORMAT_MONO16; - else if( channels == 2 ) - format = AL_FORMAT_STEREO16; - } - return format; -} - -/* -================= -S_UploadSound -================= -*/ -static void S_UploadSound( wavdata_t *sc, sfx_t *sfx ) -{ - sfx->loopStart = sc->loopStart; - sfx->samples = sc->samples; - sfx->rate = sc->rate; - sfx->sampleStep = 1000 * ( sfx->rate / (float)sfx->samples ); // samples per second - - // set buffer format - sfx->format = S_GetFormat( sc->width, sc->channels ); - - // upload the sound - palGenBuffers( 1, &sfx->bufferNum ); - palBufferData( sfx->bufferNum, sfx->format, sc->buffer, sc->size, sfx->rate ); - FS_FreeSound( sc ); // don't need to keep this data - S_CheckForErrors(); - - sfx->loaded = true; -} - -/* -================= -S_CreateDefaultSound -================= -*/ -static wavdata_t *S_CreateDefaultSound( void ) -{ - wavdata_t *sc; - int i; - - sc = Z_Malloc( sizeof( wavdata_t )); - - sc->rate = 22050; - sc->width = 2; - sc->channels = 1; - sc->samples = 11025; - sc->loopStart = -1; - sc->size = sc->samples * sc->width * sc->channels; - sc->buffer = Z_Malloc( sc->size ); - - if( s_check_errors->integer ) - { - // create 1 kHz tone as default sound - for( i = 0; i < sc->samples; i++ ) - ((short *)sc->buffer)[i] = com.sin( i * 0.1f ) * 20000; - } - else - { - // create silent sound - for( i = 0; i < sc->samples; i++ ) - ((short *)sc->buffer)[i] = i; - } - - return sc; -} - -/* -================= -S_LoadSound -================= -*/ -bool S_LoadSound( sfx_t *sfx ) -{ - wavdata_t *sc; - - if( !sfx ) return false; - if( sfx->name[0] == '*' ) return false; - if( sfx->loaded ) return true; // see if still in memory - - // load it from disk - sc = FS_LoadSound( sfx->name, NULL, 0 ); - - if( sc == NULL ) - { - sc = S_CreateDefaultSound(); - sfx->default_sound = true; - } - - // upload and resample - S_UploadSound( sc, sfx ); - - return true; -} - -// ======================================================================= -// Load a sound -// ======================================================================= -/* -================= -S_FindSound -================= -*/ -sfx_t *S_FindSound( const char *name ) -{ - int i; - sfx_t *sfx; - uint hash; - - if( !name || !name[0] ) return NULL; - if( com.strlen( name ) >= MAX_STRING ) - { - MsgDev( D_ERROR, "S_FindSound: sound name too long: %s", name ); - return NULL; - } - - // see if already loaded - hash = Com_HashKey( name, MAX_SFX_HASH ); - for( sfx = s_sfxHashList[hash]; sfx; sfx = sfx->hashNext ) - { - if( !com.strcmp( sfx->name, name )) - { - // prolonge registration - sfx->touchFrame = s_registration_sequence; - return sfx; - } - } - - // find a free sfx slot spot - for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++) - { - if( !sfx->name[0] ) break; // free spot - } - if( i == s_numSfx ) - { - if( s_numSfx == MAX_SFX ) - { - MsgDev( D_ERROR, "S_FindName: MAX_SFX limit exceeded\n" ); - return NULL; - } - s_numSfx++; - } - - sfx = &s_knownSfx[i]; - Mem_Set( sfx, 0, sizeof( *sfx )); - com.strncpy( sfx->name, name, MAX_STRING ); - sfx->touchFrame = s_registration_sequence; - sfx->hashValue = Com_HashKey( sfx->name, MAX_SFX_HASH ); - - // link it in - sfx->hashNext = s_sfxHashList[sfx->hashValue]; - s_sfxHashList[sfx->hashValue] = sfx; - - return sfx; -} - -/* -================== -S_FreeSound -================== -*/ -static void S_FreeSound( sfx_t *sfx ) -{ - sfx_t *hashSfx; - sfx_t **prev; - - if( !sfx || !sfx->name[0] ) return; - - // de-link it from the hash tree - prev = &s_sfxHashList[sfx->hashValue]; - while( 1 ) - { - hashSfx = *prev; - if( !hashSfx ) - break; - - if( hashSfx == sfx ) - { - *prev = hashSfx->hashNext; - break; - } - prev = &hashSfx->hashNext; - } - - palDeleteBuffers( 1, &sfx->bufferNum ); - Mem_Set( sfx, 0, sizeof( *sfx )); -} - -/* -===================== -S_BeginRegistration -===================== -*/ -void S_BeginRegistration( void ) -{ - s_registration_sequence++; - s_registering = true; -} - -/* -===================== -S_EndRegistration -===================== -*/ -void S_EndRegistration( void ) -{ - sfx_t *sfx; - int i; - - // free any sounds not from this registration sequence - for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) - { - if( !sfx->name[0] ) continue; - if( sfx->touchFrame != s_registration_sequence ) - S_FreeSound( sfx ); // don't need this sound - } - - // load everything in - for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) - { - if( !sfx->name[0] ) continue; - S_LoadSound( sfx ); - } - s_registering = false; -} - -/* -================= -S_RegisterSound - -================= -*/ -sound_t S_RegisterSound( const char *name ) -{ - sfx_t *sfx; - - if( name[0] == '!' ) - { - com.strncpy( s_sentenceImmediateName, name, sizeof( s_sentenceImmediateName )); - return SENTENCE_INDEX; - } - - sfx = S_FindSound( name ); - if( !sfx ) return -1; - - sfx->touchFrame = s_registration_sequence; - if( !s_registering ) S_LoadSound( sfx ); - - return sfx - s_knownSfx; -} - -sfx_t *S_GetSfxByHandle( sound_t handle ) -{ - if( handle == SENTENCE_INDEX ) - { - // create new sfx - return S_FindSound( s_sentenceImmediateName ); - } - - if( handle < 0 || handle >= s_numSfx ) - { - MsgDev( D_ERROR, "S_GetSfxByHandle: handle %i out of range (%i)\n", handle, s_numSfx ); - return NULL; - } - return &s_knownSfx[handle]; -} - -/* -================= -S_FreeSounds -================= -*/ -void S_FreeSounds( void ) -{ - sfx_t *sfx; - int i; - - // stop all sounds - S_StopAllSounds(); - - // free all sounds - for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) - S_FreeSound( sfx ); - - s_numSfx = 0; - Mem_Set( s_knownSfx, 0, sizeof( s_knownSfx )); - Mem_Set( s_sfxHashList, 0, sizeof( s_sfxHashList )); -} \ No newline at end of file diff --git a/snd_al/s_main.c b/snd_al/s_main.c deleted file mode 100644 index 7631594b..00000000 --- a/snd_al/s_main.c +++ /dev/null @@ -1,1018 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// s_main.c - sound engine -//======================================================================= - -#include "sound.h" -#include "const.h" -#include "trace_def.h" - -#define MAX_CHANNELS 128 -#define CSXROOM 29 -int MAX_DYNAMIC_CHANNELS = 24; // can be reduced by openAL limitations - -typedef struct -{ - int dwEnvironment; - float fVolume; - float fDecay; - float fDamping; -} dsproom_t; - -static soundfade_t soundfade; -static channel_t s_channels[MAX_CHANNELS]; -static listener_t s_listener; - -const guid_t DSPROPSETID_EAX20_ListenerProperties = {0x306a6a8, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}}; -const guid_t DSPROPSETID_EAX20_BufferProperties = {0x306a6a7, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}}; - -const dsproom_t eax_preset[CSXROOM] = -{ -{ EAX_ENVIRONMENT_GENERIC, 0.0F, 0.0F, 0.0F }, -{ EAX_ENVIRONMENT_ROOM, 0.417F, 0.4F, 0.666F }, -{ EAX_ENVIRONMENT_BATHROOM, 0.3F, 1.499F, 0.166F }, -{ EAX_ENVIRONMENT_BATHROOM, 0.4F, 1.499F, 0.166F }, -{ EAX_ENVIRONMENT_BATHROOM, 0.6F, 1.499F, 0.166F }, -{ EAX_ENVIRONMENT_SEWERPIPE, 0.4F, 2.886F, 0.25F }, -{ EAX_ENVIRONMENT_SEWERPIPE, 0.6F, 2.886F, 0.25F }, -{ EAX_ENVIRONMENT_SEWERPIPE, 0.8F, 2.886F, 0.25F }, -{ EAX_ENVIRONMENT_STONEROOM, 0.5F, 2.309F, 0.888F }, -{ EAX_ENVIRONMENT_STONEROOM, 0.65F, 2.309F, 0.888F }, -{ EAX_ENVIRONMENT_STONEROOM, 0.8F, 2.309F, 0.888F }, -{ EAX_ENVIRONMENT_STONECORRIDOR, 0.3F, 2.697F, 0.638F }, -{ EAX_ENVIRONMENT_STONECORRIDOR, 0.5F, 2.697F, 0.638F }, -{ EAX_ENVIRONMENT_STONECORRIDOR, 0.65F, 2.697F, 0.638F }, -{ EAX_ENVIRONMENT_UNDERWATER, 1.0F, 1.499F, 0.0F }, -{ EAX_ENVIRONMENT_UNDERWATER, 1.0F, 2.499F, 0.0F }, -{ EAX_ENVIRONMENT_UNDERWATER, 1.0F, 3.499F, 0.0F }, -{ EAX_ENVIRONMENT_GENERIC, 0.65F, 1.493F, 0.5F }, -{ EAX_ENVIRONMENT_GENERIC, 0.85F, 1.493F, 0.5F }, -{ EAX_ENVIRONMENT_GENERIC, 1.0F, 1.493F, 0.5F }, -{ EAX_ENVIRONMENT_ARENA, 0.40F, 7.284F, 0.332F }, -{ EAX_ENVIRONMENT_ARENA, 0.55F, 7.284F, 0.332F }, -{ EAX_ENVIRONMENT_ARENA, 0.70F, 7.284F, 0.332F }, -{ EAX_ENVIRONMENT_CONCERTHALL, 0.5F, 3.961F, 0.5F }, -{ EAX_ENVIRONMENT_CONCERTHALL, 0.7F, 3.961F, 0.5F }, -{ EAX_ENVIRONMENT_CONCERTHALL, 1.0F, 3.961F, 0.5F }, -{ EAX_ENVIRONMENT_DIZZY, 0.2F, 17.234F, 0.666F }, -{ EAX_ENVIRONMENT_DIZZY, 0.3F, 17.234F, 0.666F }, -{ EAX_ENVIRONMENT_DIZZY, 0.4F, 17.234F, 0.666F }, -}; - -cvar_t *s_alDevice; -cvar_t *s_allowEAX; -cvar_t *s_allowA3D; -cvar_t *s_check_errors; -cvar_t *s_volume; // master volume -cvar_t *s_musicvolume; // background track volume -cvar_t *s_room_type; -cvar_t *s_minDistance; -cvar_t *s_maxDistance; -cvar_t *s_rolloffFactor; -cvar_t *s_dopplerFactor; -cvar_t *s_dopplerVelocity; - -/* -================= -S_CheckForErrors -================= -*/ -bool S_CheckForErrors( void ) -{ - int err; - char *str; - - if( !s_check_errors->integer ) - return false; - if(( err = palGetError( )) == AL_NO_ERROR ) - return false; - - switch( err ) - { - case AL_INVALID_NAME: - str = "AL_INVALID_NAME"; - break; - case AL_INVALID_ENUM: - str = "AL_INVALID_ENUM"; - break; - case AL_INVALID_VALUE: - str = "AL_INVALID_VALUE"; - break; - case AL_INVALID_OPERATION: - str = "AL_INVALID_OPERATION"; - break; - case AL_OUT_OF_MEMORY: - str = "AL_OUT_OF_MEMORY"; - break; - default: - str = "UNKNOWN ERROR"; - break; - } - - if( al_state.active ) - Host_Error( "S_CheckForErrors: %s\n", str ); - else MsgDev( D_ERROR, "S_CheckForErrors: %s\n", str ); - - return true; -} - -/* -================= -S_GetMasterVolume -================= -*/ -float S_GetMasterVolume( void ) -{ - float scale = 1.0f; - - if( !si.IsInMenu() && soundfade.percent != 0 ) - { - scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f ); - scale = 1.0f - scale; - } - return s_volume->value * scale; -} - -/* -================= -S_FadeClientVolume -================= -*/ -void S_FadeClientVolume( float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ) -{ - soundfade.starttime = si.GetServerTime() * 0.001f; - soundfade.initial_percent = fadePercent; - soundfade.fadeouttime = fadeOutSeconds; - soundfade.holdtime = holdTime; - soundfade.fadeintime = fadeInSeconds; -} - -/* -================= -S_UpdateSoundFade -================= -*/ -void S_UpdateSoundFade( void ) -{ - float f, totaltime, elapsed; - - // determine current fade value. - // assume no fading remains - soundfade.percent = 0; - - totaltime = soundfade.fadeouttime + soundfade.fadeintime + soundfade.holdtime; - - elapsed = (si.GetServerTime() * 0.001f) - soundfade.starttime; - - // clock wrapped or reset (BUG) or we've gone far enough - if( elapsed < 0.0f || elapsed >= totaltime || totaltime <= 0.0f ) - return; - - // We are in the fade time, so determine amount of fade. - if( soundfade.fadeouttime > 0.0f && ( elapsed < soundfade.fadeouttime )) - { - // ramp up - f = elapsed / soundfade.fadeouttime; - } - else if( elapsed <= ( soundfade.fadeouttime + soundfade.holdtime )) // Inside the hold time - { - // stay - f = 1.0f; - } - else - { - // ramp down - f = ( elapsed - ( soundfade.fadeouttime + soundfade.holdtime ) ) / soundfade.fadeintime; - f = 1.0f - f; // backward interpolated... - } - - // spline it. - f = SimpleSpline( f ); - f = bound( 0.0f, f, 1.0f ); - - soundfade.percent = soundfade.initial_percent * f; -} - -/* -================= -S_IsClient -================= -*/ -bool S_IsClient( int entnum ) -{ - return ( entnum == al_state.clientnum ); -} - -/* -================= -S_AllocChannels -================= -*/ -static void S_AllocChannels( void ) -{ - channel_t *ch; - int i; - - for( i = 0, ch = s_channels; i < MAX_CHANNELS; i++, ch++) - { - palGenSources( 1, &ch->sourceNum ); - if( palGetError() != AL_NO_ERROR ) - break; - al_state.max_channels++; - } - - if( al_state.max_channels <= MAX_DYNAMIC_CHANNELS ) - { - // there are not enough channels! - MAX_DYNAMIC_CHANNELS = (int)(al_state.max_channels / 3); - MsgDev( D_WARN, "S_AllocChannels: reduced dynamic channels count from 24 to %i\n", MAX_DYNAMIC_CHANNELS ); - } - al_state.initialized = true; -} - -/* -================= -S_FreeChannels -================= -*/ -static void S_FreeChannels( void ) -{ - channel_t *ch; - int i; - - for( i = 0, ch = s_channels; i < al_state.max_channels; i++, ch++ ) - { - palDeleteSources( 1, &ch->sourceNum ); - Mem_Set( ch, 0, sizeof( *ch )); - } - al_state.max_channels = 0; -} - -/* -================= -S_ChannelState -================= -*/ -static int S_ChannelState( channel_t *ch ) -{ - int state; - - palGetSourcei( ch->sourceNum, AL_SOURCE_STATE, &state ); - return state; -} - -/* -================= -S_StopChannel -================= -*/ -static void S_StopChannel( channel_t *ch ) -{ - ch->sfx = NULL; - - palSourceStop( ch->sourceNum ); - palSourcei( ch->sourceNum, AL_BUFFER, 0 ); -} - -/* -================= -S_PlayChannel -================= -*/ -static void S_PlayChannel( channel_t *ch, sfx_t *sfx ) -{ - if( sfx == NULL ) - { - S_StopChannel( ch ); - return; - } - ch->sfx = sfx; - - palSourcei( ch->sourceNum, AL_BUFFER, sfx->bufferNum ); - palSourcei( ch->sourceNum, AL_LOOPING, false ); - palSourcei( ch->sourceNum, AL_SOURCE_RELATIVE, false ); - palSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, 0 ); - palSourcePlay( ch->sourceNum ); -} - -/* -================= -S_SpatializeChannel -================= -*/ -static void S_SpatializeChannel( channel_t *ch ) -{ - vec3_t position, velocity; - - // update position and velocity - if( ch->entnum == al_state.clientnum || !ch->dist_mult ) - { - palSourcefv( ch->sourceNum, AL_POSITION, s_listener.position ); - palSourcefv( ch->sourceNum, AL_VELOCITY, s_listener.velocity ); - } - else - { - if( ch->staticsound ) - { - palSource3f( ch->sourceNum, AL_POSITION, ch->position[1], ch->position[2], -ch->position[0] ); - palSource3f( ch->sourceNum, AL_VELOCITY, 0, 0, 0 ); - } - else - { - si.GetEntitySpatialization( ch->entnum, position, velocity ); - - palSource3f( ch->sourceNum, AL_POSITION, position[1], position[2], -position[0] ); - palSource3f( ch->sourceNum, AL_VELOCITY, velocity[1], velocity[2], -velocity[0] ); - } - } - - // update min/max distance - if( ch->dist_mult ) - palSourcef( ch->sourceNum, AL_REFERENCE_DISTANCE, s_minDistance->value * ch->dist_mult ); - else palSourcef( ch->sourceNum, AL_REFERENCE_DISTANCE, s_maxDistance->value ); - - palSourcef( ch->sourceNum, AL_MAX_DISTANCE, s_maxDistance->value ); - - // update volume and rolloff factor - palSourcef( ch->sourceNum, AL_GAIN, ch->volume ); - palSourcef( ch->sourceNum, AL_PITCH, ch->pitch ); - palSourcef( ch->sourceNum, AL_ROLLOFF_FACTOR, s_rolloffFactor->value ); -} - -/* -================= -SND_PickDynamicChannel - -Select a channel from the dynamic channel allocation area. For the given entity, -override any other sound playing on the same channel (see code comments below for -exceptions). -================= -*/ -channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx ) -{ - int ch_idx; - int first_to_die; - float life_left; - - // check for replacement sound, or find the best one to replace - first_to_die = -1; - life_left = 0x7fffffff; - - for( ch_idx = 0; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ ) - { - channel_t *ch = &s_channels[ch_idx]; - - // Never override a streaming sound that is currently playing or - // voice over IP data that is playing or any sound on CHAN_VOICE( acting ) - if( ch->sfx && ( ch->entchannel == CHAN_STREAM )) - { - continue; - } - - if( channel != 0 && ch->entnum == entnum && ( ch->entchannel == channel || channel == -1 )) - { - // always override sound from same entity - first_to_die = ch_idx; - break; - } - - // don't let monster sounds override player sounds - if( ch->sfx && S_IsClient( ch->entnum ) && !S_IsClient( entnum )) - continue; - - // don't let monster sounds override player sounds - if( entnum != al_state.clientnum && ch->entnum == al_state.clientnum ) - continue; - - // replace the oldest sound - if( ch->startTime < life_left ) - { - life_left = ch->startTime; - first_to_die = ch_idx; - } - } - - if( first_to_die == -1 ) - return NULL; - - if( s_channels[first_to_die].sfx ) - { - // don't restart looping sounds for the same entity - if( sfx->loopStart != -1 ) - { - channel_t *ch = &s_channels[first_to_die]; - - if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx == sfx ) - { - // same looping sound, same ent, same channel, don't restart the sound - return NULL; - } - } - - // be sure and release previous channel if sentence. - S_StopChannel( &( s_channels[first_to_die] )); - } - - return &s_channels[first_to_die]; -} - -/* -===================== -SND_PickStaticChannel - -Pick an empty channel from the static sound area, or allocate a new -channel. Only fails if we're at max_channels (128!!!) or if -we're trying to allocate a channel for a stream sound that is -already playing. -===================== -*/ -channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx ) -{ - channel_t *ch = NULL; - int i; - - // check for replacement sound, or find the best one to replace - for( i = MAX_DYNAMIC_CHANNELS; i < al_state.total_channels; i++ ) - { - // music or cinematic channel - if( s_channels[i].entchannel == CHAN_STREAM ) - continue; - - if( s_channels[i].sfx == NULL ) - break; - } - - if( i < al_state.total_channels ) - { - // reuse an empty static sound channel - ch = &s_channels[i]; - } - else - { - // no empty slots, alloc a new static sound channel - if( al_state.total_channels >= al_state.max_channels ) - { - MsgDev( D_ERROR, "S_PickChannel: no free channels\n" ); - return NULL; - } - // get a channel for the static sound - ch = &s_channels[al_state.total_channels]; - al_state.total_channels++; - } - return ch; -} - -/* -================= -S_AlterChannel - -search through all channels for a channel that matches this -soundsource, entchannel and sfx, and perform alteration on channel -as indicated by 'flags' parameter. If shut down request and -sfx contains a sentence name, shut off the sentence. -returns TRUE if sound was altered, -returns FALSE if sound was not found (sound is not playing) -================= -*/ -int S_AlterChannel( int entnum, int channel, sfx_t *sfx, float vol, int pitch, int flags ) -{ - channel_t *ch; - int i; - - if( S_TestSoundChar( sfx->name, '!' )) - { - // This is a sentence name. - // For sentences: assume that the entity is only playing one sentence - // at a time, so we can just shut off - // any channel that has ch->isSentence >= 0 and matches the entnum. - - for( i = 0, ch = s_channels; i < al_state.total_channels; i++, ch++ ) - { - if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx && ch->isSentence ) - { - if( flags & SND_CHANGE_PITCH ) - ch->pitch = pitch / (float)PITCH_NORM; - - if( flags & SND_CHANGE_VOL ) - ch->volume = vol; - - if( flags & SND_STOP && ch->sfx->loopStart >= 0 ) - S_StopChannel( ch ); - - return true; - } - } - // channel not found - return false; - - } - - // regular sound or streaming sound - for( i = 0, ch = s_channels; i < al_state.total_channels; i++, ch++ ) - { - if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx == sfx ) - { - if( flags & SND_CHANGE_PITCH ) - ch->pitch = pitch / (float)PITCH_NORM; - - if( flags & SND_CHANGE_VOL ) - ch->volume = vol; - - if( flags & SND_STOP ) - S_StopChannel( ch ); - - return true; - } - } - return false; -} - -/* -================= -S_StartSound - -Validates the parms and queues the sound up. -if origin is NULL, the sound will be dynamically sourced from the entity. -entchannel 0 will never override a playing sound. -================= -*/ -void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags ) -{ - sfx_t *sfx = NULL; - channel_t *target_chan; - int vol, fsentence = 0; - - sfx = S_GetSfxByHandle( handle ); - if( !sfx ) return; - - vol = bound( 0, fvol * 255, 255 ); - - if( flags & ( SND_STOP|SND_CHANGE_VOL|SND_CHANGE_PITCH )) - { - if( S_AlterChannel( ent, chan, sfx, vol, pitch, flags )) - return; - - if( flags & SND_STOP ) return; - // fall through - if we're not trying to stop the sound, - // and we didn't find it (it's not playing), go ahead and start it up - } - - if( pitch == 0 ) - { - MsgDev( D_WARN, "S_StartSound: ( %s ) ignored, called with pitch 0\n", sfx->name ); - return; - } - - if( !pos ) pos = vec3_origin; - - // pick a channel to play on - target_chan = SND_PickDynamicChannel( ent, chan, sfx ); - if( !target_chan ) - { - MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", sfx->name ); - return; - } - - target_chan->entnum = ent; - target_chan->entchannel = chan; - target_chan->startTime = Sys_DoubleTime(); - VectorCopy( pos, target_chan->position ); - target_chan->volume = vol; - target_chan->entnum = ent; - target_chan->entchannel = chan; - target_chan->isSentence = false; - target_chan->dist_mult = (attn / 1000.0f); - target_chan->sfx = sfx; - target_chan->pitch = pitch / (float)PITCH_NORM; - - // make sure the sound is loaded - if( !S_LoadSound( sfx )) - { - S_StopChannel( target_chan ); - return; - } - - // only using loop for looped sounds - if( flags & SND_STOP_LOOPING ) - target_chan->use_loop = false; - else target_chan->use_loop = ( sfx->loopStart == -1 ) ? false : true; - - S_SpatializeChannel( target_chan ); - S_PlayChannel( target_chan, sfx ); -} - -/* -================= -S_StartStaticSound - -Start playback of a sound, loaded into the static portion of the channel array. -Currently, this should be used for looping ambient sounds, looping sounds -that should not be interrupted until complete, non-creature sentences, -and one-shot ambient streaming sounds. Can also play 'regular' sounds one-shot, -in case designers want to trigger regular game sounds. -Pitch changes playback pitch of wave by % above or below 100. Ignored if pitch == 100 - -NOTE: volume is 0.0 - 1.0 and attenuation is 0.0 - 1.0 when passed in. -================= -*/ -void S_StaticSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags ) -{ - channel_t *ch; - sfx_t *sfx = NULL; - int vol, fvox = 0; - - sfx = S_GetSfxByHandle( handle ); - if( !sfx ) return; - - vol = bound( 0, fvol * 255, 255 ); - - if( flags & (SND_STOP|SND_CHANGE_VOL|SND_CHANGE_PITCH)) - { - if( S_AlterChannel( ent, chan, sfx, vol, pitch, flags )) - return; - if( flags & SND_STOP ) return; - } - - if( pitch == 0 ) - { - MsgDev( D_WARN, "S_StartStaticSound: ( %s ) ignored, called with pitch 0\n", sfx->name ); - return; - } - - if( !pos ) pos = vec3_origin; - - // pick a channel to play on from the static area - ch = SND_PickStaticChannel( ent, sfx ); // autolooping sounds are always fixed origin(?) - if( !ch ) return; - - // make sure the sound is loaded - if( !S_LoadSound( sfx )) - { - S_StopChannel( ch ); - return; - } - - VectorCopy( pos, ch->position ); - - ch->entnum = ent; - ch->entchannel = chan; - ch->startTime = Sys_DoubleTime(); - VectorCopy( pos, ch->position ); - ch->volume = vol; - ch->entnum = ent; - ch->entchannel = chan; - ch->isSentence = false; - ch->dist_mult = (attn / 1000.0f); - ch->sfx = sfx; - ch->pitch = pitch / (float)PITCH_NORM; - ch->staticsound = true; - - // only using loop for looped sounds - if( flags & SND_STOP_LOOPING ) - ch->use_loop = false; - else ch->use_loop = ( sfx->loopStart == -1 ) ? false : true; - - S_SpatializeChannel( ch ); - S_PlayChannel( ch, sfx ); -} - -/* -================= -S_StartLocalSound - -menu sound -================= -*/ -void S_StartLocalSound( const char *name ) -{ - sound_t sfxHandle; - - sfxHandle = S_RegisterSound( name ); - S_StartSound( vec3_origin, al_state.clientnum, CHAN_AUTO, sfxHandle, VOL_NORM, ATTN_NONE, PITCH_NORM, SND_STOP_LOOPING ); -} - -/* -================== -S_StopAllSounds - -stop all sounds for entity on a channel. -================== -*/ -void S_StopSound( int entnum, int channel, const char *soundname ) -{ - int i; - - for( i = 0; i < al_state.total_channels; i++ ) - { - channel_t *ch = &s_channels[i]; - - if( !ch->sfx ) continue; // already freed - if( ch->entnum == entnum && ch->entchannel == channel ) - { - if( soundname && com.strcmp( ch->sfx->name, soundname )) - continue; - S_StopChannel( ch ); - } - } -} - -/* -================= -S_StopAllSounds -================= -*/ -void S_StopAllSounds( void ) -{ - channel_t *ch; - int i; - - al_state.total_channels = MAX_DYNAMIC_CHANNELS; // no statics - - // Stop all the channels - for( i = 0, ch = s_channels; i < al_state.max_channels; i++, ch++ ) - { - if( !ch->sfx ) continue; - S_StopChannel( ch ); - } - - // clear any remaining soundfade - Mem_Set( &soundfade, 0, sizeof( soundfade )); - - S_StopStreaming(); // stop streaming channel - S_StopBackgroundTrack(); // stop background track - al_state.framecount = 0; // reset frame count -} - -/* -================= -S_AddEnvironmentEffects - -process all effects here -================= -*/ -void S_AddEnvironmentEffects( void ) -{ - uint eaxEnv; - - if( !al_config.allow_3DMode ) return; - - // if eax is enabled, apply listener environmental effects - if( s_listener.waterlevel > 2 ) - { - eaxEnv = EAX_ENVIRONMENT_UNDERWATER; - } - else - { - eaxEnv = EAX_ENVIRONMENT_GENERIC; - eaxEnv = eax_preset[bound( 0, s_room_type->integer, CSXROOM - 1 )].dwEnvironment; - } - al_config.Set3DMode( &DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ENVIRONMENT|DSPROPERTY_EAXLISTENER_DEFERRED, 0, &eaxEnv, sizeof(eaxEnv)); -} - -/* -================= -S_Update - -Called once each time through the main loop -================= -*/ -void S_Update( ref_params_t *fd ) -{ - channel_t *ch; - int i; - - if( !fd ) return; - - // bump frame count - al_state.framecount++; - al_state.paused = fd->paused; - al_state.clientnum = fd->viewentity; - al_state.refdef = fd; // for using everthing else - - // update any client side sound fade - if( !fd->paused && !si.IsInMenu( )) - S_UpdateSoundFade(); - - // set up listener - VectorSet( s_listener.position, fd->simorg[1], fd->simorg[2], -fd->simorg[0] ); - VectorSet( s_listener.velocity, fd->simvel[1], fd->simvel[2], -fd->simvel[0] ); - - // set listener orientation matrix - s_listener.orientation[0] = fd->forward[1]; - s_listener.orientation[1] = -fd->forward[2]; - s_listener.orientation[2] = -fd->forward[0]; - s_listener.orientation[3] = fd->up[1]; - s_listener.orientation[4] = -fd->up[2]; - s_listener.orientation[5] = -fd->up[0]; - s_listener.waterlevel = fd->waterlevel; - - palListenerfv( AL_POSITION, s_listener.position ); - palListenerfv( AL_VELOCITY, s_listener.velocity ); - palListenerfv( AL_ORIENTATION, s_listener.orientation ); - palListenerf( AL_GAIN, (al_state.active) ? S_GetMasterVolume () : 0.0f ); - - // Set state - palDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); - - palDopplerFactor( s_dopplerFactor->value ); - palDopplerVelocity( s_dopplerVelocity->value ); - - S_AddEnvironmentEffects (); - - // Stream background track - S_StreamBackgroundTrack (); - - // update spatialization for all sounds - for( i = 0, ch = s_channels; i < al_state.total_channels; i++, ch++ ) - { - if( !ch->sfx ) continue; // not active - - // check for stop - if( ch->use_loop && ch->sfx->loopStart >= 0 ) - { - int samplePos; - - palGetSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, &samplePos ); - - if( samplePos + ch->sfx->sampleStep >= ch->sfx->samples ) - { - palSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, ch->sfx->loopStart ); - } - else if( S_ChannelState( ch ) == AL_STOPPED ) - { - S_PlayChannel( ch, ch->sfx ); - } - } - else if( S_ChannelState( ch ) == AL_STOPPED ) - { - S_StopChannel( ch ); - continue; - } - - // respatialize channel - S_SpatializeChannel( ch ); - } - - // check for errors - S_CheckForErrors(); -} - -/* -================= -S_BeginFrame - -Starts a new rendering frame -================= -*/ -void S_BeginFrame( void ) -{ -} - -/* -================= -S_Activate - -Called when the main window gains or loses focus. -The window may have been destroyed and recreated between a deactivate -and an activate. -================= -*/ -void S_Activate( bool active, void *hInst ) -{ - al_state.active = active; - if( active ) palListenerf( AL_GAIN, S_GetMasterVolume( )); - else palListenerf( AL_GAIN, 0.0f ); -} - -/* -================= -S_Play_f -================= -*/ -void S_PlaySound_f( void ) -{ - if( Cmd_Argc() == 1 ) - { - Msg( "Usage: play \n" ); - return; - } - S_StartLocalSound( Cmd_Argv( 1 )); -} - -/* -================= -S_Music_f -================= -*/ -void S_Music_f( void ) -{ - int c = Cmd_Argc(); - - if( c == 2 ) S_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(1) ); - else if( c == 3 ) S_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(2) ); - else Msg( "Usage: music [loopfile]\n" ); -} - -/* -================= -S_StopSound_f -================= -*/ -void S_StopSound_f( void ) -{ - S_StopAllSounds(); -} - -/* -================= -S_SoundInfo_f -================= -*/ -void S_SoundInfo_f( void ) -{ - Msg( "\n" ); - Msg( "AL_VENDOR: %s\n", al_config.vendor_string ); - Msg( "AL_RENDERER: %s\n", al_config.renderer_string ); - Msg( "AL_VERSION: %s\n", al_config.version_string ); - Msg( "AL_EXTENSIONS: %s\n", al_config.extensions_string ); - Msg( "\n" ); - Msg( "DEVICE: %s\n", s_alDevice->string ); - Msg( "CHANNELS: %i\n", al_state.max_channels ); - Msg( "3D sound: %s\n", (al_config.allow_3DMode) ? "enabled" : "disabled" ); - Msg( "\n" ); -} - -/* -================= - S_Init -================= -*/ -bool S_Init( void *hInst ) -{ - int num_mono_src, num_stereo_src; - - Cmd_ExecuteString( "sndlatch\n" ); - - s_alDevice = Cvar_Get("s_device", "Generic Software", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "OpenAL current device name" ); - s_allowEAX = Cvar_Get("s_allowEAX", "1", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "allow EAX 2.0 extension" ); - s_allowA3D = Cvar_Get("s_allowA3D", "1", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "allow A3D 2.0 extension" ); - s_check_errors = Cvar_Get("s_check_errors", "1", CVAR_ARCHIVE, "ignore audio engine errors" ); - s_volume = Cvar_Get("volume", "1.0", CVAR_ARCHIVE, "sound volume" ); - s_musicvolume = Cvar_Get("musicvolume", "1.0", CVAR_ARCHIVE, "background music volume" ); - s_minDistance = Cvar_Get("s_mindistance", "240.0", CVAR_ARCHIVE, "3d sound min distance" ); - s_maxDistance = Cvar_Get("s_maxdistance", "8192.0", CVAR_ARCHIVE, "3d sound max distance" ); - s_rolloffFactor = Cvar_Get("s_rollofffactor", "1.0", CVAR_ARCHIVE, "3d sound rolloff factor" ); - s_dopplerFactor = Cvar_Get("s_dopplerfactor", "1.0", CVAR_ARCHIVE, "cutoff doppler effect value" ); - s_dopplerVelocity = Cvar_Get("s_dopplervelocity", "10976.0", CVAR_ARCHIVE, "doppler effect maxvelocity" ); - s_room_type = Cvar_Get( "room_type", "0", 0, "dsp room type" ); - - Cmd_AddCommand( "play", S_PlaySound_f, "playing a specified sound file" ); - Cmd_AddCommand( "stopsound", S_StopSound_f, "stop all sounds" ); - Cmd_AddCommand( "music", S_Music_f, "starting a background track" ); - Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" ); - Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" ); - - if(!S_Init_OpenAL()) - { - MsgDev( D_INFO, "S_Init: sound system can't initialized\n" ); - return false; - } - - palcGetIntegerv( al_state.hDevice, ALC_MONO_SOURCES, sizeof( int ), &num_mono_src ); - palcGetIntegerv( al_state.hDevice, ALC_STEREO_SOURCES, sizeof( int ), &num_stereo_src ); - MsgDev( D_NOTE, "S_Init: mono sources %d, stereo %d\n", num_mono_src, num_stereo_src ); - - sndpool = Mem_AllocPool( "Sound Zone" ); - - S_AllocChannels(); - S_StopAllSounds(); - - // initialize error catched - if(S_CheckForErrors()) - return false; - - al_state.active = true; // enabled - - return true; -} - -/* -================= -S_Shutdown -================= -*/ -void S_Shutdown( void ) -{ - - Cmd_RemoveCommand( "play" ); - Cmd_RemoveCommand( "stopsound" ); - Cmd_RemoveCommand( "music" ); - Cmd_RemoveCommand( "s_info" ); - Cmd_RemoveCommand( "soundlist" ); - - S_FreeSounds(); - S_FreeChannels(); - - Mem_FreePool( &sndpool ); - S_Free_OpenAL(); -} \ No newline at end of file diff --git a/snd_al/s_openal.c b/snd_al/s_openal.c deleted file mode 100644 index 3ff0e022..00000000 --- a/snd_al/s_openal.c +++ /dev/null @@ -1,402 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// s_openal.c - openal32.dll handler -//======================================================================= - -#include "sound.h" - -static dllfunc_t openal_funcs[] = -{ - {"alcOpenDevice", (void **) &palcOpenDevice }, - {"alcCloseDevice", (void **) &palcCloseDevice }, - {"alcCreateContext", (void **) &palcCreateContext }, - {"alcDestroyContext", (void **) &palcDestroyContext }, - {"alcMakeContextCurrent", (void **) &palcMakeContextCurrent }, - {"alcProcessContext", (void **) &palcProcessContext }, - {"alcSuspendContext", (void **) &palcSuspendContext }, - {"alcGetCurrentContext", (void **) &palcGetCurrentContext }, - {"alcGetContextsDevice", (void **) &palcGetContextsDevice }, - {"alcGetString", (void **) &palcGetString }, - {"alcGetIntegerv", (void **) &palcGetIntegerv }, - {"alcGetError", (void **) &palcGetError }, - {"alcIsExtensionPresent", (void **) &palcIsExtensionPresent }, - {"alcGetProcAddress", (void **) &palcGetProcAddress }, - {"alcGetEnumValue", (void **) &palcGetEnumValue }, - - {"alBufferData", (void **) &palBufferData }, - {"alDeleteBuffers", (void **) &palDeleteBuffers }, - {"alDeleteSources", (void **) &palDeleteSources }, - {"alDisable", (void **) &palDisable }, - {"alDistanceModel", (void **) &palDistanceModel }, - {"alDopplerFactor", (void **) &palDopplerFactor }, - {"alDopplerVelocity", (void **) &palDopplerVelocity }, - {"alEnable", (void **) &palEnable }, - {"alGenBuffers", (void **) &palGenBuffers }, - {"alGenSources", (void **) &palGenSources }, - {"alGetBoolean", (void **) &palGetBoolean }, - {"alGetBooleanv", (void **) &palGetBooleanv }, - {"alGetBufferf", (void **) &palGetBufferf }, - {"alGetBufferi", (void **) &palGetBufferi }, - {"alGetDouble", (void **) &palGetDouble }, - {"alGetDoublev", (void **) &palGetDoublev }, - {"alGetEnumValue", (void **) &palGetEnumValue }, - {"alGetError", (void **) &palGetError }, - {"alGetFloat", (void **) &palGetFloat }, - {"alGetFloatv", (void **) &palGetFloatv }, - {"alGetInteger", (void **) &palGetInteger }, - {"alGetIntegerv", (void **) &palGetIntegerv }, - {"alGetListener3f", (void **) &palGetListener3f }, - {"alGetListenerf", (void **) &palGetListenerf }, - {"alGetListenerfv", (void **) &palGetListenerfv }, - {"alGetListeneri", (void **) &palGetListeneri }, - {"alGetProcAddress", (void **) &palGetProcAddress }, - {"alGetSource3f", (void **) &palGetSource3f }, - {"alGetSourcef", (void **) &palGetSourcef }, - {"alGetSourcefv", (void **) &palGetSourcefv }, - {"alGetSourcei", (void **) &palGetSourcei }, - {"alGetString", (void **) &palGetString }, - {"alIsBuffer", (void **) &palIsBuffer }, - {"alIsEnabled", (void **) &palIsEnabled }, - {"alIsExtensionPresent", (void **) &palIsExtensionPresent }, - {"alIsSource", (void **) &palIsSource }, - {"alListener3f", (void **) &palListener3f }, - {"alListenerf", (void **) &palListenerf }, - {"alListenerfv", (void **) &palListenerfv }, - {"alListeneri", (void **) &palListeneri }, - {"alSource3f", (void **) &palSource3f }, - {"alSourcef", (void **) &palSourcef }, - {"alSourcefv", (void **) &palSourcefv }, - {"alSourcei", (void **) &palSourcei }, - {"alSourcePause", (void **) &palSourcePause }, - {"alSourcePausev", (void **) &palSourcePausev }, - {"alSourcePlay", (void **) &palSourcePlay }, - {"alSourcePlayv", (void **) &palSourcePlayv }, - {"alSourceQueueBuffers", (void **) &palSourceQueueBuffers }, - {"alSourceRewind", (void **) &palSourceRewind }, - {"alSourceRewindv", (void **) &palSourceRewindv }, - {"alSourceStop", (void **) &palSourceStop }, - {"alSourceStopv", (void **) &palSourceStopv }, - {"alSourceUnqueueBuffers", (void **) &palSourceUnqueueBuffers }, - { NULL, NULL } -}; - -static dllfunc_t openal_effects[] = -{ - {"alGenEffects", (void **) &alGenEffects }, - {"alDeleteEffects", (void **) &alDeleteEffects }, - {"alIsEffect", (void **) &alIsEffect }, - {"alEffecti", (void **) &alEffecti }, - {"alEffectiv", (void **) &alEffectiv }, - {"alEffectf", (void **) &alEffectf }, - {"alEffectfv", (void **) &alEffectfv }, - {"alGetEffecti", (void **) &alGetEffecti }, - {"alGetEffectiv", (void **) &alGetEffectiv }, - {"alGetEffectf", (void **) &alGetEffectf }, - {"alGetEffectfv", (void **) &alGetEffectfv }, - {"alGenFilters", (void **) &alGenFilters }, - {"alDeleteFilters", (void **) &alDeleteFilters }, - {"alIsFilter", (void **) &alIsFilter }, - {"alFilteri", (void **) &alFilteri }, - {"alFilteriv", (void **) &alFilteriv }, - {"alFilterf", (void **) &alFilterf }, - {"alFilterfv", (void **) &alFilterfv }, - {"alGetFilteri", (void **) &alGetFilteri }, - {"alGetFilteriv", (void **) &alGetFilteriv }, - {"alGetFilterf", (void **) &alGetFilterf }, - {"alGetFilterfv", (void **) &alGetFilterfv }, - {"alGenAuxiliaryEffectSlots", (void **) &alGenAuxiliaryEffectSlots }, - {"alDeleteAuxiliaryEffectSlots", (void **) &alDeleteAuxiliaryEffectSlots }, - {"alIsAuxiliaryEffectSlot", (void **) &alIsAuxiliaryEffectSlot }, - {"alAuxiliaryEffectSloti", (void **) &alAuxiliaryEffectSloti }, - {"alAuxiliaryEffectSlotiv", (void **) &alAuxiliaryEffectSlotiv }, - {"alAuxiliaryEffectSlotf", (void **) &alAuxiliaryEffectSlotf }, - {"alAuxiliaryEffectSlotfv", (void **) &alAuxiliaryEffectSlotfv }, - {"alGetAuxiliaryEffectSloti", (void **) &alGetAuxiliaryEffectSloti }, - {"alGetAuxiliaryEffectSlotiv", (void **) &alGetAuxiliaryEffectSlotiv }, - {"alGetAuxiliaryEffectSlotf", (void **) &alGetAuxiliaryEffectSlotf }, - {"alGetAuxiliaryEffectSlotfv", (void **) &alGetAuxiliaryEffectSlotfv }, - { NULL, NULL } -}; - -dll_info_t openal_dll = { "openal32.dll", openal_funcs, NULL, NULL, NULL, false }; - -alconfig_t al_config; -alstate_t al_state; - -cvar_t *s_eax; - -/* -================= -S_InitDriver -================= -*/ -static bool S_InitDriver( void ) -{ - int attrlist[3] = { ALC_FREQUENCY, 44100, 0 }; - int *al_contxt = attrlist; - - if(( al_state.hDevice = palcOpenDevice( s_alDevice->string )) == NULL ) - { - Msg("alOpenDevice - failed\n" ); - return false; - } - - if(( al_state.hALC = palcCreateContext( al_state.hDevice, al_contxt )) == NULL ) - goto failed; - - if( !palcMakeContextCurrent( al_state.hALC )) - goto failed; - return true; - -failed: - if( al_state.hALC ) - { - palcDestroyContext( al_state.hALC ); - al_state.hALC = NULL; - } - - if( al_state.hDevice ) - { - palcCloseDevice( al_state.hDevice ); - al_state.hDevice = NULL; - } - - // release openal at all - Sys_FreeLibrary( &openal_dll ); - Mem_Set( &al_config, 0, sizeof( alconfig_t )); - Mem_Set( &al_state, 0, sizeof( alstate_t )); - - return false; -} - -static bool S_SetupEFX( void ) -{ - const dllfunc_t *func; - - // get the function pointers - for( func = openal_effects; func && func->name != NULL; func++ ) - { - if( !( *func->func = palGetProcAddress( func->name ))) - { - MsgDev( D_ERROR, "S_InitEffects: %s missing or invalid function\n", func->name ); - return false; - } - } - return true; -} - -static void S_InitEffects( void ) -{ - uint uiEffects[1] = { 0 }; - - alGenEffects(1, &uiEffects[0]); - if( palGetError() == AL_NO_ERROR ) - { - MsgDev( D_NOTE, "S_InitEffects:" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_revrb" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_eaxrevrb" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_CHORUS ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_chorus" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_DISTORTION ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_distortion" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_ECHO ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_echo" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_FLANGER ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_flanger" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_frequency_shifter" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_vocal_morpher" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_pitch_shifter" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_ring_modulator" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_AUTOWAH ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_autowah" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_compressor" ); - alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_equalizer" ); - MsgDev( D_NOTE, "\n" ); - } - alDeleteEffects(1, &uiEffects[0]); -} - -static void S_InitFilters( void ) -{ - uint uiFilters[1] = { 0 }; - - alGenFilters(1, &uiFilters[0]); - if( palGetError() == AL_NO_ERROR ) - { - MsgDev( D_NOTE, "S_InitFilters:" ); - alFilteri( uiFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_lowpass" ); - alFilteri( uiFilters[0], AL_FILTER_TYPE, AL_FILTER_HIGHPASS ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_highpass" ); - alFilteri( uiFilters[0], AL_FILTER_TYPE, AL_FILTER_BANDPASS ); - if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_bandpass" ); - MsgDev( D_NOTE, "\n" ); - } - alDeleteFilters( 1, &uiFilters[0] ); -} - -/* -================= -S_InitExtensions - -grab extensions -================= -*/ -static void S_InitExtensions( void ) -{ - // set initial state - al_config.Get3DMode = NULL; - al_config.Set3DMode = NULL; - al_config.allow_3DMode = false; - - if( !s_allowEAX->integer ) return; - - // check I3DL2 extension for NVidia's Sound Storm chips. I3DL2 is hidden and can be missed in extension list. - if( !com.strcmp( NVIDIA_DEVICE_NAME, al_config.deviceList[0] )) - { - I3DL2Get = (void *)palGetProcAddress( "I3DL2Get" ); - I3DL2Set = (void *)palGetProcAddress( "I3DL2Set" ); - if( I3DL2Get && I3DL2Set ) - { - al_config.allow_3DMode = true; - al_config.Get3DMode = I3DL2Get; - al_config.Set3DMode = I3DL2Set; - MsgDev( D_NOTE, "S_InitExtensions: enable I3DL2\n" ); - } - } - if( palIsExtensionPresent( "EAX3.0" ) && !al_config.allow_3DMode ) - { - alEAXSet = (void *)palGetProcAddress( "EAXSet" ); - alEAXGet = (void *)palGetProcAddress( "EAXGet" ); - if( alEAXSet && alEAXGet ) - { - al_config.allow_3DMode = true; - al_config.Get3DMode = alEAXGet; - al_config.Set3DMode = alEAXSet; - MsgDev( D_NOTE, "S_InitExtensions: enable EAX 3.0\n" ); - } - } - if( palIsExtensionPresent( "EAX2.0" ) && !al_config.allow_3DMode ) - { - alEAXSet = (void *)palGetProcAddress( "EAXSet" ); - alEAXGet = (void *)palGetProcAddress( "EAXGet" ); - if( alEAXSet && alEAXGet ) - { - al_config.allow_3DMode = true; - al_config.Get3DMode = alEAXGet; - al_config.Set3DMode = alEAXSet; - MsgDev( D_NOTE, "S_InitExtensions: enable EAX 2.0\n" ); - } - } - if( palIsExtensionPresent( "EAX" ) && !al_config.allow_3DMode ) - { - alEAXSet = (void *)palGetProcAddress( "EAXSet" ); - alEAXGet = (void *)palGetProcAddress( "EAXGet" ); - if( alEAXSet && alEAXGet ) - { - al_config.allow_3DMode = true; - al_config.Get3DMode = alEAXGet; - al_config.Set3DMode = alEAXSet; - MsgDev( D_NOTE, "S_InitExtensions: enable EAX 1.0\n" ); - } - } - - if( palcIsExtensionPresent( al_state.hDevice, "ALC_EXT_EFX" )) - { - uint uiEffectSlots[MAX_EFFECTS] = { 0 }; - - if( !S_SetupEFX( )) return; - - // testing effect slots - for( al_config.num_slots = 0; al_config.num_slots < MAX_EFFECTS; al_config.num_slots++ ) - { - alGenAuxiliaryEffectSlots( 1, &uiEffectSlots[al_config.num_slots] ); - if( palGetError() != AL_NO_ERROR ) break; - - } - palcGetIntegerv( al_state.hDevice, ALC_MAX_AUXILIARY_SENDS, 1, &al_config.num_sends ); - - S_InitEffects(); - S_InitFilters(); - - alDeleteAuxiliaryEffectSlots( al_config.num_slots, uiEffectSlots ); - } -} - -bool S_Init_OpenAL( void ) -{ - Sys_LoadLibrary( NULL, &openal_dll ); - - if( !openal_dll.link ) - { - MsgDev( D_ERROR, "OpenAL driver not installed\n"); - return false; - } - - // Get device list - if( palcIsExtensionPresent( NULL, "ALC_ENUMERATION_EXT" )) - { - // get list of devices - const char *device_enum = palcGetString( NULL, ALC_DEVICE_SPECIFIER ); - al_config.defDevice = palcGetString( NULL, ALC_DEFAULT_DEVICE_SPECIFIER ); - - while( *device_enum ) - { - // enumerate devices - com.strncpy( al_config.deviceList[al_config.device_count++], device_enum, MAX_STRING ); - while(*device_enum) device_enum++; - device_enum++; - } - } - else - { - MsgDev( D_ERROR, "can't enumerate OpenAL devices\n" ); - return false; - } - - // initialize the device, context, etc... - if( !S_InitDriver( )) return false; - - // get some openal strings - al_config.vendor_string = palGetString( AL_VENDOR ); - al_config.renderer_string = palGetString( AL_RENDERER ); // stupid name :-) - al_config.version_string = palGetString( AL_VERSION ); - al_config.extensions_string = palGetString( AL_EXTENSIONS ); - MsgDev( D_INFO, "Audio: %s\n", al_config.renderer_string ); - - // Initialize extensions - S_InitExtensions(); - - return true; -} - -void S_Free_OpenAL( void ) -{ - if( al_state.hALC ) - { - if( palcMakeContextCurrent ) - palcMakeContextCurrent( NULL ); - if( palcDestroyContext ) - palcDestroyContext( al_state.hALC ); - al_state.hALC = NULL; - } - - if( al_state.hDevice ) - { - if( palcCloseDevice ) - palcCloseDevice( al_state.hDevice ); - al_state.hDevice = NULL; - } - - Sys_FreeLibrary( &openal_dll ); - Mem_Set( &al_config, 0, sizeof( alconfig_t )); - Mem_Set( &al_state, 0, sizeof( alstate_t )); -} \ No newline at end of file diff --git a/snd_al/s_openal.h b/snd_al/s_openal.h deleted file mode 100644 index 542ab5d4..00000000 --- a/snd_al/s_openal.h +++ /dev/null @@ -1,313 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// s_openal.h - openal definition -//======================================================================= - -#ifndef S_OPENAL_H -#define S_OPENAL_H - -typedef struct aldevice_s aldevice; -typedef struct alcontext_s alcontext; - -#define NVIDIA_DEVICE_NAME "NVIDIA(R) nForce(TM) Audio" -#define MAX_EFFECTS 128 - -#define AL_VENDOR 0xB001 -#define AL_VERSION 0xB002 -#define AL_RENDERER 0xB003 -#define AL_EXTENSIONS 0xB004 -#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 -#define ALC_DEVICE_SPECIFIER 0x1005 -#define ALC_EXTENSIONS 0x1006 -#define ALC_MAJOR_VERSION 0x1000 -#define ALC_MINOR_VERSION 0x1001 -#define ALC_ATTRIBUTES_SIZE 0x1002 -#define ALC_ALL_ATTRIBUTES 0x1003 -#define ALC_FREQUENCY 0x1007 -#define ALC_MAX_AUXILIARY_SENDS 0x20003 -#define ALC_MONO_SOURCES 0x1010 -#define ALC_STEREO_SOURCES 0x1011 - -#define AL_SOURCE_RELATIVE 0x202 -#define AL_CONE_INNER_ANGLE 0x1001 -#define AL_CONE_OUTER_ANGLE 0x1002 -#define AL_PITCH 0x1003 -#define AL_POSITION 0x1004 -#define AL_DIRECTION 0x1005 -#define AL_VELOCITY 0x1006 -#define AL_LOOPING 0x1007 -#define AL_BUFFER 0x1009 -#define AL_GAIN 0x100A -#define AL_MIN_GAIN 0x100D -#define AL_MAX_GAIN 0x100E -#define AL_ORIENTATION 0x100F - -#define AL_SOURCE_STATE 0x1010 -#define AL_INITIAL 0x1011 -#define AL_PLAYING 0x1012 -#define AL_PAUSED 0x1013 -#define AL_STOPPED 0x1014 - -#define AL_REFERENCE_DISTANCE 0x1020 -#define AL_ROLLOFF_FACTOR 0x1021 -#define AL_CONE_OUTER_GAIN 0x1022 -#define AL_MAX_DISTANCE 0x1023 - -#define AL_DISTANCE_MODEL 0xD000 -#define AL_INVERSE_DISTANCE 0xD001 -#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 -#define AL_LINEAR_DISTANCE 0xD003 -#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 -#define AL_EXPONENT_DISTANCE 0xD005 -#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 - -// sound format -#define AL_FORMAT_MONO8 0x1100 -#define AL_FORMAT_MONO16 0x1101 -#define AL_FORMAT_STEREO8 0x1102 -#define AL_FORMAT_STEREO16 0x1103 - -// buffer queues -#define AL_BUFFERS_QUEUED 0x1015 -#define AL_BUFFERS_PROCESSED 0x1016 - -// source buffer position information -#define AL_SEC_OFFSET 0x1024 -#define AL_SAMPLE_OFFSET 0x1025 -#define AL_BYTE_OFFSET 0x1026 - -// openal errors -#define AL_NO_ERROR 0 -#define AL_INVALID_NAME 0xA001 -#define AL_INVALID_ENUM 0xA002 -#define AL_INVALID_VALUE 0xA003 -#define AL_INVALID_OPERATION 0xA004 -#define AL_OUT_OF_MEMORY 0xA005 - -// openal effects -#define AL_EFFECT_TYPE 0x8001 -#define AL_EFFECT_NULL 0x0000 -#define AL_EFFECT_REVERB 0x0001 -#define AL_EFFECT_CHORUS 0x0002 -#define AL_EFFECT_DISTORTION 0x0003 -#define AL_EFFECT_ECHO 0x0004 -#define AL_EFFECT_FLANGER 0x0005 -#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 -#define AL_EFFECT_VOCAL_MORPHER 0x0007 -#define AL_EFFECT_PITCH_SHIFTER 0x0008 -#define AL_EFFECT_RING_MODULATOR 0x0009 -#define AL_EFFECT_AUTOWAH 0x000A -#define AL_EFFECT_COMPRESSOR 0x000B -#define AL_EFFECT_EQUALIZER 0x000C -#define AL_EFFECT_EAXREVERB 0x8000 - -// openal filters -#define AL_FILTER_TYPE 0x8001 -#define AL_FILTER_NULL 0x0000 -#define AL_FILTER_LOWPASS 0x0001 -#define AL_FILTER_HIGHPASS 0x0002 -#define AL_FILTER_BANDPASS 0x0003 - -enum -{ - EAX_ENVIRONMENT_GENERIC, - EAX_ENVIRONMENT_PADDEDCELL, - EAX_ENVIRONMENT_ROOM, - EAX_ENVIRONMENT_BATHROOM, - EAX_ENVIRONMENT_LIVINGROOM, - EAX_ENVIRONMENT_STONEROOM, - EAX_ENVIRONMENT_AUDITORIUM, - EAX_ENVIRONMENT_CONCERTHALL, - EAX_ENVIRONMENT_CAVE, - EAX_ENVIRONMENT_ARENA, - EAX_ENVIRONMENT_HANGAR, - EAX_ENVIRONMENT_CARPETEDHALLWAY, - EAX_ENVIRONMENT_HALLWAY, - EAX_ENVIRONMENT_STONECORRIDOR, - EAX_ENVIRONMENT_ALLEY, - EAX_ENVIRONMENT_FOREST, - EAX_ENVIRONMENT_CITY, - EAX_ENVIRONMENT_MOUNTAINS, - EAX_ENVIRONMENT_QUARRY, - EAX_ENVIRONMENT_PLAIN, - EAX_ENVIRONMENT_PARKINGLOT, - EAX_ENVIRONMENT_SEWERPIPE, - EAX_ENVIRONMENT_UNDERWATER, - EAX_ENVIRONMENT_DRUGGED, - EAX_ENVIRONMENT_DIZZY, - EAX_ENVIRONMENT_PSYCHOTIC, - - EAX_ENVIRONMENT_COUNT -}; - -typedef enum -{ - DSPROPERTY_EAXLISTENER_NONE, - DSPROPERTY_EAXLISTENER_ALLPARAMETERS, - DSPROPERTY_EAXLISTENER_ROOM, - DSPROPERTY_EAXLISTENER_ROOMHF, - DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR, - DSPROPERTY_EAXLISTENER_DECAYTIME, - DSPROPERTY_EAXLISTENER_DECAYHFRATIO, - DSPROPERTY_EAXLISTENER_REFLECTIONS, - DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY, - DSPROPERTY_EAXLISTENER_REVERB, - DSPROPERTY_EAXLISTENER_REVERBDELAY, - DSPROPERTY_EAXLISTENER_ENVIRONMENT, - DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE, - DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION, - DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF, - - DSPROPERTY_EAXLISTENER_FLAGS -} DSPROPERTY_EAX_LISTENERPROPERTY; - -typedef enum -{ - DSPROPERTY_EAXBUFFER_NONE, - DSPROPERTY_EAXBUFFER_ALLPARAMETERS, - DSPROPERTY_EAXBUFFER_DIRECT, - DSPROPERTY_EAXBUFFER_DIRECTHF, - DSPROPERTY_EAXBUFFER_ROOM, - DSPROPERTY_EAXBUFFER_ROOMHF, - DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR, - DSPROPERTY_EAXBUFFER_OBSTRUCTION, - DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO, - DSPROPERTY_EAXBUFFER_OCCLUSION, - DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO, - DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO, - DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF, - DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR, - DSPROPERTY_EAXBUFFER_FLAGS -} DSPROPERTY_EAX_BUFFERPROPERTY; - -// or these flags with property id -#define DSPROPERTY_EAXLISTENER_IMMEDIATE 0x00000000 // changes take effect immediately -#define DSPROPERTY_EAXLISTENER_DEFERRED 0x80000000 // changes take effect later - -// openal32.dll exports -aldevice *(_cdecl *palcOpenDevice)( const char *devicename ); -char (_cdecl *palcCloseDevice)( aldevice *device ); -alcontext *(_cdecl *palcCreateContext)( aldevice *device, const int *attrlist ); -void (_cdecl *palcDestroyContext)( alcontext *context ); -char (_cdecl *palcMakeContextCurrent)( alcontext *context ); -void (_cdecl *palcProcessContext)( alcontext *context ); -void (_cdecl *palcSuspendContext)( alcontext *context ); -alcontext *(_cdecl *palcGetCurrentContext)( void ); -aldevice *(_cdecl *palcGetContextsDevice)( alcontext *context ); -const char *(_cdecl *palcGetString )( aldevice *device, int param ); -void (_cdecl *palcGetIntegerv)( aldevice *device, int param, int size, int *dest ); -int (_cdecl *palcGetError)( aldevice *device ); -char (_cdecl *palcIsExtensionPresent)( aldevice *device, const char *extname ); -void *(_cdecl *palcGetProcAddress)( aldevice *device, const char *function ); -int (_cdecl *palcGetEnumValue)( aldevice *device, const char *enumname ); - -void (_cdecl *palBufferData)( uint bid, int format, const void* data, int size, int freq ); -void (_cdecl *palDeleteBuffers)( int n, const uint* buffers ); -void (_cdecl *palDeleteSources)( int n, const uint* sources ); -void (_cdecl *palDisable)( int capability ); -void (_cdecl *palDistanceModel)( int distanceModel ); -void (_cdecl *palDopplerFactor)( float value ); -void (_cdecl *palDopplerVelocity)( float value ); -void (_cdecl *palEnable)( int capability ); -void (_cdecl *palGenBuffers)( int n, uint* buffers ); -void (_cdecl *palGenSources)( int n, uint* sources ); -char (_cdecl *palGetBoolean)( int param ); -void (_cdecl *palGetBooleanv)( int param, char* data ); -void (_cdecl *palGetBufferf)( uint bid, int param, float* value ); -void (_cdecl *palGetBufferi)( uint bid, int param, int* value ); -double (_cdecl *palGetDouble)( int param ); -void (_cdecl *palGetDoublev)( int param, double* data ); -int (_cdecl *palGetEnumValue)( const char* ename ); -int (_cdecl *palGetError)( void ); -float (_cdecl *palGetFloat)( int param ); -void (_cdecl *palGetFloatv)( int param, float* data ); -int (_cdecl *palGetInteger)( int param ); -void (_cdecl *palGetIntegerv)( int param, int* data ); -void (_cdecl *palGetListener3f)( int param, float *value1, float *value2, float *value3 ); -void (_cdecl *palGetListenerf)( int param, float* value ); -void (_cdecl *palGetListenerfv)( int param, float* values ); -void (_cdecl *palGetListeneri)( int param, int* value ); -void *(_cdecl *palGetProcAddress)( const char* fname ); -void (_cdecl *palGetSource3f)( uint sid, int param, float* value1, float* value2, float* value3 ); -void (_cdecl *palGetSourcef)( uint sid, int param, float* value ); -void (_cdecl *palGetSourcefv)( uint sid, int param, float* values ); -void (_cdecl *palGetSourcei)( uint sid, int param, int* value ); -const char *(_cdecl *palGetString)( int param ); -char (_cdecl *palIsBuffer)( uint bid ); -char (_cdecl *palIsEnabled)( int capability ); -char (_cdecl *palIsExtensionPresent)(const char* extname ); -char (_cdecl *palIsSource)( uint sid ); -void (_cdecl *palListener3f)( int param, float value1, float value2, float value3 ); -void (_cdecl *palListenerf)( int param, float value ); -void (_cdecl *palListenerfv)( int param, const float* values ); -void (_cdecl *palListeneri)( int param, int value ); -void (_cdecl *palSource3f)( uint sid, int param, float value1, float value2, float value3 ); -void (_cdecl *palSourcef)( uint sid, int param, float value ); -void (_cdecl *palSourcefv)( uint sid, int param, const float* values ); -void (_cdecl *palSourcei)( uint sid, int param, int value); -void (_cdecl *palSourcePause)( uint sid ); -void (_cdecl *palSourcePausev)( int ns, const uint *sids ); -void (_cdecl *palSourcePlay)( uint sid ); -void (_cdecl *palSourcePlayv)( int ns, const uint *sids ); -void (_cdecl *palSourceQueueBuffers)(uint sid, int numEntries, const uint *bids ); -void (_cdecl *palSourceRewind)( uint sid ); -void (_cdecl *palSourceRewindv)( int ns, const uint *sids ); -void (_cdecl *palSourceStop)( uint sid ); -void (_cdecl *palSourceStopv)( int ns, const uint *sids ); -void (_cdecl *palSourceUnqueueBuffers)(uint sid, int numEntries, uint *bids ); - -// openal32.dll internal exports which can be get with by algetProcAddress -void (*alGenEffects)( int n, uint* effects ); -void (*alDeleteEffects)( int n, uint* effects ); -char (*alIsEffect)( uint eid ); -void (*alEffecti)( uint eid, int param, int value); -void (*alEffectiv)( uint eid, int param, int* values ); -void (*alEffectf)( uint eid, int param, float value); -void (*alEffectfv)( uint eid, int param, float* values ); -void (*alGetEffecti)( uint eid, int pname, int* value ); -void (*alGetEffectiv)( uint eid, int pname, int* values ); -void (*alGetEffectf)( uint eid, int pname, float* value ); -void (*alGetEffectfv)( uint eid, int pname, float* values ); -void (*alGenFilters)( int n, uint* filters ); -void (*alDeleteFilters)( int n, uint* filters ); -char (*alIsFilter)( uint fid ); -void (*alFilteri)( uint fid, int param, int value ); -void (*alFilteriv)( uint fid, int param, int* values ); -void (*alFilterf)( uint fid, int param, float value); -void (*alFilterfv)( uint fid, int param, float* values ); -void (*alGetFilteri)( uint fid, int pname, int* value ); -void (*alGetFilteriv)( uint fid, int pname, int* values ); -void (*alGetFilterf)( uint fid, int pname, float* value ); -void (*alGetFilterfv)( uint fid, int pname, float* values ); -void (*alGenAuxiliaryEffectSlots)( int n, uint* slots ); -void (*alDeleteAuxiliaryEffectSlots)( int n, uint* slots ); -char (*alIsAuxiliaryEffectSlot)( uint slot ); -void (*alAuxiliaryEffectSloti)( uint asid, int param, int value ); -void (*alAuxiliaryEffectSlotiv)( uint asid, int param, int* values ); -void (*alAuxiliaryEffectSlotf)( uint asid, int param, float value ); -void (*alAuxiliaryEffectSlotfv)( uint asid, int param, float* values ); -void (*alGetAuxiliaryEffectSloti)( uint asid, int pname, int* value ); -void (*alGetAuxiliaryEffectSlotiv)( uint asid, int pname, int* values ); -void (*alGetAuxiliaryEffectSlotf)( uint asid, int pname, float* value ); -void (*alGetAuxiliaryEffectSlotfv)( uint asid, int pname, float* values ); - -typedef struct guid_s -{ - dword Data1; - word Data2; - word Data3; - byte Data4[8]; -} guid_t; - -// EAX 2.0 extension -int (*alEAXSet)( const guid_t*, uint, uint, void*, uint ); -int (*alEAXGet)( const guid_t*, uint, uint, void*, uint ); - -// I3DL2 OpenAL Extension -int (*I3DL2Get)( const guid_t*, uint, uint, void*, uint ); -int (*I3DL2Set)( const guid_t*, uint, uint, void*, uint ); - -bool S_Init_OpenAL( void ); -void S_Free_OpenAL( void ); - -#endif//S_OPENAL_H \ No newline at end of file diff --git a/snd_al/s_stream.c b/snd_al/s_stream.c deleted file mode 100644 index c18fe0a3..00000000 --- a/snd_al/s_stream.c +++ /dev/null @@ -1,326 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// s_stream.c - sound streaming -//======================================================================= - -#include "sound.h" - -#define NUM_MUSIC_BUFFERS 4 -#define MUSIC_BUFFER_SIZE 4096 -#define RAW_BUFFER_SIZE 16384 - -static bg_track_t s_bgTrack; -static channel_t *s_streamingChannel; -static uint musicBuffers[NUM_MUSIC_BUFFERS]; - -/* -================= -S_CloseBackgroundTrack -================= -*/ -static void S_CloseBackgroundTrack( bg_track_t *track ) -{ - if( track->intro_stream ) - { - FS_CloseStream( track->intro_stream ); - track->intro_stream = NULL; - } - - if( track->main_stream ) - { - FS_CloseStream( track->main_stream ); - track->main_stream = NULL; - } -} - -/* -================= -S_ProcessBuffers -================= -*/ -static void S_ProcessBuffers( uint bufnum ) -{ - uint format; - stream_t *curstream; - byte decode_buffer[MUSIC_BUFFER_SIZE]; - wavdata_t *info; - size_t size; - - if( s_bgTrack.intro_stream ) - curstream = s_bgTrack.intro_stream; - else curstream = s_bgTrack.main_stream; - - if( !curstream ) return; // stopped - - size = FS_ReadStream( curstream, MUSIC_BUFFER_SIZE, decode_buffer ); - - // run out data to read, start at the beginning again - if( size == 0 ) - { - FS_CloseStream( curstream ); - - // the intro stream just finished playing so we don't need to reopen - // the music stream. - if( s_bgTrack.intro_stream ) - s_bgTrack.intro_stream = NULL; - else s_bgTrack.main_stream = FS_OpenStream( s_bgTrack.loopName ); - - curstream = s_bgTrack.main_stream; - - if( !curstream ) - { - S_StopBackgroundTrack(); - return; - } - size = FS_ReadStream( curstream, MUSIC_BUFFER_SIZE, decode_buffer ); - } - - info = FS_StreamInfo( curstream ); - - format = S_GetFormat( info->width, info->channels ); - - if( size == 0 ) - { - // we have no data to buffer, so buffer silence - byte dummyData[2] = { 0 }; - palBufferData( bufnum, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050 ); - } - else palBufferData( bufnum, format, decode_buffer, size, info->rate ); - - if( S_CheckForErrors( )) - { - S_StopBackgroundTrack (); - return; - } -} - -/* -================= -S_StreamBackgroundTrack -================= -*/ -void S_StreamBackgroundTrack( void ) -{ - int numBuffers; - int state; - - if( !s_bgTrack.active ) - return; - - palGetSourcei( s_streamingChannel->sourceNum, AL_BUFFERS_PROCESSED, &numBuffers ); - - while( numBuffers-- ) - { - uint bufNum; - - palSourceUnqueueBuffers( s_streamingChannel->sourceNum, 1, &bufNum ); - S_ProcessBuffers( bufNum ); - palSourceQueueBuffers( s_streamingChannel->sourceNum, 1, &bufNum ); - } - - // hitches can cause OpenAL to be starved of buffers when streaming. - // If this happens, it will stop playback. This restarts the source if - // it is no longer playing, and if there are buffers available - palGetSourcei( s_streamingChannel->sourceNum, AL_SOURCE_STATE, &state ); - palGetSourcei( s_streamingChannel->sourceNum, AL_BUFFERS_QUEUED, &numBuffers ); - - if( state == AL_STOPPED && numBuffers ) - { - MsgDev( D_INFO, "restarted background track\n" ); - palSourcePlay( s_streamingChannel->sourceNum ); - } - - // Set the gain property - palSourcef( s_streamingChannel->sourceNum, AL_GAIN, s_musicvolume->value ); -} - -/* -================= -S_StartBackgroundTrack -================= -*/ -void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack ) -{ - bool issame = false; - int i; - - // stop any playing tracks - S_StopBackgroundTrack(); - - if(( !introTrack || !*introTrack ) && ( !mainTrack || !*mainTrack )) - return; - - S_StartStreaming(); - - if( !mainTrack || !*mainTrack ) - { - mainTrack = introTrack; - issame = true; - } - else if( introTrack && *introTrack && !com.strcmp( introTrack, mainTrack )) - { - issame = true; - } - - // copy the loop over - com.snprintf( s_bgTrack.loopName, sizeof( s_bgTrack.loopName ), "media/%s", mainTrack ); - - if( !issame ) - { - // Open the intro and don't mind whether it succeeds. - // The important part is the loop. - s_bgTrack.intro_stream = FS_OpenStream( va( "media/%s", introTrack )); - } - else s_bgTrack.intro_stream = NULL; - - s_bgTrack.main_stream = FS_OpenStream( s_bgTrack.loopName ); - - if( !s_bgTrack.main_stream ) - { - S_StopBackgroundTrack(); - return; - } - - // generate the musicBuffers - palGenBuffers( NUM_MUSIC_BUFFERS, musicBuffers ); - - // queue the musicBuffers up - for( i = 0; i < NUM_MUSIC_BUFFERS; i++ ) - { - S_ProcessBuffers( musicBuffers[i] ); - } - - palSourceQueueBuffers( s_streamingChannel->sourceNum, NUM_MUSIC_BUFFERS, musicBuffers ); - - // set the initial gain property - palSourcef( s_streamingChannel->sourceNum, AL_GAIN, s_musicvolume->value ); - - // Start playing - palSourcePlay( s_streamingChannel->sourceNum ); - s_bgTrack.active = true; -} - -/* -================= -S_StopBackgroundTrack -================= -*/ -void S_StopBackgroundTrack( void ) -{ - S_StopStreaming(); - S_CloseBackgroundTrack(&s_bgTrack); - Mem_Set(&s_bgTrack, 0, sizeof(bg_track_t)); -} - -/* -================= -S_StartStreaming -================= -*/ -void S_StartStreaming( void ) -{ - if( s_streamingChannel ) return; // already started - - s_streamingChannel = SND_PickStaticChannel( 0, NULL ); - if( !s_streamingChannel ) return; - - // lock stream channel to avoid re-use it - s_streamingChannel->entchannel = CHAN_STREAM; - s_streamingChannel->sfx = NULL; - - // set up the source - palSourcei( s_streamingChannel->sourceNum, AL_BUFFER, 0 ); - palSourcei( s_streamingChannel->sourceNum, AL_LOOPING, 0 ); - palSourcei( s_streamingChannel->sourceNum, AL_SOURCE_RELATIVE, 1 ); - palSourcefv( s_streamingChannel->sourceNum, AL_POSITION, vec3_origin ); - palSourcefv( s_streamingChannel->sourceNum, AL_VELOCITY, vec3_origin ); - palSourcef( s_streamingChannel->sourceNum, AL_REFERENCE_DISTANCE, 1.0f ); - palSourcef( s_streamingChannel->sourceNum, AL_MAX_DISTANCE, 1.0f ); - palSourcef( s_streamingChannel->sourceNum, AL_ROLLOFF_FACTOR, 0.0f ); -} - -/* -================= -S_StopStreaming -================= -*/ -void S_StopStreaming( void ) -{ - int processed; - uint buffer; - - if( !s_streamingChannel ) return; // already stopped - - s_streamingChannel->entchannel = 0; // can be reused now - s_streamingChannel->sfx = NULL; - - // clean up the source - palSourceStop( s_streamingChannel->sourceNum ); - - palGetSourcei( s_streamingChannel->sourceNum, AL_BUFFERS_PROCESSED, &processed ); - if( processed > 0 ) - { - while( processed-- ) - { - palSourceUnqueueBuffers( s_streamingChannel->sourceNum, 1, &buffer ); - palDeleteBuffers( 1, &buffer ); - } - } - - palSourcei( s_streamingChannel->sourceNum, AL_BUFFER, 0 ); - s_streamingChannel = NULL; -} - -/* -================= -S_StreamRawSamples - -Cinematic streaming -================= -*/ -void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data ) -{ - int processed, state, size; - uint format, buffer; - - if( !al_state.initialized ) return; - if( !s_streamingChannel ) return; - - // unqueue and delete any processed buffers - palGetSourcei( s_streamingChannel->sourceNum, AL_BUFFERS_PROCESSED, &processed ); - if( processed > 0 ) - { - while( processed-- ) - { - palSourceUnqueueBuffers(s_streamingChannel->sourceNum, 1, &buffer); - palDeleteBuffers(1, &buffer); - } - } - - // calculate buffer size - size = samples * width * channels; - - // set buffer format - if( width == 2 ) - { - if( channels == 2 ) format = AL_FORMAT_STEREO16; - else format = AL_FORMAT_MONO16; - } - else - { - if( channels == 2 ) format = AL_FORMAT_STEREO8; - else format = AL_FORMAT_MONO8; - } - - // upload and queue the new buffer - palGenBuffers( 1, &buffer ); - palBufferData( buffer, format, (byte *)data, size, rate ); - palSourceQueueBuffers( s_streamingChannel->sourceNum, 1, &buffer ); - - // update volume - palSourcef( s_streamingChannel->sourceNum, AL_GAIN, 1.0f ); - - // if not playing, then do so - palGetSourcei(s_streamingChannel->sourceNum, AL_SOURCE_STATE, &state); - if( state != AL_PLAYING ) palSourcePlay( s_streamingChannel->sourceNum ); -} diff --git a/snd_al/snd_al.dsp b/snd_al/snd_al.dsp deleted file mode 100644 index e3c99177..00000000 --- a/snd_al/snd_al.dsp +++ /dev/null @@ -1,149 +0,0 @@ -# Microsoft Developer Studio Project File - Name="snd_al" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=snd_al - 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 "snd_al.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 "snd_al.mak" CFG="snd_al - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "snd_al - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "snd_al - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "snd_al - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\snd_al\!release" -# PROP Intermediate_Dir "..\temp\snd_al\!release" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../public" /I "../common" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /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 /dll /machine:I386 /opt:nowin98 -# ADD LINK32 /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libcmt.lib" /opt:nowin98 -# SUBTRACT LINK32 /profile -# Begin Custom Build -TargetDir=\Xash3D\src_main\temp\snd_al\!release -InputPath=\Xash3D\src_main\temp\snd_al\!release\snd_al.dll -SOURCE="$(InputPath)" - -"D:\Xash3D\bin\snd_al.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\snd_al.dll "D:\Xash3D\bin\snd_al.dll" - -# End Custom Build - -!ELSEIF "$(CFG)" == "snd_al - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\temp\snd_al\!debug" -# PROP Intermediate_Dir "..\temp\snd_al\!debug" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /I "../common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib:"libcmt.lib" /pdbtype:sept -# SUBTRACT LINK32 /incremental:no /nodefaultlib -# Begin Custom Build -TargetDir=\Xash3D\src_main\temp\snd_al\!debug -InputPath=\Xash3D\src_main\temp\snd_al\!debug\snd_al.dll -SOURCE="$(InputPath)" - -"D:\Xash3D\bin\snd_al.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\snd_al.dll "D:\Xash3D\bin\snd_al.dll" - -# End Custom Build - -!ENDIF - -# Begin Target - -# Name "snd_al - Win32 Release" -# Name "snd_al - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\s_export.c -# End Source File -# Begin Source File - -SOURCE=.\s_load.c -# End Source File -# Begin Source File - -SOURCE=.\s_main.c -# End Source File -# Begin Source File - -SOURCE=.\s_openal.c -# End Source File -# Begin Source File - -SOURCE=.\s_stream.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\s_openal.h -# End Source File -# Begin Source File - -SOURCE=.\sound.h -# End Source File -# End Group -# End Target -# End Project diff --git a/snd_al/sound.h b/snd_al/sound.h deleted file mode 100644 index 1de1d6ae..00000000 --- a/snd_al/sound.h +++ /dev/null @@ -1,183 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// sound.h - sndlib main header -//======================================================================= - -#ifndef SOUND_H -#define SOUND_H - -#include -#include "launch_api.h" -#include "qfiles_ref.h" -#include "engine_api.h" // trace_t declaration -#include "vsound_api.h" -#include "s_openal.h" - -extern stdlib_api_t com; -extern vsound_imp_t si; -extern byte *sndpool; - -#define SENTENCE_INDEX -99999 // unique sentence index - -#include "mathlib.h" - -typedef enum -{ - S_OPENAL_110 = 0, // base - S_EXT_EFX, - S_EXT_I3DL, - S_EXT_EAX, - S_EXT_EAX20, - S_EXT_EAX30, - S_EXTCOUNT -} s_openal_extensions; - -typedef struct sfx_s -{ - string name; - bool loaded; - int loopStart; // looping point (in samples) - int samples; - int rate; - int sampleStep; // ( samples / rate ) * 100 - uint format; - uint bufferNum; - - int touchFrame; - bool default_sound; - uint hashValue; - struct sfx_s *hashNext; -} sfx_t; - -typedef struct -{ - string loopName; - stream_t *intro_stream; - stream_t *main_stream; // mainstream he-he - bool active; -} bg_track_t; - -// structure used for fading in and out client sound volume. -typedef struct -{ - float initial_percent; - float percent; // how far to adjust client's volume down by. - float starttime; // GetHostTime() when we started adjusting volume - float fadeouttime; // # of seconds to get to faded out state - float holdtime; // # of seconds to hold - float fadeintime; // # of seconds to restore -} soundfade_t; - -typedef struct -{ - sfx_t *sfx; // NULL if unused - - int entnum; // to allow overriding a specific sound - int entchannel; - float startTime; // for overriding oldest sounds - bool staticsound; // use position instead of fetching entity's origin - vec3_t position; // only use if fixedPosition is set - float volume; - float pitch; // real-time pitch after any modulation or shift by dynamic data - float dist_mult; - uint sourceNum; // openAL source - bool use_loop; // don't loop default and local sounds - bool isSentence; // bit who indicated sentence -} channel_t; - -typedef struct -{ - vec3_t position; - vec3_t velocity; - float orientation[6]; - int waterlevel; -} listener_t; - -typedef struct -{ - const char *vendor_string; - const char *renderer_string; - const char *version_string; - const char *extensions_string; - - byte extension[S_EXTCOUNT]; - string deviceList[4]; - const char *defDevice; - uint device_count; - uint num_slots; - uint num_sends; - - bool allow_3DMode; - - // 3d mode extension (eax or i3d) - int (*Set3DMode)( const guid_t*, uint, uint, void*, uint ); - int (*Get3DMode)( const guid_t*, uint, uint, void*, uint ); -} alconfig_t; - -typedef struct -{ - aldevice *hDevice; - alcontext *hALC; - ref_params_t *refdef; - - bool initialized; - bool active; - bool paused; - uint framecount; - int max_channels; // max channels that can be allocated by openAL - int total_channels; // total playing channels at current time - int clientnum; -} alstate_t; - -extern alconfig_t al_config; -extern alstate_t al_state; - -#define Host_Error com.error -#define Z_Malloc( size ) Mem_Alloc( sndpool, size ) - -// cvars -extern cvar_t *s_alDevice; -extern cvar_t *s_allowEAX; -extern cvar_t *s_musicvolume; -extern cvar_t *s_check_errors; - -// -// s_load.c -// -bool S_TestSoundChar( const char *pch, char c ); -char *S_SkipSoundChar( const char *pch ); -uint S_GetFormat( int width, int channels ); - -bool S_Init( void *hInst ); -void S_Shutdown( void ); -void S_Activate( bool active, void *hInst ); -void S_SoundList_f( void ); -bool S_CheckForErrors( void ); -void S_BeginFrame( void ); -void S_Update( ref_params_t *fd ); -void S_StartSound( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags ); -void S_StaticSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags ); -void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data ); -void S_StartBackgroundTrack( const char *intro, const char *loop ); -channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx ); -channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx ); -void S_FadeClientVolume( float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ); -void S_StartLocalSound( const char *name ); -sfx_t *S_GetSfxByHandle( sound_t handle ); -void S_StopSound( int entnum, int channel, const char *soundname ); -void S_StreamBackgroundTrack( void ); -void S_StopBackgroundTrack( void ); -void S_ClearSoundBuffer( void ); -bool S_LoadSound( sfx_t *sfx ); -void S_StartStreaming( void ); -void S_StopStreaming( void ); -void S_StopAllSounds( void ); -void S_FreeSounds( void ); - -// registration manager -void S_BeginRegistration( void ); -sound_t S_RegisterSound( const char *sample ); -void S_EndRegistration( void ); - - -#endif//SOUND_H \ No newline at end of file diff --git a/snd_dx/s_stream.c b/snd_dx/s_stream.c index 379b2b57..6bb2017a 100644 --- a/snd_dx/s_stream.c +++ b/snd_dx/s_stream.c @@ -34,7 +34,7 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack ) if( mainTrack ) { - com.snprintf( s_bgTrack.loopName, sizeof( s_bgTrack.loopName ), "media/%s", mainTrack ); + com.strncpy( s_bgTrack.loopName, mainTrack, sizeof( s_bgTrack.loopName )); } else s_bgTrack.loopName[0] = 0; @@ -128,7 +128,7 @@ void S_StreamBackgroundTrack( void ) { FS_CloseStream( s_bgTrack.stream ); s_bgTrack.stream = NULL; - S_StartBackgroundTrack( s_bgTrack.loopName, s_bgTrack.loopName ); + S_StartBackgroundTrack( s_bgTrack.loopName, NULL ); if( !s_bgTrack.stream ) return; } else diff --git a/spirit/animation.cpp b/spirit/animation.cpp index 770c183b..ff5b5e33 100644 --- a/spirit/animation.cpp +++ b/spirit/animation.cpp @@ -18,7 +18,7 @@ #include "extdll.h" #include "const.h" -#include "studio_ref.h" +#include "studio.h" #include "util.h" #include "activitymap.h" @@ -33,15 +33,15 @@ int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); mins[0] = pseqdesc[ sequence ].bbmin[0]; mins[1] = pseqdesc[ sequence ].bbmin[1]; @@ -57,15 +57,15 @@ int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ) int LookupActivity( void *pmodel, entvars_t *pev, int activity ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); int weighttotal = 0; int seq = ACTIVITY_NOT_AVAILABLE; @@ -85,15 +85,15 @@ int LookupActivity( void *pmodel, entvars_t *pev, int activity ) int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr ) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); int weight = 0; int seq = ACTIVITY_NOT_AVAILABLE; @@ -114,9 +114,9 @@ int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) void GetEyePosition ( void *pmodel, Vector &vecEyePosition ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr ) { @@ -129,15 +129,15 @@ void GetEyePosition ( void *pmodel, Vector &vecEyePosition ) int LookupSequence( void *pmodel, const char *label ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); for (int i = 0; i < pstudiohdr->numseq; i++) { @@ -162,17 +162,17 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) int index = LookupSequence( pmodel, pSequenceName ); if ( index >= 0 ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr || index >= pstudiohdr->numseq ) return; - dstudioseqdesc_t *pseqdesc; - dstudioevent_t *pevent; + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; - pevent = (dstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; + pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); for (int i = 0; i < pseqdesc->numevents; i++) { @@ -199,13 +199,13 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; if (pev->sequence >= pstudiohdr->numseq) { @@ -214,7 +214,7 @@ void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float * return; } - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; if (pseqdesc->numframes > 1) { @@ -232,14 +232,14 @@ void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float * int GetSequenceFlags( void *pmodel, entvars_t *pev ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) return 0; - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; return pseqdesc->flags; } @@ -247,19 +247,19 @@ int GetSequenceFlags( void *pmodel, entvars_t *pev ) int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) return 0; int events = 0; - dstudioseqdesc_t *pseqdesc; - dstudioevent_t *pevent; + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - pevent = (dstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); if (pseqdesc->numevents == 0 || index > pseqdesc->numevents ) return 0; @@ -294,13 +294,13 @@ int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEve float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return flValue; - dstudiobonecontroller_t *pbonecontroller = (dstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); + mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); // find first controller that matches the index int i = 0; @@ -349,15 +349,15 @@ float SetController( void *pmodel, entvars_t *pev, int iController, float flValu float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return flValue; - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; if (pseqdesc->blendtype[iBlender] == 0) return flValue; @@ -393,14 +393,14 @@ float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return iGoalAnim; - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); // bail if we're going to or from a node 0 if (pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0) @@ -460,16 +460,16 @@ int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return; if (iGroup > pstudiohdr->numbodyparts) return; - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; if (iValue >= pbodypart->nummodels) return; @@ -482,16 +482,16 @@ void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) return 0; if (iGroup > pstudiohdr->numbodyparts) return 0; - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; if (pbodypart->nummodels <= 1) return 0; @@ -504,9 +504,9 @@ int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) //LRC int GetBoneCount( void *pmodel ) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (!pstudiohdr) { ALERT(at_error, "Bad header in SetBones!\n"); @@ -523,16 +523,16 @@ int GetBoneCount( void *pmodel ) //LRC void SetBones( void *pmodel, float (*data)[3], int datasize) { - dstudiohdr_t *pstudiohdr; + studiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t *)pmodel; + pstudiohdr = (studiohdr_t *)pmodel; if (!pstudiohdr) { ALERT(at_error, "Bad header in SetBones!\n"); return; } - dstudiobone_t *pbone = (dstudiobone_t *)((byte *)pstudiohdr + pstudiohdr->boneindex); + mstudiobone_t *pbone = (mstudiobone_t *)((byte *)pstudiohdr + pstudiohdr->boneindex); // ALERT(at_console, "List begins:\n"); int j; diff --git a/spirit/cbase.h b/spirit/cbase.h index 34cdaac9..d0a7f4cb 100644 --- a/spirit/cbase.h +++ b/spirit/cbase.h @@ -56,7 +56,7 @@ CBaseEntity #include "saverestore.h" #include "schedule.h" -#include "studio_ref.h" +#include "studio.h" #ifndef MONSTEREVENT_H #include "monsterevent.h" @@ -251,16 +251,16 @@ public: void UTIL_AutoSetSize( void )//automatically set collision box { - dstudiohdr_t *pstudiohdr; - pstudiohdr = (dstudiohdr_t*)GET_MODEL_PTR( ENT(pev) ); + studiohdr_t *pstudiohdr; + pstudiohdr = (studiohdr_t*)GET_MODEL_PTR( ENT(pev) ); if (pstudiohdr == NULL) { ALERT(at_console,"Unable to fetch model pointer!\n"); return; } - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); UTIL_SetSize(pev,pseqdesc[ pev->sequence ].bbmin,pseqdesc[ pev->sequence ].bbmax); } diff --git a/spirit/combat.cpp b/spirit/combat.cpp index 9fefd8cf..482dccde 100644 --- a/spirit/combat.cpp +++ b/spirit/combat.cpp @@ -29,7 +29,7 @@ #include "animation.h" #include "weapons.h" #include "func_break.h" -#include "studio_ref.h" //LRC +#include "studio.h" //LRC extern DLL_GLOBAL Vector g_vecAttackDir; extern DLL_GLOBAL int g_iSkillLevel; @@ -200,11 +200,11 @@ void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int notfirst, con pGib->Spawn( szGibModel ); //LRC - check the model itself to find out how many gibs are available - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)(GET_MODEL_PTR( ENT(pGib->pev) )); + studiohdr_t *pstudiohdr = (studiohdr_t *)(GET_MODEL_PTR( ENT(pGib->pev) )); if (! pstudiohdr) return; - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex); + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex); //ALERT(at_console, "read %d bodyparts, canonical is %d\n", pbodypart->nummodels, HUMAN_GIB_COUNT); for (int cSplat = 0 ; cSplat < cGibs ; cSplat++ ) diff --git a/spirit/weapons.cpp b/spirit/weapons.cpp index e85284db..f10d8df6 100644 --- a/spirit/weapons.cpp +++ b/spirit/weapons.cpp @@ -1023,12 +1023,12 @@ void CBasePlayerWeapon::SendWeaponAnim( int iAnim, float fps ) if( fps ) { - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)GET_MODEL_PTR( ENT( pev )); + studiohdr_t *pstudiohdr = (studiohdr_t *)GET_MODEL_PTR( ENT( pev )); if( pstudiohdr ) { - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + iAnim; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + iAnim; framerate = fps / pseqdesc->fps; } } diff --git a/todo.log b/todo.log deleted file mode 100644 index 2dd02da6..00000000 --- a/todo.log +++ /dev/null @@ -1,27 +0,0 @@ -Наблюдения: -Винда неадекватно реагирует на исполняемые файлы с именем setup.exe (какой-то набор умолчаний - см BC) -Ньютон - это просто пипец какой-то. С версии 1.3 до 1.53 левостороняя система координат сменилась на правую. -Коллижен менеджер (который фейсы добавляет) на версии 1.53 вылетает при парсинге половины q2 карт почему-то. -Но если все полигоны преобразовать в треугольники, то не вылетает, даже наоборот, из некоторых групп треугольников -обратно делает полигоны. (хтя он и должен так делать) -DDS Converter 2.1 некорректно высчитывает размер dds файла (баг в devil ?), юзаем только nvdxt -SprExplorer писали редкостные идиоты - он у них не то что версию файла, он даже заголовок не проверяет, -действительно, раз расширение spr, значит правильный ресурс. Если б программисты строили дома... -fopen завешивает приложение, при попытке создать файл в несуществующей директории. Ну вылетал бы чтоли, или ошибку -возвращал. -fopen завешивает приложение, даже если перепутать местами + и a, при установке режима! - -0 - восток -90 - север - - - -Отложенные задачи: -1. Поддержка loop для ogg vorbis -2. переписать studiomdl для использования VFS - -Xash 13.12.2010 first stable version! - -1. Выбросить всё лишнее из кода. -2. Отключить удаленный запуск по переменной окружения -3. Переписать утилиты в отдельные приложения diff --git a/vid_gl/r_decals.c b/vid_gl/r_decals.c index 6880bc3c..38548f65 100644 --- a/vid_gl/r_decals.c +++ b/vid_gl/r_decals.c @@ -1194,7 +1194,8 @@ int R_CreateDecalList( decallist_t *pList, bool changelevel ) continue; // another transition - ignore moved decals - if( changelevel && decal->flags & FDECAL_DONTSAVE ) + // also permanent decals can't moving across transition + if( changelevel && decal->flags & ( FDECAL_DONTSAVE|FDECAL_PERMANENT )) continue; // compute depth diff --git a/vid_gl/r_image.c b/vid_gl/r_image.c index a746d4fb..83462fae 100644 --- a/vid_gl/r_image.c +++ b/vid_gl/r_image.c @@ -1246,7 +1246,7 @@ static rgbdata_t *R_MakeLuminance( rgbdata_t *in ) out->buffer[4*(y*width+x)+0] = luminance; out->buffer[4*(y*width+x)+1] = luminance; out->buffer[4*(y*width+x)+2] = luminance; - out->buffer[4*(y*width+x)+3] = 255; + out->buffer[4*(y*width+x)+3] = in->buffer[4*(y*width+x)+3]; // copy alpha as is } } return out; @@ -2036,12 +2036,12 @@ static rgbdata_t *R_ParseMakeLuminance( script_t *script, int *samples, texFlags return NULL; } - *samples = 1; + *samples = (pic->flags & IMAGE_HAS_ALPHA) ? 2 : 1; *flags &= ~TF_INTENSITY; *flags &= ~TF_ALPHA; *flags &= ~TF_NORMALMAP; - return R_MakeIntensity( pic ); + return R_MakeLuminance( pic ); } /* @@ -2132,7 +2132,7 @@ static rgbdata_t *R_ParseStudioSkin( script_t *script, const byte *buf, size_t s string model_path; string modelT_path; string skinname; - dstudiohdr_t hdr; + studiohdr_t hdr; file_t *f; Com_ReadToken( script, 0, &token ); @@ -2199,7 +2199,7 @@ static rgbdata_t *R_ParseStudioSkin( script_t *script, const byte *buf, size_t s if( hdr.textureindex > 0 && hdr.numtextures <= MAXSTUDIOSKINS ) { // all ok, can load model into memory - dstudiotexture_t *ptexture, *tex; + mstudiotexture_t *ptexture, *tex; size_t mdl_size, tex_size; byte *pin; int i; @@ -2216,7 +2216,7 @@ static rgbdata_t *R_ParseStudioSkin( script_t *script, const byte *buf, size_t s FS_Close( f ); return NULL; } - ptexture = (dstudiotexture_t *)(pin + hdr.textureindex); + ptexture = (mstudiotexture_t *)(pin + hdr.textureindex); // find specified texture for( i = 0; i < hdr.numtextures; i++ ) @@ -2235,7 +2235,7 @@ static rgbdata_t *R_ParseStudioSkin( script_t *script, const byte *buf, size_t s // NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it tex->index = (int)pin + tex->index; - tex_size = sizeof( dstudiotexture_t ) + tex->width * tex->height + 768; + tex_size = sizeof( mstudiotexture_t ) + tex->width * tex->height + 768; // load studio texture and bind it FS_FileBase( skinname, skinname ); @@ -3290,6 +3290,8 @@ bool VID_CubemapShot( const char *base, uint size, const float *vieworg, bool sk result = FS_SaveImage( basename, r_shot ); FS_FreeImage( r_shot ); FS_FreeImage( r_side ); + Mem_Free( buffer ); + Mem_Free( temp ); return result; } diff --git a/vid_gl/r_local.h b/vid_gl/r_local.h index 5295afe6..298c59e8 100644 --- a/vid_gl/r_local.h +++ b/vid_gl/r_local.h @@ -727,6 +727,7 @@ msurface_t *R_TransformedTraceLine( trace_t *tr, const vec3_t start, const vec3_ void R_SpriteInit( void ); mspriteframe_t *R_GetSpriteFrame( ref_model_t *pModel, int frame, float yawAngle ); +ref_shader_t *CL_LoadSprite( const char *szSpriteName ); void R_DrawSpriteModel( const meshbuffer_t *mb ); bool R_SpriteOccluded( ref_entity_t *e ); bool R_CullSpriteModel( ref_entity_t *e ); diff --git a/vid_gl/r_main.c b/vid_gl/r_main.c index f356824b..5a80d1b5 100644 --- a/vid_gl/r_main.c +++ b/vid_gl/r_main.c @@ -2220,6 +2220,9 @@ shader_t Mod_RegisterShader( const char *name, int shaderType ) case SHADER_GENERIC: src = R_LoadShader( name, shaderType, false, 0, SHADER_INVALID ); break; + case SHADER_SPRITE: + src = CL_LoadSprite( name ); // hud sprites + break; case SHADER_SKY: src = R_SetupSky( name ); break; diff --git a/vid_gl/r_math.c b/vid_gl/r_math.c index 9f4d1c9e..e45f654e 100644 --- a/vid_gl/r_math.c +++ b/vid_gl/r_math.c @@ -31,14 +31,17 @@ CalcFov */ float CalcFov( float fov_x, float width, float height ) { - float x; + float x, half_fov_y; if( fov_x < 1 || fov_x > 179 ) - Host_Error( "bad fov: %f\n", fov_x ); + { + MsgDev( D_ERROR, "CalcFov: bad fov %g!\n", fov_x ); + fov_x = 90; + } - x = width / tan( fov_x / 360 * M_PI ); - - return atan( height / x ) * 360 / M_PI; + x = width / tan( DEG2RAD( fov_x ) * 0.5f ); + half_fov_y = atan( height / x ); + return RAD2DEG( half_fov_y ) * 2; } /* @@ -133,6 +136,42 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const cplane_t *p ) } } +/* +==================== +RotatePointAroundVector +==================== +*/ +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) +{ + float t0, t1; + float angle, c, s; + vec3_t vr, vu, vf; + + angle = DEG2RAD( degrees ); + com.sincos( angle, &s, &c ); + VectorCopy( dir, vf ); + VectorVectors( vf, vr, vu ); + + t0 = vr[0] * c + vu[0] * -s; + t1 = vr[0] * s + vu[0] * c; + dst[0] = (t0 * vr[0] + t1 * vu[0] + vf[0] * vf[0]) * point[0] + + (t0 * vr[1] + t1 * vu[1] + vf[0] * vf[1]) * point[1] + + (t0 * vr[2] + t1 * vu[2] + vf[0] * vf[2]) * point[2]; + + t0 = vr[1] * c + vu[1] * -s; + t1 = vr[1] * s + vu[1] * c; + dst[1] = (t0 * vr[0] + t1 * vu[0] + vf[1] * vf[0]) * point[0] + + (t0 * vr[1] + t1 * vu[1] + vf[1] * vf[1]) * point[1] + + (t0 * vr[2] + t1 * vu[2] + vf[1] * vf[2]) * point[2]; + + t0 = vr[2] * c + vu[2] * -s; + t1 = vr[2] * s + vu[2] * c; + dst[2] = (t0 * vr[0] + t1 * vu[0] + vf[2] * vf[0]) * point[0] + + (t0 * vr[1] + t1 * vu[1] + vf[2] * vf[1]) * point[1] + + (t0 * vr[2] + t1 * vu[2] + vf[2] * vf[2]) * point[2]; +} + + /* ================= PlaneFromPoints diff --git a/vid_gl/r_math.h b/vid_gl/r_math.h index 7c4f8033..1f2270b7 100644 --- a/vid_gl/r_math.h +++ b/vid_gl/r_math.h @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. float CalcFov( float fov_x, float width, float height ); void AdjustFov( float *fov_x, float *fov_y, float width, float height, bool lock_x ); int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const cplane_t *p ); +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); void PlaneFromPoints( vec3_t verts[3], cplane_t *plane ); void CategorizePlane( cplane_t *plane ); diff --git a/vid_gl/r_model.h b/vid_gl/r_model.h index c3f3aecb..ac244782 100644 --- a/vid_gl/r_model.h +++ b/vid_gl/r_model.h @@ -243,16 +243,15 @@ STUDIO MODELS ============================================================================== */ -typedef struct mstudiomodel_s +typedef struct { - dstudiohdr_t *phdr; - dstudiohdr_t *thdr; + studiohdr_t *phdr; + studiohdr_t *thdr; void *submodels; int numsubmodels; vec3_t *m_pSVectors; // UNDONE: calc SVectors on loading, simple transform on rendering - -} mstudiomodel_t; +} mstudiodata_t; /* ============================================================================== diff --git a/vid_gl/r_register.c b/vid_gl/r_register.c index b477fef9..95d94564 100644 --- a/vid_gl/r_register.c +++ b/vid_gl/r_register.c @@ -25,7 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. glconfig_t glConfig; glstate_t glState; byte *r_temppool; -byte *r_framebuffer; cvar_t *r_norefresh; cvar_t *r_drawentities; @@ -638,7 +637,6 @@ void GL_InitBackend( void ) void GL_ShutdownBackend( void ) { - if( r_framebuffer ) Mem_Free( r_framebuffer ); GL_RemoveCommands(); Mem_FreePool( &r_temppool ); @@ -860,7 +858,6 @@ void GL_InitExtensions( void ) // initialize gl extensions GL_CheckExtension( "OpenGL 1.1.0", opengl_110funcs, NULL, R_OPENGL_110 ); - if( !r_framebuffer ) r_framebuffer = Mem_Alloc( r_temppool, r_width->integer * r_height->integer * 4 ); // get our various GL strings glConfig.vendor_string = pglGetString( GL_VENDOR ); @@ -1121,6 +1118,7 @@ void R_NewMap( void ) R_StudioFreeAllExtradata(); // free boneposes R_ClearDecals(); // purge all decals + Mem_EmptyPool( r_temppool ); // release all temp data GL_SetDefaultTexState (); Mem_Set( &RI, 0, sizeof( refinst_t )); r_worldbrushmodel = NULL; // during loading process diff --git a/vid_gl/r_shader.c b/vid_gl/r_shader.c index 1f214608..88b8c45d 100644 --- a/vid_gl/r_shader.c +++ b/vid_gl/r_shader.c @@ -3414,13 +3414,16 @@ void R_DeformvBBoxForShader( const ref_shader_t *shader, vec3_t ebbox ) } } -static ref_shader_t *Shader_CreateDefault( ref_shader_t *shader, int type, int addFlags, const char *shortname, int length ) +static ref_shader_t *Shader_CreateDefault( ref_shader_t *shader, int type, int addFlags, const char *shortname ) { ref_stage_t *pass; texture_t *materialImages[MAX_STAGE_TEXTURES]; script_t *script; char *skyParms; uint i, hashKey; + size_t length; + + length = com.strlen( shortname ); // make a default shader switch( type ) @@ -3552,7 +3555,7 @@ static ref_shader_t *Shader_CreateDefault( ref_shader_t *shader, int type, int a shader->stages = (ref_stage_t *)( ( byte * )shader->name + length + 1 ); pass = &shader->stages[0]; pass->tcgen = TCGEN_BASE; - if( r_stageAnimFrequency[0] == 0.0f && r_numStageTextures == 8 ) + if( r_stageAnimFrequency[0] == -8.0f && r_numStageTextures == 8 ) { // store angled map into one bundle pass->flags |= SHADERSTAGE_ANGLEDMAP; @@ -3661,14 +3664,14 @@ static ref_shader_t *Shader_CreateDefault( ref_shader_t *shader, int type, int a case SHADER_NOMIP: shader->type = SHADER_NOMIP; shader->features = MF_STCOORDS|MF_COLORS; - shader->flags = SHADER_STATIC; + shader->flags = SHADER_STATIC|SHADER_RENDERMODE; shader->sort = SORT_ADDITIVE; shader->num_stages = 1; shader->name = Shader_Malloc( length + 1 + sizeof( ref_stage_t ) * shader->num_stages ); strcpy( shader->name, shortname ); shader->stages = ( ref_stage_t * )( ( byte * )shader->name + length + 1 ); pass = &shader->stages[0]; - pass->flags = SHADERSTAGE_BLEND_MODULATE/*|SHADERSTAGE_NOCOLORARRAY*/; + pass->flags = SHADERSTAGE_BLEND_MODULATE|SHADERSTAGE_RENDERMODE; pass->glState = GLSTATE_SRCBLEND_SRC_ALPHA|GLSTATE_DSTBLEND_ONE_MINUS_SRC_ALPHA; if( shader->name[0] == '#' ) { @@ -3924,23 +3927,76 @@ static ref_shader_t *Shader_CreateDefault( ref_shader_t *shader, int type, int a return shader; } +/* +================ +R_CleanupShaderName + +kill backward slashes and turn all leters +into lower register +================ +*/ +static bool R_CleanupShaderName( const char *name, char *outname, size_t outsize ) +{ + int i, length = 0; + + if( !name || !name[0] || !outname ) + return false; + + for( i = ( name[0] == '/' || name[0] == '\\' ); name[i] && ( length < outsize - 1 ); i++ ) + { + if( name[i] == '\\' ) outname[length++] = '/'; + else outname[length++] = com.tolower( name[i] ); + } + + if( !length ) + return false; + + outname[length] = 0; + + return true; +} + +ref_shader_t *R_FindShader( const char *name, int type, int ignoreType ) +{ + ref_shader_t *shader; + string shortname; + uint hashKey; + + if( !R_CleanupShaderName( name, shortname, sizeof( shortname ))) + return NULL; + + // see if already loaded + hashKey = Com_HashKey( shortname, SHADERS_HASH_SIZE ); + + for( shader = r_shadersHash[hashKey]; shader; shader = shader->nextHash ) + { + if( shader->type == ignoreType ) continue; + + if( !com.stricmp( shader->name, shortname )) + { + if( shader->type != type ) + { + if( shader->flags & SHADER_SKYPARMS ) + MsgDev( D_WARN, "reused shader '%s' with mixed types (%i should be %i)\n", shortname, shader->type, type ); + else continue; + } + // prolonge registration + Shader_TouchImages( shader, FREE_IGNORE ); + return shader; + } + } + return NULL; +} + ref_shader_t *R_LoadShader( const char *name, int type, bool forceDefault, int addFlags, int ignoreType ) { ref_shader_t *shader; string shortname; ref_script_t *cache = NULL; - uint i, hashKey, length; + uint i, hashKey; - if( !name || !name[0] ) return NULL; - - for( i = ( name[0] == '/' || name[0] == '\\' ), length = 0; name[i] && ( length < sizeof( shortname )-1 ); i++ ) - { - if( name[i] == '\\' ) shortname[length++] = '/'; - else shortname[length++] = com.tolower( name[i] ); - } - - if( !length ) return NULL; - shortname[length] = 0; + if( !R_CleanupShaderName( name, shortname, sizeof( shortname ))) + return NULL; // see if already loaded hashKey = Com_HashKey( shortname, SHADERS_HASH_SIZE ); @@ -4008,7 +4064,7 @@ ref_shader_t *R_LoadShader( const char *name, int type, bool forceDefault, int a // load the script text script = Com_OpenScript( cache->name, cache->buffer, cache->size ); - if( !script ) return Shader_CreateDefault( shader, type, addFlags, shortname, length ); + if( !script ) return Shader_CreateDefault( shader, type, addFlags, shortname ); if( !Shader_ParseShader( shader, script )) { @@ -4018,12 +4074,12 @@ ref_shader_t *R_LoadShader( const char *name, int type, bool forceDefault, int a shader->shadernum = i; Com_CloseScript( script ); - return Shader_CreateDefault( shader, type, addFlags, shortname, length ); + return Shader_CreateDefault( shader, type, addFlags, shortname ); } Com_CloseScript( script ); Shader_Finish( shader ); } - else return Shader_CreateDefault( shader, type, addFlags, shortname, length ); + else return Shader_CreateDefault( shader, type, addFlags, shortname ); // calculate sortkey shader->sortkey = Shader_Sortkey( shader, shader->sort ); diff --git a/vid_gl/r_shader.h b/vid_gl/r_shader.h index 0fe73973..5d117b3e 100644 --- a/vid_gl/r_shader.h +++ b/vid_gl/r_shader.h @@ -38,10 +38,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SHADER_NOMIP 3 #define SHADER_GENERIC 4 #define SHADER_DECAL 5 -#define SHADER_TEXTURE 6 -#define SHADER_FLARE 7 -#define SHADER_STUDIO 8 -#define SHADER_SPRITE 9 +#define SHADER_SPRITE 6 +#define SHADER_TEXTURE 7 +#define SHADER_FLARE 8 +#define SHADER_STUDIO 9 #define SHADER_FARBOX 10 #define SHADER_NEARBOX 11 #define SHADER_PLANAR_SHADOW 12 @@ -342,6 +342,7 @@ void R_InitShaders( void ); void R_ShutdownShaders( void ); void R_ShaderList_f( void ); void R_ShaderDump_f( void ); +ref_shader_t *R_FindShader( const char *name, int type, int ignoreType ); ref_shader_t *R_LoadShader( const char *name, int type, bool forceDefault, int addFlags, int ignoreType ); void Mod_FreeShader( const char *name ); // used for delete save menu previews only diff --git a/vid_gl/r_sprite.c b/vid_gl/r_sprite.c index 262c27e4..a94bf4e3 100644 --- a/vid_gl/r_sprite.c +++ b/vid_gl/r_sprite.c @@ -41,7 +41,7 @@ void R_SpriteInit( void ) Sprite model loader ==================== */ -dframetype_t *R_SpriteLoadFrame( ref_model_t *mod, void *pin, mspriteframe_t **ppframe, int framenum ) +static dframetype_t *R_SpriteLoadFrame( ref_model_t *mod, void *pin, mspriteframe_t **ppframe, int framenum ) { texture_t *tex; dspriteframe_t *pinframe; @@ -80,7 +80,58 @@ dframetype_t *R_SpriteLoadFrame( ref_model_t *mod, void *pin, mspriteframe_t **p return (dframetype_t *)((byte *)(pinframe + 1) + pinframe->width * pinframe->height ); } -dframetype_t *R_SpriteLoadGroup( ref_model_t *mod, void * pin, mspriteframe_t **ppframe, int framenum ) +static dframetype_t *CL_LoadSpriteFrame( const char *szSpriteName, void *pin, int framenum ) +{ + texture_t *tex; + string name; + dspriteframe_t *pinframe; + + // build uinque frame name + if( !sp_name[0] ) FS_FileBase( szSpriteName, sp_name ); + com.snprintf( name, MAX_STRING, "Sprite( \"%s_%s_%i%i\" )", sp_name, frame_prefix, framenum/10, framenum%10 ); + + pinframe = (dspriteframe_t *)pin; + SwapBlock((int *)pinframe, sizeof( dspriteframe_t )); + + // NOTE: just loading all single frame into one shader + // we spported only single frames in this case + // bacause we can't properly merge multiple groups into single shader + tex = R_FindTexture( name, (byte *)pin, pinframe->width * pinframe->height, tex_flags ); + R_ShaderAddStageTexture( tex ); + + return (dframetype_t *)((byte *)(pinframe + 1) + pinframe->width * pinframe->height ); +} + +static dframetype_t *CL_SpriteSkipGroup( const char *szSpriteName, void *pin, int framenum ) +{ + dspritegroup_t *pingroup; + dspriteinterval_t *pin_intervals; + dspriteframe_t *pinframe; + void *ptemp; + int i; + + // throw warning + MsgDev( D_WARN, "CL_LoadSprite: %s ignore group frame %i\n", szSpriteName, framenum ); + + pingroup = (dspritegroup_t *)pin; + pin_intervals = (dspriteinterval_t *)(pingroup + 1); + + // skip intervals + for( i = 0; i < LittleLong( pingroup->numframes ); i++ ) + pin_intervals++; + + // skip group frames + ptemp = (void *)pin_intervals; + for( i = 0; i < LittleLong( pingroup->numframes ); i++ ) + { + pinframe = (dspriteframe_t *)ptemp; + SwapBlock((int *)pinframe, sizeof( dspriteframe_t )); + ptemp = (dframetype_t *)((byte *)(pinframe + 1) + pinframe->width * pinframe->height ); + } + return (dframetype_t *)ptemp; +} + +static dframetype_t *R_SpriteLoadGroup( ref_model_t *mod, void * pin, mspriteframe_t **ppframe, int framenum ) { dspritegroup_t *pingroup; mspritegroup_t *pspritegroup; @@ -108,6 +159,7 @@ dframetype_t *R_SpriteLoadGroup( ref_model_t *mod, void * pin, mspriteframe_t ** *poutintervals = LittleFloat( pin_intervals->interval ); if( *poutintervals <= 0.0 ) *poutintervals = 1.0f; // set error value if( frame_type == FRAME_GROUP ) R_ShaderAddStageIntervals( *poutintervals ); + else if( frame_type == FRAME_ANGLED ) R_ShaderAddStageIntervals( -1.0f ); poutintervals++; pin_intervals++; } @@ -228,17 +280,17 @@ void Mod_SpriteLoadModel( ref_model_t *mod, const void *buffer ) case FRAME_SINGLE: tex_flags = 0; com.strncpy( frame_prefix, "one", MAX_STRING ); - pframetype = R_SpriteLoadFrame(mod, pframetype + 1, &psprite->frames[i].frameptr, i ); + pframetype = R_SpriteLoadFrame( mod, pframetype + 1, &psprite->frames[i].frameptr, i ); break; case FRAME_GROUP: tex_flags = 0; com.strncpy( frame_prefix, "grp", MAX_STRING ); - pframetype = R_SpriteLoadGroup(mod, pframetype + 1, &psprite->frames[i].frameptr, i ); + pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i ); break; case FRAME_ANGLED: tex_flags = 0; com.strncpy( frame_prefix, "ang", MAX_STRING ); - pframetype = R_SpriteLoadGroup(mod, pframetype + 1, &psprite->frames[i].frameptr, i ); + pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i ); break; } if( pframetype == NULL ) break; // technically an error @@ -247,6 +299,129 @@ void Mod_SpriteLoadModel( ref_model_t *mod, const void *buffer ) mod->type = mod_sprite; } +/* +================ +CL_LoadSprite + +client version for loading sprites +and convert them to shaders with multiple frames +================ +*/ +ref_shader_t *CL_LoadSprite( const char *szSpriteName ) +{ + dsprite_t *pin; + ref_shader_t *shader; + byte *buffer; + dframetype_t *pframetype; + bool twoSided; + int i, numframes; + short *numi; + + if( !szSpriteName || !szSpriteName[0] ) + return NULL; + + shader = R_FindShader( szSpriteName, SHADER_SPRITE, SHADER_INVALID ); + if( shader ) return shader; // already loaded + + buffer = FS_LoadFile( szSpriteName, NULL ); + if( !buffer ) return NULL; // sprite is missed + + pin = (dsprite_t *)buffer; + + // make sure what is really sprite + if( LittleLong( pin->ident ) != IDSPRITEHEADER ) + { + MsgDev( D_ERROR, "CL_LoadSprite: %s not a sprite\n", szSpriteName ); + Mem_Free( buffer ); + return NULL; + } + + if( LittleLong( pin->version ) != SPRITE_VERSION ) + { + MsgDev( D_ERROR, "CL_LoadSprite: %s invalid sprite version\n", szSpriteName ); + Mem_Free( buffer ); + return NULL; + } + + numframes = LittleLong( pin->numframes ); + twoSided = (LittleLong( pin->facetype == SPR_CULL_NONE )) ? true : false; + numi = (short *)( pin + 1 ); + + if( LittleShort( *numi ) == 256 ) + { + byte *src = (byte *)(numi+1); + rgbdata_t *pal; + + // install palette + switch( LittleLong( pin->texFormat )) + { + case SPR_ADDGLOW: + pal = FS_LoadImage( "#normal.pal", src, 768 ); + R_ShaderSetRenderMode( kRenderGlow, twoSided ); + break; + case SPR_ADDITIVE: + pal = FS_LoadImage( "#normal.pal", src, 768 ); + R_ShaderSetRenderMode( kRenderTransAdd, twoSided ); + break; + case SPR_INDEXALPHA: + pal = FS_LoadImage( "#decal.pal", src, 768 ); + R_ShaderSetRenderMode( kRenderTransTexture, twoSided ); + break; + case SPR_ALPHTEST: + pal = FS_LoadImage( "#transparent.pal", src, 768 ); + R_ShaderSetRenderMode( kRenderTransAlpha, twoSided ); + break; + case SPR_NORMAL: + default: + pal = FS_LoadImage( "#normal.pal", src, 768 ); + R_ShaderSetRenderMode( kRenderNormal, twoSided ); + break; + } + pframetype = (dframetype_t *)(src + 768); + FS_FreeImage( pal ); // palette installed, no reason to keep this data + } + else + { + MsgDev( D_ERROR, "CL_LoadSprite: %s has invalid palette\n", szSpriteName ); + Mem_Free( buffer ); + return NULL; + } + + if( numframes < 1 ) + { + MsgDev( D_ERROR, "CL_LoadSprite: %s has invalid # of frames: %d\n", szSpriteName, numframes ); + Mem_Free( buffer ); + return NULL; + } + + MsgDev( D_LOAD, "%s, rendermode %d\n", szSpriteName, LittleLong( pin->texFormat )); + com.strncpy( frame_prefix, "one", MAX_STRING ); + tex_flags = TF_CLAMP|TF_NOMIPMAP|TF_NOPICMIP; + frames = NULL; // invalidate pointer + sp_name[0] = 0; + group_num = 0; + + for( i = 0; i < numframes; i++ ) + { + switch( LittleLong( pframetype->type )) + { + case FRAME_SINGLE: + pframetype = CL_LoadSpriteFrame( szSpriteName, pframetype + 1, i ); + break; + case FRAME_GROUP: + case FRAME_ANGLED: + pframetype = CL_SpriteSkipGroup( szSpriteName, pframetype + 1, i ); + break; + } + if( pframetype == NULL ) break; // technically an error + } + + // all frames uploaded, release buffer + Mem_Free( buffer ); + + return R_LoadShader( szSpriteName, SHADER_SPRITE, true, tex_flags, SHADER_INVALID ); +} + /* ================ R_GetSpriteFrame diff --git a/vid_gl/r_studio.c b/vid_gl/r_studio.c index 5a152314..268a36d2 100644 --- a/vid_gl/r_studio.c +++ b/vid_gl/r_studio.c @@ -39,10 +39,10 @@ float m_flGaitMovement; // misc variables int m_fDoInterp; -dstudiomodel_t *m_pSubModel; -dstudiobodyparts_t *m_pBodyPart; -dstudiohdr_t *m_pStudioHeader; -dstudiohdr_t *m_pTextureHeader; +mstudiomodel_t *m_pSubModel; +mstudiobodyparts_t *m_pBodyPart; +studiohdr_t *m_pStudioHeader; +studiohdr_t *m_pTextureHeader; vec3_t studio_mins, studio_maxs; float studio_radius; @@ -229,8 +229,8 @@ void R_StudioUpdateVarsInterpolant( edict_t *in, ref_entity_t *out ) void R_StudioAllocExtradata( edict_t *in, ref_entity_t *e ) { studiovars_t *studio; - bool hasChrome = (((mstudiomodel_t *)e->model->extradata)->phdr->flags & STUDIO_HAS_CHROME) ? true : false; - int numbones = ((mstudiomodel_t *)e->model->extradata)->phdr->numbones; + bool hasChrome = (((mstudiodata_t *)e->model->extradata)->phdr->flags & STUDIO_HAS_CHROME) ? true : false; + int numbones = ((mstudiodata_t *)e->model->extradata)->phdr->numbones; if( !e->mempool ) e->mempool = Mem_AllocPool( va( "Entity Pool %i", e - r_entities )); if( !e->extradata ) e->extradata = (void *)Mem_Alloc( e->mempool, sizeof( studiovars_t )); @@ -282,8 +282,8 @@ void R_StudioAllocExtradata( edict_t *in, ref_entity_t *e ) void R_StudioAllocTentExtradata( TEMPENTITY *in, ref_entity_t *e ) { studiovars_t *studio; - bool hasChrome = (((mstudiomodel_t *)e->model->extradata)->phdr->flags & STUDIO_HAS_CHROME) ? true : false; - int i, numbones = ((mstudiomodel_t *)e->model->extradata)->phdr->numbones; + bool hasChrome = (((mstudiodata_t *)e->model->extradata)->phdr->flags & STUDIO_HAS_CHROME) ? true : false; + int i, numbones = ((mstudiodata_t *)e->model->extradata)->phdr->numbones; if( !e->mempool ) e->mempool = Mem_AllocPool( va( "TempEntity Pool %i", e - r_entities )); if( !e->extradata ) e->extradata = (void *)Mem_Alloc( e->mempool, sizeof( studiovars_t )); @@ -357,7 +357,7 @@ StudioSetupRender */ static void R_StudioSetupRender( ref_entity_t *e, ref_model_t *mod ) { - mstudiomodel_t *m_pRefModel = (mstudiomodel_t *)mod->extradata; + mstudiodata_t *m_pRefModel = (mstudiodata_t *)mod->extradata; // set global pointers m_pStudioHeader = m_pRefModel->phdr; @@ -401,10 +401,10 @@ char *R_StudioTexName( ref_model_t *mod ) return texname; } -int R_StudioExtractBbox( dstudiohdr_t *phdr, int sequence, float *mins, float *maxs ) +int R_StudioExtractBbox( studiohdr_t *phdr, int sequence, float *mins, float *maxs ) { - dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)phdr + phdr->seqindex); + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex); if( sequence < 0 || sequence >= phdr->numseq ) return 0; @@ -422,12 +422,12 @@ void R_StudioModelLerpBBox( ref_entity_t *e, ref_model_t *mod ) void R_StudioModelBBox( ref_entity_t *e, vec3_t mins, vec3_t maxs ) { - dstudiohdr_t *hdr; + studiohdr_t *hdr; if( !e->model ) return; R_StudioSetupRender( e, e->model ); - hdr = ((mstudiomodel_t *)e->model->extradata)->phdr; + hdr = ((mstudiodata_t *)e->model->extradata)->phdr; if( !hdr ) return; R_StudioExtractBbox( hdr, e->lerp->curstate.sequence, mins, maxs ); } @@ -437,7 +437,7 @@ void R_StudioModelBBox( ref_entity_t *e, vec3_t mins, vec3_t maxs ) Studio model loader ==================== */ -void R_StudioSurfaceParm( dstudiotexture_t *tex ) +void R_StudioSurfaceParm( mstudiotexture_t *tex ) { if( tex->flags & STUDIO_NF_TRANSPARENT ) R_ShaderSetRenderMode( kRenderTransAlpha, false ); @@ -448,7 +448,7 @@ void R_StudioSurfaceParm( dstudiotexture_t *tex ) else R_ShaderSetRenderMode( kRenderNormal, false ); } -texture_t *R_StudioLoadTexture( ref_model_t *mod, dstudiohdr_t *phdr, dstudiotexture_t *ptexture ) +texture_t *R_StudioLoadTexture( ref_model_t *mod, studiohdr_t *phdr, mstudiotexture_t *ptexture ) { size_t size; int flags = 0; @@ -462,7 +462,7 @@ texture_t *R_StudioLoadTexture( ref_model_t *mod, dstudiohdr_t *phdr, dstudiotex // NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it ptexture->index = (int)((byte *)phdr) + ptexture->index; - size = sizeof( dstudiotexture_t ) + ptexture->width * ptexture->height + 768; + size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768; // build the texname com.snprintf( name, sizeof( name ), "\"%s/%s\"", mod->name, ptexture->name ); @@ -472,10 +472,10 @@ texture_t *R_StudioLoadTexture( ref_model_t *mod, dstudiohdr_t *phdr, dstudiotex return R_FindTexture( va( "Studio( %s );", name ), (byte *)ptexture, size, flags ); } -static int R_StudioLoadTextures( ref_model_t *mod, dstudiohdr_t *phdr ) +static int R_StudioLoadTextures( ref_model_t *mod, studiohdr_t *phdr ) { texture_t *texs[4]; - dstudiotexture_t *ptexture = (dstudiotexture_t *)(((byte *)phdr) + phdr->textureindex); + mstudiotexture_t *ptexture = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex); string modname, texname, shadername; string normalmap, heightmap; int nm_index, hm_index; @@ -566,15 +566,15 @@ load_shader: return numshaders; } -dstudiohdr_t *R_StudioLoadHeader( ref_model_t *mod, const uint *buffer ) +studiohdr_t *R_StudioLoadHeader( ref_model_t *mod, const uint *buffer ) { byte *pin; - dstudiohdr_t *phdr; - dstudiotexture_t *ptexture; + studiohdr_t *phdr; + mstudiotexture_t *ptexture; string modname; pin = (byte *)buffer; - phdr = (dstudiohdr_t *)pin; + phdr = (studiohdr_t *)pin; if( phdr->version != STUDIO_VERSION ) { @@ -583,7 +583,7 @@ dstudiohdr_t *R_StudioLoadHeader( ref_model_t *mod, const uint *buffer ) } FS_FileBase( mod->name, modname ); - ptexture = (dstudiotexture_t *)(((byte *)phdr) + phdr->textureindex); + ptexture = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex); if( phdr->textureindex > 0 && phdr->numtextures <= MAXSTUDIOSKINS ) { mod->shaders = Mod_Malloc( mod, sizeof( shader_t* ) * phdr->numtextures ); @@ -592,19 +592,19 @@ dstudiohdr_t *R_StudioLoadHeader( ref_model_t *mod, const uint *buffer ) if( mod->numshaders != phdr->numtextures ) // bump, gloss will be merged into single shader mod->shaders = Mod_Realloc( mod, mod->shaders, sizeof( shader_t* ) * mod->numshaders ); } - return (dstudiohdr_t *)buffer; + return (studiohdr_t *)buffer; } void Mod_StudioLoadModel( ref_model_t *mod, const void *buffer ) { - dstudiohdr_t *phdr = R_StudioLoadHeader( mod, buffer ); - dstudiohdr_t *thdr = NULL; - mstudiomodel_t *poutmodel; + studiohdr_t *phdr = R_StudioLoadHeader( mod, buffer ); + studiohdr_t *thdr = NULL; + mstudiodata_t *poutmodel; void *texbuf; if( !phdr ) return; // there were problems - mod->extradata = poutmodel = (mstudiomodel_t *)Mod_Malloc( mod, sizeof( mstudiomodel_t )); - poutmodel->phdr = (dstudiohdr_t *)Mod_Malloc( mod, LittleLong( phdr->length )); + mod->extradata = poutmodel = (mstudiodata_t *)Mod_Malloc( mod, sizeof( mstudiodata_t )); + poutmodel->phdr = (studiohdr_t *)Mod_Malloc( mod, LittleLong( phdr->length )); Mem_Copy( poutmodel->phdr, buffer, LittleLong( phdr->length )); if( phdr->numtextures == 0 ) @@ -614,7 +614,7 @@ void Mod_StudioLoadModel( ref_model_t *mod, const void *buffer ) else MsgDev( D_ERROR, "StudioLoadModel: %s missing textures file\n", mod->name ); if( !thdr ) return; // there were problems - poutmodel->thdr = (dstudiohdr_t *)Mod_Malloc( mod, LittleLong( thdr->length )); + poutmodel->thdr = (studiohdr_t *)Mod_Malloc( mod, LittleLong( thdr->length )); Mem_Copy( poutmodel->thdr, texbuf, LittleLong( thdr->length )); if( texbuf ) Mem_Free( texbuf ); } @@ -635,8 +635,8 @@ R_StudioProcessEvents */ void R_StudioProcessEvents( ref_entity_t *e, edict_t *ed ) { - dstudioseqdesc_t *pseqdesc; - dstudioevent_t *pevent; + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; float flEventFrame; bool bLooped = false; int i; @@ -649,8 +649,8 @@ void R_StudioProcessEvents( ref_entity_t *e, edict_t *ed ) default: return; } - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; - pevent = (dstudioevent_t *)((byte *)m_pStudioHeader + pseqdesc->eventindex); + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; + pevent = (mstudioevent_t *)((byte *)m_pStudioHeader + pseqdesc->eventindex); // curstate.frame not used for viewmodel animating flEventFrame = e->lerp->latched.frame; @@ -726,9 +726,9 @@ void R_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, cons { int i, j; float value; - dstudiobonecontroller_t *pbonecontroller; + mstudiobonecontroller_t *pbonecontroller; - pbonecontroller = (dstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); + pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) { @@ -790,12 +790,12 @@ StudioCalcBoneQuaterion ==================== */ -void R_StudioCalcBoneQuaterion( int frame, float s, dstudiobone_t *pbone, dstudioanim_t *panim, float *adj, float *q ) +void R_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) { int j, k; vec4_t q1, q2; vec3_t angle1, angle2; - dstudioanimvalue_t *panimvalue; + mstudioanimvalue_t *panimvalue; for( j = 0; j < 3; j++ ) { @@ -805,7 +805,7 @@ void R_StudioCalcBoneQuaterion( int frame, float s, dstudiobone_t *pbone, dstudi } else { - panimvalue = (dstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); k = frame; // debug @@ -880,10 +880,10 @@ StudioCalcBonePosition ==================== */ -void R_StudioCalcBonePosition( int frame, float s, dstudiobone_t *pbone, dstudioanim_t *panim, float *adj, float *pos ) +void R_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) { int j, k; - dstudioanimvalue_t *panimvalue; + mstudioanimvalue_t *panimvalue; for( j = 0; j < 3; j++ ) { @@ -891,7 +891,7 @@ void R_StudioCalcBonePosition( int frame, float s, dstudiobone_t *pbone, dstudio if( panim->offset[j] != 0 ) { - panimvalue = (dstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); //if( j == 0 ) Msg( "%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); k = frame; @@ -997,19 +997,19 @@ StudioGetAnim ==================== */ -dstudioanim_t *R_StudioGetAnim( ref_model_t *m_pRefModel, dstudioseqdesc_t *pseqdesc ) +mstudioanim_t *R_StudioGetAnim( ref_model_t *m_pRefModel, mstudioseqdesc_t *pseqdesc ) { - dstudioseqgroup_t *pseqgroup; + mstudioseqgroup_t *pseqgroup; cache_user_t *paSequences; - mstudiomodel_t *m_pSubModel = (mstudiomodel_t *)m_pRefModel->extradata; + mstudiodata_t *m_pSubModel = (mstudiodata_t *)m_pRefModel->extradata; size_t filesize; byte *buf; Com_Assert( m_pSubModel == NULL ); - pseqgroup = (dstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; + pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; if( pseqdesc->seqgroup == 0 ) - return (dstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex); + return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex); paSequences = (cache_user_t *)m_pSubModel->submodels; @@ -1038,7 +1038,7 @@ dstudioanim_t *R_StudioGetAnim( ref_model_t *m_pRefModel, dstudioseqdesc_t *pseq Mem_Copy( paSequences[pseqdesc->seqgroup].data, buf, filesize ); Mem_Free( buf ); } - return (dstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); + return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); } /* @@ -1047,7 +1047,7 @@ StudioPlayerBlend ==================== */ -void R_StudioPlayerBlend( dstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) +void R_StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) { // calc up/down pointing *pBlend = (*pPitch * 3); @@ -1128,9 +1128,9 @@ void R_StudioSetUpTransform( ref_entity_t *e, bool trivial_accept ) if( m_pGroundEntity && m_pGroundEntity->v.movetype == MOVETYPE_PUSH && !VectorIsNull( m_pGroundEntity->v.velocity )) { - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; d = RI.lerpFrac; origin[0] += ( e->origin[0] - m_pEntity->v.oldorigin[0] ) * d; @@ -1216,11 +1216,11 @@ StudioCalcRotations ==================== */ -void R_StudioCalcRotations( float pos[][3], vec4_t *q, dstudioseqdesc_t *pseqdesc, dstudioanim_t *panim, float f ) +void R_StudioCalcRotations( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) { int i; int frame; - dstudiobone_t *pbone; + mstudiobone_t *pbone; studiovars_t *pstudio; float s, mouthopen; float adj[MAXSTUDIOCONTROLLERS]; @@ -1251,7 +1251,7 @@ void R_StudioCalcRotations( float pos[][3], vec4_t *q, dstudioseqdesc_t *pseqdes s = (f - frame); // add in programtic controllers - pbone = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); mouthopen = ri.GetMouthOpen( RI.currententity->index ); R_StudioCalcBoneAdj( dadt, adj, pstudio->lerp->curstate.controller, pstudio->lerp->latched.controller, mouthopen ); @@ -1281,7 +1281,7 @@ StudioEstimateFrame ==================== */ -float R_StudioEstimateFrame( dstudioseqdesc_t *pseqdesc ) +float R_StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) { double dfdt, f; @@ -1321,9 +1321,9 @@ void R_StudioSetupBones( ref_entity_t *e ) int i; double f; - dstudiobone_t *pbones; - dstudioseqdesc_t *pseqdesc; - dstudioanim_t *panim; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; studiovars_t *pstudio; static float pos[MAXSTUDIOBONES][3]; @@ -1347,7 +1347,7 @@ void R_StudioSetupBones( ref_entity_t *e ) RI.currententity = e; cl_entity = ri.GetClientEdict( e->index ); if( e->lerp->curstate.sequence >= m_pStudioHeader->numseq ) e->lerp->curstate.sequence = 0; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; f = R_StudioEstimateFrame( pseqdesc ); @@ -1395,7 +1395,7 @@ void R_StudioSetupBones( ref_entity_t *e ) static vec4_t q1b[MAXSTUDIOBONES]; float s; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pstudio->lerp->latched.sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pstudio->lerp->latched.sequence; panim = R_StudioGetAnim( e->model, pseqdesc ); // clip prevframe @@ -1435,7 +1435,7 @@ void R_StudioSetupBones( ref_entity_t *e ) pstudio->lerp->latched.frame = f; } - pbones = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); // calc gait animation if( e->gaitsequence != 0 ) @@ -1443,7 +1443,7 @@ void R_StudioSetupBones( ref_entity_t *e ) if( e->gaitsequence >= m_pStudioHeader->numseq ) e->gaitsequence = 0; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->gaitsequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->gaitsequence; panim = R_StudioGetAnim( e->model, pseqdesc ); R_StudioCalcRotations( pos2, q2, pseqdesc, panim, pstudio->lerp->curstate.gaitframe ); @@ -1465,7 +1465,7 @@ void R_StudioSetupBones( ref_entity_t *e ) static vec4_t q1b[MAXSTUDIOBONES]; float s; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pstudio->lerp->latched.gaitsequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pstudio->lerp->latched.gaitsequence; panim = R_StudioGetAnim( e->model, pseqdesc ); // clip prevframe @@ -1503,7 +1503,7 @@ StudioSaveBones */ static void R_StudioSaveBones( ref_entity_t *e ) { - dstudiobone_t *pbones = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + mstudiobone_t *pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); int i; for( i = 0; i < m_pStudioHeader->numbones; i++ ) @@ -1521,9 +1521,9 @@ void R_StudioMergeBones( ref_entity_t *e, ref_model_t *m_pSubModel ) int i, j; double f; int sequence = e->lerp->curstate.sequence; - dstudiobone_t *pbones; - dstudioseqdesc_t *pseqdesc; - dstudioanim_t *panim; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; studiovars_t *pstudio; matrix4x4 bonematrix; static vec4_t q[MAXSTUDIOBONES]; @@ -1542,7 +1542,7 @@ void R_StudioMergeBones( ref_entity_t *e, ref_model_t *m_pSubModel ) // weaponmodel can't change e->sequence! if( sequence >= m_pStudioHeader->numseq ) sequence = 0; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + sequence; f = R_StudioEstimateFrame( pseqdesc ); @@ -1550,7 +1550,7 @@ void R_StudioMergeBones( ref_entity_t *e, ref_model_t *m_pSubModel ) panim = R_StudioGetAnim( m_pSubModel, pseqdesc ); R_StudioCalcRotations( pos, q, pseqdesc, panim, f ); - pbones = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); for( i = 0; i < m_pStudioHeader->numbones; i++ ) { @@ -1594,7 +1594,7 @@ static void R_StudioCalcAttachments( ref_entity_t *e ) { int i; matrix4x4 out; - dstudioattachment_t *pAtt; + mstudioattachment_t *pAtt; vec3_t axis[3]; vec3_t localOrg, localAng, bonepos; @@ -1612,7 +1612,7 @@ static void R_StudioCalcAttachments( ref_entity_t *e ) } // calculate attachment points - pAtt = (dstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + pAtt = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); for( i = 0; i < m_pStudioHeader->numattachments; i++ ) { // NOTE: m_pbonestransform not contained rotate component so we need do it here @@ -1681,12 +1681,12 @@ static void R_StudioSetupSubModel( int body, int bodypart ) int index; if( bodypart > m_pStudioHeader->numbodyparts ) bodypart = 0; - m_pBodyPart = (dstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + bodypart; + m_pBodyPart = (mstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + bodypart; index = body / m_pBodyPart->base; index = index % m_pBodyPart->nummodels; - m_pSubModel = (dstudiomodel_t *)((byte *)m_pStudioHeader + m_pBodyPart->modelindex) + index; + m_pSubModel = (mstudiomodel_t *)((byte *)m_pStudioHeader + m_pBodyPart->modelindex) + index; } void R_StudioSetupChrome( float *pchrome, int modelnum, int bone, float *normal ) @@ -1808,7 +1808,7 @@ render_now: void R_StudioDrawBones( void ) { - dstudiobone_t *pbones = (dstudiobone_t *) ((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + mstudiobone_t *pbones = (mstudiobone_t *) ((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); vec3_t point; int i; @@ -1861,7 +1861,7 @@ void R_StudioDrawHitboxes( void ) for( i = 0; i < m_pStudioHeader->numhitboxes; i++ ) { - dstudiobbox_t *pbboxes = (dstudiobbox_t *)((byte *)m_pStudioHeader + m_pStudioHeader->hitboxindex); + mstudiobbox_t *pbboxes = (mstudiobbox_t *)((byte *)m_pStudioHeader + m_pStudioHeader->hitboxindex); vec3_t v[8], v2[8], bbmin, bbmax; VectorCopy( pbboxes[i].bbmin, bbmin ); @@ -1936,7 +1936,7 @@ void R_StudioDrawAttachments( void ) for( i = 0; i < m_pStudioHeader->numattachments; i++ ) { - dstudioattachment_t *pattachments = (dstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + mstudioattachment_t *pattachments = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); vec3_t v[4]; Matrix4x4_VectorTransform( m_pbonestransform[pattachments[i].bone], pattachments[i].org, v[0] ); @@ -2092,14 +2092,14 @@ StudioProcessGait */ void R_StudioProcessGait( ref_entity_t *e, edict_t *pplayer, studiovars_t *pstudio ) { - dstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; float dt, flYaw; // view direction relative to movement int iBlend; if( e->lerp->curstate.sequence >= m_pStudioHeader->numseq ) e->lerp->curstate.sequence = 0; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; R_StudioPlayerBlend( pseqdesc, &iBlend, &e->angles[PITCH] ); pstudio->lerp->curstate.blending[0] = iBlend; @@ -2149,7 +2149,7 @@ void R_StudioProcessGait( ref_entity_t *e, edict_t *pplayer, studiovars_t *pstud if( pplayer->v.gaitsequence >= m_pStudioHeader->numseq ) pplayer->v.gaitsequence = 0; - pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->v.gaitsequence; + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->v.gaitsequence; // calc gait frame if( pseqdesc->linearmovement[0] > 0 ) @@ -2251,9 +2251,9 @@ void R_StudioDrawPoints( const meshbuffer_t *mb, ref_entity_t *e ) byte *pvertbone, *pnormbone; short *pskinref, *ptricmds; int flags, features; - dstudiotexture_t *ptexture; + mstudiotexture_t *ptexture; studiovars_t *studio; - dstudiomesh_t *pmesh; + mstudiomesh_t *pmesh; ref_shader_t *shader; float s, t; @@ -2269,8 +2269,8 @@ void R_StudioDrawPoints( const meshbuffer_t *mb, ref_entity_t *e ) pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex); pvertbone = ((byte *)m_pStudioHeader + m_pSubModel->vertinfoindex); pnormbone = ((byte *)m_pStudioHeader + m_pSubModel->norminfoindex); - pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + meshnum; - ptexture = (dstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex); + pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + meshnum; + ptexture = (mstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex); pskinref = (short *)((byte *)m_pTextureHeader + m_pTextureHeader->skinindex); ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); if( m_skinnum != 0 && m_skinnum < m_pTextureHeader->numskinfamilies ) @@ -2320,7 +2320,7 @@ void R_StudioDrawPoints( const meshbuffer_t *mb, ref_entity_t *e ) // cache transforms if( studio->mesh[modelnum]->m_nCachedFrame != r_framecount2 ) { - dstudiomesh_t *pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex); + mstudiomesh_t *pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex); float *lv = (float *)m_pxformlight; int vertspermesh = 0; @@ -2393,7 +2393,7 @@ bool R_CullStudioModel( ref_entity_t *e ) int sequence; bool frustum, query; uint modhandle; - dstudiotexture_t *ptexture; + mstudiotexture_t *ptexture; short *pskinref; meshbuffer_t *mb; @@ -2437,7 +2437,7 @@ bool R_CullStudioModel( ref_entity_t *e ) R_StudioSetupModel( e, e->model ); // add it - ptexture = (dstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex); + ptexture = (mstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex); for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) { R_StudioSetupSubModel( RI.currententity->body, i ); @@ -2448,9 +2448,9 @@ bool R_CullStudioModel( ref_entity_t *e ) for( j = 0; j < m_pSubModel->nummesh; j++ ) { ref_shader_t *shader; - dstudiomesh_t *pmesh; + mstudiomesh_t *pmesh; - pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; + pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; if( e->customShader ) shader = e->customShader; else shader = &r_shaders[ptexture[pskinref[pmesh->skinref]].shader]; @@ -2470,7 +2470,7 @@ void R_AddStudioModelToList( ref_entity_t *e ) uint entnum = e - r_entities; ref_model_t *mod = e->model; mfog_t *fog = NULL; - dstudiotexture_t *ptexture; + mstudiotexture_t *ptexture; short *pskinref; int sequence; int i, j; @@ -2532,7 +2532,7 @@ void R_AddStudioModelToList( ref_entity_t *e ) R_StudioSetupModel( e, e->model ); // add base model - ptexture = (dstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex); + ptexture = (mstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex); for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) { R_StudioSetupSubModel( e->body, i ); @@ -2543,9 +2543,9 @@ void R_AddStudioModelToList( ref_entity_t *e ) for( j = 0; j < m_pSubModel->nummesh; j++ ) { ref_shader_t *shader; - dstudiomesh_t *pmesh; + mstudiomesh_t *pmesh; - pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; + pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; if( e->customShader ) shader = e->customShader; else shader = &r_shaders[ptexture[pskinref[pmesh->skinref]].shader]; diff --git a/xash.dsw b/xash.dsw index 594f7cad..dc1fb4a2 100644 --- a/xash.dsw +++ b/xash.dsw @@ -99,18 +99,6 @@ Package=<4> ############################################################################### -Project: "server"=".\server\server.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - Project: "spirit"=".\spirit\spirit.dsp" - Package Owner=<4> Package=<5> @@ -135,18 +123,6 @@ Package=<4> ############################################################################### -Project: "snd_al"=".\snd_al\snd_al.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - Project: "snd_dx"=".\snd_dx\snd_dx.dsp" - Package Owner=<4> Package=<5> diff --git a/xtools/mdllib.h b/xtools/mdllib.h index a44809e5..ab10fcab 100644 --- a/xtools/mdllib.h +++ b/xtools/mdllib.h @@ -126,7 +126,7 @@ typedef struct vec3_t *pos[MAXSTUDIOSRCBONES]; vec3_t *rot[MAXSTUDIOSRCBONES]; int numanim[MAXSTUDIOSRCBONES][6]; - dstudioanimvalue_t *anim[MAXSTUDIOSRCBONES][6]; + mstudioanimvalue_t *anim[MAXSTUDIOSRCBONES][6]; } s_animation_t; typedef struct diff --git a/xtools/spritegen.c b/xtools/spritegen.c index 45a0bb85..3fe6f71a 100644 --- a/xtools/spritegen.c +++ b/xtools/spritegen.c @@ -110,12 +110,12 @@ void WriteSprite( file_t *f ) dspriteinterval_t temp; totinterval += frames[groupframe+1+j].interval; - temp.interval = LittleFloat(totinterval); - FS_Write(f, &temp, sizeof(temp)); + temp.interval = LittleFloat( totinterval ); + FS_Write( f, &temp, sizeof( temp )); } for( j = 0; j < numframes; j++ ) { - WriteFrame(f, curframe); + WriteFrame( f, curframe ); curframe++; } } diff --git a/xtools/studio.c b/xtools/studio.c index 926fed9f..ee56efe6 100644 --- a/xtools/studio.c +++ b/xtools/studio.c @@ -3,6 +3,7 @@ // studio.c - half-life model compiler //======================================================================= +#include "const.h" #include "mdllib.h" #include "matrix_lib.h" #include "stdio.h" // sscanf @@ -79,8 +80,8 @@ string mirrored[MAXSTUDIOSRCBONES]; s_mesh_t *pmesh; token_t token; -dstudiohdr_t *phdr; -dstudioseqhdr_t *pseqhdr; +studiohdr_t *phdr; +mstudioseqhdr_t *pseqhdr; file_t *smdfile; char line[2048]; int linecount; @@ -110,13 +111,13 @@ WriteBoneInfo void WriteBoneInfo( void ) { int i, j; - dstudiobone_t *pbone; - dstudiobonecontroller_t *pbonecontroller; - dstudioattachment_t *pattachment; - dstudiobbox_t *pbbox; + mstudiobone_t *pbone; + mstudiobonecontroller_t *pbonecontroller; + mstudioattachment_t *pattachment; + mstudiobbox_t *pbbox; // save bone info - pbone = (dstudiobone_t *)pData; + pbone = (mstudiobone_t *)pData; phdr->numbones = numbones; phdr->boneindex = (pData - pStart); @@ -139,7 +140,7 @@ void WriteBoneInfo( void ) pbone[i].scale[5] = bonetable[i].rotscale[2]; } - pData += numbones * sizeof( dstudiobone_t ); + pData += numbones * sizeof( mstudiobone_t ); ALIGN( pData ); // map bonecontroller to bones @@ -179,7 +180,7 @@ void WriteBoneInfo( void ) } // save bonecontroller info - pbonecontroller = (dstudiobonecontroller_t *)pData; + pbonecontroller = (mstudiobonecontroller_t *)pData; phdr->numbonecontrollers = numbonecontrollers; phdr->bonecontrollerindex = (pData - pStart); @@ -192,11 +193,11 @@ void WriteBoneInfo( void ) pbonecontroller[i].end = bonecontroller[i].end; } - pData += numbonecontrollers * sizeof( dstudiobonecontroller_t ); + pData += numbonecontrollers * sizeof( mstudiobonecontroller_t ); ALIGN( pData ); // save attachment info - pattachment = (dstudioattachment_t *)pData; + pattachment = (mstudioattachment_t *)pData; phdr->numattachments = numattachments; phdr->attachmentindex = (pData - pStart); @@ -206,11 +207,11 @@ void WriteBoneInfo( void ) VectorCopy( attachment[i].org, pattachment[i].org ); } - pData += numattachments * sizeof( dstudioattachment_t ); + pData += numattachments * sizeof( mstudioattachment_t ); ALIGN( pData ); // save bbox info - pbbox = (dstudiobbox_t *)pData; + pbbox = (mstudiobbox_t *)pData; phdr->numhitboxes = numhitboxes; phdr->hitboxindex = (pData - pStart); @@ -222,7 +223,7 @@ void WriteBoneInfo( void ) VectorCopy( hitbox[i].bmax, pbbox[i].bbmax ); } - pData += numhitboxes * sizeof( dstudiobbox_t ); + pData += numhitboxes * sizeof( mstudiobbox_t ); ALIGN( pData ); } @@ -235,20 +236,20 @@ void WriteSequenceInfo( void ) { int i, j; - dstudioseqgroup_t *pseqgroup; - dstudioseqdesc_t *pseqdesc; - dstudioseqdesc_t *pbaseseqdesc; - dstudioevent_t *pevent; - dstudiopivot_t *ppivot; + mstudioseqgroup_t *pseqgroup; + mstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pbaseseqdesc; + mstudioevent_t *pevent; + mstudiopivot_t *ppivot; byte *ptransition; // save sequence info - pseqdesc = (dstudioseqdesc_t *)pData; + pseqdesc = (mstudioseqdesc_t *)pData; pbaseseqdesc = pseqdesc; phdr->numseq = numseq; phdr->seqindex = (pData - pStart); - pData += numseq * sizeof( dstudioseqdesc_t ); + pData += numseq * sizeof( mstudioseqdesc_t ); for (i = 0; i < numseq; i++, pseqdesc++) { @@ -285,10 +286,10 @@ void WriteSequenceInfo( void ) totalseconds += sequence[i]->numframes / sequence[i]->fps; // save events - pevent = (dstudioevent_t *)pData; + pevent = (mstudioevent_t *)pData; pseqdesc->numevents = sequence[i]->numevents; pseqdesc->eventindex = (pData - pStart); - pData += pseqdesc->numevents * sizeof( dstudioevent_t ); + pData += pseqdesc->numevents * sizeof( mstudioevent_t ); for (j = 0; j < sequence[i]->numevents; j++) { @@ -300,10 +301,10 @@ void WriteSequenceInfo( void ) ALIGN( pData ); // save pivots - ppivot = (dstudiopivot_t *)pData; + ppivot = (mstudiopivot_t *)pData; pseqdesc->numpivots = sequence[i]->numpivots; pseqdesc->pivotindex = (pData - pStart); - pData += pseqdesc->numpivots * sizeof( dstudiopivot_t ); + pData += pseqdesc->numpivots * sizeof( mstudiopivot_t ); for (j = 0; j < sequence[i]->numpivots; j++) { @@ -316,10 +317,10 @@ void WriteSequenceInfo( void ) } // save sequence group info - pseqgroup = (dstudioseqgroup_t *)pData; + pseqgroup = (mstudioseqgroup_t *)pData; phdr->numseqgroups = 1; phdr->seqgroupindex = (pData - pStart); - pData += sizeof( dstudioseqgroup_t ); + pData += sizeof( mstudioseqgroup_t ); ALIGN( pData ); @@ -347,20 +348,20 @@ byte *WriteAnimations( byte *pData, byte *pStart, int group ) { int i, j, k, q, n; - dstudioanim_t *panim; - dstudioanimvalue_t *panimvalue; + mstudioanim_t *panim; + mstudioanimvalue_t *panimvalue; for (i = 0; i < numseq; i++) { if (sequence[i]->seqgroup == group) { // save animations - panim = (dstudioanim_t *)pData; + panim = (mstudioanim_t *)pData; sequence[i]->animindex = (pData - pStart); - pData += sequence[i]->numblends * numbones * sizeof( dstudioanim_t ); + pData += sequence[i]->numblends * numbones * sizeof( mstudioanim_t ); ALIGN( pData ); - panimvalue = (dstudioanimvalue_t *)pData; + panimvalue = (mstudioanimvalue_t *)pData; for (q = 0; q < sequence[i]->numblends; q++) { // save animation value info @@ -402,15 +403,15 @@ WriteTextures */ void WriteTextures( void ) { - dstudiotexture_t *ptexture; + mstudiotexture_t *ptexture; short *pref; int i, j; // save bone info - ptexture = (dstudiotexture_t *)pData; + ptexture = (mstudiotexture_t *)pData; phdr->numtextures = numtextures; phdr->textureindex = (pData - pStart); - pData += numtextures * sizeof( dstudiotexture_t ); + pData += numtextures * sizeof( mstudiotexture_t ); ALIGN( pData ); phdr->skinindex = (pData - pStart); @@ -453,24 +454,24 @@ WriteModel */ void WriteModel( void ) { - dstudiobodyparts_t *pbodypart; - dstudiomodel_t *pmodel; + mstudiobodyparts_t *pbodypart; + mstudiomodel_t *pmodel; byte *pbone; vec3_t *pvert; vec3_t *pnorm; - dstudiomesh_t *pmesh; + mstudiomesh_t *pmesh; s_trianglevert_t *psrctri; int i, j, k, cur; int total_tris = 0; int total_strips = 0; - pbodypart = (dstudiobodyparts_t *)pData; + pbodypart = (mstudiobodyparts_t *)pData; phdr->numbodyparts = numbodyparts; phdr->bodypartindex = (pData - pStart); - pData += numbodyparts * sizeof( dstudiobodyparts_t ); + pData += numbodyparts * sizeof( mstudiobodyparts_t ); - pmodel = (dstudiomodel_t *)pData; - pData += nummodels * sizeof( dstudiomodel_t ); + pmodel = (mstudiomodel_t *)pData; + pData += nummodels * sizeof( mstudiomodel_t ); for (i = 0, j = 0; i < numbodyparts; i++) { @@ -549,10 +550,10 @@ void WriteModel( void ) cur = (int)pData; // save mesh info - pmesh = (dstudiomesh_t *)pData; + pmesh = (mstudiomesh_t *)pData; pmodel[i].nummesh = model[i]->nummesh; pmodel[i].meshindex = (pData - pStart); - pData += pmodel[i].nummesh * sizeof( dstudiomesh_t ); + pData += pmodel[i].nummesh * sizeof( mstudiomesh_t ); ALIGN( pData ); @@ -610,11 +611,11 @@ void WriteMDLFile( void ) com.snprintf( texname, MAX_STRING, "%sT.mdl", modeloutname ); Msg( "writing %s:\n", texname ); - phdr = (dstudiohdr_t *)pStart; + phdr = (studiohdr_t *)pStart; phdr->ident = IDSTUDIOHEADER; phdr->version = STUDIO_VERSION; - pData = (byte *)phdr + sizeof( dstudiohdr_t ); + pData = (byte *)phdr + sizeof( studiohdr_t ); WriteTextures( ); @@ -633,7 +634,7 @@ void WriteMDLFile( void ) Msg ("---------------------\n"); Msg ("writing %s:\n", modeloutname); - phdr = (dstudiohdr_t *)pStart; + phdr = (studiohdr_t *)pStart; phdr->ident = IDSTUDIOHEADER; phdr->version = STUDIO_VERSION; com.strncpy( phdr->name, modeloutname, 64 ); @@ -645,7 +646,7 @@ void WriteMDLFile( void ) VectorCopy( cbox[1], phdr->bbmax ); phdr->flags = gflags; - pData = (byte *)phdr + sizeof( dstudiohdr_t ); + pData = (byte *)phdr + sizeof( studiohdr_t ); WriteBoneInfo(); Msg("bones %6s (%d)\n", memprint( pData - pStart - total ), numbones ); @@ -1154,9 +1155,9 @@ void SimplifyModel( void ) { for (k = 0; k < 6; k++) { - dstudioanimvalue_t *pcount, *pvalue; + mstudioanimvalue_t *pcount, *pvalue; short value[MAXSTUDIOANIMATIONS]; - dstudioanimvalue_t data[MAXSTUDIOANIMATIONS]; + mstudioanimvalue_t data[MAXSTUDIOANIMATIONS]; float v; for (n = 0; n < sequence[i]->numframes; n++) @@ -1236,8 +1237,8 @@ void SimplifyModel( void ) } else { - sequence[i]->panim[q]->anim[j][k] = Kalloc( (pvalue - data) * sizeof( dstudioanimvalue_t )); - memmove( sequence[i]->panim[q]->anim[j][k], data, (pvalue - data) * sizeof( dstudioanimvalue_t )); + sequence[i]->panim[q]->anim[j][k] = Kalloc( (pvalue - data) * sizeof( mstudioanimvalue_t )); + memmove( sequence[i]->panim[q]->anim[j][k], data, (pvalue - data) * sizeof( mstudioanimvalue_t )); } } } diff --git a/xtools/utils.c b/xtools/utils.c index 42618db0..1dd7bf2b 100644 --- a/xtools/utils.c +++ b/xtools/utils.c @@ -4,7 +4,7 @@ //======================================================================= #include "xtools.h" -#include "byteorder.h" +#include "const.h" #include "utils.h" #include "mdllib.h"