Merge branch 'acs-get-set' into 'master'

ACS: Property get/set functions

See merge request KartKrew/Kart!1203
This commit is contained in:
Sal 2023-05-03 13:30:15 +00:00
commit 2cba1b7820
12 changed files with 2410 additions and 9 deletions

View file

@ -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)

File diff suppressed because it is too large Load diff

View file

@ -83,4 +83,18 @@ bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM
bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_SetSideProperty(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_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_SetThingProperty(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__

View file

@ -128,14 +128,22 @@ Environment::Environment()
// This style is preferred for added functions
// that aren't mimicing one from Hexen's or ZDoom's
// ACS implementations.
//addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineUDMFInt));
//addFuncDataACS0( 2, addCallFunc(CallFunc_GetLineUDMFFixed));
//addFuncDataACS0( 3, addCallFunc(CallFunc_GetThingUDMFInt));
//addFuncDataACS0( 4, addCallFunc(CallFunc_GetThingUDMFFixed));
//addFuncDataACS0( 5, addCallFunc(CallFunc_GetSectorUDMFInt));
//addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUDMFFixed));
//addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideUDMFInt));
//addFuncDataACS0( 8, addCallFunc(CallFunc_GetSideUDMFFixed));
addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineProperty));
addFuncDataACS0( 2, addCallFunc(CallFunc_SetLineProperty));
addFuncDataACS0( 3, addCallFunc(CallFunc_GetLineUserProperty));
addFuncDataACS0( 4, addCallFunc(CallFunc_GetSectorProperty));
addFuncDataACS0( 5, addCallFunc(CallFunc_SetSectorProperty));
addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUserProperty));
addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideProperty));
addFuncDataACS0( 8, addCallFunc(CallFunc_SetSideProperty));
addFuncDataACS0( 9, addCallFunc(CallFunc_GetSideUserProperty));
addFuncDataACS0( 10, addCallFunc(CallFunc_GetThingProperty));
addFuncDataACS0( 11, addCallFunc(CallFunc_SetThingProperty));
addFuncDataACS0( 12, addCallFunc(CallFunc_GetThingUserProperty));
//addFuncDataACS0( 13, addCallFunc(CallFunc_GetPlayerProperty));
//addFuncDataACS0( 14, addCallFunc(CallFunc_SetPlayerProperty));
//addFuncDataACS0( 15, addCallFunc(CallFunc_GetPolyobjProperty));
//addFuncDataACS0( 16, addCallFunc(CallFunc_SetPolyobjProperty));
addFuncDataACS0( 100, addCallFunc(CallFunc_strcmp));
addFuncDataACS0( 101, addCallFunc(CallFunc_strcasecmp));

View file

@ -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;
};

View file

@ -540,6 +540,7 @@ void M_TokenizerClose(void);
const char *M_TokenizerRead(UINT32 i);
UINT32 M_TokenizerGetEndPos(void);
void M_TokenizerSetEndPos(UINT32 newPos);
boolean M_TokenizerJustReadString(void);
char *sizeu1(size_t num);
char *sizeu2(size_t num);

180
src/k_mapuser.c Normal file
View 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_LEVEL,
NULL,
sizeof(mapUserProperty_t) * 8
);
}
prop = &user->properties[ user->length ];
prop->key = Z_Malloc(keyLength + 1, PU_LEVEL, 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_LEVEL, 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
View 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__

View file

@ -2295,6 +2295,7 @@ static UINT32 tokenizerStartPos = 0;
static UINT32 tokenizerEndPos = 0;
static UINT32 tokenizerInputLength = 0;
static UINT8 tokenizerInComment = 0; // 0 = not in comment, 1 = // Single-line, 2 = /* Multi-line */
static boolean tokenizerIsString = false; // did we strip quotes from this token?
void M_TokenizerOpen(const char *inputString)
{
@ -2319,6 +2320,7 @@ void M_TokenizerClose(void)
tokenizerStartPos = 0;
tokenizerEndPos = 0;
tokenizerInComment = 0;
tokenizerIsString = false;
}
static void M_DetectComment(UINT32 *pos)
@ -2349,8 +2351,10 @@ static void M_ReadTokenString(UINT32 i)
// Assign the memory. Don't forget an extra byte for the end of the string!
tokenizerToken[i] = (char *)Z_Malloc(tokenCapacity[i] * sizeof(char), PU_STATIC, NULL);
}
// Copy the string.
M_Memcpy(tokenizerToken[i], tokenizerInput + tokenizerStartPos, (size_t)tokenLength);
// Make the final character NUL.
tokenizerToken[i][tokenLength] = '\0';
}
@ -2362,6 +2366,9 @@ const char *M_TokenizerRead(UINT32 i)
tokenizerStartPos = tokenizerEndPos;
// Reset string flag
tokenizerIsString = false;
// Try to detect comments now, in case we're pointing right at one
M_DetectComment(&tokenizerStartPos);
@ -2416,6 +2423,10 @@ const char *M_TokenizerRead(UINT32 i)
M_ReadTokenString(i);
tokenizerEndPos++;
// Tell us the the token was a string.
tokenizerIsString = true;
return tokenizerToken[i];
}
@ -2451,6 +2462,11 @@ void M_TokenizerSetEndPos(UINT32 newPos)
tokenizerEndPos = newPos;
}
boolean M_TokenizerJustReadString(void)
{
return tokenizerIsString;
}
/** Count bits in a number.
*/
UINT8 M_CountBits(UINT32 num, UINT8 size)

View file

@ -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,82 @@ 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 boolean valIsString = M_TokenizerJustReadString();
const char *key = param + 5;
const size_t valLen = strlen(val);
UINT8 numberType = PROP_NUM_TYPE_INT;
size_t i = 0;
if (valIsString == true)
{
// Value is a string. Upload directly!
K_UserPropertyPush(user, key, USER_PROP_STR, &val);
return;
}
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_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;
}
case PROP_NUM_TYPE_NA:
default:
{
// Value is some other kind of type.
// Currently we just support bool.
boolean vBool = fastcmp("true", val);
if (vBool == true || fastcmp("false", val))
{
// Value is a boolean.
K_UserPropertyPush(user, key, USER_PROP_BOOL, &vBool);
}
else
{
// Value is invalid.
CONS_Alert(CONS_WARNING, "Could not interpret user property \"%s\" value (%s)\n", param, val);
}
break;
}
}
}
}
static void ParseTextmapVertexParameter(UINT32 i, const char *param, const char *val)
{
if (fastcmp(param, "x"))
@ -1657,6 +1734,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(&sectors[i].user, param, val);
}
static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val)
@ -1675,6 +1754,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 +1863,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 +1922,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 +2062,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 +2098,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 +2114,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 +2407,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 +2555,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 +2598,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 +2803,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 +2832,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 +2946,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 +3001,7 @@ static void P_LoadTextmap(void)
ld->sidenum[1] = 0xffff;
ld->activation = 0;
K_UserPropertiesClear(&ld->user);
TextmapParse(linesPos[i], i, ParseTextmapLinedefParameter);
@ -2786,6 +3026,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 +3053,8 @@ static void P_LoadTextmap(void)
mt->layer = 0;
mt->mobj = NULL;
K_UserPropertiesClear(&mt->user);
TextmapParse(mapthingsPos[i], i, ParseTextmapThingParameter);
}
}

View file

@ -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;
};
//

View file

@ -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;