mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-05-10 19:01:50 +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_vote.c
|
||||||
k_serverstats.c
|
k_serverstats.c
|
||||||
k_zvote.c
|
k_zvote.c
|
||||||
|
k_mapuser.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
|
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
|
||||||
|
|
|
||||||
|
|
@ -2226,3 +2226,268 @@ bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV,
|
||||||
|
|
||||||
return false;
|
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_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_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__
|
#endif // __SRB2_ACS_CALL_FUNCS_HPP__
|
||||||
|
|
|
||||||
|
|
@ -130,16 +130,16 @@ Environment::Environment()
|
||||||
// ACS implementations.
|
// ACS implementations.
|
||||||
addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineProperty));
|
addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineProperty));
|
||||||
addFuncDataACS0( 2, addCallFunc(CallFunc_SetLineProperty));
|
addFuncDataACS0( 2, addCallFunc(CallFunc_SetLineProperty));
|
||||||
//addFuncDataACS0( 3, addCallFunc(CallFunc_GetLineUserProperty));
|
addFuncDataACS0( 3, addCallFunc(CallFunc_GetLineUserProperty));
|
||||||
addFuncDataACS0( 4, addCallFunc(CallFunc_GetSectorProperty));
|
addFuncDataACS0( 4, addCallFunc(CallFunc_GetSectorProperty));
|
||||||
addFuncDataACS0( 5, addCallFunc(CallFunc_SetSectorProperty));
|
addFuncDataACS0( 5, addCallFunc(CallFunc_SetSectorProperty));
|
||||||
//addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUserProperty));
|
addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUserProperty));
|
||||||
addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideProperty));
|
addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideProperty));
|
||||||
addFuncDataACS0( 8, addCallFunc(CallFunc_SetSideProperty));
|
addFuncDataACS0( 8, addCallFunc(CallFunc_SetSideProperty));
|
||||||
//addFuncDataACS0( 9, addCallFunc(CallFunc_GetSideUserProperty));
|
addFuncDataACS0( 9, addCallFunc(CallFunc_GetSideUserProperty));
|
||||||
//addFuncDataACS0( 10, addCallFunc(CallFunc_GetThingProperty));
|
//addFuncDataACS0( 10, addCallFunc(CallFunc_GetThingProperty));
|
||||||
//addFuncDataACS0( 11, addCallFunc(CallFunc_SetThingProperty));
|
//addFuncDataACS0( 11, addCallFunc(CallFunc_SetThingProperty));
|
||||||
//addFuncDataACS0( 12, addCallFunc(CallFunc_GetThingUserProperty));
|
addFuncDataACS0( 12, addCallFunc(CallFunc_GetThingUserProperty));
|
||||||
//addFuncDataACS0( 13, addCallFunc(CallFunc_GetPlayerProperty));
|
//addFuncDataACS0( 13, addCallFunc(CallFunc_GetPlayerProperty));
|
||||||
//addFuncDataACS0( 14, addCallFunc(CallFunc_SetPlayerProperty));
|
//addFuncDataACS0( 14, addCallFunc(CallFunc_SetPlayerProperty));
|
||||||
//addFuncDataACS0( 15, addCallFunc(CallFunc_GetPolyobjProperty));
|
//addFuncDataACS0( 15, addCallFunc(CallFunc_GetPolyobjProperty));
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,21 @@ struct mapnode_t
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
#endif
|
#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 NUMMAPTHINGARGS 10
|
||||||
#define NUMMAPTHINGSTRINGARGS 2
|
#define NUMMAPTHINGSTRINGARGS 2
|
||||||
|
|
||||||
|
|
@ -252,6 +267,7 @@ struct mapthing_t
|
||||||
INT32 args[NUMMAPTHINGARGS];
|
INT32 args[NUMMAPTHINGARGS];
|
||||||
char *stringargs[NUMMAPTHINGSTRINGARGS];
|
char *stringargs[NUMMAPTHINGSTRINGARGS];
|
||||||
UINT8 layer; // FOF layer to spawn on, see P_GetMobjSpawnHeight
|
UINT8 layer; // FOF layer to spawn on, see P_GetMobjSpawnHeight
|
||||||
|
mapUserProperties_t user; // UDMF user-defined custom properties.
|
||||||
mobj_t *mobj;
|
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 "doomstat.h" // MAXMUSNAMES
|
||||||
#include "k_podium.h"
|
#include "k_podium.h"
|
||||||
#include "k_rank.h"
|
#include "k_rank.h"
|
||||||
|
#include "k_mapuser.h"
|
||||||
|
|
||||||
// Replay names have time
|
// Replay names have time
|
||||||
#if !defined (UNDER_CE)
|
#if !defined (UNDER_CE)
|
||||||
|
|
@ -1388,6 +1389,80 @@ static boolean TextmapCount(size_t size)
|
||||||
return true;
|
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)
|
static void ParseTextmapVertexParameter(UINT32 i, const char *param, const char *val)
|
||||||
{
|
{
|
||||||
if (fastcmp(param, "x"))
|
if (fastcmp(param, "x"))
|
||||||
|
|
@ -1657,6 +1732,8 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
|
||||||
sectors[i].activation |= SECSPAC_FLOORMISSILE;
|
sectors[i].activation |= SECSPAC_FLOORMISSILE;
|
||||||
else if (fastcmp(param, "missileceiling") && fastcmp("true", val))
|
else if (fastcmp(param, "missileceiling") && fastcmp("true", val))
|
||||||
sectors[i].activation |= SECSPAC_CEILINGMISSILE;
|
sectors[i].activation |= SECSPAC_CEILINGMISSILE;
|
||||||
|
else
|
||||||
|
ParseUserProperty(§ors[i].user, param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *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));
|
P_SetSidedefSector(i, atol(val));
|
||||||
else if (fastcmp(param, "repeatcnt"))
|
else if (fastcmp(param, "repeatcnt"))
|
||||||
sides[i].repeatcnt = atol(val);
|
sides[i].repeatcnt = atol(val);
|
||||||
|
else
|
||||||
|
ParseUserProperty(&sides[i].user, param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char *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;
|
lines[i].activation |= SPAC_PUSHMONSTER;
|
||||||
else if (fastcmp(param, "impact") && fastcmp("true", val))
|
else if (fastcmp(param, "impact") && fastcmp("true", val))
|
||||||
lines[i].activation |= SPAC_IMPACT;
|
lines[i].activation |= SPAC_IMPACT;
|
||||||
|
else
|
||||||
|
ParseUserProperty(&lines[i].user, param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ParseTextmapThingParameter(UINT32 i, const char *param, const char *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;
|
return;
|
||||||
mapthings[i].args[argnum] = atol(val);
|
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.
|
/** 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));
|
memcpy(wsides, sides, numsides * sizeof(*sides));
|
||||||
|
|
||||||
for (i = 0; i < nummapthings; i++)
|
for (i = 0; i < nummapthings; i++)
|
||||||
|
{
|
||||||
if (mapthings[i].tags.count)
|
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));
|
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++)
|
for (i = 0; i < numsectors; i++)
|
||||||
|
{
|
||||||
if (sectors[i].tags.count)
|
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));
|
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++)
|
for (i = 0; i < numlines; i++)
|
||||||
{
|
{
|
||||||
size_t v;
|
size_t v;
|
||||||
|
|
@ -1991,6 +2096,15 @@ static void P_WriteTextmap(void)
|
||||||
if (lines[i].tags.count)
|
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));
|
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;
|
v = lines[i].v1 - vertexes;
|
||||||
wusedvertexes[v] = true;
|
wusedvertexes[v] = true;
|
||||||
|
|
||||||
|
|
@ -1998,6 +2112,18 @@ static void P_WriteTextmap(void)
|
||||||
wusedvertexes[v] = true;
|
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);
|
freetag = Tag_NextUnused(0);
|
||||||
|
|
||||||
for (i = 0; i < nummapthings; i++)
|
for (i = 0; i < nummapthings; i++)
|
||||||
|
|
@ -2279,6 +2405,28 @@ static void P_WriteTextmap(void)
|
||||||
for (j = 0; j < NUMMAPTHINGSTRINGARGS; j++)
|
for (j = 0; j < NUMMAPTHINGSTRINGARGS; j++)
|
||||||
if (mapthings[i].stringargs[j])
|
if (mapthings[i].stringargs[j])
|
||||||
fprintf(f, "stringarg%s = \"%s\";\n", sizeu1(j), 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");
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -2405,6 +2553,28 @@ static void P_WriteTextmap(void)
|
||||||
fprintf(f, "monsterpush = true;\n");
|
fprintf(f, "monsterpush = true;\n");
|
||||||
if (wlines[i].activation & SPAC_IMPACT)
|
if (wlines[i].activation & SPAC_IMPACT)
|
||||||
fprintf(f, "impact = true;\n");
|
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");
|
||||||
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);
|
fprintf(f, "texturemiddle = \"%.*s\";\n", 8, textures[wsides[i].midtexture]->name);
|
||||||
if (wsides[i].repeatcnt != 0)
|
if (wsides[i].repeatcnt != 0)
|
||||||
fprintf(f, "repeatcnt = %d;\n", wsides[i].repeatcnt);
|
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");
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -2609,6 +2801,28 @@ static void P_WriteTextmap(void)
|
||||||
fprintf(f, "missilefloor = true;\n");
|
fprintf(f, "missilefloor = true;\n");
|
||||||
if (wsectors[i].activation & SECSPAC_CEILINGMISSILE)
|
if (wsectors[i].activation & SECSPAC_CEILINGMISSILE)
|
||||||
fprintf(f, "missileceiling = true;\n");
|
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");
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -2616,17 +2830,38 @@ static void P_WriteTextmap(void)
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
for (i = 0; i < nummapthings; i++)
|
for (i = 0; i < nummapthings; i++)
|
||||||
|
{
|
||||||
if (wmapthings[i].tags.count)
|
if (wmapthings[i].tags.count)
|
||||||
Z_Free(wmapthings[i].tags.tags);
|
Z_Free(wmapthings[i].tags.tags);
|
||||||
|
|
||||||
|
if (wmapthings[i].user.length)
|
||||||
|
Z_Free(wmapthings[i].user.properties);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < numsectors; i++)
|
for (i = 0; i < numsectors; i++)
|
||||||
|
{
|
||||||
if (wsectors[i].tags.count)
|
if (wsectors[i].tags.count)
|
||||||
Z_Free(wsectors[i].tags.tags);
|
Z_Free(wsectors[i].tags.tags);
|
||||||
|
|
||||||
|
if (wsectors[i].user.length)
|
||||||
|
Z_Free(wsectors[i].user.properties);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < numlines; i++)
|
for (i = 0; i < numlines; i++)
|
||||||
|
{
|
||||||
if (wlines[i].tags.count)
|
if (wlines[i].tags.count)
|
||||||
Z_Free(wlines[i].tags.tags);
|
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(wmapthings);
|
||||||
Z_Free(wvertexes);
|
Z_Free(wvertexes);
|
||||||
Z_Free(wsectors);
|
Z_Free(wsectors);
|
||||||
|
|
@ -2709,6 +2944,8 @@ static void P_LoadTextmap(void)
|
||||||
memset(sc->stringargs, 0x00, NUMSECTORSTRINGARGS*sizeof(*sc->stringargs));
|
memset(sc->stringargs, 0x00, NUMSECTORSTRINGARGS*sizeof(*sc->stringargs));
|
||||||
sc->activation = 0;
|
sc->activation = 0;
|
||||||
|
|
||||||
|
K_UserPropertiesClear(&sc->user);
|
||||||
|
|
||||||
textmap_colormap.used = false;
|
textmap_colormap.used = false;
|
||||||
textmap_colormap.lightcolor = 0;
|
textmap_colormap.lightcolor = 0;
|
||||||
textmap_colormap.lightalpha = 25;
|
textmap_colormap.lightalpha = 25;
|
||||||
|
|
@ -2762,6 +2999,7 @@ static void P_LoadTextmap(void)
|
||||||
ld->sidenum[1] = 0xffff;
|
ld->sidenum[1] = 0xffff;
|
||||||
|
|
||||||
ld->activation = 0;
|
ld->activation = 0;
|
||||||
|
K_UserPropertiesClear(&ld->user);
|
||||||
|
|
||||||
TextmapParse(linesPos[i], i, ParseTextmapLinedefParameter);
|
TextmapParse(linesPos[i], i, ParseTextmapLinedefParameter);
|
||||||
|
|
||||||
|
|
@ -2786,6 +3024,8 @@ static void P_LoadTextmap(void)
|
||||||
sd->sector = NULL;
|
sd->sector = NULL;
|
||||||
sd->repeatcnt = 0;
|
sd->repeatcnt = 0;
|
||||||
|
|
||||||
|
K_UserPropertiesClear(&sd->user);
|
||||||
|
|
||||||
TextmapParse(sidesPos[i], i, ParseTextmapSidedefParameter);
|
TextmapParse(sidesPos[i], i, ParseTextmapSidedefParameter);
|
||||||
|
|
||||||
if (!sd->sector)
|
if (!sd->sector)
|
||||||
|
|
@ -2811,6 +3051,8 @@ static void P_LoadTextmap(void)
|
||||||
mt->layer = 0;
|
mt->layer = 0;
|
||||||
mt->mobj = NULL;
|
mt->mobj = NULL;
|
||||||
|
|
||||||
|
K_UserPropertiesClear(&mt->user);
|
||||||
|
|
||||||
TextmapParse(mapthingsPos[i], i, ParseTextmapThingParameter);
|
TextmapParse(mapthingsPos[i], i, ParseTextmapThingParameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
src/r_defs.h
11
src/r_defs.h
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "taglist.h"
|
#include "taglist.h"
|
||||||
|
|
||||||
|
#include "k_mapuser.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -551,6 +553,9 @@ struct sector_t
|
||||||
INT32 args[NUMSECTORARGS];
|
INT32 args[NUMSECTORARGS];
|
||||||
char *stringargs[NUMSECTORSTRINGARGS];
|
char *stringargs[NUMSECTORSTRINGARGS];
|
||||||
sectoractionflags_t activation;
|
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.
|
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
|
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
|
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.
|
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.
|
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 (midVote_t);
|
||||||
TYPEDEF (midVoteGUI_t);
|
TYPEDEF (midVoteGUI_t);
|
||||||
|
|
||||||
|
// k_mapuser.h
|
||||||
|
TYPEDEF (mapUserProperty_t);
|
||||||
|
TYPEDEF (mapUserProperties_t);
|
||||||
|
|
||||||
// lua_hudlib_drawlist.h
|
// lua_hudlib_drawlist.h
|
||||||
typedef struct huddrawlist_s *huddrawlist_h;
|
typedef struct huddrawlist_s *huddrawlist_h;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue