Implement adding new teams

This commit is contained in:
Lactozilla 2023-08-05 20:14:44 -03:00
parent 4a2f3a2b18
commit f2bbc445a0
14 changed files with 660 additions and 71 deletions

View file

@ -4262,7 +4262,7 @@ void D_GameTypeChanged(INT32 lastgametype)
// When swapping to a gametype that supports spectators,
// make everyone a spectator initially.
// Averted with GTR_NOSPECTATORSPAWN.
if (!splitscreen && (G_GametypeHasSpectators()))
if (!splitscreen && G_GametypeHasSpectators())
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)

View file

@ -131,6 +131,22 @@ static inline int lib_freeslot(lua_State *L)
if (i == NUMCOLORFREESLOTS)
CONS_Alert(CONS_WARNING, "Ran out of free skincolor slots!\n");
}
else if (fastcmp(type, "TEAM"))
{
UINT8 i;
for (i = 0; i < MAXTEAMS; i++)
if (!teamnames[i]) {
CONS_Printf("Team TEAM_%s allocated.\n",word);
teamnames[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL);
strcpy(teamnames[i],word);
lua_pushinteger(L, i);
numteams++;
r++;
break;
}
if (i == MAXTEAMS)
CONS_Alert(CONS_WARNING, "Ran out of free team slots!\n");
}
else if (fastcmp(type, "SPR2"))
{
// Search if we already have an SPR2 by that name...
@ -560,6 +576,19 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
}
return luaL_error(L, "skincolor '%s' could not be found.\n", word);
}
else if (fastncmp("TEAM_",word,5)) {
p = word+5;
for (i = 0; i < MAXTEAMS; i++)
{
if (!teamnames[i])
break;
if (fastcmp(p, teamnames[i])) {
CacheAndPushConstant(L, word, i);
return 1;
}
}
return luaL_error(L, "team '%s' could not be found.\n", word);
}
else if (fastncmp("GRADE_",word,6))
{
p = word+6;

View file

@ -473,6 +473,16 @@ void readfreeslots(MYFILE *f)
break;
}
}
else if (fastcmp(type, "TEAM"))
{
for (i = 0; i < MAXTEAMS; i++)
if (!teamnames[i]) {
teamnames[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL);
strcpy(teamnames[i],word);
numteams++;
break;
}
}
else if (fastcmp(type, "SPR2"))
{
// Search if we already have an SPR2 by that name...
@ -1149,11 +1159,15 @@ void readgametype(MYFILE *f, char *gtname)
int newgtinttype = 0;
char gtdescription[441];
char gtconst[MAXLINELEN];
UINT8 teamcount = 0;
UINT8 teamlist[MAXTEAMS];
// Empty strings.
gtdescription[0] = '\0';
gtconst[0] = '\0';
strcpy(gtdescription, "???");
do
{
if (myfgets(s, MAXLINELEN, f))
@ -1278,10 +1292,37 @@ void readgametype(MYFILE *f, char *gtname)
newgttol = tol;
}
}
// The SOC probably provided gametype rules as words,
// instead of using the RULES keyword.
// Like for example "NOSPECTATORSPAWN = TRUE".
// This is completely valid, and looks better anyway.
// Teams
else if (fastcmp(word, "TEAMLIST"))
{
tmp = strtok(word2,",");
do {
if (teamcount == MAXTEAMS)
{
deh_warning("readgametype %s: too many teams\n", gtname);
break;
}
UINT8 team_id = TEAM_NONE;
for (i = 1; i < MAXTEAMS; i++)
{
if (!teamnames[i])
break;
if (fasticmp(tmp, teamnames[i]))
{
team_id = i;
break;
}
}
if (team_id == TEAM_NONE)
deh_warning("readgametype %s: unknown team %s\n", gtname, tmp);
else
{
teamlist[teamcount++] = team_id;
}
} while((tmp = strtok(NULL,",")) != NULL);
}
// This SOC probably provided gametype rules as words, instead of using the RULES keyword.
// (For example, "NOSPECTATORSPAWN = TRUE")
else
{
UINT32 wordgt = 0;
@ -1323,6 +1364,11 @@ void readgametype(MYFILE *f, char *gtname)
gametypes[newgtidx].pointlimit = newgtpointlimit;
gametypes[newgtidx].timelimit = newgttimelimit;
// Copy the teams
gametypes[newgtidx].teams.num = teamcount;
if (teamcount)
memcpy(gametypes[newgtidx].teams.list, teamlist, sizeof(teamlist[0]) * teamcount);
// Write the new gametype name.
gametypes[newgtidx].name = Z_StrDup(gtname);

View file

@ -406,7 +406,7 @@ typedef struct
{
char *name;
char *flag_name;
UINT8 flag;
UINT16 flag;
UINT32 flag_mobj_type;
UINT16 color;
UINT16 weapon_color;
@ -417,6 +417,8 @@ typedef struct
extern team_t teams[MAXTEAMS];
extern UINT8 numteams;
extern char *teamnames[MAXTEAMS];
#define NUMGAMETYPEFREESLOTS 128
// Gametypes
@ -484,6 +486,12 @@ enum
RANKINGS_RACE
};
typedef struct
{
UINT8 num;
UINT8 list[MAXTEAMS];
} teamlist_t;
typedef struct
{
char *name;
@ -494,8 +502,7 @@ typedef struct
INT16 rankings_type;
INT32 pointlimit;
INT32 timelimit;
UINT8 numteams;
UINT8 teams[MAXTEAMS];
teamlist_t teams;
} gametype_t;
extern gametype_t gametypes[NUMGAMETYPES];

View file

@ -3465,8 +3465,10 @@ gametype_t gametypes[NUMGAMETYPES] = {
// default settings for match: timelimit 10 mins, no pointlimit
.timelimit = 10,
.pointlimit = 0,
.numteams = 2,
.teams = { TEAM_RED, TEAM_BLUE }
.teams = {
.num = 2,
.list = { TEAM_RED, TEAM_BLUE }
}
},
// GT_TAG
{
@ -3499,8 +3501,10 @@ gametype_t gametypes[NUMGAMETYPES] = {
// default settings for CTF: no timelimit, pointlimit 5
.timelimit = 0,
.pointlimit = 5,
.numteams = 2,
.teams = { TEAM_RED, TEAM_BLUE }
.teams = {
.num = 2,
.list = { TEAM_RED, TEAM_BLUE }
}
},
};
@ -3525,6 +3529,8 @@ team_t teams[MAXTEAMS] = {
}
};
char *teamnames[MAXTEAMS];
static void G_InitTeams(void)
{
numteams = 3;
@ -3532,6 +3538,7 @@ static void G_InitTeams(void)
teams[TEAM_NONE].name = Z_StrDup("None");
teams[TEAM_NONE].flag_name = Z_StrDup("Thingmabob");
teamnames[TEAM_NONE] = Z_StrDup("NONE");
teams[TEAM_RED].name = Z_StrDup("Red");
teams[TEAM_RED].flag_name = Z_StrDup("Red Flag");
@ -3539,6 +3546,7 @@ static void G_InitTeams(void)
teams[TEAM_RED].icons[TEAM_ICON_FLAG] = Z_StrDup("RFLAGICO");
teams[TEAM_RED].icons[TEAM_ICON_GOT_FLAG] = Z_StrDup("GOTRFLAG");
teams[TEAM_RED].icons[TEAM_ICON_MISSING_FLAG] = Z_StrDup("NONICON2");
teamnames[TEAM_RED] = Z_StrDup("RED");
teams[TEAM_BLUE].name = Z_StrDup("Blue");
teams[TEAM_BLUE].flag_name = Z_StrDup("Blue Flag");
@ -3546,6 +3554,7 @@ static void G_InitTeams(void)
teams[TEAM_BLUE].icons[TEAM_ICON_FLAG] = Z_StrDup("BFLAGICO");
teams[TEAM_BLUE].icons[TEAM_ICON_GOT_FLAG] = Z_StrDup("GOTBFLAG");
teams[TEAM_BLUE].icons[TEAM_ICON_MISSING_FLAG] = Z_StrDup("NONICON");
teamnames[TEAM_BLUE] = Z_StrDup("BLUE");
G_UpdateTeamSelection();
}
@ -3572,11 +3581,20 @@ void G_UpdateTeamSelection(void)
i++;
}
for (UINT8 j = 1; j < teamsingame; j++, i++)
if (G_GametypeHasTeams())
{
UINT8 team = G_GetTeam(j);
dummyteam_cons_t[i].value = team;
dummyteam_cons_t[i].strvalue = teams[team].name;
for (UINT8 j = 1; j < teamsingame; j++, i++)
{
UINT8 team = G_GetTeam(j);
dummyteam_cons_t[i].value = team;
dummyteam_cons_t[i].strvalue = teams[team].name;
}
}
else
{
dummyteam_cons_t[i].value = 1;
dummyteam_cons_t[i].strvalue = "Playing";
i++;
}
dummyteam_cons_t[i].value = 0;
@ -3584,6 +3602,7 @@ void G_UpdateTeamSelection(void)
cv_dummyteam.defaultvalue = dummyteam_cons_t[0].strvalue;
cv_dummyteam.value = 0;
cv_dummyteam.string = cv_dummyteam.defaultvalue;
}
//
@ -3595,9 +3614,9 @@ void G_SetGametype(INT16 gtype)
gametyperules = gametypes[gametype].rules;
if (G_GametypeHasTeams())
teamsingame = gametypes[gametype].numteams + 1;
teamsingame = gametypes[gametype].teams.num + 1;
else
teamsingame = 3;
teamsingame = 0;
G_UpdateTeamSelection();
}
@ -3804,7 +3823,10 @@ boolean G_GametypeUsesCoopStarposts(void)
//
boolean G_GametypeHasTeams(void)
{
return (gametyperules & GTR_TEAMS);
if (gametyperules & GTR_TEAMS)
return gametypes[gametype].teams.num > 0;
return false;
}
//
@ -3885,10 +3907,10 @@ UINT32 G_TOLFlag(INT32 pgametype)
UINT8 G_GetGametypeTeam(UINT8 gtype, UINT8 team)
{
if (team == TEAM_NONE || team >= gametypes[gtype].numteams + 1)
if (team == TEAM_NONE || team >= gametypes[gtype].teams.num + 1)
return TEAM_NONE;
return gametypes[gtype].teams[team - 1] % MAXTEAMS;
return gametypes[gtype].teams.list[team - 1] % MAXTEAMS;
}
UINT8 G_GetTeam(UINT8 team)
@ -3982,6 +4004,39 @@ boolean G_HasTeamIcon(UINT8 team, UINT8 icon_type)
return true;
}
void G_SetTeamIcon(UINT8 team, UINT8 icon_type, const char *icon)
{
if (team >= numteams || icon_type >= TEAM_ICON_MAX)
return;
Z_Free(teams[team].icons[icon_type]);
teams[team].icons[icon_type] = NULL;
if (icon)
teams[team].icons[icon_type] = Z_StrDup(icon);
}
void G_FreeTeamData(UINT8 team)
{
if (team >= numteams)
return;
team_t *team_ptr = &teams[team];
if (team_ptr->name)
Z_Free(team_ptr->name);
if (team_ptr->flag_name)
Z_Free(team_ptr->flag_name);
for (UINT8 i = 0; i < TEAM_ICON_MAX; i++)
{
Z_Free(team_ptr->icons[i]);
team_ptr->icons[i] = NULL;
}
team_ptr->name = NULL;
team_ptr->flag_name = NULL;
}
/** Select a random map with the given typeoflevel flags.
* If no map has those flags, this arbitrarily gives you map 1.
* \param tolflags The typeoflevel flags to insist on. Other bits may

View file

@ -231,6 +231,8 @@ UINT16 G_GetTeamWeaponColor(UINT8 team);
UINT16 G_GetTeamMissileColor(UINT8 team);
const char *G_GetTeamIcon(UINT8 team, UINT8 icon_type);
boolean G_HasTeamIcon(UINT8 team, UINT8 icon_type);
void G_SetTeamIcon(UINT8 team, UINT8 icon_type, const char *icon);
void G_FreeTeamData(UINT8 team);
void G_Ticker(boolean run);
boolean G_Responder(event_t *ev);

View file

@ -2323,13 +2323,13 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
greycheck = greycheckdef;
supercheck = supercheckdef;
if (tab[i].team == TEAM_RED) //red
if (tab[i].team == G_GetTeam(1)) //red
{
redplayers++;
x = 14 + (BASEVIDWIDTH/2);
y = (redplayers * 9) + 20;
}
else if (tab[i].team == TEAM_BLUE) //blue
else if (tab[i].team == G_GetTeam(2)) //blue
{
blueplayers++;
x = 14;
@ -2409,7 +2409,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (players[tab[i].num].spectator)
continue; //ignore them.
if (tab[i].team == TEAM_RED) //red
if (tab[i].team == G_GetTeam(1)) //red
{
if (redplayers++ > 8)
{
@ -2417,7 +2417,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
break; // don't make more loops than we need to.
}
}
else if (tab[i].team == TEAM_BLUE) //blue
else if (tab[i].team == G_GetTeam(2)) //blue
{
if (blueplayers++ > 8)
{
@ -2448,14 +2448,14 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (players[tab[i].num].spectator)
continue; //ignore them.
if (tab[i].team == TEAM_RED) //red
if (tab[i].team == G_GetTeam(1)) //red
{
if (redplayers++ > 8)
continue;
x = 32 + (BASEVIDWIDTH/2);
y = (redplayers * 16) + 16;
}
else if (tab[i].team == TEAM_BLUE) //blue
else if (tab[i].team == G_GetTeam(2)) //blue
{
if (blueplayers++ > 8)
continue;

View file

@ -156,6 +156,8 @@ static const struct {
{META_SKINCOLOR, "skincolor_t"},
{META_COLORRAMP, "skincolor_t.ramp"},
{META_GAMETYPE, "gametype_t"},
{META_TEAM, "team_t"},
{META_TEAMLIST, "teamlist_t"},
{META_SPRITEINFO, "spriteinfo_t"},
{META_PIVOTLIST, "spriteframepivot_t[]"},
{META_FRAMEPIVOT, "spriteframepivot_t"},
@ -3402,7 +3404,6 @@ static int lib_sResumeMusic(lua_State *L)
// G_GAME
////////////
// Copypasted from lib_cvRegisterVar :]
static int lib_gAddGametype(lua_State *L)
{
const char *k;
@ -3420,6 +3421,8 @@ static int lib_gAddGametype(lua_State *L)
UINT8 newgtrightcolor = 0;
INT16 newgtrankingstype = -1;
int newgtinttype = 0;
UINT8 teamcount = 0;
UINT8 teamlist[MAXTEAMS];
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
@ -3445,7 +3448,6 @@ static int lib_gAddGametype(lua_State *L)
else if (lua_isstring(L, 2))
k = lua_tostring(L, 2);
// Sorry, no gametype rules as key names.
if (i == 1 || (k && fasticmp(k, "name"))) {
if (!lua_isstring(L, 3))
TYPEERROR("name", LUA_TSTRING)
@ -3490,6 +3492,36 @@ static int lib_gAddGametype(lua_State *L)
if (!lua_isnumber(L, 3))
TYPEERROR("headerrightcolor", LUA_TNUMBER)
newgtrightcolor = (UINT8)lua_tointeger(L, 3);
} else if (i == 12 || (k && fasticmp(k, "teams"))) {
if (lua_istable(L, 3))
{
lua_pushnil(L);
while (lua_next(L, 3)) {
lua_Integer idx = luaL_checkinteger(L, -2) - 1;
if (idx >= 0 && idx < MAXTEAMS)
{
int team_index = luaL_checkinteger(L, -1);
if (team_index < 0 || team_index >= numteams)
luaL_error(L, "team index %d out of range (0 - %d)", team_index, numteams-1);
teamlist[idx] = (UINT8)team_index;
if ((lua_Integer)teamcount < idx + 1)
teamcount = (UINT8)idx + 1;
}
lua_pop(L, 1);
}
}
else if (lua_isuserdata(L, 3))
{
teamlist_t *tl = *((teamlist_t **)luaL_checkudata(L, 3, META_TEAMLIST));
teamcount = tl->num;
memcpy(teamlist, tl->list, sizeof(teamlist[0]) * teamcount);
}
else
TYPEERROR("teams", LUA_TTABLE)
// Key name specified
} else if ((!i) && (k && fasticmp(k, "headercolor"))) {
if (!lua_isnumber(L, 3))
@ -3514,8 +3546,7 @@ static int lib_gAddGametype(lua_State *L)
// Add the new gametype
newgtidx = G_AddGametype(newgtrules);
G_AddGametypeTOL(newgtidx, newgttol);
G_SetGametypeDescription(newgtidx, NULL, newgtleftcolor, newgtrightcolor);
strncpy(gametypedesc[newgtidx].notes, gtdescription, 441);
G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor);
// Not covered by G_AddGametype alone.
if (newgtrankingstype == -1)
@ -3525,6 +3556,11 @@ static int lib_gAddGametype(lua_State *L)
gametypes[newgtidx].pointlimit = newgtpointlimit;
gametypes[newgtidx].timelimit = newgttimelimit;
// Copy the teams
gametypes[newgtidx].teams.num = teamcount;
if (teamcount)
memcpy(gametypes[newgtidx].teams.list, teamlist, sizeof(teamlist[0]) * teamcount);
// Write the new gametype name.
gametypes[newgtidx].name = gtname;

View file

@ -1930,7 +1930,8 @@ enum gametype_e
gametype_intermission_type,
gametype_rankings_type,
gametype_pointlimit,
gametype_timelimit
gametype_timelimit,
gametype_teams
};
const char *const gametype_opt[] = {
@ -1941,6 +1942,7 @@ const char *const gametype_opt[] = {
"rankings_type",
"point_limit",
"time_limit",
"teams",
NULL,
};
@ -1977,6 +1979,11 @@ static int gametype_get(lua_State *L)
case gametype_timelimit:
lua_pushinteger(L, gt->timelimit);
break;
case gametype_teams:
LUA_PushUserdata(L, &gt->teams, META_TEAMLIST);
break;
default:
return luaL_error(L, LUA_QL("gametype_t") " has no field named " LUA_QS, gametype_opt[field]);
}
return 1;
}
@ -1986,6 +1993,8 @@ static int gametype_set(lua_State *L)
gametype_t *gt = *((gametype_t **)luaL_checkudata(L, 1, META_GAMETYPE));
enum gametype_e field = Lua_optoption(L, 2, -1, gametype_fields_ref);
if (!lua_lumploading)
return luaL_error(L, "Do not alter gametype data from within a hook or coroutine!");
if (hud_running)
return luaL_error(L, "Do not alter gametype data in HUD rendering code!");
if (hook_cmd_running)
@ -1994,6 +2003,8 @@ static int gametype_set(lua_State *L)
I_Assert(gt != NULL);
I_Assert(gt >= gametypes);
INT16 gametype_id = gt - gametypes;
switch (field)
{
case gametype_name:
@ -2019,6 +2030,52 @@ static int gametype_set(lua_State *L)
case gametype_timelimit:
gt->timelimit = luaL_checkinteger(L, 3);
break;
case gametype_teams:
if (lua_istable(L, 3))
{
gt->teams.num = 0;
memset(gt->teams.list, TEAM_NONE, sizeof(gt->teams.list));
lua_pushnil(L);
while (lua_next(L, 3)) {
lua_Integer i = luaL_checkinteger(L, -2) - 1;
if (i >= 0 && i < MAXTEAMS)
{
int team_index = luaL_checkinteger(L, -1);
if (team_index < 0 || team_index >= numteams)
luaL_error(L, "team index %d out of range (0 - %d)", team_index, numteams-1);
gt->teams.list[i] = (UINT8)team_index;
if ((lua_Integer)gt->teams.num < i + 1)
gt->teams.num = (UINT8)i + 1;
}
lua_pop(L, 1);
}
if (gametype == gametype_id)
{
teamsingame = gt->teams.num;
G_UpdateTeamSelection();
}
}
else
{
teamlist_t *teamlist = *((teamlist_t **)luaL_checkudata(L, 3, META_TEAMLIST));
memcpy(&gt->teams, teamlist, sizeof(teamlist_t));
if (gametype == gametype_id)
{
teamsingame = gt->teams.num;
G_UpdateTeamSelection();
}
}
break;
default:
return luaL_error(L, LUA_QL("gametype_t") " has no field named " LUA_QS, gametype_opt[field]);
}
return 0;
}
@ -2034,6 +2091,313 @@ static int gametype_num(lua_State *L)
return 1;
}
///////////
// TEAMS //
///////////
enum team_e
{
team_name,
team_flag_name,
team_flag,
team_flag_mobj_type,
team_color,
team_weapon_color,
team_missile_color,
team_icon,
team_icon_flag,
team_icon_got_flag,
team_icon_missing_flag
};
const char *const team_opt[] = {
"name",
"flag_name",
"flag",
"flag_mobj_type",
"color",
"weapon_color",
"missile_color",
"icon",
"flag_icon",
"captured_flag_icon",
"missing_flag_icon",
NULL,
};
static int team_fields_ref = LUA_NOREF;
static int lib_getTeams(lua_State *L)
{
INT16 i;
lua_remove(L, 1);
i = luaL_checkinteger(L, 1);
if (i < 0 || i >= numteams)
return luaL_error(L, "teams[] index %d out of range (0 - %d)", i, numteams-1);
LUA_PushUserdata(L, &teams[i], META_GAMETYPE);
return 1;
}
static int set_team_field(lua_State *L, team_t *team, enum team_e field)
{
switch (field)
{
case team_name:
Z_Free(team->name);
team->name = Z_StrDup(luaL_checkstring(L, 3));
G_UpdateTeamSelection();
break;
case team_flag_name:
Z_Free(team->flag_name);
team->flag_name = Z_StrDup(luaL_checkstring(L, 3));
break;
case team_flag:
team->flag = (UINT16)luaL_checkinteger(L, 3);
break;
case team_flag_mobj_type:
{
mobjtype_t type = luaL_checkinteger(L, 3);
if (type >= NUMMOBJTYPES)
{
luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
return 0;
}
team->flag_mobj_type = type;
break;
}
case team_color:
{
UINT16 newcolor = (UINT16)luaL_checkinteger(L, 3);
if (newcolor >= numskincolors)
{
luaL_error(L, "skincolor %d out of range (0 - %d).", newcolor, numskincolors-1);
return 0;
}
team->color = newcolor;
break;
}
case team_weapon_color:
{
UINT16 newcolor = (UINT16)luaL_checkinteger(L, 3);
if (newcolor >= numskincolors)
{
luaL_error(L, "skincolor %d out of range (0 - %d).", newcolor, numskincolors-1);
return 0;
}
team->weapon_color = newcolor;
break;
}
case team_missile_color:
{
UINT16 newcolor = (UINT16)luaL_checkinteger(L, 3);
if (newcolor >= numskincolors)
{
luaL_error(L, "skincolor %d out of range (0 - %d).", newcolor, numskincolors-1);
return 0;
}
team->missile_color = newcolor;
break;
}
case team_icon:
G_SetTeamIcon(team - teams, TEAM_ICON, luaL_checkstring(L, 3));
ST_LoadTeamIcons();
break;
case team_icon_flag:
G_SetTeamIcon(team - teams, TEAM_ICON_FLAG, luaL_checkstring(L, 3));
ST_LoadTeamIcons();
break;
case team_icon_got_flag:
G_SetTeamIcon(team - teams, TEAM_ICON_GOT_FLAG, luaL_checkstring(L, 3));
ST_LoadTeamIcons();
break;
case team_icon_missing_flag:
G_SetTeamIcon(team - teams, TEAM_ICON_MISSING_FLAG, luaL_checkstring(L, 3));
ST_LoadTeamIcons();
break;
default:
return -1;
}
return 1;
}
static int lib_setTeams(lua_State *L)
{
UINT32 teamnum;
team_t *team;
lua_remove(L, 1);
{
teamnum = luaL_checkinteger(L, 1);
if (teamnum >= numteams)
return luaL_error(L, "teams[] index %d out of range (0 - %d)", teamnum, numteams-1);
team = &teams[teamnum];
}
luaL_checktype(L, 2, LUA_TTABLE);
lua_remove(L, 1);
lua_settop(L, 1);
if (hud_running)
return luaL_error(L, "Do not alter team data in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter team data in CMD building code!");
G_FreeTeamData(teamnum);
memset(team, 0, sizeof(team_t));
lua_pushnil(L);
while (lua_next(L, 1)) {
const char *str = luaL_checkstring(L, 2);
int field = -1;
for (int i = 0; team_opt[i]; i++) {
if (fastcmp(str, team_opt[i]))
{
field = i;
break;
}
}
if (field != -1)
set_team_field(L, team, field);
else
luaL_error(L, LUA_QL("team_t") " has no field named " LUA_QS, str);
lua_pop(L, 1);
}
return 0;
}
// #teams -> numteams
static int lib_teamslen(lua_State *L)
{
lua_pushinteger(L, numteams);
return 1;
}
static int team_get(lua_State *L)
{
team_t *team = *((team_t **)luaL_checkudata(L, 1, META_GAMETYPE));
enum team_e field = Lua_optoption(L, 2, team_name, team_fields_ref);
I_Assert(team != NULL);
I_Assert(team >= teams);
switch (field)
{
case team_name:
lua_pushstring(L, team->name);
break;
case team_flag_name:
lua_pushstring(L, team->flag_name);
break;
case team_flag:
lua_pushinteger(L, team->flag);
break;
case team_flag_mobj_type:
lua_pushinteger(L, team->flag_mobj_type);
break;
case team_color:
lua_pushinteger(L, team->color);
break;
case team_weapon_color:
lua_pushinteger(L, team->weapon_color);
break;
case team_missile_color:
lua_pushinteger(L, team->missile_color);
break;
case team_icon:
if (G_HasTeamIcon(team - teams, TEAM_ICON))
lua_pushstring(L, G_GetTeamIcon(team - teams, TEAM_ICON));
else
lua_pushnil(L);
break;
case team_icon_flag:
if (G_HasTeamIcon(team - teams, TEAM_ICON_FLAG))
lua_pushstring(L, G_GetTeamIcon(team - teams, TEAM_ICON_FLAG));
else
lua_pushnil(L);
break;
case team_icon_got_flag:
if (G_HasTeamIcon(team - teams, TEAM_ICON_GOT_FLAG))
lua_pushstring(L, G_GetTeamIcon(team - teams, TEAM_ICON_GOT_FLAG));
else
lua_pushnil(L);
break;
case team_icon_missing_flag:
if (G_HasTeamIcon(team - teams, TEAM_ICON_MISSING_FLAG))
lua_pushstring(L, G_GetTeamIcon(team - teams, TEAM_ICON_MISSING_FLAG));
else
lua_pushnil(L);
break;
default:
return luaL_error(L, LUA_QL("team_t") " has no field named " LUA_QS, lua_tostring(L, 2));
}
return 1;
}
static int team_set(lua_State *L)
{
team_t *team = *((team_t **)luaL_checkudata(L, 1, META_GAMETYPE));
enum team_e field = Lua_optoption(L, 2, -1, team_fields_ref);
if (!lua_lumploading)
return luaL_error(L, "Do not alter team data from within a hook or coroutine!");
if (hud_running)
return luaL_error(L, "Do not alter team data in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter team data in CMD building code!");
I_Assert(team != NULL);
I_Assert(team >= teams);
if (set_team_field(L, team, field) < 0)
return luaL_error(L, LUA_QL("team_t") " has no field named " LUA_QS, lua_tostring(L, 2));
return 0;
}
static int team_num(lua_State *L)
{
team_t *team = *((team_t **)luaL_checkudata(L, 1, META_GAMETYPE));
I_Assert(team != NULL);
I_Assert(team >= teams);
lua_pushinteger(L, team-teams);
return 1;
}
static int teamlist_len(lua_State *L)
{
teamlist_t *teamlist = *((teamlist_t **)luaL_checkudata(L, 1, META_TEAMLIST));
lua_pushinteger(L, teamlist->num);
return 1;
}
static int teamlist_get(lua_State *L)
{
teamlist_t *teamlist = *((teamlist_t **)luaL_checkudata(L, 1, META_TEAMLIST));
int i = luaL_checkinteger(L, 2);
if (i < 0 || i > teamlist->num)
return luaL_error(L, "list index %d out of range (1 - %d)", i, teamlist->num);
lua_pushinteger(L, teamlist->list[i - 1]);
return 1;
}
static int teamlist_set(lua_State *L)
{
teamlist_t *teamlist = *((teamlist_t **)luaL_checkudata(L, 1, META_TEAMLIST));
int i = luaL_checkinteger(L, 2);
if (i < 0 || i > teamlist->num)
return luaL_error(L, "list index %d out of range (1 - %d)", i, teamlist->num);
int team = luaL_checkinteger(L, 3);
if (team < 0 || team >= numteams)
return luaL_error(L, "team index %d out of range (0 - %d)", i, numteams - 1);
teamlist->list[i - 1] = (UINT8)team;
return 0;
}
//////////////////////////////
//
// Now push all these functions into the Lua state!
@ -2086,6 +2450,30 @@ int LUA_InfoLib(lua_State *L)
gametype_fields_ref = Lua_CreateFieldTable(L, gametype_opt);
luaL_newmetatable(L, META_TEAM);
lua_pushcfunction(L, team_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, team_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, team_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
team_fields_ref = Lua_CreateFieldTable(L, team_opt);
luaL_newmetatable(L, META_TEAMLIST);
lua_pushcfunction(L, teamlist_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, teamlist_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, teamlist_len);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
luaL_newmetatable(L, META_SKINCOLOR);
lua_pushcfunction(L, skincolor_get);
lua_setfield(L, -2, "__index");
@ -2262,6 +2650,19 @@ int LUA_InfoLib(lua_State *L)
lua_setmetatable(L, -2);
lua_setglobal(L, "gametypes");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getTeams);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_setTeams);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, lib_teamslen);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "teams");
luaL_newmetatable(L, META_LUABANKS);
lua_pushcfunction(L, lib_getluabanks);
lua_setfield(L, -2, "__index");

View file

@ -29,6 +29,8 @@ extern boolean mousegrabbedbylua;
#define META_COLORRAMP "SKINCOLOR_T*RAMP"
#define META_SPRITEINFO "SPRITEINFO_T*"
#define META_GAMETYPE "GAMETYPE_T*"
#define META_TEAM "TEAM_T*"
#define META_TEAMLIST "TEAMLIST_T*"
#define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
#define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"

View file

@ -214,10 +214,10 @@ int LUA_PushGlobals(lua_State *L, const char *word)
lua_pushboolean(L, paused);
return 1;
} else if (fastcmp(word,"bluescore")) {
lua_pushinteger(L, teamscores[TEAM_BLUE]);
lua_pushinteger(L, teamscores[G_GetTeam(2)]);
return 1;
} else if (fastcmp(word,"redscore")) {
lua_pushinteger(L, teamscores[TEAM_RED]);
lua_pushinteger(L, teamscores[G_GetTeam(1)]);
return 1;
} else if (fastcmp(word,"timelimit")) {
lua_pushinteger(L, cv_timelimit.value);
@ -226,16 +226,16 @@ int LUA_PushGlobals(lua_State *L, const char *word)
lua_pushinteger(L, cv_pointlimit.value);
return 1;
} else if (fastcmp(word, "redflag")) {
LUA_PushUserdata(L, flagmobjs[TEAM_RED], META_MOBJ);
LUA_PushUserdata(L, flagmobjs[G_GetTeam(1)], META_MOBJ);
return 1;
} else if (fastcmp(word, "blueflag")) {
LUA_PushUserdata(L, flagmobjs[TEAM_BLUE], META_MOBJ);
LUA_PushUserdata(L, flagmobjs[G_GetTeam(2)], META_MOBJ);
return 1;
} else if (fastcmp(word, "rflagpoint")) {
LUA_PushUserdata(L, flagpoints[TEAM_RED], META_MAPTHING);
LUA_PushUserdata(L, flagpoints[G_GetTeam(1)], META_MAPTHING);
return 1;
} else if (fastcmp(word, "bflagpoint")) {
LUA_PushUserdata(L, flagpoints[TEAM_BLUE], META_MAPTHING);
LUA_PushUserdata(L, flagpoints[G_GetTeam(2)], META_MAPTHING);
return 1;
// begin map vars
} else if (fastcmp(word,"spstage_start")) {
@ -271,6 +271,12 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
} else if (fastcmp(word,"numteams")) {
lua_pushinteger(L, max(numteams - 1, 0));
return 1;
} else if (fastcmp(word,"teamsingame")) {
lua_pushinteger(L, max(teamsingame - 1, 0));
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {
@ -991,6 +997,7 @@ enum
ARCH_MOUSE,
ARCH_SKIN,
ARCH_GAMETYPE,
ARCH_TEAM,
ARCH_TEND=0xFF,
};
@ -1021,6 +1028,7 @@ static const struct {
{META_MOUSE, ARCH_MOUSE},
{META_SKIN, ARCH_SKIN},
{META_GAMETYPE, ARCH_GAMETYPE},
{META_TEAM, ARCH_TEAM},
{NULL, ARCH_NULL}
};
@ -1356,6 +1364,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
WRITEUINT8(save_p, gt - gametypes);
break;
}
case ARCH_TEAM:
{
team_t *team = *((team_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_TEAM);
WRITEUINT8(save_p, team - teams);
break;
}
default:
WRITEUINT8(save_p, ARCH_NULL);
return 2;
@ -1608,6 +1623,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
case ARCH_GAMETYPE:
LUA_PushUserdata(gL, &gametypes[READUINT8(save_p)], META_GAMETYPE);
break;
case ARCH_TEAM:
LUA_PushUserdata(gL, &teams[READUINT8(save_p)], META_TEAM);
break;
case ARCH_TEND:
return 1;
}

View file

@ -473,7 +473,7 @@ static CV_PossibleValue_t dummymares_cons_t[] = {
{-1, "END"}, {0,"Overall"}, {1,"Mare 1"}, {2,"Mare 2"}, {3,"Mare 3"}, {4,"Mare 4"}, {5,"Mare 5"}, {6,"Mare 6"}, {7,"Mare 7"}, {8,"Mare 8"}, {0,NULL}
};
CV_PossibleValue_t dummyteam_cons_t[MAXTEAMS + 1];
CV_PossibleValue_t dummyteam_cons_t[MAXTEAMS + 2];
consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDEN, dummyteam_cons_t, NULL);
@ -6992,18 +6992,7 @@ static void M_ConfirmTeamChange(INT32 choice)
M_ClearMenus(true);
switch (cv_dummyteam.value)
{
case 0:
COM_ImmedExecute("changeteam spectator");
break;
case 1:
COM_ImmedExecute("changeteam red");
break;
case 2:
COM_ImmedExecute("changeteam blue");
break;
}
COM_ImmedExecute(va("changeteam %d", cv_dummyteam.value));
}
static void M_Options(INT32 choice)

View file

@ -2282,8 +2282,20 @@ void P_CheckTimeLimit(void)
}
else
{
//In team match and CTF, determining a tie is much simpler. =P
if (teamscores[TEAM_RED] == teamscores[TEAM_BLUE])
boolean is_tied = true;
UINT32 lastscore = teamscores[G_GetTeam(1)];
for (UINT8 j = 2; j < teamsingame; j++)
{
if (teamscores[G_GetTeam(j)] != lastscore)
{
is_tied = false;
break;
}
lastscore = teamscores[G_GetTeam(j)];
}
if (is_tied)
return;
}
}
@ -2303,7 +2315,8 @@ void P_CheckTimeLimit(void)
*/
void P_CheckPointLimit(void)
{
INT32 i;
if (!server)
return;
if (!cv_pointlimit.value)
return;
@ -2314,27 +2327,28 @@ void P_CheckPointLimit(void)
if (!(gametyperules & GTR_POINTLIMIT))
return;
// pointlimit is nonzero, check if it's been reached by this player
if (G_GametypeHasTeams())
{
// Just check both teams
if ((UINT32)cv_pointlimit.value <= teamscores[TEAM_RED] || (UINT32)cv_pointlimit.value <= teamscores[TEAM_BLUE])
for (UINT8 i = 1; i < teamsingame; i++)
{
if (server)
if (teamscores[G_GetTeam(i)] >= (UINT32)cv_pointlimit.value)
{
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
return;
}
}
}
else
{
for (i = 0; i < MAXPLAYERS; i++)
// pointlimit is nonzero, check if it's been reached by this player
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if ((UINT32)cv_pointlimit.value <= players[i].score)
{
if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
return;
}
}

View file

@ -4340,12 +4340,7 @@ static void P_NetArchiveMisc(boolean resending)
WRITEUINT8(save_p, teamsingame);
for (i = 0; i < MAXTEAMS; i++)
{
WRITEUINT32(save_p, teamscores[i]);
WRITEUINT16(save_p, teams[i].color);
WRITEUINT16(save_p, teams[i].weapon_color);
WRITEUINT16(save_p, teams[i].missile_color);
}
WRITEINT32(save_p, modulothing);
@ -4440,12 +4435,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
teamsingame = READUINT8(save_p);
for (i = 0; i < MAXTEAMS; i++)
{
teamscores[i] = READUINT32(save_p);
teams[i].color = READUINT16(save_p);
teams[i].weapon_color = READUINT16(save_p);
teams[i].missile_color = READUINT16(save_p);
}
modulothing = READINT32(save_p);