Fixes and changes for Emblem system

- New `flags` field
    - Permits coexistence of var and flags
- `notMedal` boolean is now `GE_NOTMEDAL`
- New `GE_TIMED` flag
    - Disappears `var` tics after `starttime`
- Improved M_GetConditionString handling for specific Emblem grabs
- More explicit error handling for invalid Emblem
This commit is contained in:
toaster 2022-12-13 22:19:37 +00:00
parent 0e8c739efc
commit 7081ffd509
6 changed files with 83 additions and 21 deletions

View file

@ -2164,8 +2164,8 @@ void reademblemdata(MYFILE *f, INT32 num)
emblemlocations[num-1].var = get_number(word2);
}
else if (fastcmp(word, "NOTMEDAL"))
emblemlocations[num-1].notMedal = (boolean)(value != 0 || word2[0] == 'T' || word2[0] == 'Y');
else if (fastcmp(word, "FLAGS"))
emblemlocations[num-1].flags = get_number(word2);
else
deh_warning("Emblem %d: unknown word '%s'", num, word);
}

View file

@ -6341,7 +6341,8 @@ struct int_const_s const INT_CONST[] = {
{"SF_X2AWAYSOUND",SF_X2AWAYSOUND},
// Global emblem var flags
// none in kart yet
{"GE_NOTMEDAL", GE_NOTMEDAL},
{"GE_TIMED", GE_TIMED},
// Map emblem var flags
{"ME_ENCORE",ME_ENCORE},

View file

@ -7985,7 +7985,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance

View file

@ -655,6 +655,42 @@ static const char *M_GetConditionString(condition_t *cn)
work = va("Get the %s Medal for %s", skincolors[emblemlocations[i].color].name, title);
break;
case ET_GLOBAL:
{
const char *astr, *colorstr, *medalstr;
if (emblemlocations[i].flags & GE_NOTMEDAL)
{
astr = "a ";
colorstr = "";
medalstr = "secret";
}
else if (emblemlocations[i].color <= 0 || emblemlocations[i].color >= numskincolors)
{
Z_Free(title);
return va("INVALID MEDAL COLOR \"%d:%d:%d\"", cn->requirement, emblemlocations[i].tag, checkLevel);
}
else
{
astr = "the ";
colorstr = skincolors[emblemlocations[i].color].name;
medalstr = " Medal";
}
if (emblemlocations[i].flags & GE_TIMED)
{
work = va("Find %s%s%s in %s before %i:%02i.%02i",
astr, colorstr, medalstr, title,
G_TicsToMinutes(emblemlocations[i].var, true),
G_TicsToSeconds(emblemlocations[i].var),
G_TicsToCentiseconds(emblemlocations[i].var));
}
else
{
work = va("Find %s%s%s in %s",
astr, colorstr, medalstr, title);
}
break;
}
default:
work = va("Find a secret in %s", title);
break;
@ -941,7 +977,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
continue;
levelnum = checkLevel;
embtype = emblemlocations[i].var;
embtype = emblemlocations[i].flags;
flags = MV_BEATEN;
if (embtype & ME_ENCORE)
@ -1067,7 +1103,8 @@ INT32 M_CountMedals(boolean all)
INT32 found = 0, i;
for (i = 0; i < numemblems; ++i)
{
if (emblemlocations[i].notMedal)
if ((emblemlocations[i].type == ET_GLOBAL)
&& (emblemlocations[i].flags & GE_NOTMEDAL))
continue;
if (!all && !gamedata->collected[i])
continue;

View file

@ -55,17 +55,17 @@ struct conditionset_t
};
// Emblem information
#define ET_GLOBAL 0 // Emblem with a position in space
#define ET_MAP 1 // Beat the map
#define ET_TIME 2 // Get the time
#define ET_GLOBAL 0 // Emblem with a position in space
#define ET_MAP 1 // Beat the map
#define ET_TIME 2 // Get the time
//#define ET_DEVTIME 3 // Time, but the value is tied to a Time Trial demo, not pre-defined
// Global emblem flags
// (N/A to Kart yet)
//#define GE_OH 1
#define GE_NOTMEDAL 1 // Doesn't count towards number of medals
#define GE_TIMED 2 // Disappears after var time
// Map emblem flags
#define ME_ENCORE 1
#define ME_ENCORE 1 // Achieve in Encore
struct emblem_t
{
@ -74,9 +74,9 @@ struct emblem_t
char * level; ///< Level on which this emblem can be found.
UINT8 sprite; ///< emblem sprite to use, 0 - 25
UINT16 color; ///< skincolor to use
INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin)
INT32 flags; ///< GE or ME constants
INT32 var; ///< If needed, specifies extra information
char *stringVar; ///< String version
boolean notMedal; ///< Not a Medal?
};
// Unlockable information

View file

@ -6931,17 +6931,38 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
break;
case MT_EMBLEM:
{
INT32 trans = 0;
mobj->frame &= ~FF_TRANSMASK;
mobj->renderflags &= ~RF_TRANSMASK;
if (P_EmblemWasCollected(mobj->health - 1) || !P_CanPickupEmblem(&players[consoleplayer], mobj->health - 1))
{
mobj->frame |= (tr_trans50 << FF_TRANSSHIFT);
trans = tr_trans50;
mobj->renderflags |= (tr_trans50 << RF_TRANSSHIFT);
}
else
if (mobj->reactiontime > 0
&& leveltime > starttime)
{
mobj->frame &= ~FF_TRANSMASK;
INT32 diff = mobj->reactiontime - (signed)(leveltime - starttime);
if (diff < 10)
{
if (diff <= 0)
{
P_RemoveMobj(mobj);
return false;
}
trans = max(trans, 10-diff);
}
}
if (mobj->flags2 & MF2_NIGHTSPULL)
P_NightsItemChase(mobj);
mobj->renderflags |= (trans << RF_TRANSSHIFT);
break;
}
case MT_FLOATINGITEM:
{
mobj->pitch = mobj->roll = 0;
@ -12008,7 +12029,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
if (!emblem)
{
CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, Tag_FGet(&mthing->tags));
CONS_Alert(CONS_WARNING, "P_SetupEmblem: No map emblem for map %d with tag %d found!\n", gamemap, Tag_FGet(&mthing->tags));
return false;
}
@ -12023,7 +12044,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
mobj->frame &= ~FF_TRANSMASK;
if (emblemlocations[j].type == ET_GLOBAL)
if (emblemlocations[j].flags & GE_TIMED)
{
mobj->reactiontime = emblemlocations[j].var;
}
@ -12471,7 +12492,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
case MT_EMBLEM:
{
if (!P_SetupEmblem(mthing, mobj))
{
P_RemoveMobj(mobj);
return false;
}
break;
}
case MT_SKYBOX: