Implement and parse the propdata system from Source 2004 and make our
func_breakable entity aware of it.
This commit is contained in:
parent
3cc01ca512
commit
3bceff6a2c
11 changed files with 464 additions and 2 deletions
|
@ -20,7 +20,6 @@
|
||||||
void
|
void
|
||||||
CSQC_Init(float apilevel, string enginename, float engineversion)
|
CSQC_Init(float apilevel, string enginename, float engineversion)
|
||||||
{
|
{
|
||||||
Sound_Init();
|
|
||||||
pSeat = &g_seats[0];
|
pSeat = &g_seats[0];
|
||||||
pSeatLocal = &g_seatslocal[0];
|
pSeatLocal = &g_seatslocal[0];
|
||||||
|
|
||||||
|
@ -86,6 +85,10 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
|
||||||
registercommand("+zoomin");
|
registercommand("+zoomin");
|
||||||
registercommand("-zoomin");
|
registercommand("-zoomin");
|
||||||
|
|
||||||
|
/* Sound shaders */
|
||||||
|
Sound_Init();
|
||||||
|
PropData_Init();
|
||||||
|
|
||||||
/* VOX */
|
/* VOX */
|
||||||
Vox_Init();
|
Vox_Init();
|
||||||
|
|
||||||
|
@ -1107,6 +1110,7 @@ CSQC_Shutdown(void)
|
||||||
Sentences_Shutdown();
|
Sentences_Shutdown();
|
||||||
Titles_Shutdown();
|
Titles_Shutdown();
|
||||||
Sound_Shutdown();
|
Sound_Shutdown();
|
||||||
|
PropData_Shutdown();
|
||||||
Vox_Shutdown();
|
Vox_Shutdown();
|
||||||
EFX_Shutdown();
|
EFX_Shutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ void
|
||||||
Event_ProcessModel(float flTimeStamp, int iCode, string strData)
|
Event_ProcessModel(float flTimeStamp, int iCode, string strData)
|
||||||
{
|
{
|
||||||
switch(iCode) {
|
switch(iCode) {
|
||||||
|
case 1004:
|
||||||
|
sound(self, CHAN_BODY, strData, 1.0f, ATTN_NORM);
|
||||||
|
break;
|
||||||
case 5004: /* view model sound */
|
case 5004: /* view model sound */
|
||||||
localsound(strData, CHAN_AUTO, 1.0);
|
localsound(strData, CHAN_AUTO, 1.0);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -108,6 +108,7 @@ class func_breakable:CBaseTrigger
|
||||||
int m_iMaterial;
|
int m_iMaterial;
|
||||||
float m_flDelay;
|
float m_flDelay;
|
||||||
float m_flExplodeMag;
|
float m_flExplodeMag;
|
||||||
|
float m_flExplodeRad;
|
||||||
string m_strBreakSpawn;
|
string m_strBreakSpawn;
|
||||||
|
|
||||||
/*entity m_pressAttacker;
|
/*entity m_pressAttacker;
|
||||||
|
@ -170,7 +171,7 @@ func_breakable::Explode(void)
|
||||||
vector rp = absmin + (0.5 * (absmax - absmin));
|
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], m_iMaterial);
|
||||||
FX_Explosion(rp);
|
FX_Explosion(rp);
|
||||||
Damage_Radius(rp, this, m_flExplodeMag, m_flExplodeMag * 2.5f, TRUE, 0);
|
Damage_Radius(rp, this, m_flExplodeMag, m_flExplodeRad, TRUE, 0);
|
||||||
UseTargets(this, TRIG_TOGGLE, 0.0f); /* delay... ignored. */
|
UseTargets(this, TRIG_TOGGLE, 0.0f); /* delay... ignored. */
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
|
@ -299,6 +300,12 @@ func_breakable::Respawn(void)
|
||||||
if (!health) {
|
if (!health) {
|
||||||
health = 15;
|
health = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HasPropData()) {
|
||||||
|
health = GetPropData(PROPINFO_HEALTH);
|
||||||
|
m_flExplodeMag = GetPropData(PROPINFO_EXPLOSIVE_DMG);
|
||||||
|
m_flExplodeRad = GetPropData(PROPINFO_EXPLOSIVE_RADIUS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -310,6 +317,7 @@ func_breakable::SpawnKey(string strKey, string strValue)
|
||||||
break;
|
break;
|
||||||
case "explodemagnitude":
|
case "explodemagnitude":
|
||||||
m_flExplodeMag = stof(strValue);
|
m_flExplodeMag = stof(strValue);
|
||||||
|
m_flExplodeRad = m_flExplodeMag * 2.5f;
|
||||||
break;
|
break;
|
||||||
case "spawnobject":
|
case "spawnobject":
|
||||||
int oid = stoi(strValue);
|
int oid = stoi(strValue);
|
||||||
|
|
|
@ -18,6 +18,9 @@ class CBaseEntity
|
||||||
{
|
{
|
||||||
int m_iBody;
|
int m_iBody;
|
||||||
|
|
||||||
|
/* prop data */
|
||||||
|
int m_iPropData;
|
||||||
|
|
||||||
#ifdef CLIENT
|
#ifdef CLIENT
|
||||||
float m_flSentenceTime;
|
float m_flSentenceTime;
|
||||||
sound_t *m_pSentenceQue;
|
sound_t *m_pSentenceQue;
|
||||||
|
@ -62,6 +65,8 @@ class CBaseEntity
|
||||||
virtual vector(void) GetSpawnAngles;
|
virtual vector(void) GetSpawnAngles;
|
||||||
virtual string(void) GetSpawnModel;
|
virtual string(void) GetSpawnModel;
|
||||||
virtual float(void) GetSpawnHealth;
|
virtual float(void) GetSpawnHealth;
|
||||||
|
virtual int(void) HasPropData;
|
||||||
|
virtual __variant(int) GetPropData;
|
||||||
|
|
||||||
/* Input/Output System */
|
/* Input/Output System */
|
||||||
string m_strOnTrigger;
|
string m_strOnTrigger;
|
||||||
|
|
|
@ -816,6 +816,9 @@ CBaseEntity::SpawnInit(void)
|
||||||
SpawnKey(argv(i), argv(i+1));
|
SpawnKey(argv(i), argv(i+1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tokenization complete, now we can load propdata */
|
||||||
|
PropData_Finish();
|
||||||
|
|
||||||
/* some entity might involuntarily call SpawnInit as part of being
|
/* some entity might involuntarily call SpawnInit as part of being
|
||||||
a member of CBaseEntity. So we need to make sure that it doesn't
|
a member of CBaseEntity. So we need to make sure that it doesn't
|
||||||
inherit stuff from the last previously loaded entity */
|
inherit stuff from the last previously loaded entity */
|
||||||
|
@ -848,6 +851,18 @@ CBaseEntity::Hide(void)
|
||||||
SetMovetype(MOVETYPE_NONE);
|
SetMovetype(MOVETYPE_NONE);
|
||||||
takedamage = DAMAGE_NO;
|
takedamage = DAMAGE_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CBaseEntity::HasPropData(void)
|
||||||
|
{
|
||||||
|
return (m_iPropData != -1) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
__variant
|
||||||
|
CBaseEntity::GetPropData(int type)
|
||||||
|
{
|
||||||
|
return Prop_GetInfo(m_iPropData, type);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -860,7 +875,14 @@ client doesn't have to do a whole lot here
|
||||||
void
|
void
|
||||||
CBaseEntity::CBaseEntity(void)
|
CBaseEntity::CBaseEntity(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
|
/* don't call this function more than once per entity */
|
||||||
|
if (identity == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_iPropData = -1;
|
||||||
|
|
||||||
/* Not in Deathmatch */
|
/* Not in Deathmatch */
|
||||||
if (spawnflags & 2048) {
|
if (spawnflags & 2048) {
|
||||||
if (cvar("sv_playerslots") > 1) {
|
if (cvar("sv_playerslots") > 1) {
|
||||||
|
@ -943,6 +965,10 @@ CBaseEntity::SetModel(string newModel)
|
||||||
model = newModel;
|
model = newModel;
|
||||||
setmodel(this, newModel);
|
setmodel(this, newModel);
|
||||||
SetSendFlags(BASEFL_CHANGED_MODELINDEX);
|
SetSendFlags(BASEFL_CHANGED_MODELINDEX);
|
||||||
|
|
||||||
|
if (model && m_iPropData == -1) {
|
||||||
|
PropData_ForModel(model);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
CBaseEntity::SetModelindex(float newModelIndex)
|
CBaseEntity::SetModelindex(float newModelIndex)
|
||||||
|
@ -1103,6 +1129,9 @@ CBaseEntity::SpawnKey(string strKey, string strValue)
|
||||||
/* we do re-read a lot of the builtin fields in case we want to set
|
/* we do re-read a lot of the builtin fields in case we want to set
|
||||||
defaults. just in case anybody is wondering. */
|
defaults. just in case anybody is wondering. */
|
||||||
switch (strKey) {
|
switch (strKey) {
|
||||||
|
case "propdata":
|
||||||
|
PropData_SetStage(strValue);
|
||||||
|
break;
|
||||||
case "scale":
|
case "scale":
|
||||||
scale = stof(strValue);
|
scale = stof(strValue);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -427,6 +427,7 @@ initents(void)
|
||||||
|
|
||||||
/* sound shader init */
|
/* sound shader init */
|
||||||
Sound_Init();
|
Sound_Init();
|
||||||
|
PropData_Init();
|
||||||
|
|
||||||
/* only bother doing so on Half-Life BSP */
|
/* only bother doing so on Half-Life BSP */
|
||||||
if (serverkeyfloat("*bspversion") == BSPVER_HL) {
|
if (serverkeyfloat("*bspversion") == BSPVER_HL) {
|
||||||
|
|
|
@ -39,6 +39,8 @@ Event_ServerModelEvent(float flTimeStamp, int iCode, string strData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 1004:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dprint(sprintf("^3[SERVER]^7 Unknown model-event code " \
|
dprint(sprintf("^3[SERVER]^7 Unknown model-event code " \
|
||||||
"%i with data %s\n", iCode, strData));
|
"%i with data %s\n", iCode, strData));
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "spectator.h"
|
#include "spectator.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "propdata.h"
|
||||||
#include "vehicles.h"
|
#include "vehicles.h"
|
||||||
|
|
||||||
#define BSPVER_PREREL 28
|
#define BSPVER_PREREL 28
|
||||||
|
|
|
@ -6,5 +6,6 @@ sound.qc
|
||||||
math.qc
|
math.qc
|
||||||
player.qc
|
player.qc
|
||||||
player_pmove.qc
|
player_pmove.qc
|
||||||
|
propdata.qc
|
||||||
vehicles.qc
|
vehicles.qc
|
||||||
#endlist
|
#endlist
|
||||||
|
|
126
src/shared/propdata.h
Normal file
126
src/shared/propdata.h
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Prop-Data specs
|
||||||
|
|
||||||
|
According to Source SDK's propdata.txt we've got
|
||||||
|
a kinda sorta hacky definition table for this stuff:
|
||||||
|
|
||||||
|
"PropData.txt"
|
||||||
|
{
|
||||||
|
|
||||||
|
"sometype"
|
||||||
|
{
|
||||||
|
// .. key/field attributes
|
||||||
|
// e.g.
|
||||||
|
"health" "10"
|
||||||
|
"breakable_model" "somematerial"
|
||||||
|
}
|
||||||
|
|
||||||
|
"BreakableModels"
|
||||||
|
{
|
||||||
|
// completely unrelated to types defined in propdata.txt
|
||||||
|
// but somehow still part of it?
|
||||||
|
|
||||||
|
"somematerial"
|
||||||
|
{
|
||||||
|
// model path / fadeout time pair
|
||||||
|
// e.g.
|
||||||
|
"foo.vvm" "2.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
The idea is that props specify the type of prop they are ("sometype") and it defines
|
||||||
|
a set of sensible defaults.
|
||||||
|
|
||||||
|
However, props can override any parts of this inside the model data itself.
|
||||||
|
Currently no model format FTEQW supports allows for reading of said propdata.
|
||||||
|
However we'll be loading "foobar.vvm.propdata" to remedy this for those.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var string g_curPropData;
|
||||||
|
|
||||||
|
typedef enumflags
|
||||||
|
{
|
||||||
|
PDFL_BLOCKLOS, /* Does this block an AIs light of sight? */
|
||||||
|
PDFL_AIWALKABLE, /* can AI walk on this? */
|
||||||
|
PDFL_ALLOWSTATIC /* static simulation possible? */
|
||||||
|
} propdataFlag_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
string base;
|
||||||
|
float health; /* health until break */
|
||||||
|
propdataFlag_t flags;
|
||||||
|
float damage_bullets; /* dmg multipliers */
|
||||||
|
float damage_melee;
|
||||||
|
float damage_explosive;
|
||||||
|
float explosive_damage; /* once the damage/radius keys are set, make explosion upon break */
|
||||||
|
float explosive_radius;
|
||||||
|
string breakable_model; /* name of BreakableModels entry in PropData.txt */
|
||||||
|
int breakable_count;
|
||||||
|
} propdata_t;
|
||||||
|
|
||||||
|
/* entity will have to have a .propdata field pointing to a propdata id */
|
||||||
|
propdata_t *g_propdata;
|
||||||
|
int g_propdata_count;
|
||||||
|
var hashtable g_hashpropdata;
|
||||||
|
|
||||||
|
/* necessary API functions */
|
||||||
|
void PropData_Init(void);
|
||||||
|
void PropData_Shutdown(void);
|
||||||
|
|
||||||
|
int PropData_Load(string); /* called when we read entity data, returns -1 when not found */
|
||||||
|
int PropData_ForModel(string); /* called when we set a model, returns -1 when not found */
|
||||||
|
//int PropData_Read(string); /* this just handles the contents of a prop_data model string */
|
||||||
|
|
||||||
|
void PropData_SetStage(string);
|
||||||
|
void PropData_Finish(void);
|
||||||
|
|
||||||
|
/* querying API */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PROPINFO_HEALTH,
|
||||||
|
PROPINFO_FLAGS,
|
||||||
|
PROPINFO_DMG_BULLET,
|
||||||
|
PROPINFO_DMG_MELEE,
|
||||||
|
PROPINFO_DMG_EXPLOSIVE,
|
||||||
|
PROPINFO_EXPLOSIVE_DMG,
|
||||||
|
PROPINFO_EXPLOSIVE_RADIUS,
|
||||||
|
PROPINFO_BREAKMODEL,
|
||||||
|
PROPINFO_BREAKCOUNT
|
||||||
|
} propinfo_t;
|
||||||
|
__variant Prop_GetInfo(int, int);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
string model;
|
||||||
|
float fadetime;
|
||||||
|
} breakmodel_t;
|
||||||
|
|
||||||
|
/* entity will have a .breakmodel field pointing to a breakmodel id */
|
||||||
|
propdata_t *g_breakmodel;
|
||||||
|
int g_breakmodel_count;
|
||||||
|
|
||||||
|
/* necessary API functions */
|
||||||
|
//void BreakModel_Init(void);
|
||||||
|
//void BreakModel_Shutdown(void);
|
||||||
|
|
||||||
|
//int BreakModel_Load(string); /* called when we precache a model, returns -1 when not found */
|
||||||
|
//int BreakModel_Read(string); /* this just handles the contents of a prop_data model string */
|
282
src/shared/propdata.qc
Normal file
282
src/shared/propdata.qc
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
PropData_Shutdown(void)
|
||||||
|
{
|
||||||
|
if (g_propdata) {
|
||||||
|
memfree(g_propdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_propdata_count = 0;
|
||||||
|
g_hashpropdata = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PropData_Init(void)
|
||||||
|
{
|
||||||
|
PropData_Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
__variant
|
||||||
|
Prop_GetInfo(int i, int type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case PROPINFO_HEALTH:
|
||||||
|
return (__variant)g_propdata[i].health;
|
||||||
|
case PROPINFO_FLAGS:
|
||||||
|
return (__variant)g_propdata[i].flags;
|
||||||
|
case PROPINFO_DMG_BULLET:
|
||||||
|
return (__variant)g_propdata[i].damage_bullets;
|
||||||
|
case PROPINFO_DMG_MELEE:
|
||||||
|
return (__variant)g_propdata[i].damage_melee;
|
||||||
|
case PROPINFO_DMG_EXPLOSIVE:
|
||||||
|
return (__variant)g_propdata[i].damage_explosive;
|
||||||
|
case PROPINFO_EXPLOSIVE_DMG:
|
||||||
|
return (__variant)g_propdata[i].explosive_damage;
|
||||||
|
case PROPINFO_EXPLOSIVE_RADIUS:
|
||||||
|
return (__variant)g_propdata[i].explosive_radius;
|
||||||
|
case PROPINFO_BREAKMODEL:
|
||||||
|
return (__variant)g_propdata[i].breakable_model;
|
||||||
|
case PROPINFO_BREAKCOUNT:
|
||||||
|
return (__variant)g_propdata[i].breakable_count;
|
||||||
|
default:
|
||||||
|
return __NULL__;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PropData_ParseField(int i, int a)
|
||||||
|
{
|
||||||
|
switch (argv(0)) {
|
||||||
|
case "base":
|
||||||
|
g_propdata[i].base = argv(1);
|
||||||
|
break;
|
||||||
|
case "blockLOS":
|
||||||
|
g_propdata[i].flags |= PDFL_BLOCKLOS;
|
||||||
|
break;
|
||||||
|
case "AIWalkable":
|
||||||
|
g_propdata[i].flags |= PDFL_AIWALKABLE;
|
||||||
|
break;
|
||||||
|
case "allow_static":
|
||||||
|
g_propdata[i].flags |= PDFL_ALLOWSTATIC;
|
||||||
|
break;
|
||||||
|
case "dmg.bullets":
|
||||||
|
g_propdata[i].damage_bullets = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "dmg.club":
|
||||||
|
g_propdata[i].damage_melee = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "dmg.explosive":
|
||||||
|
g_propdata[i].damage_explosive = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "health":
|
||||||
|
g_propdata[i].health = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "explosive_damage":
|
||||||
|
g_propdata[i].explosive_damage = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "explosive_radius":
|
||||||
|
g_propdata[i].explosive_radius = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "breakable_model":
|
||||||
|
g_propdata[i].breakable_model = argv(1);
|
||||||
|
break;
|
||||||
|
case "breakable_count":
|
||||||
|
g_propdata[i].breakable_count = stof(argv(1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* concerned with dealing with keeping track of braces and parsing lines */
|
||||||
|
int
|
||||||
|
PropData_Parse(int i, string line, string type)
|
||||||
|
{
|
||||||
|
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 = "";
|
||||||
|
|
||||||
|
/* done */
|
||||||
|
if (braced == 0)
|
||||||
|
return (1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (braced == 2 && t_name != "") {
|
||||||
|
PropData_ParseField(i, c);
|
||||||
|
} else if (braced == 1) {
|
||||||
|
/* name/identifer of our message */
|
||||||
|
t_name = strtolower(key);
|
||||||
|
|
||||||
|
if (t_name == type) {
|
||||||
|
/* I guess it's what we want */
|
||||||
|
g_propdata[i].name = type;
|
||||||
|
} else {
|
||||||
|
/* not what we're looking for */
|
||||||
|
t_name = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* goes through and looks for a specifically named propdata type inside the scripts dir */
|
||||||
|
int
|
||||||
|
PropData_Load(string type)
|
||||||
|
{
|
||||||
|
searchhandle sh;
|
||||||
|
filestream fh;
|
||||||
|
string line;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (!type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
index = g_propdata_count;
|
||||||
|
type = strtolower(type);
|
||||||
|
|
||||||
|
/* create the hash-table if it doesn't exist */
|
||||||
|
if (!g_hashpropdata) {
|
||||||
|
g_hashpropdata = hash_createtab(2, HASH_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if it's already cached */
|
||||||
|
for (int i = 0; i < g_propdata_count; i++) {
|
||||||
|
if (type == g_propdata[i].name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_propdata_count++;
|
||||||
|
g_propdata = (propdata_t *)memrealloc(g_propdata, sizeof(propdata_t), index, g_propdata_count);
|
||||||
|
|
||||||
|
/* Defaults go here */
|
||||||
|
|
||||||
|
sh = search_begin("scripts/propdata*.txt", TRUE, TRUE);
|
||||||
|
|
||||||
|
for (int i = 0; i < search_getsize(sh); i++) {
|
||||||
|
fh = fopen(search_getfilename(sh, i), FILE_READ);
|
||||||
|
if (fh < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((line = fgets(fh))) {
|
||||||
|
/* when we found it, quit */
|
||||||
|
if (PropData_Parse(index, line, type) == TRUE) {
|
||||||
|
search_end(sh);
|
||||||
|
fclose(fh);
|
||||||
|
hash_add(g_hashpropdata, type, (int)index);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("^1[PROPDATA] No type found for ");
|
||||||
|
print(type);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
search_end(sh);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* goes through and looks for a specifically named propdata type inside the scripts dir */
|
||||||
|
int
|
||||||
|
PropData_ForModel(string modelname)
|
||||||
|
{
|
||||||
|
filestream fh;
|
||||||
|
string line;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (!modelname)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (substring(modelname, 0, 1) == "*")
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
index = g_propdata_count;
|
||||||
|
modelname = strtolower(modelname);
|
||||||
|
|
||||||
|
dprint("[PROPDATA] Loading model propdata ");
|
||||||
|
dprint(modelname);
|
||||||
|
dprint("\n");
|
||||||
|
|
||||||
|
/* create the hash-table if it doesn't exist */
|
||||||
|
if (!g_hashpropdata) {
|
||||||
|
g_hashpropdata = hash_createtab(2, HASH_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if it's already cached */
|
||||||
|
for (int i = 0; i < g_propdata_count; i++) {
|
||||||
|
if (modelname == g_propdata[i].name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_propdata_count++;
|
||||||
|
g_propdata = (propdata_t *)memrealloc(g_propdata, sizeof(propdata_t), index, g_propdata_count);
|
||||||
|
|
||||||
|
/* Defaults go here */
|
||||||
|
|
||||||
|
fh = fopen(strcat(modelname, ".propdata"), FILE_READ);
|
||||||
|
if (fh < 0) {
|
||||||
|
dprint(sprintf("Can't find propdata for model %s\n", modelname));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while ((line = fgets(fh))) {
|
||||||
|
/* when we found it, quit */
|
||||||
|
if (PropData_Parse(index, line, "prop_data") == TRUE) {
|
||||||
|
fclose(fh);
|
||||||
|
hash_add(g_hashpropdata, modelname, (int)index);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
dprint("^1[PROPDATA] No type found for ");
|
||||||
|
dprint(modelname);
|
||||||
|
dprint("\n");
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we can only tokenize one thing at a time, so we save the type for the current
|
||||||
|
entity away for later, so we can parse it properly by then when we've exited the
|
||||||
|
SpawnKey loop. Using a global will save us some memory at least */
|
||||||
|
void
|
||||||
|
PropData_SetStage(string type)
|
||||||
|
{
|
||||||
|
g_curPropData = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PropData_Finish(void)
|
||||||
|
{
|
||||||
|
PropData_Load(g_curPropData);
|
||||||
|
g_curPropData = "";
|
||||||
|
}
|
Loading…
Reference in a new issue