halflife-thewastes-sdk/cl_dll/studioevent.cpp
2023-09-06 03:25:39 +03:00

321 lines
No EOL
8.5 KiB
C++

/***
*
* Copyright (C) 2002 The Wastes Project, All Rights Reserved.
*
* This product contains software technology from Valve Software, LLC,
* Copyright © 1996-2001, Valve LLC, All rights reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* The Wastes Project. All other use, distribution, or modification is prohibited
* without written permission from The Wastes Project.
*
***/
//
// studioevent.cpp -> Model Event code
//
#include <memory.h>
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "entity_types.h"
#include "studio_event.h" // def. of mstudioevent_t
#include "r_efx.h"
#include "event_api.h"
#include "pm_defs.h"
#include "pmtrace.h"
#include "twm.h"
#include "twmmanager.h"
#define DLLEXPORT __declspec( dllexport )
extern "C"
{
#if 0
// THE ORIGINAL HUD_StudioEvent declaration is
void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity );
// But we want to modify the cl_entity_s* parameter. Since C doesnt have the concept of const,
// and to the best of my knowledge the HL code is still c, i Figured i'd remove it... if we
// have problems with studio events dont hesitate to point at this.
// Gage - July 02, 2002
#else
void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, struct cl_entity_s *entity );
#endif
}
void HUD_GetCurrentAmmoInfo(int &cur_ammo,int &max_ammo);
extern int cam_thirdperson;
extern vec3_t v_origin,v_angles;
/*
=========================
STUDIO_SmokePuff
=========================
*/
void STUDIO_SmokePuff(float *vecSrc,float scale,cl_entity_t *entity)
{
// create the puff
TEMPENTITY *pTent = gEngfuncs.pEfxAPI->R_TempSprite(vecSrc,
Vector(0,0,5),
scale,
gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/smoke1.spr"),
kRenderTransAlpha,
0,
25,
5,
FTENT_SPRANIMATE);
// state settings
if(pTent != NULL)
{
pTent->clientIndex = entity->index;
//pTent->entity.curstate.rendercolor = Color;
pTent->entity.curstate.framerate = 10;
pTent->entity.curstate.renderamt = 128;
}
}
/*
=========================
STUDIO_EjectModel
=========================
*/
void STUDIO_EjectModel(int iEventId,const char *szEventOptions,struct cl_entity_s *entity,int count)
{
char szShellname[64];
int shell_index;
int attachment_num,velocity_type,sound_type,quality_check;
float scaleR,scaleU;
vec3_t shell_velocity;
vec3_t shell_origin;
vec3_t angles,forward,right,up;
vec3_t endpos;
// Read options from event parameters
sscanf(szEventOptions,"%i,%i,%i,%i,%s",&attachment_num,&velocity_type,&sound_type,&quality_check,szShellname);
// Finalize shellcase parameter (set high or low quality)
if(quality_check)
sprintf(szShellname,"%s%s",szShellname,CVAR_GET_FLOAT("cl_shellcase_quality") ? "_hi.mdl" : "_lo.mdl");
#if 0
gEngfuncs.pfnCenterPrint(szShellname);
#endif
// set up shell properties
shell_index = gEngfuncs.pEventAPI->EV_FindModelIndex(szShellname);
if(shell_index == 0)
gEngfuncs.Con_DPrintf("STUDIO_EjectModel: invalid model %s\n",szShellname);
// Get needed angles
VectorCopy(entity->angles,angles);
AngleVectors(angles,forward,right,up);
for(int i = 0;i < count;i++)
{
switch(velocity_type)
{
case 1:
// Pistols, Small arms ejection
scaleR = gEngfuncs.pfnRandomFloat( 50, 70 );
scaleU = gEngfuncs.pfnRandomFloat( 100, 150 );
VectorClear(shell_origin);
break;
case 2:
// No velocity, magazine dropping
scaleR = gEngfuncs.pfnRandomFloat(0.0,0.0);
scaleU = gEngfuncs.pfnRandomFloat(0.0,0.0);
// Randomize the location a bit,
// so events that call multiple times
// (such as ruger reload) have shellcases
// going everywhere
VectorClear(shell_origin);
shell_origin[0] = gEngfuncs.pfnRandomFloat(-1.0f,6.0f);
shell_origin[1] = gEngfuncs.pfnRandomFloat(-1.0f,6.0f);
shell_origin[2] = gEngfuncs.pfnRandomFloat(-1.0f,6.0f);
break;
}
for(int i = 0;i< 3;i++)
{
shell_velocity[i] = right[i] * scaleR + up[i] * scaleU + forward[i] * 25;
// go by ent origin, not attachment
if(attachment_num == -1)
{
shell_origin[i] += entity->origin[i];
// Spawn a bit lower
if(i == 2)
shell_origin[i] -= 16;
}
else
shell_origin[i] += entity->attachment[attachment_num][i];
}
// Eject the shell
VectorClear( endpos );
endpos[1] = angles[1];
// sound type, we do a
// switch in the unlikely event
// that these macros change on us
switch(sound_type)
{
case 0: sound_type = TE_BOUNCE_NULL; break;
case 1: sound_type = TE_BOUNCE_SHELL; break;
case 2: sound_type = TE_BOUNCE_SHOTSHELL; break;
}
gEngfuncs.pEfxAPI->R_TempModel(shell_origin,shell_velocity,endpos,CVAR_GET_FLOAT("cl_shellcase_lifetime"),shell_index,sound_type);
}
}
void STUDIO_TwmMuzzleFlash(int iEventId,const char *szEventOptions,struct cl_entity_s *entity)
{
CTwmModel *pTwm;
twm_clientinfo_t *clientinfo = NULL;
int attachment_num;
float fadetime;
// sanity check
if(g_iNumMuzzleflashModels > 64)
{
gEngfuncs.Con_Printf("STUDIO_TwmMuzzleFlash: too many muzzle flashes!\n");
return;
}
g_iNumMuzzleflashModels++;
// TODO: use szEventOptions for this stuff
pTwm = g_TwmManager.GetModelByName("models/muz_test.twm");
attachment_num = 0;
fadetime = 2.5f;
// end of array
clientinfo = &g_MuzzleflashModels[g_iNumMuzzleflashModels - 1];
// We go through the current muzzleflash
// array, if this entity has a
// muzzleflash for it, put in our new data
for(int i = 0;i < g_iNumMuzzleflashModels;i++)
{
twm_clientinfo_t *cur_info = &g_MuzzleflashModels[i];
if(cur_info->attached_ent == entity)
{
clientinfo = &g_MuzzleflashModels[i];
g_iNumMuzzleflashModels--; // reset value
break;
}
}
clientinfo->twm_info = &pTwm->twminfo;
clientinfo->attached_ent = entity;
clientinfo->attachment_num = attachment_num;
clientinfo->fadetime = fadetime;
// triAPI information
clientinfo->render_mode = kRenderTransAdd;
clientinfo->sprite_frame = 0; // TODO: make a random frame
clientinfo->brightness = gEngfuncs.pfnRandomFloat(0.8f,1.0f);
// RGBA
clientinfo->color[0] = 1.0f;
clientinfo->color[1] = 1.0f;
clientinfo->color[2] = 1.0f;
clientinfo->color[3] = gEngfuncs.pfnRandomFloat(0.5f,1.0f);
}
/*
=========================
HUD_StudioEvent
The entity's studio model description indicated an event was
fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound )
=========================
*/
void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, struct cl_entity_s *entity )
{
switch( event->event )
{
/*******************
* muzzle flashes *
*******************/
case 5001:
// STUDIO_TwmMuzzleFlash(event->event,event->options,entity);
gEngfuncs.pEfxAPI->R_MuzzleFlash((float *)&entity->attachment[0], atoi( event->options) );
break;
case 5011:
// STUDIO_TwmMuzzleFlash(event->event,event->options,entity);
gEngfuncs.pEfxAPI->R_MuzzleFlash((float *)&entity->attachment[1], atoi( event->options) );
break;
case 5021:
// STUDIO_TwmMuzzleFlash(event->event,event->options,entity);
gEngfuncs.pEfxAPI->R_MuzzleFlash((float *)&entity->attachment[2], atoi( event->options) );
break;
case 5031:
// STUDIO_TwmMuzzleFlash(event->event,event->options,entity);
gEngfuncs.pEfxAPI->R_MuzzleFlash((float *)&entity->attachment[3], atoi( event->options) );
break;
/*******************
* smoke puffs *
*******************/
case 5041:
STUDIO_SmokePuff((float *)&entity->attachment[1],0.5f,entity);
break;
/*******************
* sparks *
*******************/
case 5002:
gEngfuncs.pEfxAPI->R_SparkEffect((float *)&entity->attachment[0], atoi( event->options), -100, 100 );
break;
/*******************
* sound *
*******************/
case 5004:
gEngfuncs.pfnPlaySoundByNameAtLocation((char*)event->options,1.0,(float*)&entity->attachment[0]);
break;
/*******************
* skin change *
*******************/
case 5005:
entity->curstate.skin = atoi(event->options);
break;
/*******************
* model ejection *
*******************/
case 5006:
STUDIO_EjectModel(event->event,event->options,entity,1);
break;
// Ruger reload
case 5007:
STUDIO_EjectModel(event->event,event->options,entity,5 - gHUD.m_Ammo.GetCurWeapon()->iClip);
break;
// Sawed off reload
case 5008:
STUDIO_EjectModel(event->event,event->options,entity,2 - gHUD.m_Ammo.GetCurWeapon()->iClip);
break;
default:
break;
}
}