- 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)
{
FTextureID texid = FNullTextureID();
int picno = -1;
int x = 0, y = 0, z = 0;
ESpriteFlags cstat = 0;
PClassActor* cls = nullptr;
@ -74,14 +76,19 @@ static int ccmd_spawn(CCmdFuncPtr parm)
[[fallthrough]];
case 1: // tile number
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
{
cls = PClass::FindActor(parm->parms[0]);
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)
{
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]);
return CCMD_OK;
@ -100,7 +107,9 @@ static int ccmd_spawn(CCmdFuncPtr parm)
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 (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* spawnsprite(DDukeActor* origin, int typeId);
// return type is int for scripting - the value must still be true or false!
inline int badguy(const DDukeActor* pSprite)

View file

@ -1894,7 +1894,7 @@ int ParseState::parse(void)
case concmd_spawn:
insptr++;
if(g_ac->insector())
spawn(g_ac, GetSpawnType(*insptr));
spawnsprite(g_ac, *insptr);
insptr++;
break;
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;
// spawning out of range sprites will also crash.
if (clstype == nullptr) return nullptr;
SpawnRec* info = nullptr;
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;
SetupGameVarsForActor(act);
setFromSpawnRec(act, info);
setFromSpawnRec(act, nullptr);
act->spr.pos = pos;
act->spr.shade = s_shd;
if (!scale.isZero()) act->spr.scale = DVector2(scale.X, scale.Y);
@ -258,6 +257,26 @@ DDukeActor* spawn(DDukeActor* actj, PClassActor * cls)
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));
}
DDukeActor* DukeActor_Spawnsprite(DDukeActor* origin, int typeId)
{
auto st = GetSpawnType(typeId);
if (st)
{
return spawn(origin, st);
}
return nullptr;
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, spawnsprite, DukeActor_Spawnsprite)
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, spawnsprite, spawnsprite)
{
PARAM_SELF_PROLOGUE(DDukeActor);
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)