mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-04 12:46:06 +00:00
ACS: UDMF user properties
Lines, sides, sectors, and things now all support the "Custom" tab properly. Label a property as `user_[whatever you want]` in this tab, and it will be added to the structure. ACS will then be able to retrieve it using the `Get[x]UserProperty()` function.
This commit is contained in:
parent
a366948c62
commit
d9382f2100
10 changed files with 822 additions and 4 deletions
|
|
@ -144,6 +144,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
k_vote.c
|
||||
k_serverstats.c
|
||||
k_zvote.c
|
||||
k_mapuser.c
|
||||
)
|
||||
|
||||
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
|
||||
|
|
|
|||
|
|
@ -2226,3 +2226,268 @@ bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_Get[x]UserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
User-defined property management.
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_GetLineUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
auto info = &static_cast<Thread *>(thread)->info;
|
||||
Environment *env = &ACSEnv;
|
||||
|
||||
mtag_t tag = 0;
|
||||
INT32 lineID = 0;
|
||||
INT32 activatorID = -1;
|
||||
line_t *line = NULL;
|
||||
|
||||
const char *key = NULL;
|
||||
|
||||
mapUserProperty_t *prop = NULL;
|
||||
INT32 ret = 0;
|
||||
|
||||
tag = argV[0];
|
||||
key = thread->scopeMap->getString(argV[1])->str;
|
||||
|
||||
if (info != NULL && info->line != NULL)
|
||||
{
|
||||
activatorID = info->line - lines;
|
||||
}
|
||||
|
||||
if ((lineID = NextLine(tag, lineID, activatorID)) != -1)
|
||||
{
|
||||
line = &lines[ lineID ];
|
||||
}
|
||||
|
||||
if (line != NULL)
|
||||
{
|
||||
prop = K_UserPropertyFind(&line->user, key);
|
||||
}
|
||||
|
||||
if (prop != NULL)
|
||||
{
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueBool);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_INT:
|
||||
{
|
||||
ret = prop->valueInt;
|
||||
break;
|
||||
}
|
||||
case USER_PROP_FIXED:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueFixed);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_STR:
|
||||
{
|
||||
ret = static_cast<INT32>( ~env->getString( prop->valueStr )->idx );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread->dataStk.push(ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CallFunc_GetSideUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
auto info = &static_cast<Thread *>(thread)->info;
|
||||
Environment *env = &ACSEnv;
|
||||
|
||||
mtag_t tag = 0;
|
||||
INT32 lineID = 0;
|
||||
INT32 activatorID = -1;
|
||||
line_t *line = NULL;
|
||||
|
||||
UINT8 sideID = 0;
|
||||
side_t *side = NULL;
|
||||
|
||||
const char *key = NULL;
|
||||
|
||||
mapUserProperty_t *prop = NULL;
|
||||
INT32 ret = 0;
|
||||
|
||||
tag = argV[0];
|
||||
sideID = argV[1];
|
||||
key = thread->scopeMap->getString(argV[2])->str;
|
||||
|
||||
if (info != NULL && info->line != NULL)
|
||||
{
|
||||
activatorID = info->line - lines;
|
||||
}
|
||||
|
||||
if ((lineID = NextLine(tag, lineID, activatorID)) != -1)
|
||||
{
|
||||
line = &lines[ lineID ];
|
||||
}
|
||||
|
||||
if (sideID < 0 || sideID > 1)
|
||||
{
|
||||
sideID = info->side;
|
||||
}
|
||||
|
||||
if (line != NULL && line->sidenum[sideID] != 0xffff)
|
||||
{
|
||||
side = &sides[line->sidenum[sideID]];
|
||||
}
|
||||
|
||||
if (side != NULL)
|
||||
{
|
||||
prop = K_UserPropertyFind(&side->user, key);
|
||||
}
|
||||
|
||||
if (prop != NULL)
|
||||
{
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueBool);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_INT:
|
||||
{
|
||||
ret = prop->valueInt;
|
||||
break;
|
||||
}
|
||||
case USER_PROP_FIXED:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueFixed);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_STR:
|
||||
{
|
||||
ret = static_cast<INT32>( ~env->getString( prop->valueStr )->idx );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread->dataStk.push(ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CallFunc_GetSectorUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
auto info = &static_cast<Thread *>(thread)->info;
|
||||
Environment *env = &ACSEnv;
|
||||
|
||||
mtag_t tag = 0;
|
||||
INT32 sectorID = 0;
|
||||
INT32 activatorID = -1;
|
||||
sector_t *sector = NULL;
|
||||
|
||||
const char *key = NULL;
|
||||
|
||||
mapUserProperty_t *prop = NULL;
|
||||
INT32 ret = 0;
|
||||
|
||||
tag = argV[0];
|
||||
key = thread->scopeMap->getString(argV[1])->str;
|
||||
|
||||
if (info != NULL && info->sector != NULL)
|
||||
{
|
||||
activatorID = info->sector - sectors;
|
||||
}
|
||||
|
||||
if ((sectorID = NextSector(tag, sectorID, activatorID)) != -1)
|
||||
{
|
||||
sector = §ors[ sectorID ];
|
||||
}
|
||||
|
||||
if (sector != NULL)
|
||||
{
|
||||
prop = K_UserPropertyFind(§or->user, key);
|
||||
}
|
||||
|
||||
if (prop != NULL)
|
||||
{
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueBool);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_INT:
|
||||
{
|
||||
ret = prop->valueInt;
|
||||
break;
|
||||
}
|
||||
case USER_PROP_FIXED:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueFixed);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_STR:
|
||||
{
|
||||
ret = static_cast<INT32>( ~env->getString( prop->valueStr )->idx );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread->dataStk.push(ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CallFunc_GetThingUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
auto info = &static_cast<Thread *>(thread)->info;
|
||||
Environment *env = &ACSEnv;
|
||||
|
||||
mtag_t tag = 0;
|
||||
mobj_t *mobj = NULL;
|
||||
|
||||
const char *key = NULL;
|
||||
|
||||
mapUserProperty_t *prop = NULL;
|
||||
INT32 ret = 0;
|
||||
|
||||
tag = argV[0];
|
||||
key = thread->scopeMap->getString(argV[1])->str;
|
||||
|
||||
mobj = P_FindMobjFromTID(tag, mobj, info->mo);
|
||||
|
||||
if (mobj != NULL && mobj->spawnpoint != NULL)
|
||||
{
|
||||
prop = K_UserPropertyFind(&mobj->spawnpoint->user, key);
|
||||
}
|
||||
|
||||
if (prop != NULL)
|
||||
{
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueBool);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_INT:
|
||||
{
|
||||
ret = prop->valueInt;
|
||||
break;
|
||||
}
|
||||
case USER_PROP_FIXED:
|
||||
{
|
||||
ret = static_cast<INT32>(prop->valueFixed);
|
||||
break;
|
||||
}
|
||||
case USER_PROP_STR:
|
||||
{
|
||||
ret = static_cast<INT32>( ~env->getString( prop->valueStr )->idx );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread->dataStk.push(ret);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,4 +90,9 @@ bool CallFunc_SetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, AC
|
|||
bool CallFunc_GetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
||||
bool CallFunc_GetLineUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_GetSideUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_GetSectorUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_GetThingUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
||||
#endif // __SRB2_ACS_CALL_FUNCS_HPP__
|
||||
|
|
|
|||
|
|
@ -130,16 +130,16 @@ Environment::Environment()
|
|||
// ACS implementations.
|
||||
addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineProperty));
|
||||
addFuncDataACS0( 2, addCallFunc(CallFunc_SetLineProperty));
|
||||
//addFuncDataACS0( 3, addCallFunc(CallFunc_GetLineUserProperty));
|
||||
addFuncDataACS0( 3, addCallFunc(CallFunc_GetLineUserProperty));
|
||||
addFuncDataACS0( 4, addCallFunc(CallFunc_GetSectorProperty));
|
||||
addFuncDataACS0( 5, addCallFunc(CallFunc_SetSectorProperty));
|
||||
//addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUserProperty));
|
||||
addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUserProperty));
|
||||
addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideProperty));
|
||||
addFuncDataACS0( 8, addCallFunc(CallFunc_SetSideProperty));
|
||||
//addFuncDataACS0( 9, addCallFunc(CallFunc_GetSideUserProperty));
|
||||
addFuncDataACS0( 9, addCallFunc(CallFunc_GetSideUserProperty));
|
||||
//addFuncDataACS0( 10, addCallFunc(CallFunc_GetThingProperty));
|
||||
//addFuncDataACS0( 11, addCallFunc(CallFunc_SetThingProperty));
|
||||
//addFuncDataACS0( 12, addCallFunc(CallFunc_GetThingUserProperty));
|
||||
addFuncDataACS0( 12, addCallFunc(CallFunc_GetThingUserProperty));
|
||||
//addFuncDataACS0( 13, addCallFunc(CallFunc_GetPlayerProperty));
|
||||
//addFuncDataACS0( 14, addCallFunc(CallFunc_SetPlayerProperty));
|
||||
//addFuncDataACS0( 15, addCallFunc(CallFunc_GetPolyobjProperty));
|
||||
|
|
|
|||
|
|
@ -233,6 +233,21 @@ struct mapnode_t
|
|||
#pragma pack()
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USER_PROP_BOOL,
|
||||
USER_PROP_INT,
|
||||
USER_PROP_FIXED,
|
||||
USER_PROP_STR
|
||||
} mapUserPropertyType_e;
|
||||
|
||||
struct mapUserProperties_t
|
||||
{
|
||||
mapUserProperty_t *properties;
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
#define NUMMAPTHINGARGS 10
|
||||
#define NUMMAPTHINGSTRINGARGS 2
|
||||
|
||||
|
|
@ -252,6 +267,7 @@ struct mapthing_t
|
|||
INT32 args[NUMMAPTHINGARGS];
|
||||
char *stringargs[NUMMAPTHINGSTRINGARGS];
|
||||
UINT8 layer; // FOF layer to spawn on, see P_GetMobjSpawnHeight
|
||||
mapUserProperties_t user; // UDMF user-defined custom properties.
|
||||
mobj_t *mobj;
|
||||
};
|
||||
|
||||
|
|
|
|||
180
src/k_mapuser.c
Normal file
180
src/k_mapuser.c
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_mapuser.c
|
||||
/// \brief UDMF: Custom user properties
|
||||
|
||||
#include "k_mapuser.h"
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "doomdata.h"
|
||||
#include "doomtype.h"
|
||||
#include "z_zone.h"
|
||||
#include "m_misc.h"
|
||||
#include "m_fixed.h"
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UserPropertyPush(mapUserProperties_t *user, const char *key, mapUserPropertyType_e type, void *value)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_UserPropertyPush(mapUserProperties_t *user, const char *key, mapUserPropertyType_e type, void *value)
|
||||
{
|
||||
const size_t keyLength = strlen(key);
|
||||
mapUserProperty_t *prop = NULL;
|
||||
|
||||
I_Assert(keyLength > 0);
|
||||
|
||||
if (user->length >= user->capacity)
|
||||
{
|
||||
if (user->capacity == 0)
|
||||
{
|
||||
user->capacity = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
user->capacity *= 2;
|
||||
}
|
||||
|
||||
user->properties = (mapUserProperty_t *)Z_ReallocAlign(
|
||||
user->properties,
|
||||
sizeof(mapUserProperty_t) * user->capacity,
|
||||
PU_STATIC, // PU_LEVEL
|
||||
NULL,
|
||||
sizeof(mapUserProperty_t) * 8
|
||||
);
|
||||
}
|
||||
|
||||
prop = &user->properties[ user->length ];
|
||||
|
||||
prop->key = Z_Malloc(keyLength + 1, PU_STATIC, NULL);
|
||||
M_Memcpy(prop->key, key, keyLength + 1);
|
||||
prop->key[keyLength] = '\0';
|
||||
|
||||
prop->hash = quickncasehash(prop->key, keyLength);
|
||||
|
||||
prop->type = type;
|
||||
switch (type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
{
|
||||
prop->valueBool = *(boolean *)value;
|
||||
break;
|
||||
}
|
||||
case USER_PROP_INT:
|
||||
{
|
||||
prop->valueInt = *(INT32 *)value;
|
||||
break;
|
||||
}
|
||||
case USER_PROP_FIXED:
|
||||
{
|
||||
prop->valueFixed = *(fixed_t *)value;
|
||||
break;
|
||||
}
|
||||
case USER_PROP_STR:
|
||||
{
|
||||
const char *string = *(const char **)value;
|
||||
const size_t stringLength = strlen(string);
|
||||
|
||||
prop->valueStr = Z_Malloc(stringLength + 1, PU_STATIC, NULL);
|
||||
M_Memcpy(prop->valueStr, string, stringLength + 1);
|
||||
prop->valueStr[stringLength] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
user->length++;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
mapUserProperty_t *K_UserPropertyFind(mapUserProperties_t *user, const char *key)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
mapUserProperty_t *K_UserPropertyFind(mapUserProperties_t *user, const char *key)
|
||||
{
|
||||
const size_t keyLength = strlen(key);
|
||||
const UINT32 hash = quickncasehash(key, keyLength);
|
||||
size_t i;
|
||||
|
||||
if (user->length == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < user->length; i++)
|
||||
{
|
||||
mapUserProperty_t *const prop = &user->properties[ i ];
|
||||
|
||||
if (hash != prop->hash)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, prop->key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_UserPropertyFree(mapUserProperty_t *prop)
|
||||
|
||||
Frees the memory of a single user property.
|
||||
|
||||
Input Arguments:-
|
||||
prop - User property memory structure to free.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
static void K_UserPropertyFree(mapUserProperty_t *prop)
|
||||
{
|
||||
if (prop->key != NULL)
|
||||
{
|
||||
Z_Free(prop->key);
|
||||
prop->key = NULL;
|
||||
}
|
||||
|
||||
if (prop->valueStr != NULL)
|
||||
{
|
||||
Z_Free(prop->valueStr);
|
||||
prop->valueStr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UserPropertiesClear(mapUserProperties_t *user)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_UserPropertiesClear(mapUserProperties_t *user)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (user->properties == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < user->length; i++)
|
||||
{
|
||||
K_UserPropertyFree(&user->properties[i]);
|
||||
}
|
||||
|
||||
Z_Free(user->properties);
|
||||
user->properties = NULL;
|
||||
user->length = user->capacity = 0;
|
||||
}
|
||||
94
src/k_mapuser.h
Normal file
94
src/k_mapuser.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_mapuser.h
|
||||
/// \brief UDMF: Custom user properties
|
||||
|
||||
#ifndef __K_MAPUSER__
|
||||
#define __K_MAPUSER__
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "doomdata.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mapUserProperty_t
|
||||
{
|
||||
UINT32 hash;
|
||||
char *key;
|
||||
|
||||
mapUserPropertyType_e type;
|
||||
|
||||
boolean valueBool;
|
||||
INT32 valueInt;
|
||||
fixed_t valueFixed;
|
||||
char *valueStr;
|
||||
};
|
||||
|
||||
// mapUserProperties_t has to be defined in doomdata.h instead
|
||||
// because of circular dependency issues
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UserPropertyPush(mapUserProperties_t *user, const char *key, mapUserPropertyType_e type, void *value);
|
||||
|
||||
Adds a new key value to the user properties struct.
|
||||
|
||||
Input Arguments:-
|
||||
user - User properties memory structure.
|
||||
key - The key to add.
|
||||
type - Enum representing the type of the value to add.
|
||||
value - The value to add, as a void pointer.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_UserPropertyPush(mapUserProperties_t *user, const char *key, mapUserPropertyType_e type, void *value);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
mapUserProperty_t *K_UserPropertyFind(mapUserProperties_t *user, const char *key);
|
||||
|
||||
Tries to find if the key value already exists in this
|
||||
user properties struct.
|
||||
|
||||
Input Arguments:-
|
||||
user - User properties memory structure.
|
||||
key - The key to find.
|
||||
|
||||
Return:-
|
||||
The struct of the property we just got, or NULL if the key didn't exist already.
|
||||
--------------------------------------------------*/
|
||||
|
||||
mapUserProperty_t *K_UserPropertyFind(mapUserProperties_t *user, const char *key);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UserPropertiesClear(mapUserProperties_t *user);
|
||||
|
||||
Frees an entire user properties struct.
|
||||
|
||||
Input Arguments:-
|
||||
user - User properties memory structure to free.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_UserPropertiesClear(mapUserProperties_t *user);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // __K_MAPUSER__
|
||||
242
src/p_setup.c
242
src/p_setup.c
|
|
@ -103,6 +103,7 @@
|
|||
#include "doomstat.h" // MAXMUSNAMES
|
||||
#include "k_podium.h"
|
||||
#include "k_rank.h"
|
||||
#include "k_mapuser.h"
|
||||
|
||||
// Replay names have time
|
||||
#if !defined (UNDER_CE)
|
||||
|
|
@ -1388,6 +1389,80 @@ static boolean TextmapCount(size_t size)
|
|||
return true;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_NUM_TYPE_NA,
|
||||
PROP_NUM_TYPE_INT,
|
||||
PROP_NUM_TYPE_FLOAT
|
||||
};
|
||||
|
||||
static void ParseUserProperty(mapUserProperties_t *user, const char *param, const char *val)
|
||||
{
|
||||
if (fastncmp(param, "user_", 5) && strlen(param) > 5)
|
||||
{
|
||||
const char *key = param + 5;
|
||||
const size_t valLen = strlen(val);
|
||||
UINT8 numberType = PROP_NUM_TYPE_INT;
|
||||
size_t i = 0;
|
||||
|
||||
for (i = 0; i < valLen; i++)
|
||||
{
|
||||
if (val[i] == '.')
|
||||
{
|
||||
numberType = PROP_NUM_TYPE_FLOAT;
|
||||
}
|
||||
else if (val[i] < '0' || val[i] > '9')
|
||||
{
|
||||
numberType = PROP_NUM_TYPE_NA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (numberType)
|
||||
{
|
||||
case PROP_NUM_TYPE_NA:
|
||||
default:
|
||||
{
|
||||
// Value is a boolean or a string.
|
||||
|
||||
// Unfortunately, our UDMF parser discards the quotation marks,
|
||||
// so we can't differentiate strings from booleans properly.
|
||||
// Don't feel like tearing it apart to fix that, so we just
|
||||
// turn true & false into booleans, even if they were actually
|
||||
// supposed to be text.
|
||||
|
||||
boolean vBool = fastcmp("true", val);
|
||||
if (vBool == true || fastcmp("false", val))
|
||||
{
|
||||
// Value is *probably* a boolean.
|
||||
K_UserPropertyPush(user, key, USER_PROP_BOOL, &vBool);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Value is a string.
|
||||
K_UserPropertyPush(user, key, USER_PROP_STR, &val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROP_NUM_TYPE_INT:
|
||||
{
|
||||
// Value is an integer.
|
||||
INT32 vInt = atol(val);
|
||||
K_UserPropertyPush(user, key, USER_PROP_INT, &vInt);
|
||||
break;
|
||||
}
|
||||
case PROP_NUM_TYPE_FLOAT:
|
||||
{
|
||||
// Value is a float. Convert to fixed.
|
||||
fixed_t vFixed = FLOAT_TO_FIXED(atof(val));
|
||||
K_UserPropertyPush(user, key, USER_PROP_FIXED, &vFixed);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ParseTextmapVertexParameter(UINT32 i, const char *param, const char *val)
|
||||
{
|
||||
if (fastcmp(param, "x"))
|
||||
|
|
@ -1657,6 +1732,8 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
|
|||
sectors[i].activation |= SECSPAC_FLOORMISSILE;
|
||||
else if (fastcmp(param, "missileceiling") && fastcmp("true", val))
|
||||
sectors[i].activation |= SECSPAC_CEILINGMISSILE;
|
||||
else
|
||||
ParseUserProperty(§ors[i].user, param, val);
|
||||
}
|
||||
|
||||
static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val)
|
||||
|
|
@ -1675,6 +1752,8 @@ static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char
|
|||
P_SetSidedefSector(i, atol(val));
|
||||
else if (fastcmp(param, "repeatcnt"))
|
||||
sides[i].repeatcnt = atol(val);
|
||||
else
|
||||
ParseUserProperty(&sides[i].user, param, val);
|
||||
}
|
||||
|
||||
static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char *val)
|
||||
|
|
@ -1782,6 +1861,8 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char
|
|||
lines[i].activation |= SPAC_PUSHMONSTER;
|
||||
else if (fastcmp(param, "impact") && fastcmp("true", val))
|
||||
lines[i].activation |= SPAC_IMPACT;
|
||||
else
|
||||
ParseUserProperty(&lines[i].user, param, val);
|
||||
}
|
||||
|
||||
static void ParseTextmapThingParameter(UINT32 i, const char *param, const char *val)
|
||||
|
|
@ -1839,6 +1920,8 @@ static void ParseTextmapThingParameter(UINT32 i, const char *param, const char *
|
|||
return;
|
||||
mapthings[i].args[argnum] = atol(val);
|
||||
}
|
||||
else
|
||||
ParseUserProperty(&mapthings[i].user, param, val);
|
||||
}
|
||||
|
||||
/** From a given position table, run a specified parser function through a {}-encapsuled text.
|
||||
|
|
@ -1977,13 +2060,35 @@ static void P_WriteTextmap(void)
|
|||
memcpy(wsides, sides, numsides * sizeof(*sides));
|
||||
|
||||
for (i = 0; i < nummapthings; i++)
|
||||
{
|
||||
if (mapthings[i].tags.count)
|
||||
wmapthings[i].tags.tags = memcpy(Z_Malloc(mapthings[i].tags.count * sizeof(mtag_t), PU_LEVEL, NULL), mapthings[i].tags.tags, mapthings[i].tags.count * sizeof(mtag_t));
|
||||
|
||||
if (mapthings[i].user.length)
|
||||
{
|
||||
wmapthings[i].user.properties = memcpy(
|
||||
Z_Malloc(mapthings[i].user.length * sizeof(mapUserProperty_t), PU_LEVEL, NULL),
|
||||
mapthings[i].user.properties,
|
||||
mapthings[i].user.length * sizeof(mapUserProperty_t)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numsectors; i++)
|
||||
{
|
||||
if (sectors[i].tags.count)
|
||||
wsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t));
|
||||
|
||||
if (sectors[i].user.length)
|
||||
{
|
||||
wsectors[i].user.properties = memcpy(
|
||||
Z_Malloc(sectors[i].user.length * sizeof(mapUserProperty_t), PU_LEVEL, NULL),
|
||||
sectors[i].user.properties,
|
||||
sectors[i].user.length * sizeof(mapUserProperty_t)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
{
|
||||
size_t v;
|
||||
|
|
@ -1991,6 +2096,15 @@ static void P_WriteTextmap(void)
|
|||
if (lines[i].tags.count)
|
||||
wlines[i].tags.tags = memcpy(Z_Malloc(lines[i].tags.count * sizeof(mtag_t), PU_LEVEL, NULL), lines[i].tags.tags, lines[i].tags.count * sizeof(mtag_t));
|
||||
|
||||
if (lines[i].user.length)
|
||||
{
|
||||
wlines[i].user.properties = memcpy(
|
||||
Z_Malloc(lines[i].user.length * sizeof(mapUserProperty_t), PU_LEVEL, NULL),
|
||||
lines[i].user.properties,
|
||||
lines[i].user.length * sizeof(mapUserProperty_t)
|
||||
);
|
||||
}
|
||||
|
||||
v = lines[i].v1 - vertexes;
|
||||
wusedvertexes[v] = true;
|
||||
|
||||
|
|
@ -1998,6 +2112,18 @@ static void P_WriteTextmap(void)
|
|||
wusedvertexes[v] = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < numsides; i++)
|
||||
{
|
||||
if (sides[i].user.length)
|
||||
{
|
||||
wsides[i].user.properties = memcpy(
|
||||
Z_Malloc(sides[i].user.length * sizeof(mapUserProperty_t), PU_LEVEL, NULL),
|
||||
sides[i].user.properties,
|
||||
sides[i].user.length * sizeof(mapUserProperty_t)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
freetag = Tag_NextUnused(0);
|
||||
|
||||
for (i = 0; i < nummapthings; i++)
|
||||
|
|
@ -2279,6 +2405,28 @@ static void P_WriteTextmap(void)
|
|||
for (j = 0; j < NUMMAPTHINGSTRINGARGS; j++)
|
||||
if (mapthings[i].stringargs[j])
|
||||
fprintf(f, "stringarg%s = \"%s\";\n", sizeu1(j), mapthings[i].stringargs[j]);
|
||||
if (wmapthings[i].user.length > 0)
|
||||
{
|
||||
for (j = 0; j < wmapthings[i].user.length; j++)
|
||||
{
|
||||
mapUserProperty_t *const prop = &wmapthings[i].user.properties[j];
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
fprintf(f, "user_%s = %s;\n", prop->key, (prop->valueBool == true) ? "true" : "false");
|
||||
break;
|
||||
case USER_PROP_INT:
|
||||
fprintf(f, "user_%s = %d;\n", prop->key, prop->valueInt);
|
||||
break;
|
||||
case USER_PROP_FIXED:
|
||||
fprintf(f, "user_%s = %f;\n", prop->key, FIXED_TO_FLOAT(prop->valueFixed));
|
||||
break;
|
||||
case USER_PROP_STR:
|
||||
fprintf(f, "user_%s = \"%s\";\n", prop->key, prop->valueStr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "}\n");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
|
@ -2405,6 +2553,28 @@ static void P_WriteTextmap(void)
|
|||
fprintf(f, "monsterpush = true;\n");
|
||||
if (wlines[i].activation & SPAC_IMPACT)
|
||||
fprintf(f, "impact = true;\n");
|
||||
if (wlines[i].user.length > 0)
|
||||
{
|
||||
for (j = 0; j < wlines[i].user.length; j++)
|
||||
{
|
||||
mapUserProperty_t *const prop = &wlines[i].user.properties[j];
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
fprintf(f, "user_%s = %s;\n", prop->key, (prop->valueBool == true) ? "true" : "false");
|
||||
break;
|
||||
case USER_PROP_INT:
|
||||
fprintf(f, "user_%s = %d;\n", prop->key, prop->valueInt);
|
||||
break;
|
||||
case USER_PROP_FIXED:
|
||||
fprintf(f, "user_%s = %f;\n", prop->key, FIXED_TO_FLOAT(prop->valueFixed));
|
||||
break;
|
||||
case USER_PROP_STR:
|
||||
fprintf(f, "user_%s = \"%s\";\n", prop->key, prop->valueStr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "}\n");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
|
@ -2426,6 +2596,28 @@ static void P_WriteTextmap(void)
|
|||
fprintf(f, "texturemiddle = \"%.*s\";\n", 8, textures[wsides[i].midtexture]->name);
|
||||
if (wsides[i].repeatcnt != 0)
|
||||
fprintf(f, "repeatcnt = %d;\n", wsides[i].repeatcnt);
|
||||
if (wsides[i].user.length > 0)
|
||||
{
|
||||
for (j = 0; j < wsides[i].user.length; j++)
|
||||
{
|
||||
mapUserProperty_t *const prop = &wsides[i].user.properties[j];
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
fprintf(f, "user_%s = %s;\n", prop->key, (prop->valueBool == true) ? "true" : "false");
|
||||
break;
|
||||
case USER_PROP_INT:
|
||||
fprintf(f, "user_%s = %d;\n", prop->key, prop->valueInt);
|
||||
break;
|
||||
case USER_PROP_FIXED:
|
||||
fprintf(f, "user_%s = %f;\n", prop->key, FIXED_TO_FLOAT(prop->valueFixed));
|
||||
break;
|
||||
case USER_PROP_STR:
|
||||
fprintf(f, "user_%s = \"%s\";\n", prop->key, prop->valueStr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "}\n");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
|
@ -2609,6 +2801,28 @@ static void P_WriteTextmap(void)
|
|||
fprintf(f, "missilefloor = true;\n");
|
||||
if (wsectors[i].activation & SECSPAC_CEILINGMISSILE)
|
||||
fprintf(f, "missileceiling = true;\n");
|
||||
if (wsectors[i].user.length > 0)
|
||||
{
|
||||
for (j = 0; j < wsectors[i].user.length; j++)
|
||||
{
|
||||
mapUserProperty_t *const prop = &wsectors[i].user.properties[j];
|
||||
switch (prop->type)
|
||||
{
|
||||
case USER_PROP_BOOL:
|
||||
fprintf(f, "user_%s = %s;\n", prop->key, (prop->valueBool == true) ? "true" : "false");
|
||||
break;
|
||||
case USER_PROP_INT:
|
||||
fprintf(f, "user_%s = %d;\n", prop->key, prop->valueInt);
|
||||
break;
|
||||
case USER_PROP_FIXED:
|
||||
fprintf(f, "user_%s = %f;\n", prop->key, FIXED_TO_FLOAT(prop->valueFixed));
|
||||
break;
|
||||
case USER_PROP_STR:
|
||||
fprintf(f, "user_%s = \"%s\";\n", prop->key, prop->valueStr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "}\n");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
|
@ -2616,17 +2830,38 @@ static void P_WriteTextmap(void)
|
|||
fclose(f);
|
||||
|
||||
for (i = 0; i < nummapthings; i++)
|
||||
{
|
||||
if (wmapthings[i].tags.count)
|
||||
Z_Free(wmapthings[i].tags.tags);
|
||||
|
||||
if (wmapthings[i].user.length)
|
||||
Z_Free(wmapthings[i].user.properties);
|
||||
}
|
||||
|
||||
for (i = 0; i < numsectors; i++)
|
||||
{
|
||||
if (wsectors[i].tags.count)
|
||||
Z_Free(wsectors[i].tags.tags);
|
||||
|
||||
if (wsectors[i].user.length)
|
||||
Z_Free(wsectors[i].user.properties);
|
||||
}
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
{
|
||||
if (wlines[i].tags.count)
|
||||
Z_Free(wlines[i].tags.tags);
|
||||
|
||||
if (wlines[i].user.length)
|
||||
Z_Free(wlines[i].user.properties);
|
||||
}
|
||||
|
||||
for (i = 0; i < numsides; i++)
|
||||
{
|
||||
if (wsides[i].user.length)
|
||||
Z_Free(wsides[i].user.properties);
|
||||
}
|
||||
|
||||
Z_Free(wmapthings);
|
||||
Z_Free(wvertexes);
|
||||
Z_Free(wsectors);
|
||||
|
|
@ -2709,6 +2944,8 @@ static void P_LoadTextmap(void)
|
|||
memset(sc->stringargs, 0x00, NUMSECTORSTRINGARGS*sizeof(*sc->stringargs));
|
||||
sc->activation = 0;
|
||||
|
||||
K_UserPropertiesClear(&sc->user);
|
||||
|
||||
textmap_colormap.used = false;
|
||||
textmap_colormap.lightcolor = 0;
|
||||
textmap_colormap.lightalpha = 25;
|
||||
|
|
@ -2762,6 +2999,7 @@ static void P_LoadTextmap(void)
|
|||
ld->sidenum[1] = 0xffff;
|
||||
|
||||
ld->activation = 0;
|
||||
K_UserPropertiesClear(&ld->user);
|
||||
|
||||
TextmapParse(linesPos[i], i, ParseTextmapLinedefParameter);
|
||||
|
||||
|
|
@ -2786,6 +3024,8 @@ static void P_LoadTextmap(void)
|
|||
sd->sector = NULL;
|
||||
sd->repeatcnt = 0;
|
||||
|
||||
K_UserPropertiesClear(&sd->user);
|
||||
|
||||
TextmapParse(sidesPos[i], i, ParseTextmapSidedefParameter);
|
||||
|
||||
if (!sd->sector)
|
||||
|
|
@ -2811,6 +3051,8 @@ static void P_LoadTextmap(void)
|
|||
mt->layer = 0;
|
||||
mt->mobj = NULL;
|
||||
|
||||
K_UserPropertiesClear(&mt->user);
|
||||
|
||||
TextmapParse(mapthingsPos[i], i, ParseTextmapThingParameter);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
src/r_defs.h
11
src/r_defs.h
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "taglist.h"
|
||||
|
||||
#include "k_mapuser.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
@ -551,6 +553,9 @@ struct sector_t
|
|||
INT32 args[NUMSECTORARGS];
|
||||
char *stringargs[NUMSECTORSTRINGARGS];
|
||||
sectoractionflags_t activation;
|
||||
|
||||
// UDMF user-defined custom properties.
|
||||
mapUserProperties_t user;
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -609,6 +614,9 @@ struct line_t
|
|||
|
||||
char *text; // a concatenation of all front and back texture names, for linedef specials that require a string.
|
||||
INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0
|
||||
|
||||
// UDMF user-defined custom properties.
|
||||
mapUserProperties_t user;
|
||||
};
|
||||
|
||||
struct side_t
|
||||
|
|
@ -635,6 +643,9 @@ struct side_t
|
|||
char *text; // a concatenation of all top, bottom, and mid texture names, for linedef specials that require a string.
|
||||
|
||||
extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors.
|
||||
|
||||
// UDMF user-defined custom properties.
|
||||
mapUserProperties_t user;
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -217,6 +217,10 @@ TYPEDEF (gpRank_t);
|
|||
TYPEDEF (midVote_t);
|
||||
TYPEDEF (midVoteGUI_t);
|
||||
|
||||
// k_mapuser.h
|
||||
TYPEDEF (mapUserProperty_t);
|
||||
TYPEDEF (mapUserProperties_t);
|
||||
|
||||
// lua_hudlib_drawlist.h
|
||||
typedef struct huddrawlist_s *huddrawlist_h;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue