FX: Cleaned up inits and organized everything into the relevant game

specific directories, so mods can now inherit/override effects easier.
This commit is contained in:
Marco Cawthorne 2020-04-23 03:13:29 +02:00
parent 781d896bfd
commit d72fc4d17c
80 changed files with 1152 additions and 785 deletions

View File

@ -17,23 +17,98 @@
void
Game_Parse_Event(float fHeader)
{
if (fHeader == EV_CHAT) {
switch (fHeader) {
case EV_SPARK:
vector vSparkPos, vSparkAngle;
vSparkPos[0] = readcoord();
vSparkPos[1] = readcoord();
vSparkPos[2] = readcoord();
vSparkAngle[0] = readcoord();
vSparkAngle[1] = readcoord();
vSparkAngle[2] = readcoord();
FX_Spark(vSparkPos, vSparkAngle);
break;
case EV_GIBHUMAN:
vector vGibPos;
vGibPos[0] = readcoord();
vGibPos[1] = readcoord();
vGibPos[2] = readcoord();
FX_GibHuman(vGibPos);
break;
case EV_BLOOD:
vector vBloodPos;
vector vBloodColor;
vBloodPos[0] = readcoord();
vBloodPos[1] = readcoord();
vBloodPos[2] = readcoord();
vBloodColor[0] = readbyte() / 255;
vBloodColor[1] = readbyte() / 255;
vBloodColor[2] = readbyte() / 255;
FX_Blood(vBloodPos, vBloodColor);
break;
case EV_EXPLOSION:
vector vExploPos;
vExploPos[0] = readcoord();
vExploPos[1] = readcoord();
vExploPos[2] = readcoord();
FX_Explosion(vExploPos);
break;
case EV_MODELGIB:
vector vecPos;
vecPos[0] = readcoord();
vecPos[1] = readcoord();
vecPos[2] = readcoord();
vector vSize;
vSize[0] = readcoord();
vSize[1] = readcoord();
vSize[2] = readcoord();
float fStyle = readbyte();
int count = readbyte();
FX_BreakModel(count, vecPos, vSize, [0,0,0], fStyle);
break;
case EV_IMPACT:
int iType;
vector vOrigin, vNormal;
iType = (int)readbyte();
vOrigin[0] = readcoord();
vOrigin[1] = readcoord();
vOrigin[2] = readcoord();
vNormal[0] = readcoord();
vNormal[1] = readcoord();
vNormal[2] = readcoord();
FX_Impact(iType, vOrigin, vNormal);
break;
case EV_CHAT:
float fSender = readbyte();
float fTeam = readbyte();
string sMessage = readstring();
CSQC_Parse_Print(sprintf("%s: %s", getplayerkeyvalue(fSender, "name"), sMessage), PRINT_CHAT);
} else if (fHeader == EV_CHAT_TEAM) {
break;
case EV_CHAT_TEAM:
float fSender2 = readbyte();
float fTeam2 = readbyte();
string sMessage2 = readstring();
CSQC_Parse_Print(sprintf("[TEAM] %s: %s", getplayerkeyvalue(fSender2, "name"), sMessage2), PRINT_CHAT);
} else if (fHeader == EV_CHAT_VOX) {
break;
case EV_CHAT_VOX:
Sound_PlayVOX(readstring());
} else if (fHeader == EV_VIEWMODEL) {
break;
case EV_VIEWMODEL:
View_PlayAnimation(readbyte());
} else if (fHeader == EV_WEAPON_PICKUP) {
break;
case EV_WEAPON_PICKUP:
int w = readbyte();
if (autocvar_cl_autoweaponswitch == 1) {
@ -48,9 +123,12 @@ Game_Parse_Event(float fHeader)
}
HUD_WeaponPickupNotify(w);
} else if (fHeader == EV_RADIOMSG) {
break;
case EV_RADIOMSG:
Radio_PlayMessage(readbyte());
} else if (fHeader == EV_RADIOMSG2) {
break;
case EV_RADIOMSG2:
Radio_PlayPlayerMessage(readbyte(), readbyte());
break;
}
}

View File

@ -116,6 +116,13 @@ Client_InitDone(void)
void
Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");

View File

@ -40,7 +40,14 @@
../../shared/pmove.c
predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_spark.c
../../shared/cstrike/fx_impact.c
../../shared/cstrike/fx_flashbang.c
../../shared/cstrike/fx_smokenade.c
../npc.c
../../shared/cstrike/radio.c

View File

@ -65,9 +65,6 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
/* VOX */
Sound_InitVOX();
/* Effects */
Effects_Init();
precache_sound("common/wpn_hudon.wav");
precache_sound("common/wpn_hudoff.wav");
precache_sound("common/wpn_moveselect.wav");
@ -497,61 +494,6 @@ CSQC_Parse_Event(void)
case EV_MESSAGE:
GameMessage_Parse();
break;
case EV_SPARK:
vector vSparkPos, vSparkAngle;
vSparkPos[0] = readcoord();
vSparkPos[1] = readcoord();
vSparkPos[2] = readcoord();
vSparkAngle[0] = readcoord();
vSparkAngle[1] = readcoord();
vSparkAngle[2] = readcoord();
Effect_CreateSpark(vSparkPos, vSparkAngle);
break;
case EV_GIBHUMAN:
vector vGibPos;
vGibPos[0] = readcoord();
vGibPos[1] = readcoord();
vGibPos[2] = readcoord();
Effect_GibHuman(vGibPos);
break;
case EV_BLOOD:
vector vBloodPos;
vector vBloodColor;
vBloodPos[0] = readcoord();
vBloodPos[1] = readcoord();
vBloodPos[2] = readcoord();
vBloodColor[0] = readbyte() / 255;
vBloodColor[1] = readbyte() / 255;
vBloodColor[2] = readbyte() / 255;
Effect_CreateBlood(vBloodPos, vBloodColor);
break;
case EV_EXPLOSION:
vector vExploPos;
vExploPos[0] = readcoord();
vExploPos[1] = readcoord();
vExploPos[2] = readcoord();
Effect_CreateExplosion(vExploPos);
break;
case EV_MODELGIB:
vector vecPos;
vecPos[0] = readcoord();
vecPos[1] = readcoord();
vecPos[2] = readcoord();
vector vSize;
vSize[0] = readcoord();
vSize[1] = readcoord();
vSize[2] = readcoord();
float fStyle = readbyte();
int count = readbyte();
Effect_BreakModel(count, vecPos, vSize, [0,0,0], fStyle);
break;
case EV_CAMERATRIGGER:
pSeat->m_vecCameraOrigin.x = readcoord();
pSeat->m_vecCameraOrigin.y = readcoord();
@ -563,21 +505,6 @@ CSQC_Parse_Event(void)
pSeat->m_flCameraTime = time + readfloat();
break;
case EV_IMPACT:
int iType;
vector vOrigin, vNormal;
iType = (int)readbyte();
vOrigin[0] = readcoord();
vOrigin[1] = readcoord();
vOrigin[2] = readcoord();
vNormal[0] = readcoord();
vNormal[1] = readcoord();
vNormal[2] = readcoord();
Effect_Impact(iType, vOrigin, vNormal);
break;
case EV_ANGLE:
vector a;
a[0] = readfloat();

View File

@ -27,6 +27,23 @@ Comparable to worldspawn in SSQC in that it's mostly used for precaches
void
Client_Init(float apilevel, string enginename, float engineversion)
{
}
void
Client_InitDone(void)
{
}
void
Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");
@ -45,14 +62,3 @@ Client_Init(float apilevel, string enginename, float engineversion)
BEAM_TRIPMINE = particleeffectnum("beam_tripmine");
}
void
Client_InitDone(void)
{
}
void
Game_RendererRestarted(string rstr)
{
}

View File

@ -36,7 +36,12 @@
../../shared/pmove.c
../valve/predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../npc.c
init.c
../../shared/gearbox/items.h

View File

@ -27,6 +27,23 @@ Comparable to worldspawn in SSQC in that it's mostly used for precaches
void
Client_Init(float apilevel, string enginename, float engineversion)
{
}
void
Client_InitDone(void)
{
}
void
Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");
@ -41,17 +58,5 @@ Client_Init(float apilevel, string enginename, float engineversion)
precache_model("sprites/tfchud06.spr");
precache_model("sprites/tfc_dmsg.spr");
precache_model("sprites/nmxhair2.spr");
BEAM_TRIPMINE = particleeffectnum("beam_tripmine");
}
void
Client_InitDone(void)
{
}
void
Game_RendererRestarted(string rstr)
{
}

View File

@ -36,7 +36,12 @@
../../shared/pmove.c
../valve/predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../npc.c
init.c
../../shared/hunger/items.h

View File

@ -27,6 +27,23 @@ Comparable to worldspawn in SSQC in that it's mostly used for precaches
void
Client_Init(float apilevel, string enginename, float engineversion)
{
}
void
Client_InitDone(void)
{
}
void
Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");
@ -39,14 +56,3 @@ Client_Init(float apilevel, string enginename, float engineversion)
BEAM_TRIPMINE = particleeffectnum("beam_tripmine");
}
void
Client_InitDone(void)
{
}
void
Game_RendererRestarted(string rstr)
{
}

View File

@ -36,7 +36,12 @@
../../shared/pmove.c
../valve/predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../npc.c
init.c
../../shared/poke646/items.h

View File

@ -23,6 +23,21 @@ Comparable to worldspawn in SSQC in that it's mostly used for precaches
*/
void Client_Init(float apilevel, string enginename, float engineversion)
{
}
void Client_InitDone(void)
{
}
void Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");
@ -32,81 +47,3 @@ void Client_Init(float apilevel, string enginename, float engineversion)
BEAM_TRIPMINE = particleeffectnum("beam_tripmine");
}
void Client_InitDone(void)
{
}
void Game_RendererRestarted(string rstr)
{
}
/*
#ifdef REWOLF
case "decore_asteroid":
eEnt = spawn(decore_asteroid);
iClass = TRUE;
break;
case "decore_baboon":
eEnt = spawn(decore_baboon);
iClass = TRUE;
break;
case "decore_bodygib":
eEnt = spawn(decore_bodygib);
iClass = TRUE;
break;
case "decore_butterflyflock":
eEnt = spawn(decore_butterflyflock);
iClass = TRUE;
break;
case "decore_explodable":
eEnt = spawn(decore_explodable);
iClass = TRUE;
break;
case "decore_foot":
eEnt = spawn(decore_foot);
iClass = TRUE;
break;
case "decore_goldskull":
eEnt = spawn(decore_goldskull);
iClass = TRUE;
break;
case "decore_hatgib":
eEnt = spawn(decore_hatgib);
iClass = TRUE;
break;
case "decore_nest":
eEnt = spawn(decore_nest);
iClass = TRUE;
break;
case "decore_pteradon":
eEnt = spawn(decore_pteradon);
iClass = TRUE;
break;
case "decore_torch":
eEnt = spawn(decore_torch);
iClass = TRUE;
break;
case "decore_spacedebris":
eEnt = spawn(decore_spacedebris);
iClass = TRUE;
break;
case "decore_swampplants":
eEnt = spawn(decore_swampplants);
iClass = TRUE;
break;
case "decore_mushroom":
eEnt = spawn(decore_mushroom);
iClass = TRUE;
break;
case "decore_mushroom2":
eEnt = spawn(decore_mushroom2);
iClass = TRUE;
break;
#endif
default:
eEnt.classname = strValue;
}
break;
*/

View File

@ -17,7 +17,6 @@
../../vgui/include.src
../util.c
init.c
../fade.c
../titles.c
@ -43,8 +42,14 @@ decore.cpp
../../shared/pmove.c
../valve/predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../npc.c
init.c
../../shared/rewolf/items.h
../../shared/valve/weapon_common.h

View File

@ -26,6 +26,21 @@ Comparable to worldspawn in SSQC in that it's mostly used for precaches
*/
void Client_Init(float apilevel, string enginename, float engineversion)
{
}
void Client_InitDone(void)
{
}
void Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");
@ -38,12 +53,3 @@ void Client_Init(float apilevel, string enginename, float engineversion)
BEAM_TRIPMINE = particleeffectnum("beam_tripmine");
}
void Client_InitDone(void)
{
}
void Game_RendererRestarted(string rstr)
{
}

View File

@ -39,7 +39,12 @@
../../shared/pmove.c
../valve/predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../npc.c
init.c

View File

@ -27,6 +27,24 @@ Comparable to worldspawn in SSQC in that it's mostly used for precaches
void
Client_Init(float apilevel, string enginename, float engineversion)
{
}
void
Client_InitDone(void)
{
VGUI_ChooseTeam();
}
void
Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");
@ -49,15 +67,3 @@ Client_Init(float apilevel, string enginename, float engineversion)
BEAM_TRIPMINE = particleeffectnum("beam_tripmine");
}
void
Client_InitDone(void)
{
VGUI_ChooseTeam();
}
void
Game_RendererRestarted(string rstr)
{
}

View File

@ -18,7 +18,6 @@
vgui_chooseteam.cpp
../util.c
init.c
../fade.c
../titles.c
@ -42,7 +41,13 @@ init.c
../../shared/pmove.c
../valve/predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
init.c
../npc.c
../../shared/tfc/items.h

View File

@ -17,23 +17,98 @@
void
Game_Parse_Event(float fHeader)
{
if (fHeader == EV_CHAT) {
switch (fHeader) {
case EV_SPARK:
vector vSparkPos, vSparkAngle;
vSparkPos[0] = readcoord();
vSparkPos[1] = readcoord();
vSparkPos[2] = readcoord();
vSparkAngle[0] = readcoord();
vSparkAngle[1] = readcoord();
vSparkAngle[2] = readcoord();
FX_Spark(vSparkPos, vSparkAngle);
break;
case EV_GIBHUMAN:
vector vGibPos;
vGibPos[0] = readcoord();
vGibPos[1] = readcoord();
vGibPos[2] = readcoord();
FX_GibHuman(vGibPos);
break;
case EV_BLOOD:
vector vBloodPos;
vector vBloodColor;
vBloodPos[0] = readcoord();
vBloodPos[1] = readcoord();
vBloodPos[2] = readcoord();
vBloodColor[0] = readbyte() / 255;
vBloodColor[1] = readbyte() / 255;
vBloodColor[2] = readbyte() / 255;
FX_Blood(vBloodPos, vBloodColor);
break;
case EV_EXPLOSION:
vector vExploPos;
vExploPos[0] = readcoord();
vExploPos[1] = readcoord();
vExploPos[2] = readcoord();
FX_Explosion(vExploPos);
break;
case EV_MODELGIB:
vector vecPos;
vecPos[0] = readcoord();
vecPos[1] = readcoord();
vecPos[2] = readcoord();
vector vSize;
vSize[0] = readcoord();
vSize[1] = readcoord();
vSize[2] = readcoord();
float fStyle = readbyte();
int count = readbyte();
FX_BreakModel(count, vecPos, vSize, [0,0,0], fStyle);
break;
case EV_IMPACT:
int iType;
vector vOrigin, vNormal;
iType = (int)readbyte();
vOrigin[0] = readcoord();
vOrigin[1] = readcoord();
vOrigin[2] = readcoord();
vNormal[0] = readcoord();
vNormal[1] = readcoord();
vNormal[2] = readcoord();
FX_Impact(iType, vOrigin, vNormal);
break;
case EV_CHAT:
float fSender = readbyte();
float fTeam = readbyte();
string sMessage = readstring();
CSQC_Parse_Print(sprintf("%s: %s", getplayerkeyvalue(fSender, "name"), sMessage), PRINT_CHAT);
} else if (fHeader == EV_CHAT_TEAM) {
break;
case EV_CHAT_TEAM:
float fSender2 = readbyte();
float fTeam2 = readbyte();
string sMessage2 = readstring();
CSQC_Parse_Print(sprintf("[TEAM] %s: %s", getplayerkeyvalue(fSender2, "name"), sMessage2), PRINT_CHAT);
} else if (fHeader == EV_CHAT_VOX) {
break;
case EV_CHAT_VOX:
Sound_PlayVOX(readstring());
} else if (fHeader == EV_VIEWMODEL) {
break;
case EV_VIEWMODEL:
View_PlayAnimation(readbyte());
} else if (fHeader == EV_WEAPON_PICKUP) {
break;
case EV_WEAPON_PICKUP:
int w = readbyte();
if (autocvar_cl_autoweaponswitch == 1) {
@ -41,5 +116,6 @@ Game_Parse_Event(float fHeader)
}
HUD_WeaponPickupNotify(w);
break;
}
}

View File

@ -34,6 +34,13 @@ Client_InitDone(void)
void
Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");

View File

@ -17,7 +17,6 @@
../../vgui/include.src
../util.c
../valve/init.c
../fade.c
../titles.c
@ -41,7 +40,14 @@
../../shared/pmove.c
../valve/predict.c
../predict.c
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../valve/init.c
../npc.c
../../shared/valve/items.h

View File

@ -129,7 +129,7 @@ void
CBaseMonster::Gib(void)
{
takedamage = DAMAGE_NO;
Effect_GibHuman(this.origin);
FX_GibHuman(this.origin);
Hide();
}

View File

@ -18,8 +18,8 @@
.float wait;
.float wait;
void Effect_CreateSpark(vector, vector);
void Effect_BreakModel(int, vector, vector, vector, float);
void FX_Spark(vector, vector);
void FX_BreakModel(int, vector, vector, vector, float);
/* This is required because people who use Hammer do awful things
to get their models to update. We get a multitude of juicy

View File

@ -58,7 +58,7 @@ void env_explosion::env_explosion(void)
void env_explosion::Trigger(void)
{
Effect_CreateExplosion(origin);
FX_Explosion(origin);
if (!(spawnflags & ENVEXPLO_NODAMAGE)) {
Damage_Radius(origin, this, m_iMagnitude, m_iMagnitude * 2.5f, TRUE, 0);

View File

@ -59,7 +59,7 @@ void env_spark::CreateSpark(void)
{
int r = floor((random() * spark_snd.length));
sound(this, CHAN_AUTO, spark_snd[r], 1.0f, ATTN_IDLE);
Effect_CreateSpark(self.origin, self.angles);
FX_Spark(self.origin, self.angles);
}
void env_spark::TimedSpark(void)

View File

@ -132,8 +132,8 @@ void func_breakable::Explode(void)
vWorldPos[0] = absmin[0] + (0.5 * (absmax[0] - absmin[0]));
vWorldPos[1] = absmin[1] + (0.5 * (absmax[1] - absmin[1]));
vWorldPos[2] = absmin[2] + (0.5 * (absmax[2] - absmin[2]));
Effect_BreakModel(vlen(size) / 10, absmin, absmax, '0 0 0', m_iMaterial);
Effect_CreateExplosion(vWorldPos);
FX_BreakModel(vlen(size) / 10, absmin, absmax, '0 0 0', m_iMaterial);
FX_Explosion(vWorldPos);
Damage_Radius(vWorldPos, this, m_flExplodeMag, m_flExplodeMag * 2.5f, TRUE, 0);
CBaseTrigger::UseTargets();
CBaseEntity::Hide();
@ -157,7 +157,7 @@ void func_breakable::Death(int body)
think = Explode;
nextthink = time + random(0.0,0.5);
} else {
Effect_BreakModel(vlen(size) / 10, absmin, absmax, '0 0 0', m_iMaterial);
FX_BreakModel(vlen(size) / 10, absmin, absmax, '0 0 0', m_iMaterial);
CBaseTrigger::UseTargets();
CBaseEntity::Hide();
}

View File

@ -25,7 +25,7 @@ CSSingleplayerRules::PlayerDeath(player pl)
if (pl.health < -50) {
pl.health = 0;
Effect_GibHuman(pl.origin);
FX_GibHuman(pl.origin);
return;
}

View File

@ -25,7 +25,14 @@
../../shared/cstrike/player.h
../cstrike/defs.h
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_spark.c
../../shared/cstrike/fx_impact.c
../../shared/cstrike/fx_flashbang.c
../../shared/cstrike/fx_smokenade.c
../cstrike/player.c
../../shared/cstrike/pmove.c
../../shared/pmove.c

View File

@ -19,9 +19,9 @@
var int autocvar_mp_flashlight = TRUE;
var int g_hlbsp_materials = FALSE;
void Effect_Impact(int iType, vector vecPos, vector vNormal);
void Effect_CreateExplosion(vector vecPos);
void Effect_GibHuman(vector vecPos);
void FX_Impact(int iType, vector vecPos, vector vNormal);
void FX_Explosion(vector vecPos);
void FX_GibHuman(vector vecPos);
void Footsteps_Update(void);
void Vox_Broadcast(string sMessage);
void TraceAttack_FireBullets(int , vector, int, vector, int);

View File

@ -62,7 +62,12 @@
../gearbox/monster_drillsergeant.cpp
../gearbox/monster_recruit.cpp
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../valve/player.c
../../shared/valve/pmove.c
../../shared/pmove.c

View File

@ -59,7 +59,12 @@
../valve/monster_turret.cpp
../valve/monster_zombie.cpp
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../valve/player.c
../../shared/valve/pmove.c
../../shared/pmove.c

View File

@ -28,7 +28,7 @@ HLMultiplayerRules::PlayerDeath(player pl)
if (pl.health < -50) {
pl.health = 0;
Effect_GibHuman(pl.origin);
FX_GibHuman(pl.origin);
return;
}

View File

@ -59,7 +59,12 @@
../valve/monster_turret.cpp
../valve/monster_zombie.cpp
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../valve/player.c
../../shared/valve/pmove.c
../../shared/pmove.c

View File

@ -29,7 +29,7 @@ HLMultiplayerRules::PlayerDeath(player pl)
if (pl.health < -50) {
pl.health = 0;
Effect_GibHuman(pl.origin);
FX_GibHuman(pl.origin);
return;
}

View File

@ -31,7 +31,12 @@ monster_human_chopper.cpp
monster_human_demoman.cpp
monster_human_gunman.cpp
monster_human_unarmed.cpp
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../valve/player.c
../../shared/valve/pmove.c
../../shared/pmove.c

View File

@ -33,7 +33,7 @@ SHMultiplayerRules::PlayerDeath(player pl)
if (pl.health < -50) {
pl.health = 0;
Effect_GibHuman(pl.origin);
FX_GibHuman(pl.origin);
return;
}

View File

@ -60,7 +60,12 @@ monster_scientist.cpp
../valve/monster_turret.cpp
../valve/monster_zombie.cpp
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../valve/player.c
../../shared/valve/pmove.c

View File

@ -23,7 +23,13 @@
../../shared/valve/player.cpp
../tfc/defs.h
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
../valve/player.c
../../shared/valve/pmove.c
../../shared/pmove.c

View File

@ -66,7 +66,7 @@ TraceAttack_FireSingle(vector vecPos, vector vAngle, int iDamage, int iWeapon)
}
if (trace_ent.iBleeds == TRUE) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
return;
}
@ -77,25 +77,25 @@ TraceAttack_FireSingle(vector vecPos, vector vAngle, int iDamage, int iWeapon)
switch ((float)hash_get(hashMaterials, tex)) {
case 'G':
case 'V':
Effect_Impact(IMPACT_METAL, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_METAL, trace_endpos, trace_plane_normal);
break;
case 'M':
case 'P':
Effect_Impact(IMPACT_METAL, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_METAL, trace_endpos, trace_plane_normal);
break;
case 'D':
case 'W':
Effect_Impact(IMPACT_WOOD, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_WOOD, trace_endpos, trace_plane_normal);
break;
case 'Y':
Effect_Impact(IMPACT_GLASS, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_GLASS, trace_endpos, trace_plane_normal);
break;
case 'N':
Effect_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
break;
case 'T':
default:
Effect_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
break;
}

View File

@ -30,7 +30,7 @@ HLMultiplayerRules::PlayerDeath(player pl)
if (pl.health < -50) {
pl.health = 0;
Effect_GibHuman(pl.origin);
FX_GibHuman(pl.origin);
return;
}

View File

@ -26,7 +26,7 @@ HLSingleplayerRules::PlayerDeath(player pl)
if (pl.health < -50) {
pl.health = 0;
Effect_GibHuman(pl.origin);
FX_GibHuman(pl.origin);
return;
}

View File

@ -35,7 +35,7 @@ class monster_barney_dead:CBaseEntity
void monster_barney_dead::Gib(void)
{
takedamage = DAMAGE_NO;
Effect_GibHuman(this.origin);
FX_GibHuman(this.origin);
Hide();
}

View File

@ -35,7 +35,7 @@ class monster_hevsuit_dead:CBaseMonster
void monster_hevsuit_dead::Gib(void)
{
takedamage = DAMAGE_NO;
Effect_GibHuman(this.origin);
FX_GibHuman(this.origin);
Hide();
}

View File

@ -35,7 +35,7 @@ class monster_hgrunt_dead:CBaseMonster
void monster_hgrunt_dead::Gib(void)
{
takedamage = DAMAGE_NO;
Effect_GibHuman(this.origin);
FX_GibHuman(this.origin);
Hide();
}

View File

@ -46,7 +46,7 @@ class monster_scientist_dead:CBaseMonster
void monster_scientist_dead::Gib(void)
{
takedamage = DAMAGE_NO;
Effect_GibHuman(this.origin);
FX_GibHuman(this.origin);
Hide();
}

View File

@ -48,7 +48,7 @@ class monster_sitting_scientist:CBaseMonster
void monster_sitting_scientist::Gib(void)
{
takedamage = DAMAGE_NO;
Effect_GibHuman(this.origin);
FX_GibHuman(this.origin);
Hide();
}

View File

@ -58,7 +58,13 @@
../valve/monster_turret.cpp
../valve/monster_zombie.cpp
../../shared/effects.c
../../shared/valve/fx_blood.c
../../shared/valve/fx_breakmodel.c
../../shared/valve/fx_explosion.c
../../shared/valve/fx_gibhuman.c
../../shared/valve/fx_impact.c
../../shared/valve/fx_spark.c
player.c
../../shared/valve/pmove.c
../../shared/pmove.c

View File

@ -38,12 +38,12 @@ int BaseMelee_Attack(void) {
if (trace_ent.takedamage) {
if (trace_ent.iBleeds == TRUE) {
Effect_Impact(IMPACT_FLESH, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_FLESH, trace_endpos, trace_plane_normal);
sound(self, CHAN_WEAPON, sprintf("weapons/knife_hit%d.wav", floor((random() * 4) + 1)), 1, ATTN_NORM);
}
Damage_Apply(trace_ent, self, wptTable[self.weapon].iDamage, FALSE, self.weapon);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
return TRUE;

View File

@ -93,7 +93,7 @@ void WeaponHEGRENADE_PrimaryFire(void) {
#ifdef SERVER
void WeaponHEGRENADE_Throw(void) {
static void WeaponHEGRENADE_Explode(void) {
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self, 100, 512, TRUE);
sound(self, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(self);

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef SERVER
void
FX_Flashbang(entity eTarget)
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_FLASH);
msg_entity = eTarget;
multicast([0,0,0], MULTICAST_ONE);
}
#endif

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
FX_Impact_Init(void)
{
precache_sound("weapons/ric_metal-1.wav");
precache_sound("weapons/ric_metal-2.wav");
precache_sound("weapons/ric_conc-1.wav");
precache_sound("weapons/ric_conc-2.wav");
precache_sound("weapons/knife_hitwall1.wav");
precache_sound("weapons/ric1.wav");
precache_sound("weapons/ric2.wav");
precache_sound("weapons/ric3.wav");
precache_sound("weapons/ric4.wav");
precache_sound("weapons/ric5.wav");
}
void
FX_Impact(int iType, vector vecPos, vector vNormal)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_IMPACT);
WriteByte(MSG_MULTICAST, (float)iType);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
WriteCoord(MSG_MULTICAST, vNormal[0]);
WriteCoord(MSG_MULTICAST, vNormal[1]);
WriteCoord(MSG_MULTICAST, vNormal[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
/* decals */
switch (iType) {
case IMPACT_GLASS:
Decals_Place(vecPos, sprintf("{break%d", floor(random(1,4))));
break;
case IMPACT_MELEE:
Decals_Place(vecPos, sprintf("{shot%d", floor(random(1,6))));
break;
default:
Decals_Place(vecPos, sprintf("{bigshot%d", floor(random(1,6))));
break;
}
switch (iType) {
case IMPACT_MELEE:
pointsound(vecPos, "weapons/knife_hitwall1.wav", 1, ATTN_STATIC);
break;
case IMPACT_EXPLOSION:
break;
case IMPACT_GLASS:
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
break;
case IMPACT_WOOD:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SMOKE_BROWN, vecPos, vNormal, 1);
break;
case IMPACT_METAL:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
break;
case IMPACT_FLESH:
pointparticles(PARTICLE_BLOOD, vecPos, vNormal, 1);
break;
case IMPACT_DEFAULT:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SMOKE_GREY, vecPos, vNormal, 1);
break;
default:
}
switch (iType) {
case IMPACT_METAL:
pointsound(vecPos, sprintf("weapons/ric_metal-%d.wav", floor((random() * 2) + 1)), 1, ATTN_STATIC);
break;
case IMPACT_ROCK:
pointsound(vecPos, sprintf("weapons/ric_conc-%d.wav", floor((random() * 2) + 1)), 1, ATTN_STATIC);
break;
case IMPACT_FLESH:
break;
default:
pointsound(vecPos, sprintf("weapons/ric%d.wav", floor((random() * 5) + 1)), 1, ATTN_STATIC);
break;
}
#endif
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
FX_Smokenade(vector vecPos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_SMOKE);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
msg_entity = self;
multicast([0,0,0], MULTICAST_ALL);
#else
static void Effect_CreateSmoke_Think(void) {
// HACK: This should only ever happen when rounds restart!
// Any way this can go wrong?
if (self.skin < getstatf(STAT_GAMETIME)) {
remove(self);
}
if (self.frame <= 0) {
remove(self);
return;
}
// pointparticles(PARTICLE_SMOKEGRENADE, self.origin, [0,0,0], 1);
self.frame--;
self.nextthink = time + 0.2f;
self.skin = getstatf(STAT_GAMETIME);
}
entity eSmoke = spawn();
setorigin(eSmoke, vecPos);
eSmoke.think = Effect_CreateSmoke_Think;
eSmoke.nextthink = time;
eSmoke.frame = 200;
eSmoke.skin = getstatf(STAT_GAMETIME);
#endif
}

View File

@ -102,7 +102,7 @@ void w_hegrenade_throw(void)
static void hegrenade_explode(void)
{
float dmg = 100;
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_HEGRENADE);
Sound_Play(self, CHAN_BODY, "weapon_hegrenade.explode");
remove(self);

View File

@ -124,7 +124,7 @@ w_knife_primary(void)
}
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
Sound_Play(pl, CHAN_WEAPON, "weapon_knife.hitbody");
} else {
Sound_Play(pl, CHAN_WEAPON, "weapon_knife.hit");
@ -162,7 +162,7 @@ w_knife_secondary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
Sound_Play(pl, CHAN_WEAPON, "weapon_knife.hitbody");
} else {
Sound_Play(pl, CHAN_WEAPON, "weapon_knife.hit");

View File

@ -1,477 +0,0 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CLIENT
string g_hgibs[] = {
"models/gib_b_bone.mdl",
"models/gib_legbone.mdl",
"models/gib_lung.mdl",
"models/gib_skull.mdl",
"models/gib_b_gib.mdl"
};
void
Effects_Init(void)
{
precache_model("sprites/fexplo.spr");
precache_model("sprites/bloodspray.spr");
precache_model("sprites/blood.spr");
precache_model("models/glassgibs.mdl");
precache_model("models/woodgibs.mdl");
precache_model("models/metalplategibs.mdl");
precache_model("models/fleshgibs.mdl");
precache_model("models/ceilinggibs.mdl");
precache_model("models/computergibs.mdl");
precache_model("models/rockgibs.mdl");
precache_model("models/cindergibs.mdl");
precache_sound("debris/bustglass1.wav");
precache_sound("debris/bustglass2.wav");
precache_sound("debris/bustglass3.wav");
precache_sound("debris/bustcrate1.wav");
precache_sound("debris/bustcrate2.wav");
precache_sound("debris/bustcrate3.wav");
precache_sound("debris/bustmetal1.wav");
precache_sound("debris/bustmetal2.wav");
precache_sound("debris/bustflesh1.wav");
precache_sound("debris/bustflesh2.wav");
precache_sound("debris/bustconcrete1.wav");
precache_sound("debris/bustconcrete2.wav");
precache_sound("debris/bustceiling.wav");
precache_sound("weapons/explode3.wav");
precache_sound("weapons/explode4.wav");
precache_sound("weapons/explode5.wav");
precache_sound("buttons/spark1.wav");
precache_sound("buttons/spark2.wav");
precache_sound("buttons/spark3.wav");
precache_sound("buttons/spark4.wav");
precache_sound("buttons/spark5.wav");
precache_sound("buttons/spark6.wav");
precache_sound("weapons/ric1.wav");
precache_sound("weapons/ric2.wav");
precache_sound("weapons/ric3.wav");
precache_sound("weapons/ric4.wav");
precache_sound("weapons/ric5.wav");
precache_sound("common/bodysplat.wav");
for (int i = 0; i < g_hgibs.length; i++) {
precache_model(g_hgibs[i]);
}
// Half-Life only has generic ric1-5
#ifdef OLD_CSTRIKE
precache_sound("weapons/ric_metal-1.wav");
precache_sound("weapons/ric_metal-2.wav");
precache_sound("weapons/ric_conc-1.wav");
precache_sound("weapons/ric_conc-2.wav");
precache_sound("weapons/knife_hitwall1.wav");
#endif
}
#endif
void
Effect_GibHuman(vector pos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_GIBHUMAN);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
msg_entity = __NULL__;
multicast(pos, MULTICAST_PVS);
#else
static void Gib_Remove(void) {
remove(self);
}
static void Gib_Touch(void)
{
Decals_Place(self.origin, sprintf("{blood%d", floor(random(1,9))));
}
for (int i = 0; i < 5; i++) {
vector vel;
vel[0] = random(-128,128);
vel[1] = random(-128,128);
vel[2] = (300 + random() * 64);
entity gibb = spawn();
setmodel(gibb, g_hgibs[i]);
setorigin(gibb, pos);
gibb.movetype = MOVETYPE_BOUNCE;
gibb.solid = SOLID_BBOX;
setsize(gibb, [0,0,0], [0,0,0]);
gibb.velocity = vel;
gibb.avelocity = vectoangles(gibb.velocity);
gibb.think = Gib_Remove;
gibb.touch = Gib_Touch;
gibb.nextthink = time + 5.0f;
gibb.drawmask = MASK_ENGINE;
}
pointsound(pos, "common/bodysplat.wav", 1, ATTN_NORM);
#endif
}
void
Effect_CreateExplosion(vector vecPos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_EXPLOSION);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
Decals_Place(vecPos, sprintf("{scorch%d", floor(random(1,4))));
vecPos[2] += 48;
env_sprite eExplosion = spawn(env_sprite);
setorigin(eExplosion, vecPos);
setmodel(eExplosion, "sprites/fexplo.spr");
sound(eExplosion, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 3) + 3), 1, ATTN_NORM);
//eExplosion.think = Effect_CreateExplosion_Animate;
eExplosion.effects = EF_ADDITIVE;
eExplosion.drawmask = MASK_ENGINE;
eExplosion.maxframe = modelframecount(eExplosion.modelindex);
eExplosion.loops = 0;
eExplosion.framerate = 20;
eExplosion.nextthink = time + 0.05f;
te_explosion(vecPos);
#endif
}
void Effect_CreateBlood(vector pos, vector color) {
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_BLOOD);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
WriteByte(MSG_MULTICAST, color[0] * 255);
WriteByte(MSG_MULTICAST, color[1] * 255);
WriteByte(MSG_MULTICAST, color[2] * 255);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
static void Blood_Touch(void)
{
Decals_Place(self.origin, sprintf("{blood%d", floor(random(1,9))));
self.touch = __NULL__;
}
env_sprite eBlood = spawn(env_sprite);
setorigin(eBlood, pos);
setmodel(eBlood, "sprites/bloodspray.spr");
//eExplosion.think = Effect_CreateExplosion_Animate;
//eBlood.effects = EF_ADDITIVE;
eBlood.drawmask = MASK_ENGINE;
eBlood.maxframe = modelframecount(eBlood.modelindex);
eBlood.loops = 0;
eBlood.scale = 1.0f;
eBlood.colormod = color;
eBlood.framerate = 20;
eBlood.nextthink = time + 0.05f;
for (int i = 0; i < 3; i++) {
env_sprite ePart = spawn(env_sprite);
setorigin(ePart, pos);
setmodel(ePart, "sprites/blood.spr");
ePart.movetype = MOVETYPE_BOUNCE;
ePart.gravity = 0.5f;
ePart.scale = 0.5f;
ePart.drawmask = MASK_ENGINE;
ePart.maxframe = modelframecount(ePart.modelindex);
ePart.loops = 0;
ePart.colormod = color;
ePart.framerate = 15;
ePart.nextthink = time + 0.1f;
ePart.velocity = randomvec() * 64;
ePart.touch = Blood_Touch;
ePart.solid = SOLID_BBOX;
setsize(ePart, [0,0,0], [0,0,0]);
}
#endif
}
void Effect_CreateSpark(vector vecPos, vector vAngle) {
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_SPARK);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
WriteCoord(MSG_MULTICAST, vAngle[0]);
WriteCoord(MSG_MULTICAST, vAngle[1]);
WriteCoord(MSG_MULTICAST, vAngle[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
pointparticles(PARTICLE_SPARK, vecPos, vAngle, 1);
pointsound(vecPos, sprintf("buttons/spark%d.wav", floor(random() * 6) + 1), 1, ATTN_STATIC);
#endif
}
#ifdef OLD_CSTRIKE
#ifdef SERVER
void Effect_CreateFlash(entity eTarget) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_FLASH);
msg_entity = eTarget;
multicast([0,0,0], MULTICAST_ONE);
}
#endif
#endif
#ifdef OLD_CSTRIKE
void Effect_CreateSmoke(vector vecPos) {
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_SMOKE);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
msg_entity = self;
multicast([0,0,0], MULTICAST_ALL);
#else
static void Effect_CreateSmoke_Think(void) {
// HACK: This should only ever happen when rounds restart!
// Any way this can go wrong?
if (self.skin < getstatf(STAT_GAMETIME)) {
remove(self);
}
if (self.frame <= 0) {
remove(self);
return;
}
pointparticles(PARTICLE_SMOKEGRENADE, self.origin, [0,0,0], 1);
self.frame--;
self.nextthink = time + 0.2f;
self.skin = getstatf(STAT_GAMETIME);
}
entity eSmoke = spawn();
setorigin(eSmoke, vecPos);
eSmoke.think = Effect_CreateSmoke_Think;
eSmoke.nextthink = time;
eSmoke.frame = 200;
eSmoke.skin = getstatf(STAT_GAMETIME);
#endif
}
#endif
void Effect_Impact(int iType, vector vecPos, vector vNormal) {
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_IMPACT);
WriteByte(MSG_MULTICAST, (float)iType);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
WriteCoord(MSG_MULTICAST, vNormal[0]);
WriteCoord(MSG_MULTICAST, vNormal[1]);
WriteCoord(MSG_MULTICAST, vNormal[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
/* decals */
switch (iType) {
case IMPACT_GLASS:
Decals_Place(vecPos, sprintf("{break%d", floor(random(1,4))));
break;
case IMPACT_MELEE:
Decals_Place(vecPos, sprintf("{shot%d", floor(random(1,6))));
break;
default:
Decals_Place(vecPos, sprintf("{bigshot%d", floor(random(1,6))));
break;
}
switch (iType) {
case IMPACT_MELEE:
pointsound(vecPos, "weapons/knife_hitwall1.wav", 1, ATTN_STATIC);
break;
case IMPACT_EXPLOSION:
break;
case IMPACT_GLASS:
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
break;
case IMPACT_WOOD:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SMOKE_BROWN, vecPos, vNormal, 1);
break;
case IMPACT_METAL:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
break;
case IMPACT_FLESH:
pointparticles(PARTICLE_BLOOD, vecPos, vNormal, 1);
break;
case IMPACT_DEFAULT:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SMOKE_GREY, vecPos, vNormal, 1);
break;
default:
}
switch (iType) {
#ifdef OLD_CSTRIKE
case IMPACT_METAL:
pointsound(vecPos, sprintf("weapons/ric_metal-%d.wav", floor((random() * 2) + 1)), 1, ATTN_STATIC);
break;
case IMPACT_ROCK:
pointsound(vecPos, sprintf("weapons/ric_conc-%d.wav", floor((random() * 2) + 1)), 1, ATTN_STATIC);
break;
#endif
case IMPACT_FLESH:
break;
default:
pointsound(vecPos, sprintf("weapons/ric%d.wav", floor((random() * 5) + 1)), 1, ATTN_STATIC);
break;
}
#endif
}
void Effect_BreakModel(int count, vector vMins, vector vMaxs, vector vVel, float fStyle) {
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_MODELGIB);
WriteCoord(MSG_MULTICAST, vMins[0]);
WriteCoord(MSG_MULTICAST, vMins[1]);
WriteCoord(MSG_MULTICAST, vMins[2]);
WriteCoord(MSG_MULTICAST, vMaxs[0]);
WriteCoord(MSG_MULTICAST, vMaxs[1]);
WriteCoord(MSG_MULTICAST, vMaxs[2]);
WriteByte(MSG_MULTICAST, fStyle);
WriteByte(MSG_MULTICAST, count);
msg_entity = self;
vector vWorldPos;
vWorldPos[0] = vMins[0] + (0.5 * (vMaxs[0] - vMins[0]));
vWorldPos[1] = vMins[1] + (0.5 * (vMaxs[1] - vMins[1]));
vWorldPos[2] = vMins[2] + (0.5 * (vMaxs[2] - vMins[2]));
multicast(vWorldPos, MULTICAST_PVS);
#else
static void Effect_BreakModel_Remove(void) { remove(self) ; }
float fModelCount;
vector vecPos;
string sModel = "";
switch (fStyle) {
case GSMATERIAL_GLASS:
case GSMATERIAL_GLASS_UNBREAKABLE:
sModel = "models/glassgibs.mdl";
fModelCount = 8;
break;
case GSMATERIAL_WOOD:
sModel = "models/woodgibs.mdl";
fModelCount = 3;
break;
case GSMATERIAL_METAL:
sModel = "models/metalplategibs.mdl";
fModelCount = 13;
break;
case GSMATERIAL_FLESH:
sModel = "models/fleshgibs.mdl";
fModelCount = 4;
break;
case GSMATERIAL_TILE:
sModel = "models/ceilinggibs.mdl";
fModelCount = 4;
break;
case GSMATERIAL_COMPUTER:
sModel = "models/computergibs.mdl";
fModelCount = 15;
break;
case GSMATERIAL_ROCK:
sModel = "models/rockgibs.mdl";
fModelCount = 3;
break;
default:
case GSMATERIAL_CINDER:
sModel = "models/cindergibs.mdl";
fModelCount = 9;
break;
}
vector vWorldPos;
vWorldPos[0] = vMins[0] + (0.5 * (vMaxs[0] - vMins[0]));
vWorldPos[1] = vMins[1] + (0.5 * (vMaxs[1] - vMins[1]));
vWorldPos[2] = vMins[2] + (0.5 * (vMaxs[2] - vMins[2]));
switch (fStyle) {
case GSMATERIAL_GLASS:
pointsound(vWorldPos, sprintf("debris/bustglass%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_WOOD:
pointsound(vWorldPos, sprintf("debris/bustcrate%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_METAL:
case GSMATERIAL_COMPUTER:
pointsound(vWorldPos, sprintf("debris/bustmetal%d.wav", random(1, 3)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_FLESH:
pointsound(vWorldPos, sprintf("debris/bustflesh%d.wav", random(1, 3)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_CINDER:
case GSMATERIAL_ROCK:
pointsound(vWorldPos, sprintf("debris/bustconcrete%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_TILE:
pointsound(vWorldPos, "debris/bustceiling.wav", 1.0f, ATTN_NORM);
break;
}
for (int i = 0; i < count; i++) {
entity eGib = spawn();
eGib.classname = "gib";
vecPos[0] = vMins[0] + (random() * (vMaxs[0] - vMins[0]));
vecPos[1] = vMins[1] + (random() * (vMaxs[1] - vMins[1]));
vecPos[2] = vMins[2] + (random() * (vMaxs[2] - vMins[2]));
setorigin(eGib, vecPos);
setmodel(eGib, sModel);
setcustomskin(eGib, "", sprintf("geomset 0 %f\n", random(1, fModelCount + 1)));
eGib.movetype = MOVETYPE_BOUNCE;
eGib.solid = SOLID_NOT;
eGib.avelocity[0] = random()*600;
eGib.avelocity[1] = random()*600;
eGib.avelocity[2] = random()*600;
eGib.think = Effect_BreakModel_Remove;
eGib.nextthink = time + 10;
if ((fStyle == GSMATERIAL_GLASS) || (fStyle == GSMATERIAL_GLASS_UNBREAKABLE)) {
eGib.effects = EF_ADDITIVE;
}
eGib.drawmask = MASK_ENGINE;
}
#endif
}

View File

@ -153,9 +153,9 @@ w_knife_primary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {

View File

@ -142,7 +142,7 @@ penguin_die(int i)
self.health = 0;
/* now we can explodededededed */
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, 150, 150 * 2.5f, TRUE, WEAPON_PENGUIN);
if (random() < 0.5) {

View File

@ -151,9 +151,9 @@ w_pipewrench_primary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {
@ -228,9 +228,9 @@ w_pipewrench_release(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
#endif
Weapons_ViewAnimation(PIPE_ATTACKBIGHIT);

View File

@ -122,9 +122,9 @@ w_shockrifle_shoothornet(void)
}
if (other.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_CreateSpark(self.origin, trace_plane_normal);
FX_Spark(self.origin, trace_plane_normal);
}
remove(self);
}

View File

@ -117,9 +117,9 @@ w_spanner_primary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {

View File

@ -68,7 +68,7 @@ void w_tnt_throw(void)
static void WeaponFrag_Throw_Explode(void)
{
float dmg = Skill_GetValue("plr_hand_grenade");
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_HANDGRENADE);
sound(self, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(self);

View File

@ -93,7 +93,7 @@ w_bradnailer_shootnail(void)
{
player pl = (player)self;
static void Nail_Touch(void) {
Effect_CreateSpark(self.origin, trace_plane_normal);
FX_Spark(self.origin, trace_plane_normal);
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 15, WEAPON_BRADNAILER, DMG_GENERIC);
Sound_Play(self, CHAN_WEAPON, "weapon_bradnailer.hitbody");

View File

@ -68,7 +68,7 @@ w_nailgun_primary(void)
#ifdef SERVER
static void Nail_Touch(void) {
Effect_CreateSpark(self.origin, trace_plane_normal);
FX_Spark(self.origin, trace_plane_normal);
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 15, WEAPON_NAILGUN, DMG_GENERIC);
if (random() < 0.5) {

View File

@ -117,7 +117,7 @@ void s_pipebomb_detonate(entity master)
for (entity b = world; (b = find(b, ::classname, "satchel"));) {
if (b.owner == master) {
float dmg = Skill_GetValue("plr_satchel");
Effect_CreateExplosion(b.origin);
FX_Explosion(b.origin);
Damage_Radius(b.origin, master, dmg, dmg * 2.5f, TRUE, WEAPON_SATCHEL);
sound(b, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(b);

View File

@ -86,7 +86,7 @@ void w_chainsaw_primary(void)
Weapons_PlaySound(pl, CHAN_WEAPON, "sh/chainsaw_idle2.wav", 1, ATTN_NORM);
pl.w_attack_next = 0.2f;
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
if (trace_ent.takedamage) {
if (trace_ent.iBleeds) {
@ -97,7 +97,7 @@ void w_chainsaw_primary(void)
Damage_Apply(trace_ent, self, 10, WEAPON_CHAINSAW, DMG_BLUNT);
Weapons_PlaySound(pl, CHAN_WEAPON, "sh/chainsaw_cutintoflesh.wav", 1, ATTN_NORM);
} else {
Effect_CreateSpark(trace_endpos, trace_plane_normal);
FX_Spark(trace_endpos, trace_plane_normal);
Weapons_PlaySound(pl, CHAN_WEAPON, "sh/chainsaw_cutinto.wav", 1, ATTN_NORM);
}
pl.w_attack_next = 0.1f;

View File

@ -130,9 +130,9 @@ w_crowbar_primary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {

View File

@ -133,9 +133,9 @@ w_umbrella_primary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {

View File

@ -123,9 +123,9 @@ w_wrench_primary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
FX_Blood_Init(void)
{
precache_model("sprites/bloodspray.spr");
precache_model("sprites/blood.spr");
}
void
FX_Blood(vector pos, vector color)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_BLOOD);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
WriteByte(MSG_MULTICAST, color[0] * 255);
WriteByte(MSG_MULTICAST, color[1] * 255);
WriteByte(MSG_MULTICAST, color[2] * 255);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
static void Blood_Touch(void)
{
Decals_Place(self.origin, sprintf("{blood%d", floor(random(1,9))));
self.touch = __NULL__;
}
env_sprite eBlood = spawn(env_sprite);
setorigin(eBlood, pos);
setmodel(eBlood, "sprites/bloodspray.spr");
//eExplosion.think = FX_Explosion_Animate;
//eBlood.effects = EF_ADDITIVE;
eBlood.drawmask = MASK_ENGINE;
eBlood.maxframe = modelframecount(eBlood.modelindex);
eBlood.loops = 0;
eBlood.scale = 1.0f;
eBlood.colormod = color;
eBlood.framerate = 20;
eBlood.nextthink = time + 0.05f;
for (int i = 0; i < 3; i++) {
env_sprite ePart = spawn(env_sprite);
setorigin(ePart, pos);
setmodel(ePart, "sprites/blood.spr");
ePart.movetype = MOVETYPE_BOUNCE;
ePart.gravity = 0.5f;
ePart.scale = 0.5f;
ePart.drawmask = MASK_ENGINE;
ePart.maxframe = modelframecount(ePart.modelindex);
ePart.loops = 0;
ePart.colormod = color;
ePart.framerate = 15;
ePart.nextthink = time + 0.1f;
ePart.velocity = randomvec() * 64;
ePart.touch = Blood_Touch;
ePart.solid = SOLID_BBOX;
setsize(ePart, [0,0,0], [0,0,0]);
}
#endif
}

View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
FX_BreakModel_Init(void)
{
precache_model("models/glassgibs.mdl");
precache_model("models/woodgibs.mdl");
precache_model("models/metalplategibs.mdl");
precache_model("models/fleshgibs.mdl");
precache_model("models/ceilinggibs.mdl");
precache_model("models/computergibs.mdl");
precache_model("models/rockgibs.mdl");
precache_model("models/cindergibs.mdl");
precache_sound("debris/bustglass1.wav");
precache_sound("debris/bustglass2.wav");
precache_sound("debris/bustglass3.wav");
precache_sound("debris/bustcrate1.wav");
precache_sound("debris/bustcrate2.wav");
precache_sound("debris/bustcrate3.wav");
precache_sound("debris/bustmetal1.wav");
precache_sound("debris/bustmetal2.wav");
precache_sound("debris/bustflesh1.wav");
precache_sound("debris/bustflesh2.wav");
precache_sound("debris/bustconcrete1.wav");
precache_sound("debris/bustconcrete2.wav");
precache_sound("debris/bustceiling.wav");
}
void
FX_BreakModel(int count, vector vMins, vector vMaxs, vector vVel, float fStyle)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_MODELGIB);
WriteCoord(MSG_MULTICAST, vMins[0]);
WriteCoord(MSG_MULTICAST, vMins[1]);
WriteCoord(MSG_MULTICAST, vMins[2]);
WriteCoord(MSG_MULTICAST, vMaxs[0]);
WriteCoord(MSG_MULTICAST, vMaxs[1]);
WriteCoord(MSG_MULTICAST, vMaxs[2]);
WriteByte(MSG_MULTICAST, fStyle);
WriteByte(MSG_MULTICAST, count);
msg_entity = self;
vector vWorldPos;
vWorldPos[0] = vMins[0] + (0.5 * (vMaxs[0] - vMins[0]));
vWorldPos[1] = vMins[1] + (0.5 * (vMaxs[1] - vMins[1]));
vWorldPos[2] = vMins[2] + (0.5 * (vMaxs[2] - vMins[2]));
multicast(vWorldPos, MULTICAST_PVS);
#else
static void FX_BreakModel_Remove(void) { remove(self) ; }
float fModelCount;
vector vecPos;
string sModel = "";
switch (fStyle) {
case GSMATERIAL_GLASS:
case GSMATERIAL_GLASS_UNBREAKABLE:
sModel = "models/glassgibs.mdl";
fModelCount = 8;
break;
case GSMATERIAL_WOOD:
sModel = "models/woodgibs.mdl";
fModelCount = 3;
break;
case GSMATERIAL_METAL:
sModel = "models/metalplategibs.mdl";
fModelCount = 13;
break;
case GSMATERIAL_FLESH:
sModel = "models/fleshgibs.mdl";
fModelCount = 4;
break;
case GSMATERIAL_TILE:
sModel = "models/ceilinggibs.mdl";
fModelCount = 4;
break;
case GSMATERIAL_COMPUTER:
sModel = "models/computergibs.mdl";
fModelCount = 15;
break;
case GSMATERIAL_ROCK:
sModel = "models/rockgibs.mdl";
fModelCount = 3;
break;
default:
case GSMATERIAL_CINDER:
sModel = "models/cindergibs.mdl";
fModelCount = 9;
break;
}
vector vWorldPos;
vWorldPos[0] = vMins[0] + (0.5 * (vMaxs[0] - vMins[0]));
vWorldPos[1] = vMins[1] + (0.5 * (vMaxs[1] - vMins[1]));
vWorldPos[2] = vMins[2] + (0.5 * (vMaxs[2] - vMins[2]));
switch (fStyle) {
case GSMATERIAL_GLASS:
pointsound(vWorldPos, sprintf("debris/bustglass%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_WOOD:
pointsound(vWorldPos, sprintf("debris/bustcrate%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_METAL:
case GSMATERIAL_COMPUTER:
pointsound(vWorldPos, sprintf("debris/bustmetal%d.wav", random(1, 3)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_FLESH:
pointsound(vWorldPos, sprintf("debris/bustflesh%d.wav", random(1, 3)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_CINDER:
case GSMATERIAL_ROCK:
pointsound(vWorldPos, sprintf("debris/bustconcrete%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_TILE:
pointsound(vWorldPos, "debris/bustceiling.wav", 1.0f, ATTN_NORM);
break;
}
for (int i = 0; i < count; i++) {
entity eGib = spawn();
eGib.classname = "gib";
vecPos[0] = vMins[0] + (random() * (vMaxs[0] - vMins[0]));
vecPos[1] = vMins[1] + (random() * (vMaxs[1] - vMins[1]));
vecPos[2] = vMins[2] + (random() * (vMaxs[2] - vMins[2]));
setorigin(eGib, vecPos);
setmodel(eGib, sModel);
setcustomskin(eGib, "", sprintf("geomset 0 %f\n", random(1, fModelCount + 1)));
eGib.movetype = MOVETYPE_BOUNCE;
eGib.solid = SOLID_NOT;
eGib.avelocity[0] = random()*600;
eGib.avelocity[1] = random()*600;
eGib.avelocity[2] = random()*600;
eGib.think = FX_BreakModel_Remove;
eGib.nextthink = time + 10;
if ((fStyle == GSMATERIAL_GLASS) || (fStyle == GSMATERIAL_GLASS_UNBREAKABLE)) {
eGib.effects = EF_ADDITIVE;
}
eGib.drawmask = MASK_ENGINE;
}
#endif
}

56
src/shared/valve/fx_explosion.c Executable file
View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
FX_Explosion_Init(void)
{
precache_sound("weapons/explode3.wav");
precache_sound("weapons/explode4.wav");
precache_sound("weapons/explode5.wav");
precache_model("sprites/fexplo.spr");
}
void
FX_Explosion(vector vecPos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_EXPLOSION);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
Decals_Place(vecPos, sprintf("{scorch%d", floor(random(1,4))));
vecPos[2] += 48;
env_sprite eExplosion = spawn(env_sprite);
setorigin(eExplosion, vecPos);
setmodel(eExplosion, "sprites/fexplo.spr");
sound(eExplosion, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 3) + 3), 1, ATTN_NORM);
//eExplosion.think = FX_Explosion_Animate;
eExplosion.effects = EF_ADDITIVE;
eExplosion.drawmask = MASK_ENGINE;
eExplosion.maxframe = modelframecount(eExplosion.modelindex);
eExplosion.loops = 0;
eExplosion.framerate = 20;
eExplosion.nextthink = time + 0.05f;
te_explosion(vecPos);
#endif
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
string g_hgibs[] = {
"models/gib_b_bone.mdl",
"models/gib_legbone.mdl",
"models/gib_lung.mdl",
"models/gib_skull.mdl",
"models/gib_b_gib.mdl"
};
void
FX_GibHuman_Init(void)
{
precache_model("models/gib_b_bone.mdl");
precache_model("models/gib_legbone.mdl");
precache_model("models/gib_lung.mdl");
precache_model("models/gib_skull.mdl");
precache_model("models/gib_b_gib.mdl");
precache_sound("common/bodysplat.wav");
}
void
FX_GibHuman(vector pos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_GIBHUMAN);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
msg_entity = __NULL__;
multicast(pos, MULTICAST_PVS);
#else
static void Gib_Remove(void) {
remove(self);
}
static void Gib_Touch(void)
{
Decals_Place(self.origin, sprintf("{blood%d", floor(random(1,9))));
}
for (int i = 0; i < 5; i++) {
vector vel;
vel[0] = random(-128,128);
vel[1] = random(-128,128);
vel[2] = (300 + random() * 64);
entity gibb = spawn();
setmodel(gibb, g_hgibs[i]);
setorigin(gibb, pos);
gibb.movetype = MOVETYPE_BOUNCE;
gibb.solid = SOLID_BBOX;
setsize(gibb, [0,0,0], [0,0,0]);
gibb.velocity = vel;
gibb.avelocity = vectoangles(gibb.velocity);
gibb.think = Gib_Remove;
gibb.touch = Gib_Touch;
gibb.nextthink = time + 5.0f;
gibb.drawmask = MASK_ENGINE;
}
pointsound(pos, "common/bodysplat.wav", 1, ATTN_NORM);
#endif
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
FX_Impact_Init(void)
{
precache_sound("weapons/ric1.wav");
precache_sound("weapons/ric2.wav");
precache_sound("weapons/ric3.wav");
precache_sound("weapons/ric4.wav");
precache_sound("weapons/ric5.wav");
}
void
FX_Impact(int iType, vector vecPos, vector vNormal)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_IMPACT);
WriteByte(MSG_MULTICAST, (float)iType);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
WriteCoord(MSG_MULTICAST, vNormal[0]);
WriteCoord(MSG_MULTICAST, vNormal[1]);
WriteCoord(MSG_MULTICAST, vNormal[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
/* decals */
switch (iType) {
case IMPACT_GLASS:
Decals_Place(vecPos, sprintf("{break%d", floor(random(1,4))));
break;
case IMPACT_MELEE:
Decals_Place(vecPos, sprintf("{shot%d", floor(random(1,6))));
break;
default:
Decals_Place(vecPos, sprintf("{bigshot%d", floor(random(1,6))));
break;
}
switch (iType) {
case IMPACT_EXPLOSION:
break;
case IMPACT_GLASS:
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
break;
case IMPACT_WOOD:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SMOKE_BROWN, vecPos, vNormal, 1);
break;
case IMPACT_METAL:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
break;
case IMPACT_FLESH:
pointparticles(PARTICLE_BLOOD, vecPos, vNormal, 1);
break;
case IMPACT_DEFAULT:
pointparticles(PARTICLE_SPARK, vecPos, vNormal, 1);
pointparticles(PARTICLE_PIECES_BLACK, vecPos, vNormal, 1);
pointparticles(PARTICLE_SMOKE_GREY, vecPos, vNormal, 1);
break;
default:
}
switch (iType) {
case IMPACT_FLESH:
break;
default:
pointsound(vecPos, sprintf("weapons/ric%d.wav", floor((random() * 5) + 1)), 1, ATTN_STATIC);
break;
}
#endif
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
FX_Spark_Init(void)
{
precache_sound("buttons/spark1.wav");
precache_sound("buttons/spark2.wav");
precache_sound("buttons/spark3.wav");
precache_sound("buttons/spark4.wav");
precache_sound("buttons/spark5.wav");
precache_sound("buttons/spark6.wav");
}
void
FX_Spark(vector pos, vector ang)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_SPARK);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
WriteCoord(MSG_MULTICAST, ang[0]);
WriteCoord(MSG_MULTICAST, ang[1]);
WriteCoord(MSG_MULTICAST, ang[2]);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
pointparticles(PARTICLE_SPARK, pos, ang, 1);
pointsound(pos, sprintf("buttons/spark%d.wav", floor(random() * 6) + 1), 1, ATTN_STATIC);
#endif
}

View File

@ -119,7 +119,7 @@ void Crossbolt_Touch(void) {
/* explode mode, multiplayer */
if (self.weapon) {
float dmg = Skill_GetValue("plr_xbow_bolt_monster");
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_CROSSBOW);
if (random() < 0.5) {
sound(self, 1, "weapons/explode3.wav", 1.0f, ATTN_NORM);
@ -132,7 +132,7 @@ void Crossbolt_Touch(void) {
/* walls, etc. */
if (other.takedamage != DAMAGE_YES) {
Effect_CreateSpark(self.origin, trace_plane_normal);
FX_Spark(self.origin, trace_plane_normal);
Sound_Play(self, 1, "weapon_crossbow.hit");
remove(self);
return;
@ -143,9 +143,9 @@ void Crossbolt_Touch(void) {
Sound_Play(self, 1, "weapon_crossbow.hitbody");
if (other.iBleeds == FALSE) {
Effect_CreateSpark(self.origin, trace_plane_normal);
FX_Spark(self.origin, trace_plane_normal);
} else {
Effect_CreateBlood(self.origin, [1,0,0]);
FX_Blood(self.origin, [1,0,0]);
}
remove(self);
}

View File

@ -137,9 +137,9 @@ w_crowbar_primary(void)
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [1,0,0]);
FX_Blood(trace_endpos, [1,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {

View File

@ -84,7 +84,7 @@ void w_handgrenade_throw(void)
static void WeaponFrag_Throw_Explode(void)
{
float dmg = Skill_GetValue("plr_hand_grenade");
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_HANDGRENADE);
sound(self, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(self);

View File

@ -194,7 +194,7 @@ w_mp5_secondary(void)
#else
static void Grenade_ExplodeTouch(void) {
float dmg = Skill_GetValue("plr_9mmAR_grenade");
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_MP5);
if (random() < 0.5) {

View File

@ -125,7 +125,7 @@ void w_rpg_primary(void)
#else
static void Rocket_Touch(void) {
float dmg = Skill_GetValue("plr_rpg");
Effect_CreateExplosion(self.origin);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_RPG);
sound(self, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(self);

View File

@ -127,7 +127,7 @@ void s_satchel_detonate(entity master)
for (entity b = world; (b = find(b, ::classname, "satchel"));) {
if (b.owner == master) {
float dmg = Skill_GetValue("plr_satchel");
Effect_CreateExplosion(b.origin);
FX_Explosion(b.origin);
Damage_Radius(b.origin, master, dmg, dmg * 2.5f, TRUE, WEAPON_SATCHEL);
sound(b, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(b);

View File

@ -85,7 +85,7 @@ monster_snark::customphysics(void)
if (trace_ent.takedamage == DAMAGE_YES) {
Sound_Play(self, CHAN_BODY, "weapon_snark.deploy");
Damage_Apply(trace_ent, self.goalentity, Skill_GetValue("snark_dmg_bite"), WEAPON_SNARK, DMG_GENERIC);
Effect_CreateBlood(self.origin + [0,0,16], [1,0,0]);
FX_Blood(self.origin + [0,0,16], [1,0,0]);
}
if (self.aiment.health <= 0) {
@ -101,7 +101,7 @@ monster_snark::Death(int i)
{
float dmg = Skill_GetValue("snark_dmg_pop");
Damage_Radius(origin, goalentity, dmg, dmg * 2.5f, TRUE, WEAPON_SNARK);
Effect_CreateBlood(self.origin + [0,0,16], [203,183,15] / 255);
FX_Blood(self.origin + [0,0,16], [203,183,15] / 255);
Sound_Play(self, CHAN_VOICE, "weapon_snark.die");
Sound_Play(self, CHAN_BODY, "weapon_snark.blast");
self.customphysics = __NULL__;

View File

@ -68,7 +68,7 @@ monster_tripmine::Trip(int walkthrough)
Pain = __NULL__;
takedamage = DAMAGE_NO;
dmg = Skill_GetValue("plr_tripmine");
Effect_CreateExplosion(origin);
FX_Explosion(origin);
Damage_Radius(origin, real_owner, dmg, dmg * 2.5f, TRUE, WEAPON_TRIPMINE);
sound(this, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(this);