/*** * * 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 #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; } }