Add support for Source styled surfaceproperties.txt definitions, which

is incorporated into func_breakable/pushable already. Mods can now control
material/surface properties without code.
This commit is contained in:
Marco Cawthorne 2021-10-15 18:06:04 +02:00
parent 736ecb61f8
commit 70fe95e5a7
Signed by: eukara
GPG Key ID: C196CD8BA993248A
19 changed files with 833 additions and 331 deletions

View File

@ -0,0 +1,76 @@
"PropData.txt"
{
"gs_material_glass"
{
"breakable_model" "gibs_glass"
}
"gs_material_wood"
{
"breakable_model" "gibs_wood"
}
"gs_material_metal"
{
"breakable_model" "gibs_metalplate"
}
"gs_material_flesh"
{
"breakable_model" "gibs_flesh"
}
"gs_material_cinderblock"
{
"breakable_model" "gibs_cinder"
}
"gs_material_tile"
{
"breakable_model" "gibs_ceiling"
}
"gs_material_computer"
{
"breakable_model" "gibs_computer"
}
"gs_material_unbreakableglass"
{
"breakable_model" "gibs_glass"
}
"gs_material_rocks"
{
"breakable_model" "gibs_rock"
}
"BreakableModels"
{
"gibs_glass"
{
"models/glassgibs.mdl" "5.0"
}
"gibs_wood"
{
"models/woodgibs.mdl" "5.0"
}
"gibs_metalplate"
{
"models/metalplategibs.mdl" "5.0"
}
"gibs_flesh"
{
"models/fleshgibs.mdl" "5.0"
}
"gibs_ceiling"
{
"models/ceilinggibs.mdl" "5.0"
}
"gibs_computer"
{
"models/computergibs.mdl" "5.0"
}
"gibs_rock"
{
"models/rockgibs.mdl" "5.0"
}
"gibs_cinder"
{
"models/cindergibs.mdl" "5.0"
}
}
}

View File

@ -0,0 +1,53 @@
gs_material_glass
{
gamematerial Y
bulletimpact "func_breakable.impact_glass"
}
gs_material_wood
{
gamematerial W
bulletimpact "func_breakable.impact_wood"
}
gs_material_metal
{
gamematerial M
bulletimpact "func_breakable.impact_metal"
}
gs_material_flesh
{
gamematerial F
bulletimpact "func_breakable.impact_flesh"
}
gs_material_cinderblock
{
gamematerial C
bulletimpact "func_breakable.impact_cinderblock"
}
gs_material_tile
{
gamematerial T
bulletimpact "func_breakable.impact_tile"
}
gs_material_computer
{
gamematerial P
bulletimpact "func_breakable.impact_computer"
}
gs_material_unbreakableglass
{
gamematerial Y
bulletimpact "func_breakable.impact_glassunbreakable"
}
gs_material_rocks
{
gamematerial C
bulletimpact "func_breakable.impact_rock"
}

View File

@ -5,7 +5,6 @@
#includelist
baseentity.h
decals.h
materials.h
client/defs.h
client/basefx.qc
shared/baseentity.qc

View File

@ -1,51 +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.
*/
/* submodel materials */
enum
{
GSMATERIAL_GLASS,
GSMATERIAL_WOOD,
GSMATERIAL_METAL,
GSMATERIAL_FLESH,
GSMATERIAL_CINDER,
GSMATERIAL_TILE,
GSMATERIAL_COMPUTER,
GSMATERIAL_GLASS_UNBREAKABLE,
GSMATERIAL_ROCK,
GSMATERIAL_NONE
};
/* straight from q3map2 */
#define SURF_NODAMAGE 0x1i /* never give falling damage */
#define SURF_SLICK 0x2i /* effects game physics */
#define SURF_SKY 0x4i /* lighting from environment map */
#define SURF_LADDER 0x8i /* climb this surface */
#define SURF_NOIMPACT 0x10i /* don't make missile explosions */
#define SURF_NOMARKS 0x20i /* don't leave missile marks */
#define SURF_Q3FLESH 0x40i /* make flesh sounds and effects */
#define SURF_NODRAW 0x80i /* don't generate a drawsurface at all */
#define SURF_HINT 0x100i /* make a primary bsp splitter */
#define SURF_SKIP 0x200i /* completely ignore, allowing non-closed brushes */
#define SURF_NOLIGHTMAP 0x400i /* surface doesn't need a lightmap */
#define SURF_POINTLIGHT 0x800i /* generate lighting info at vertexes */
#define SURF_METALSTEPS 0x1000i /* clanking footsteps */
#define SURF_NOSTEPS 0x2000i /* no footstep sounds */
#define SURF_NONSOLID 0x4000i /* don't collide against curves with this set */
#define SURF_LIGHTFILTER 0x8000i /* act as a light filter during q3map -light */
#define SURF_ALPHASHADOW 0x10000i /* do per-pixel light shadow casting in q3map */
#define SURF_NODLIGHT 0x20000i /* don't dlight even if solid (solid lava, skies) */
#define SURF_DUST 0x40000i /* leave a dust trail when walking on this surface */

View File

@ -5,7 +5,6 @@
#includelist
baseentity.h
decals.h
materials.h
shared/baseentity.qc
server/baseoutput.qc
server/basetrigger.qc

View File

@ -196,7 +196,7 @@ CBasePhysics::Death(void)
string gibeffect = GetPropData(PROPINFO_BREAKMODEL);
int breakcount = GetPropData(PROPINFO_BREAKCOUNT);
BreakModel_Spawn(origin, [0,0,0], [100,100], 100, breakcount, gibeffect);
BreakModel_Spawn(absmin, absmax, [0,0,0], 100, breakcount, gibeffect);
/* handle explosions */
float flExplodeMag, flExplodeRad;

View File

@ -103,6 +103,18 @@ const string funcbreakable_objtable[] = {
};
#endif
const string funcbreakable_surftable[] = {
"gs_material_glass",
"gs_material_wood",
"gs_material_metal",
"gs_material_flesh",
"gs_material_cinderblock",
"gs_material_tile",
"gs_material_computer",
"gs_material_unbreakableglass",
"gs_material_rocks"
};
class func_breakable:CBaseTrigger
{
float m_flDelay;
@ -131,36 +143,8 @@ func_breakable::Pain(void)
if (spawnflags & SF_TRIGGER) {
return;
}
if (serverkeyfloat("*bspversion") != BSPVER_HL) {
return;
}
switch (m_iMaterial) {
case BREAKMT_GLASS:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_glass");
break;
case BREAKMT_COMPUTER:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_computer");
break;
case BREAKMT_GLASS_UNBREAKABLE:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_glassunbreakable");
break;
case BREAKMT_WOOD:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_wood");
break;
case BREAKMT_METAL:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_metal");
break;
case BREAKMT_FLESH:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_flesh");
break;
case BREAKMT_CINDER:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_cinder");
break;
case BREAKMT_ROCK:
Sound_Play(this, CHAN_VOICE, "func_breakable.impact_rock");
break;
}
Sound_Play(this, CHAN_VOICE, SurfData_GetInfo(m_iMaterial, SURFDATA_SND_BULLETIMPACT));
}
@ -168,7 +152,7 @@ void
func_breakable::Explode(void)
{
vector rp = absmin + (0.5 * (absmax - absmin));
FX_BreakModel(vlen(size) / 10, absmin, absmax, [0,0,0], m_iMaterial);
FX_BreakModel(vlen(size) / 10, absmin, absmax, [0,0,0], SurfData_GetInfo(m_iMaterial, SURFDATA_MATERIAL));
FX_Explosion(rp);
Damage_Radius(rp, this, m_flExplodeMag, m_flExplodeRad, TRUE, 0);
UseTargets(this, TRIG_TOGGLE, 0.0f); /* delay... ignored. */
@ -220,7 +204,7 @@ func_breakable::Death(void)
think = Explode;
nextthink = time + random(0.0,0.5);
} else {
FX_BreakModel(vlen(size) / 10, absmin, absmax, [0,0,0], m_iMaterial);
FX_BreakModel(vlen(size) / 10, absmin, absmax, [0,0,0], SurfData_GetInfo(m_iMaterial, SURFDATA_MATERIAL));
/* TODO: ability to have whoever destroyed the crate be the activator */
UseTargets(this, TRIG_TOGGLE, 0.0f);
Hide();
@ -296,15 +280,15 @@ func_breakable::Respawn(void)
health = GetSpawnHealth();
if (!health) {
health = 15;
}
if (HasPropData()) {
health = GetPropData(PROPINFO_HEALTH);
m_flExplodeMag = GetPropData(PROPINFO_EXPLOSIVE_DMG);
m_flExplodeRad = GetPropData(PROPINFO_EXPLOSIVE_RADIUS);
}
if (!health) {
health = 15;
}
}
void
@ -312,7 +296,8 @@ func_breakable::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "material":
m_iMaterial = stoi(strValue);
float id = stof(strValue);
SurfData_SetStage(funcbreakable_surftable[id]);
break;
case "explodemagnitude":
m_flExplodeMag = stof(strValue);
@ -341,35 +326,21 @@ func_breakable::SpawnKey(string strKey, string strValue)
void
func_breakable::func_breakable(void)
{
/* func_breakable defaults to glass */
if (classname == "func_breakable") {
PropData_SetStage(funcbreakable_surftable[0]);
SurfData_SetStage(funcbreakable_surftable[0]);
} else {
PropData_SetStage(funcbreakable_surftable[1]);
SurfData_SetStage(funcbreakable_surftable[1]);
}
/* proper init */
CBaseTrigger::CBaseTrigger();
/* contrary to what some map designers think, angles are not supported */
GetSpawnAngles() = angles = [0,0,0];
switch (m_iMaterial) {
case BREAKMT_GLASS:
Sound_Precache("func_breakable.impact_glass");
break;
case BREAKMT_COMPUTER:
Sound_Precache("func_breakable.impact_computer");
break;
case BREAKMT_GLASS_UNBREAKABLE:
Sound_Precache("func_breakable.impact_glassunbreakable");
break;
case BREAKMT_WOOD:
Sound_Precache("func_breakable.impact_wood");
break;
case BREAKMT_METAL:
Sound_Precache("func_breakable.impact_metal");
break;
case BREAKMT_FLESH:
Sound_Precache("func_breakable.impact_flesh");
break;
case BREAKMT_CINDER:
Sound_Precache("func_breakable.impact_cinder");
break;
case BREAKMT_ROCK:
Sound_Precache("func_breakable.impact_rock");
break;
}
/* precache impact sound */
Sound_Precache(SurfData_GetInfo(m_iMaterial, SURFDATA_SND_BULLETIMPACT));
}

View File

@ -921,6 +921,18 @@ CBaseEntity::GetPropData(int type)
{
return Prop_GetInfo(m_iPropData, type);
}
int
CBaseEntity::HasSurfaceData(void)
{
return (m_iMaterial != -1) ? TRUE : FALSE;
}
__variant
CBaseEntity::GetSurfaceData(int type)
{
return SurfData_GetInfo(m_iMaterial, type);
}
#endif
/*
@ -940,6 +952,7 @@ CBaseEntity::CBaseEntity(void)
return;
m_iPropData = -1;
m_iMaterial = -1;
/* Not in Deathmatch */
if (spawnflags & 2048) {
@ -959,6 +972,7 @@ CBaseEntity::CBaseEntity(void)
/* tokenization complete, now we can load propdata */
m_iPropData = PropData_Finish();
m_iMaterial = SurfData_Finish();
m_oldAngle = angles;
m_oldOrigin = origin;

View File

@ -388,6 +388,7 @@ init(float prevprogs)
iprint("Initializing Server-Module");
Plugin_Init();
PropData_Init();
SurfData_Init();
}
/*

View File

@ -14,61 +14,6 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* HLBSP materials.txt character id's */
//#define MATID_UNUSED1 'A'
#define MATID_BLOODYFLESH 'B'
#define MATID_CONCRETE 'C'
#define MATID_DIRT 'D'
//#define MATID_UNUSED2 'E'
#define MATID_FLESH 'F'
#define MATID_GRATE 'G'
#define MATID_ALIEN 'H'
//#define MATID_UNUSED3 'I'
//#define MATID_GRASS 'J'
//#define MATID_PLASTIC 'L'
#define MATID_METAL 'M'
#define MATID_FOLIAGE 'O'
#define MATID_COMPUTER 'P'
//#define MATID_ASPHALT 'Q'
//#define MATID_BRICK 'R'
#define MATID_SLOSH 'S'
#define MATID_TILE 'T'
#define MATID_CARDBOARD 'U'
#define MATID_VENT 'V'
#define MATID_WOOD 'W'
//#define MATID_UNUSED4 'X'
#define MATID_GLASS 'Y'
//#define MATID_UNUSED5 'Z'
/* CS defines snow as 'N' on GoldSrc, whereas in Source it's reserved for sand */
#ifdef CSTRIKE
#define MATID_SNOW 'N'
#define MATID_SAND 'K'
#else
#define MATID_SNOW 'K'
#define MATID_SAND 'N'
#endif
/* other notes:
in The Wastes (2003) 'I' is sand, 'U' is plaster,
'R' is rust.
*/
/* modern additions, not implemented yet */
#define MATID_CLAY 1
#define MATID_PLASTER 2
#define MATID_ROCK 3
#define MATID_RUBBER 4
#define MATID_SHEETROCK 5
#define MATID_CLOTH 6
#define MATID_CARPET 7
#define MATID_PAPER 8
#define MATID_UPHOLSTERY 9
#define MATID_PUDDLE 10
#define MATID_MUD 11
#define MATID_SANDBARREL 12
void Footsteps_Init(void);
void Footsteps_HLBSP(base_player target);
void Footsteps_VVBSP(base_player target);

View File

@ -17,6 +17,12 @@
/* FIXME: world.... sigh, we should box this into a worldspawn class */
.string materials_file;
float
HLMaterials_Fetch(string tex_name)
{
return (float)hash_get(hashMaterials, tex_name);
}
void
HLMaterials_Load(string filename)
{

View File

@ -36,124 +36,7 @@ TraceAttack_Apply(entity eAttacker, int iWeapon)
void
TraceAttack_ImpactWorld(void)
{
string tex_name;
float surf;
switch (serverkeyfloat("*bspversion")) {
case BSPVER_HL:
surf = getsurfacenearpoint(trace_ent, trace_endpos);
tex_name = Materials_FixName(getsurfacetexture(trace_ent, surf));
/* our hashtable is the key to all this */
switch ((float)hash_get(hashMaterials, tex_name)) {
case MATID_ALIEN:
FX_Impact(IMPACT_ALIEN, trace_endpos, trace_plane_normal);
break;
case MATID_COMPUTER:
FX_Impact(IMPACT_COMPUTER, trace_endpos, trace_plane_normal);
break;
case MATID_CONCRETE:
FX_Impact(IMPACT_CONCRETE, trace_endpos, trace_plane_normal);
break;
case MATID_DIRT:
FX_Impact(IMPACT_DIRT, trace_endpos, trace_plane_normal);
break;
case MATID_BLOODYFLESH:
case MATID_FLESH:
FX_Impact(IMPACT_FLESH, trace_endpos, trace_plane_normal);
break;
case MATID_FOLIAGE:
FX_Impact(IMPACT_FOLIAGE, trace_endpos, trace_plane_normal);
break;
case MATID_GLASS:
FX_Impact(IMPACT_GLASS, trace_endpos, trace_plane_normal);
break;
case MATID_GRATE:
FX_Impact(IMPACT_GRATE, trace_endpos, trace_plane_normal);
break;
case MATID_METAL:
FX_Impact(IMPACT_METAL, trace_endpos, trace_plane_normal);
break;
case MATID_SAND:
FX_Impact(IMPACT_SAND, trace_endpos, trace_plane_normal);
break;
case MATID_SLOSH:
FX_Impact(IMPACT_SLOSH, trace_endpos, trace_plane_normal);
break;
case MATID_SNOW:
FX_Impact(IMPACT_SNOW, trace_endpos, trace_plane_normal);
break;
case MATID_TILE:
FX_Impact(IMPACT_TILE, trace_endpos, trace_plane_normal);
break;
case MATID_VENT:
FX_Impact(IMPACT_VENT, trace_endpos, trace_plane_normal);
break;
case MATID_WOOD:
FX_Impact(IMPACT_WOOD, trace_endpos, trace_plane_normal);
break;
default:
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
break;
}
break;
case BSPVER_Q3: /* Q3 */
case BSPVER_RTCW: /* RtCW */
case BSPVER_RBSP: /* RFVBSP */
switch (trace_surfaceflagsi) {
case SURF_ALIEN:
FX_Impact(IMPACT_ALIEN, trace_endpos, trace_plane_normal);
break;
case SURF_COMPUTER:
FX_Impact(IMPACT_COMPUTER, trace_endpos, trace_plane_normal);
break;
case SURF_CONCRETE:
FX_Impact(IMPACT_CONCRETE, trace_endpos, trace_plane_normal);
break;
case SURF_DIRT:
FX_Impact(IMPACT_DIRT, trace_endpos, trace_plane_normal);
break;
case SURF_BLOODYFLESH:
FX_Impact(IMPACT_FLESH, trace_endpos, trace_plane_normal);
break;
case SURF_FOLIAGE:
FX_Impact(IMPACT_FOLIAGE, trace_endpos, trace_plane_normal);
break;
case SURF_GLASS:
FX_Impact(IMPACT_GLASS, trace_endpos, trace_plane_normal);
break;
case SURF_GRATE:
FX_Impact(IMPACT_GRATE, trace_endpos, trace_plane_normal);
break;
case SURF_METAL:
FX_Impact(IMPACT_METAL, trace_endpos, trace_plane_normal);
break;
case SURF_SAND:
FX_Impact(IMPACT_SAND, trace_endpos, trace_plane_normal);
break;
case SURF_SLOSH:
FX_Impact(IMPACT_SLOSH, trace_endpos, trace_plane_normal);
break;
case SURF_SNOW:
FX_Impact(IMPACT_SNOW, trace_endpos, trace_plane_normal);
break;
case SURF_TILE:
FX_Impact(IMPACT_TILE, trace_endpos, trace_plane_normal);
break;
case SURF_VENT:
FX_Impact(IMPACT_VENT, trace_endpos, trace_plane_normal);
break;
case SURF_WOOD:
FX_Impact(IMPACT_WOOD, trace_endpos, trace_plane_normal);
break;
default:
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
break;
}
break;
default:
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
}
}
/* cast a single bullet shot */
@ -211,43 +94,7 @@ TraceAttack_FireSingle(vector vecPos, vector vAngle, int iDamage, int iWeapon)
/* impact per bullet */
if (trace_ent.iBleeds == 0) {
if (trace_ent == world) {
TraceAttack_ImpactWorld();
} else {
CBaseEntity foo = (CBaseEntity)trace_ent;
switch (foo.m_iMaterial) {
case BREAKMT_GLASS:
FX_Impact(IMPACT_GLASS, trace_endpos, trace_plane_normal);
break;
case BREAKMT_WOOD:
FX_Impact(IMPACT_WOOD, trace_endpos, trace_plane_normal);
break;
case BREAKMT_METAL:
FX_Impact(IMPACT_METAL, trace_endpos, trace_plane_normal);
break;
case BREAKMT_FLESH:
FX_Impact(IMPACT_FLESH, trace_endpos, trace_plane_normal);
break;
case BREAKMT_CINDER:
FX_Impact(IMPACT_CONCRETE, trace_endpos, trace_plane_normal);
break;
case BREAKMT_TILE:
FX_Impact(IMPACT_TILE, trace_endpos, trace_plane_normal);
break;
case BREAKMT_COMPUTER:
FX_Impact(IMPACT_COMPUTER, trace_endpos, trace_plane_normal);
break;
case BREAKMT_GLASS_UNBREAKABLE:
FX_Impact(IMPACT_GLASS, trace_endpos, trace_plane_normal);
break;
case BREAKMT_ROCK:
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
break;
case BREAKMT_NONE:
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
break;
}
}
SurfData_Impact(trace_ent, trace_surfaceflagsi, trace_endpos, trace_plane_normal);
}
/* combine them into one single Damage_Apply call later */

View File

@ -29,6 +29,7 @@
#include "spectator.h"
#include "platform.h"
#include "propdata.h"
#include "surfaceproperties.h"
#include "vehicles.h"
#define BSPVER_PREREL 28

View File

@ -7,5 +7,6 @@ math.qc
player.qc
player_pmove.qc
propdata.qc
surfaceproperties.qc
vehicles.qc
#endlist

View File

@ -37,7 +37,70 @@ typedef enum
IMPACT_WOOD
} impactType_t;
/* TW/NEXT specific game flags */
typedef enum
{
GSMATERIAL_GLASS,
GSMATERIAL_WOOD,
GSMATERIAL_METAL,
GSMATERIAL_FLESH,
GSMATERIAL_CINDER,
GSMATERIAL_TILE,
GSMATERIAL_COMPUTER,
GSMATERIAL_GLASS_UNBREAKABLE,
GSMATERIAL_ROCK,
GSMATERIAL_NONE
} materialType_t;
/* HLBSP materials.txt character id's */
//#define MATID_UNUSED1 'A'
#define MATID_BLOODYFLESH 'B'
#define MATID_CONCRETE 'C'
#define MATID_DIRT 'D'
//#define MATID_UNUSED2 'E'
#define MATID_FLESH 'F'
#define MATID_GRATE 'G'
#define MATID_ALIEN 'H'
//#define MATID_UNUSED3 'I'
//#define MATID_GRASS 'J'
//#define MATID_PLASTIC 'L'
#define MATID_METAL 'M'
#define MATID_FOLIAGE 'O'
#define MATID_COMPUTER 'P'
//#define MATID_ASPHALT 'Q'
//#define MATID_BRICK 'R'
#define MATID_SLOSH 'S'
#define MATID_TILE 'T'
#define MATID_CARDBOARD 'U'
#define MATID_VENT 'V'
#define MATID_WOOD 'W'
//#define MATID_UNUSED4 'X'
#define MATID_GLASS 'Y'
//#define MATID_UNUSED5 'Z'
/* CS defines snow as 'N' on GoldSrc, whereas in Source it's reserved for sand */
#ifdef CSTRIKE
#define MATID_SNOW 'N'
#define MATID_SAND 'K'
#else
#define MATID_SNOW 'K'
#define MATID_SAND 'N'
#endif
/* modern additions, not implemented yet */
#define MATID_CLAY 1
#define MATID_PLASTER 2
#define MATID_ROCK 3
#define MATID_RUBBER 4
#define MATID_SHEETROCK 5
#define MATID_CLOTH 6
#define MATID_CARPET 7
#define MATID_PAPER 8
#define MATID_UPHOLSTERY 9
#define MATID_PUDDLE 10
#define MATID_MUD 11
#define MATID_SANDBARREL 12
/* q3 bsp base flags */
#define SURF_NODAMAGE 0x1i // never give falling damage

View File

@ -73,6 +73,7 @@ typedef struct
float damage_explosive;
float explosive_damage; /* once the damage/radius keys are set, make explosion upon break */
float explosive_radius;
string breakable_particle; /* name of BreakableModels entry in PropData.txt */
string breakable_model; /* name of BreakableModels entry in PropData.txt */
int breakable_count;
} propdata_t;

View File

@ -92,6 +92,9 @@ PropData_ParseField(int i, int a)
case "explosive_radius":
g_propdata[i].explosive_radius = stof(argv(1));
break;
case "breakable_particle":
g_propdata[i].breakable_particle = argv(1);
break;
case "breakable_model":
g_propdata[i].breakable_model = argv(1);
break;
@ -411,7 +414,7 @@ PropData_Finish(void)
/* BreakModel related helper API */
void
BreakModel_Spawn(vector pos, vector dir, vector spread, float speed, int count, string type)
BreakModel_Spawn(vector smins, vector smaxs, vector dir, float speed, int count, string type)
{
int index;
index = (int)hash_get(g_hashbreakmodel, type, -1);
@ -425,6 +428,7 @@ BreakModel_Spawn(vector pos, vector dir, vector spread, float speed, int count,
int modelcount = x / 2;
for (int i = 0; i < count; i++) {
vector endpos;
string mname;
float fadetime;
entity gib;
@ -437,14 +441,16 @@ BreakModel_Spawn(vector pos, vector dir, vector spread, float speed, int count,
mname = argv((r * 2));
fadetime = stof(argv((r * 2) + 1));
endpos[0] = smins[0] + ( random() * ( smaxs[0] - smins[0] ) );
endpos[1] = smins[1] + ( random() * ( smaxs[1] - smins[1] ) );
endpos[2] = smins[2] + ( random() * ( smaxs[2] - smins[2] ) );
gib = spawn();
setmodel(gib, mname);
setsize(gib, [0,0,0], [0,0,0]);
setorigin(gib, pos);
setorigin(gib, endpos);
makevectors(dir);
gib.velocity = v_forward * speed;
gib.velocity += random(-1,1) * spread[0] * v_right;
gib.velocity += random(-1,1) * spread[1] * v_up;
gib.avelocity = vectoangles(gib.velocity);
gib.movetype = MOVETYPE_BOUNCE;

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2016-2021 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.
*/
/*
Surface Data Specs
Scripts are formatted like our sound shaders:
typename
{
key/value pairs
...
}
Available keys are:
"base" <string> what type to inherit
"gamematerial" <char> material character, e.g. W for wood
"climbable" <bool> ???
"thickness" <float> non-solid, air (?) thickness
"density" <int> material density in kg / m^3
"elasticity" <float> 0.0 - 1.0 ; soft to hard
"friction" <float> friction multiplier
"dampening" <float> drag multiplier
"jumpfactor" <float> bouncyness?
"maxspeedfactor" <float> maxvelocity?
"stepleft" <string> footstep left
"stepright" <string> footstep right
"bulletimpact" <string> sound shader to play on impact
"scraperough" <string> sound shader to play on rough scraping
"scrapesmooth" <string> sound shader to play on smooth scraping
"impacthard" <string> sound shader for hard impacts
"impactsoft" <string> sound shader for soft impacts
"shake" <string> sound to play when object is being shaken
"strain" <string> sound to play when object is being strained?
"break" <string> sound to play when object breaks
"roll/rolling" <string> sound to play when object rolls
none of these are concerning us right now:
"audioreflectivity" <float>
"audiohardnessfactor" <float>
"audioroughnessfactor" <float>
"scrapeRoughThreshold" <float>
"impactHardThreshold" <float>
"audioHardMinVelocity" <float>
*/
#ifdef SERVER
typedef struct
{
string m_strBase;
float m_flMaterial;
float m_flThickness;
float m_flDensity;
float m_flElasticity;
float m_flFriction;
float m_flDampening;
float m_flJumpFactor;
float m_flMaxSpeedFactor;
string m_sndStepLeft;
string m_sndStepRight;
string m_sndBulletImpact;
string m_sndScrapeRough;
string m_sndScrapeSoft;
string m_sndImpactHard;
string m_sndImpactSoft;
string m_sndShake;
string m_sndStrain;
string m_sndRoll;
string m_sndBreak;
} surfaceData_t;
/* entity will have to have a .surfdata field pointing to an id */
surfaceData_t *g_surfdata;
int g_surfdata_count;
var hashtable g_hashsurfdata;
/* querying API */
typedef enum
{
SURFDATA_MATERIAL,
SURFDATA_THICKNESS,
SURFDATA_DENSITY,
SURFDATA_ELASTICITY,
SURFDATA_FRICTION,
SURFDATA_DAMPENING,
SURFDATA_JUMPFACTOR,
SURFDATA_MAXSPEEDFACTOR,
SURFDATA_SND_STEPLEFT,
SURFDATA_SND_STEPRIGHT,
SURFDATA_SND_BULLETIMPACT,
SURFDATA_SND_SCRAPEROUGH,
SURFDATA_SND_SCRAPESOFT,
SURFDATA_SND_IMPACTHARD,
SURFDATA_SND_IMPACTSOFT,
SURFDATA_SND_SHAKE,
SURFDATA_SND_STRAIN,
SURFDATA_SND_ROLL,
SURFDATA_SND_BREAK,
SURFDATA_FX_IMPACT,
} surfinfo_t;
/* initialized SurfaceKit */
void SurfData_Init(void);
/* Prepares an object for SurfaceKit initialization */
void SurfData_SetStage(string type);
/* Finishes initialization, returns valid SurfaceKit id */
int SurfData_Finish(void);
/* Call an impact effect against an entity surface */
void SurfData_Impact(entity e, int fl, vector org, vector ang);
/* Get information from a Surface */
__variant SurfData_GetInfo(int, int);
#endif

View File

@ -0,0 +1,437 @@
/*
* Copyright (c) 2016-2021 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
float HLMaterials_Fetch(string);
/* takes a material id (e.g. 'W' for wood) and returns an breakmodel id */
static materialType_t
SurfData_IDtoMaterial(float mat)
{
switch (mat) {
case MATID_GLASS:
return GSMATERIAL_GLASS;
break;
case MATID_WOOD:
return GSMATERIAL_WOOD;
break;
case MATID_METAL:
return GSMATERIAL_METAL;
break;
case MATID_FLESH:
return GSMATERIAL_FLESH;
break;
case MATID_CONCRETE:
return GSMATERIAL_CINDER;
break;
case MATID_TILE:
return GSMATERIAL_TILE;
break;
case MATID_COMPUTER:
return GSMATERIAL_COMPUTER;
break;
case MATID_ROCK:
return GSMATERIAL_ROCK;
break;
default:
return GSMATERIAL_NONE;
}
}
/* takes a material id (e.g. 'W' for wood) and returns an impact */
static impactType_t
SurfData_IDtoImpact(float mat)
{
switch (mat) {
case MATID_GLASS:
return IMPACT_GLASS;
break;
case MATID_WOOD:
return IMPACT_WOOD;
break;
case MATID_METAL:
return IMPACT_METAL;
break;
case MATID_FLESH:
return IMPACT_FLESH;
break;
case MATID_CONCRETE:
return IMPACT_CONCRETE;
break;
case MATID_TILE:
return IMPACT_TILE;
break;
case MATID_COMPUTER:
return IMPACT_COMPUTER;
break;
case MATID_GLASS:
return IMPACT_GLASS;
break;
default:
return IMPACT_DEFAULT;
}
}
/* takes a surfaceflag material bit and returns an impact */
static impactType_t
SurfData_SurfaceFlagtoImpact(int fl)
{
switch (fl) {
case SURF_ALIEN:
return IMPACT_ALIEN;
case SURF_COMPUTER:
return IMPACT_COMPUTER;
case SURF_CONCRETE:
return IMPACT_CONCRETE;
case SURF_DIRT:
return IMPACT_DIRT;
case SURF_BLOODYFLESH:
return IMPACT_FLESH;
case SURF_FOLIAGE:
return IMPACT_FOLIAGE;
case SURF_GLASS:
return IMPACT_GLASS;
case SURF_GRATE:
return IMPACT_GRATE;
case SURF_METAL:
return IMPACT_METAL;
case SURF_SAND:
return IMPACT_SAND;
case SURF_SLOSH:
return IMPACT_SLOSH;
case SURF_SNOW:
return IMPACT_SNOW;
case SURF_TILE:
return IMPACT_TILE;
case SURF_VENT:
return IMPACT_VENT;
case SURF_WOOD:
return IMPACT_WOOD;
default:
return IMPACT_DEFAULT;
}
}
static void
SurfData_ParseField(int i, int a)
{
switch (argv(0)) {
case "base":
g_surfdata[i].m_strBase = argv(1);
break;
case "gamematerial":
string mat = argv(1);
g_surfdata[i].m_flMaterial = str2chr(mat, 0);
break;
case "thickness":
g_surfdata[i].m_flThickness = stof(argv(1));
break;
case "density":
g_surfdata[i].m_flDensity = stof(argv(1));
break;
case "elasticity":
g_surfdata[i].m_flElasticity = stof(argv(1));
break;
case "friction":
g_surfdata[i].m_flFriction = stof(argv(1));
break;
case "dampening":
g_surfdata[i].m_flDampening = stof(argv(1));
break;
case "jumpfactor":
g_surfdata[i].m_flJumpFactor = stof(argv(1));
break;
case "maxspeedfactor":
g_surfdata[i].m_flMaxSpeedFactor = stof(argv(1));
break;
case "stepleft":
g_surfdata[i].m_sndStepLeft = argv(1);
break;
case "stepright":
g_surfdata[i].m_sndStepRight = argv(1);
break;
case "bulletimpact":
g_surfdata[i].m_sndBulletImpact = argv(1);
break;
case "scraperough":
g_surfdata[i].m_sndScrapeRough = argv(1);
break;
case "scrapesmooth":
g_surfdata[i].m_sndScrapeSoft = argv(1);
break;
case "impacthard":
g_surfdata[i].m_sndImpactHard = argv(1);
break;
case "impactsoft":
g_surfdata[i].m_sndImpactSoft = argv(1);
break;
case "shake":
g_surfdata[i].m_sndShake = argv(1);
break;
case "strain":
g_surfdata[i].m_sndStrain = argv(1);
break;
case "break":
g_surfdata[i].m_sndRoll = argv(1);
break;
case "roll":
case "rolling":
g_surfdata[i].m_sndBreak = argv(1);
break;
}
}
/* concerned with dealing with keeping track of braces and parsing lines */
static int
SurfData_Parse(string line)
{
int c;
string key;
static string t_name;
static int braced = 0;
static int i;
c = tokenize_console(line);
key = argv(0);
switch(key) {
case "{":
braced++;
break;
case "}":
/* increase counter when done */
if (t_name)
i++;
braced--;
t_name = "";
break;
default:
if (braced == 1 && t_name != "") {
SurfData_ParseField(i, c);
} else if (braced == 0) {
t_name = strtolower(line);
hash_add(g_hashsurfdata, t_name, (int)i);
}
}
return (0);
}
static int
SurfData_Load(string type)
{
int index;
if (!type)
return -1;
type = strtolower(type);
index = (int)hash_get(g_hashsurfdata, type, -1);
if (index < 0) {
crossprint(sprintf("^1 SurfData_Load: type %s is not defined\n", type));
return -1;
} else {
return index;
}
}
/* stripped down ParseLine that just counts how many slots we have to allocate */
static void
SurfData_CountLine(string line)
{
int c;
string key;
static string t_name;
static int braced = 0;
c = tokenize_console(line);
key = argv(0);
switch(key) {
case "{":
braced++;
break;
case "}":
braced--;
t_name = "";
break;
default:
/* new definition starts */
if (braced == 0) {
t_name = strtolower(line);
if (t_name)
g_surfdata_count++;
}
}
return;
}
/* Public API functions */
__variant
SurfData_GetInfo(int i, int type)
{
if (i < 0)
return __NULL__;
switch (type)
{
case SURFDATA_MATERIAL:
return (__variant)SurfData_IDtoMaterial(g_surfdata[i].m_flMaterial);
case SURFDATA_THICKNESS:
return (__variant)g_surfdata[i].m_flThickness;
case SURFDATA_DENSITY:
return (__variant)g_surfdata[i].m_flDensity;
case SURFDATA_ELASTICITY:
return (__variant)g_surfdata[i].m_flElasticity;
case SURFDATA_FRICTION:
return (__variant)g_surfdata[i].m_flFriction;
case SURFDATA_DAMPENING:
return (__variant)g_surfdata[i].m_flDampening;
case SURFDATA_JUMPFACTOR:
return (__variant)g_surfdata[i].m_flJumpFactor;
case SURFDATA_MAXSPEEDFACTOR:
return (__variant)g_surfdata[i].m_flMaxSpeedFactor;
case SURFDATA_SND_STEPLEFT:
return (__variant)g_surfdata[i].m_sndStepLeft;
case SURFDATA_SND_STEPRIGHT:
return (__variant)g_surfdata[i].m_sndStepRight;
case SURFDATA_SND_BULLETIMPACT:
return (__variant)g_surfdata[i].m_sndBulletImpact;
case SURFDATA_SND_SCRAPEROUGH:
return (__variant)g_surfdata[i].m_sndScrapeRough;
case SURFDATA_SND_SCRAPESOFT:
return (__variant)g_surfdata[i].m_sndScrapeSoft;
case SURFDATA_SND_IMPACTHARD:
return (__variant)g_surfdata[i].m_sndImpactHard;
case SURFDATA_SND_IMPACTSOFT:
return (__variant)g_surfdata[i].m_sndImpactSoft;
case SURFDATA_SND_SHAKE:
return (__variant)g_surfdata[i].m_sndShake;
case SURFDATA_SND_STRAIN:
return (__variant)g_surfdata[i].m_sndStrain;
case SURFDATA_SND_ROLL:
return (__variant)g_surfdata[i].m_sndRoll;
case SURFDATA_SND_BREAK:
return (__variant)g_surfdata[i].m_sndBreak;
case SURFDATA_FX_IMPACT:
return (__variant)SurfData_IDtoImpact(g_surfdata[i].m_flMaterial);
default:
return __NULL__;
}
}
void
SurfData_Shutdown(void)
{
if (g_surfdata) {
memfree(g_surfdata);
}
g_surfdata_count = 0;
g_hashsurfdata = 0;
}
void
SurfData_Init(void)
{
filestream fh;
string line;
int index;
/* remove old data */
SurfData_Shutdown();
index = g_surfdata_count;
/* create the hash-table if it doesn't exist */
if (!g_hashsurfdata) {
g_hashsurfdata = hash_createtab(2, HASH_ADD);
}
/* Defaults go here */
fh = fopen("scripts/surfaceproperties.txt", FILE_READ);
if (fh < 0) {
print("^1[SURFDATA] Can't find surfaceproperties.txt\n");
return;
}
/* count content */
while ((line = fgets(fh))) {
SurfData_CountLine(line);
}
/* alocate our stuff */
g_surfdata = (surfaceData_t *)memalloc(sizeof(surfaceData_t) * g_surfdata_count);
fseek(fh, 0);
while ((line = fgets(fh))) {
/* when we found it, quit */
SurfData_Parse(line);
}
fclose(fh);
}
static string g_curSurfData;
void
SurfData_SetStage(string type)
{
g_curSurfData = type;
}
int
SurfData_Finish(void)
{
string toload = g_curSurfData;
g_curSurfData = __NULL__;
if (toload) {
return SurfData_Load(toload);
} else {
return -1;
}
}
void
SurfData_Impact(entity e, int fl, vector org, vector ang)
{
if (e == world) { /* the static world */
switch (serverkeyfloat("*bspversion")) {
case BSPVER_HL:
float surf;
string tex_name;
surf = getsurfacenearpoint(e, org);
tex_name = Materials_FixName(getsurfacetexture(e, surf));
FX_Impact(SurfData_IDtoImpact(HLMaterials_Fetch(tex_name)), org, ang);
break;
case BSPVER_Q3: /* Q3 */
case BSPVER_RTCW: /* RtCW */
case BSPVER_RBSP: /* RFVBSP */
FX_Impact(SurfData_SurfaceFlagtoImpact(fl), org, ang);
break;
default:
FX_Impact(IMPACT_DEFAULT, org, ang);
}
} else { /* props, entities */
CBaseEntity foo = (CBaseEntity)e;
FX_Impact(SurfData_GetInfo(foo.m_iMaterial, SURFDATA_FX_IMPACT), org, ang);
}
}
#endif