- handle cases where CON tries to spawn unknown actors.

It must fall back to spawning an inert sprite in these cases, not just fail.
This commit is contained in:
Christoph Oelckers 2022-12-31 19:56:41 +01:00
parent 34160a4354
commit 8a331e226f
5 changed files with 38 additions and 19 deletions

View file

@ -42,6 +42,8 @@ int getlabelvalue(const char* text);
static int ccmd_spawn(CCmdFuncPtr parm) static int ccmd_spawn(CCmdFuncPtr parm)
{ {
FTextureID texid = FNullTextureID();
int picno = -1;
int x = 0, y = 0, z = 0; int x = 0, y = 0, z = 0;
ESpriteFlags cstat = 0; ESpriteFlags cstat = 0;
PClassActor* cls = nullptr; PClassActor* cls = nullptr;
@ -74,14 +76,19 @@ static int ccmd_spawn(CCmdFuncPtr parm)
[[fallthrough]]; [[fallthrough]];
case 1: // tile number case 1: // tile number
if (isdigit((uint8_t)parm->parms[0][0])) { if (isdigit((uint8_t)parm->parms[0][0])) {
cls = GetSpawnType((unsigned short)atol(parm->parms[0])); picno = (unsigned short)atol(parm->parms[0]);
cls = GetSpawnType(picno);
} }
else else
{ {
cls = PClass::FindActor(parm->parms[0]); cls = PClass::FindActor(parm->parms[0]);
if (!cls) if (!cls)
{ {
int picno = tileForName(parm->parms[0]); texid = TexMan.CheckForTexture(parm->parms[0], ETextureType::Any, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnAll);
if (texid.isValid())
{
picno = legacyTileNum(texid);
}
if (picno < 0) if (picno < 0)
{ {
picno = getlabelvalue(parm->parms[0]); picno = getlabelvalue(parm->parms[0]);
@ -90,7 +97,7 @@ static int ccmd_spawn(CCmdFuncPtr parm)
} }
} }
if (cls == nullptr) if (cls == nullptr && !texid.isValid())
{ {
Printf("spawn: Invalid actor type '%s'\n", parm->parms[0]); Printf("spawn: Invalid actor type '%s'\n", parm->parms[0]);
return CCMD_OK; return CCMD_OK;
@ -100,7 +107,9 @@ static int ccmd_spawn(CCmdFuncPtr parm)
return CCMD_SHOWHELP; return CCMD_SHOWHELP;
} }
auto spawned = spawn(ps[myconnectindex].GetActor(), cls); DDukeActor* spawned;
if (!cls) spawned = spawnsprite(ps[myconnectindex].GetActor(), picno);
else spawned = spawn(ps[myconnectindex].GetActor(), cls);
if (spawned) if (spawned)
{ {
if (set & 1) spawned->spr.pal = (uint8_t)pal; if (set & 1) spawned->spr.pal = (uint8_t)pal;

View file

@ -20,6 +20,7 @@ inline int player_struct::GetPlayerNum()
} }
DDukeActor* spawn(DDukeActor* spawner, PClassActor* pname); DDukeActor* spawn(DDukeActor* spawner, PClassActor* pname);
DDukeActor* spawnsprite(DDukeActor* origin, int typeId);
// return type is int for scripting - the value must still be true or false! // return type is int for scripting - the value must still be true or false!
inline int badguy(const DDukeActor* pSprite) inline int badguy(const DDukeActor* pSprite)

View file

@ -1894,7 +1894,7 @@ int ParseState::parse(void)
case concmd_spawn: case concmd_spawn:
insptr++; insptr++;
if(g_ac->insector()) if(g_ac->insector())
spawn(g_ac, GetSpawnType(*insptr)); spawnsprite(g_ac, *insptr);
insptr++; insptr++;
break; break;
case concmd_ifwasweapon: case concmd_ifwasweapon:

View file

@ -82,7 +82,6 @@ DDukeActor* CreateActor(sectortype* whatsectp, const DVector3& pos, PClassActor*
if (whatsectp == nullptr || !validSectorIndex(sectindex(whatsectp))) return nullptr; if (whatsectp == nullptr || !validSectorIndex(sectindex(whatsectp))) return nullptr;
// spawning out of range sprites will also crash. // spawning out of range sprites will also crash.
if (clstype == nullptr) return nullptr; if (clstype == nullptr) return nullptr;
SpawnRec* info = nullptr;
if (s_stat < 0) s_stat = clstype ? GetDefaultByType(clstype)->spr.statnum : 0; if (s_stat < 0) s_stat = clstype ? GetDefaultByType(clstype)->spr.statnum : 0;
@ -90,7 +89,7 @@ DDukeActor* CreateActor(sectortype* whatsectp, const DVector3& pos, PClassActor*
if (act == nullptr) return nullptr; if (act == nullptr) return nullptr;
SetupGameVarsForActor(act); SetupGameVarsForActor(act);
setFromSpawnRec(act, info); setFromSpawnRec(act, nullptr);
act->spr.pos = pos; act->spr.pos = pos;
act->spr.shade = s_shd; act->spr.shade = s_shd;
if (!scale.isZero()) act->spr.scale = DVector2(scale.X, scale.Y); if (!scale.isZero()) act->spr.scale = DVector2(scale.X, scale.Y);
@ -258,6 +257,26 @@ DDukeActor* spawn(DDukeActor* actj, PClassActor * cls)
return nullptr; return nullptr;
} }
//---------------------------------------------------------------------------
//
// This spawns an actor from a spawnclasses type ID.
//
//---------------------------------------------------------------------------
DDukeActor* spawnsprite(DDukeActor* origin, int typeId)
{
auto srec = spawnMap.CheckKey(typeId);
if (srec && !srec->basetex.isValid()) return spawn(origin, srec->cls);
PClassActor* cls = srec ? srec->cls : (PClassActor*)RUNTIME_CLASS(DDukeActor);
auto spawned = spawn(origin, cls);
if (!spawned) return nullptr;
setFromSpawnRec(spawned, srec);
if (!srec) spawned->spr.setspritetexture(tileGetTextureID(typeId));
return spawned;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// //

View file

@ -491,21 +491,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, movesprite_ex, DukeActor_movesprite_ex
ACTION_RETURN_INT(DukeActor_movesprite_ex(self, velx, vely, velz, clipmask, coll)); ACTION_RETURN_INT(DukeActor_movesprite_ex(self, velx, vely, velz, clipmask, coll));
} }
DDukeActor* DukeActor_Spawnsprite(DDukeActor* origin, int typeId) DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, spawnsprite, spawnsprite)
{
auto st = GetSpawnType(typeId);
if (st)
{
return spawn(origin, st);
}
return nullptr;
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, spawnsprite, DukeActor_Spawnsprite)
{ {
PARAM_SELF_PROLOGUE(DDukeActor); PARAM_SELF_PROLOGUE(DDukeActor);
PARAM_INT(type); PARAM_INT(type);
ACTION_RETURN_POINTER(DukeActor_Spawnsprite(self, type)); ACTION_RETURN_POINTER(spawnsprite(self, type));
} }
void DukeActor_Lotsofglass(DDukeActor* origin, int count, walltype* wal) void DukeActor_Lotsofglass(DDukeActor* origin, int count, walltype* wal)