mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-04-20 09:11:01 +00:00
Change behavior of Spawn to match ZDoom
Add SpawnForced and SpawnProjectile
This commit is contained in:
parent
6b4d193fdf
commit
985a0be20a
6 changed files with 206 additions and 28 deletions
|
@ -26,6 +26,7 @@ special
|
|||
-211:SetActorFlag(2,3),
|
||||
-212:SetActorClass(2),
|
||||
-213:SetActorDye(2),
|
||||
-214:SpawnForced(4,6),
|
||||
-300:CountEnemies(2),
|
||||
-301:CountPushables(2),
|
||||
-302:HasUnlockable(1),
|
||||
|
|
|
@ -577,6 +577,27 @@ static UINT32 ACS_SectorTagThingCounter(mtag_t sectorTag, sector_t *activator, m
|
|||
return count;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static bool ACS_IsLocationValid(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z)
|
||||
|
||||
Helper function for CallFunc_SpawnObject and CallFunc_SetObjectPosition.
|
||||
Checks if the given coordinates are valid for an actor to exist in.
|
||||
--------------------------------------------------*/
|
||||
static bool ACS_IsLocationValid(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z)
|
||||
{
|
||||
if (P_CheckPosition(mobj, x, y) == true)
|
||||
{
|
||||
fixed_t floorz = P_FloorzAtPos(x, y, z, mobj->height);
|
||||
fixed_t ceilingz = P_CeilingzAtPos(x, y, z, mobj->height);
|
||||
if (z >= floorz && (z + mobj->height) <= ceilingz)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_Random(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
|
@ -1791,6 +1812,42 @@ bool CallFunc_SetViewpoint(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM
|
|||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static bool ACS_SpawnObject(player_t *player, INT32 property, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Helper function for CallFunc_SpawnObject and CallFunc_SpawnObjectForced.
|
||||
--------------------------------------------------*/
|
||||
static bool ACS_SpawnObject(mobjtype_t mobjType, bool forceSpawn, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
fixed_t x = argV[1];
|
||||
fixed_t y = argV[2];
|
||||
fixed_t z = argV[3];
|
||||
|
||||
mobj_t *mobj = P_SpawnMobj(x, y, z, mobjType);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!forceSpawn && ACS_IsLocationValid(mobj, x, y, z) == false)
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Spawned successfully
|
||||
if (argC >= 5)
|
||||
P_SetThingTID(mobj, argV[4]);
|
||||
|
||||
if (argC >= 6)
|
||||
mobj->angle = ACS_FixedToAngle(argV[5]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
|
@ -1803,7 +1860,7 @@ bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:
|
|||
{
|
||||
CONS_Alert(CONS_WARNING, "Spawn actor class was not provided.\n");
|
||||
|
||||
NO_RETURN(thread);
|
||||
thread->dataStk.push(0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1812,6 +1869,8 @@ bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:
|
|||
|
||||
mobjtype_t mobjType = MT_NULL;
|
||||
|
||||
int numSpawned = 0;
|
||||
|
||||
if (ACS_GetMobjTypeFromString(className, &mobjType) == false)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
|
@ -1821,29 +1880,52 @@ bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:
|
|||
}
|
||||
else
|
||||
{
|
||||
fixed_t x = argV[1];
|
||||
fixed_t y = argV[2];
|
||||
fixed_t z = argV[3];
|
||||
|
||||
mobj_t *mobj = P_SpawnMobj(x, y, z, mobjType);
|
||||
if (!P_MobjWasRemoved(mobj))
|
||||
{
|
||||
if (argC >= 5)
|
||||
P_SetThingTID(mobj, argV[4]);
|
||||
|
||||
if (argC >= 6)
|
||||
mobj->angle = ACS_FixedToAngle(argV[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
"Spawn: Couldn't spawn actor class \"%s\".\n",
|
||||
className
|
||||
);
|
||||
}
|
||||
if (ACS_SpawnObject(mobjType, false, argV, argC) == true)
|
||||
numSpawned = 1;
|
||||
}
|
||||
|
||||
NO_RETURN(thread);
|
||||
thread->dataStk.push(numSpawned);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_SpawnObjectForced(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Spawns an actor, even in locations where it would not normally be able to exist.
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_SpawnObjectForced(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
ACSVM::String *str = thread->scopeMap->getString( argV[0] );
|
||||
if (!str->str || str->len == 0)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "SpawnForced actor class was not provided.\n");
|
||||
|
||||
thread->dataStk.push(0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *className = str->str;
|
||||
|
||||
mobjtype_t mobjType = MT_NULL;
|
||||
|
||||
int numSpawned = 0;
|
||||
|
||||
if (ACS_GetMobjTypeFromString(className, &mobjType) == false)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
"Couldn't find actor class \"%s\" for SpawnForced.\n",
|
||||
className
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ACS_SpawnObject(mobjType, true, argV, argC) == true)
|
||||
numSpawned = 1;
|
||||
}
|
||||
|
||||
thread->dataStk.push(numSpawned);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -2569,11 +2651,9 @@ bool CallFunc_SetObjectPosition(ACSVM::Thread *thread, const ACSVM::Word *argV,
|
|||
fixed_t y = argV[2];
|
||||
fixed_t z = argV[3];
|
||||
|
||||
if (mobj != NULL && P_MobjWasRemoved(mobj) == false && P_CheckPosition(mobj, x, y) == true)
|
||||
if (mobj != NULL && P_MobjWasRemoved(mobj) == false)
|
||||
{
|
||||
fixed_t floorz = P_FloorzAtPos(x, y, z, mobj->height);
|
||||
fixed_t ceilingz = P_CeilingzAtPos(x, y, z, mobj->height);
|
||||
if (z >= floorz && (z + mobj->height) <= ceilingz)
|
||||
if (ACS_IsLocationValid(mobj, x, y, z))
|
||||
{
|
||||
P_SetOrigin(mobj, x, y, z);
|
||||
success = true;
|
||||
|
@ -4516,7 +4596,7 @@ bool CallFunc_CheckPowerUp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM
|
|||
/*--------------------------------------------------
|
||||
static void ACS_SetPowerUp(player_t *player, INT32 property, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Helper for CallFunc_GivePowerUp.
|
||||
Helper function for CallFunc_GivePowerUp.
|
||||
--------------------------------------------------*/
|
||||
static void ACS_SetPowerUp(player_t *player, INT32 property, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
|
@ -4674,7 +4754,7 @@ bool CallFunc_CheckAmmo(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W
|
|||
/*--------------------------------------------------
|
||||
static void ACS_GiveAmmo(player_t *player, INT32 weapon, INT32 value)
|
||||
|
||||
Helper for CallFunc_GiveAmmo/CallFunc_TakeAmmo.
|
||||
Helper function for CallFunc_GiveAmmo/CallFunc_TakeAmmo.
|
||||
--------------------------------------------------*/
|
||||
static bool ACS_GiveAmmo(player_t *player, INT32 weapon, INT32 value)
|
||||
{
|
||||
|
@ -5200,6 +5280,58 @@ bool CallFunc_PlayerFinished(ACSVM::Thread *thread, const ACSVM::Word *argV, ACS
|
|||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_SpawnProjectile(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Spawns a projectile. Yeah...
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_SpawnProjectile(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
(void)argC;
|
||||
|
||||
auto info = &static_cast<Thread *>(thread)->info;
|
||||
|
||||
mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo);
|
||||
if (mobj != NULL && P_MobjWasRemoved(mobj) == false)
|
||||
{
|
||||
ACSVM::String *str = thread->scopeMap->getString( argV[1] );
|
||||
if (!str->str || str->len == 0)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "SpawnProjectile projectile class was not provided.\n");
|
||||
|
||||
NO_RETURN(thread);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *className = str->str;
|
||||
|
||||
mobjtype_t mobjType = MT_NULL;
|
||||
|
||||
if (ACS_GetMobjTypeFromString(className, &mobjType) == false)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
"Couldn't find actor class \"%s\" for SpawnProjectile.\n",
|
||||
className
|
||||
);
|
||||
|
||||
NO_RETURN(thread);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
mobj_t *missile = P_SpawnMissileAtSpeeds(mobj, mobjType, ACS_FixedToAngle(argV[2]), argV[3], argV[4], argV[5] != 0);
|
||||
if (missile && argV[6] != 0)
|
||||
{
|
||||
P_SetThingTID(mobj, argV[6]);
|
||||
}
|
||||
}
|
||||
|
||||
NO_RETURN(thread);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_Sin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ bool CallFunc_PlayerExiting(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSV
|
|||
bool CallFunc_Teleport(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_SetViewpoint(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_SpawnObjectForced(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_TrackObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_StopTrackingObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
@ -165,6 +166,8 @@ bool CallFunc_PlayerHoldingFlag(ACSVM::Thread *thread, const ACSVM::Word *argV,
|
|||
bool CallFunc_PlayerIsIt(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerFinished(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
||||
bool CallFunc_SpawnProjectile(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
||||
bool CallFunc_Sin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_Cos(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_Tan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
|
|
@ -134,6 +134,7 @@ Environment::Environment()
|
|||
addCodeDataACS0(270, {"", 0, addCallFunc(CallFunc_EndLog)});
|
||||
// 273 to 275: Implemented by ACSVM
|
||||
addCodeDataACS0(276, {"", 2, addCallFunc(CallFunc_SetObjectAngle)});
|
||||
addCodeDataACS0(280, {"", 7, addCallFunc(CallFunc_SpawnProjectile)});
|
||||
addCodeDataACS0(282, {"", 1, addCallFunc(CallFunc_GetObjectCeilingZ)});
|
||||
|
||||
// 291 to 325: Implemented by ACSVM
|
||||
|
@ -189,6 +190,7 @@ Environment::Environment()
|
|||
addFuncDataACS0( 211, addCallFunc(CallFunc_SetObjectFlag));
|
||||
addFuncDataACS0( 212, addCallFunc(CallFunc_SetObjectClass));
|
||||
addFuncDataACS0( 213, addCallFunc(CallFunc_SetObjectDye));
|
||||
addFuncDataACS0( 214, addCallFunc(CallFunc_SpawnObjectForced));
|
||||
|
||||
addFuncDataACS0( 300, addCallFunc(CallFunc_CountEnemies));
|
||||
addFuncDataACS0( 301, addCallFunc(CallFunc_CountPushables));
|
||||
|
|
|
@ -342,6 +342,7 @@ mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type, fixed_t
|
|||
mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za, mobjtype_t type, fixed_t x, fixed_t y, fixed_t z);
|
||||
mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t x, fixed_t y, fixed_t z, INT32 shiftingAngle);
|
||||
mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 aimtype, UINT32 flags2);
|
||||
mobj_t *P_SpawnMissileAtSpeeds(mobj_t *source, mobjtype_t type, angle_t angle, fixed_t hspeed, fixed_t vspeed, boolean useGravity);
|
||||
#define P_SpawnPlayerMissile(s,t,f) P_SPMAngle(s,t,s->angle,true,f)
|
||||
#define P_SpawnNameFinder(s,t) P_SPMAngle(s,t,s->angle,true,0)
|
||||
void P_ColorTeamMissile(mobj_t *missile, player_t *source);
|
||||
|
|
39
src/p_mobj.c
39
src/p_mobj.c
|
@ -14369,6 +14369,45 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
|
|||
return slope ? th : NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// P_SpawnMissileAtSpeeds
|
||||
// Fires missile at angle and X/Y speeds
|
||||
//
|
||||
mobj_t *P_SpawnMissileAtSpeeds(mobj_t *source, mobjtype_t type, angle_t angle, fixed_t hspeed, fixed_t vspeed, boolean useGravity)
|
||||
{
|
||||
fixed_t x = source->x;
|
||||
fixed_t y = source->y;
|
||||
fixed_t z;
|
||||
|
||||
if (source->eflags & MFE_VERTICALFLIP)
|
||||
z = source->z + 2*source->height/3 - FixedMul(mobjinfo[type].height, source->scale);
|
||||
else
|
||||
z = source->z + source->height/3;
|
||||
|
||||
mobj_t *th = P_SpawnMobj(x, y, z, type);
|
||||
if (P_MobjWasRemoved(th))
|
||||
return NULL;
|
||||
|
||||
if (source->eflags & MFE_VERTICALFLIP)
|
||||
th->flags2 |= MF2_OBJECTFLIP;
|
||||
|
||||
P_SetScale(th, source->scale, true);
|
||||
P_SetTarget(&th->target, source);
|
||||
|
||||
th->angle = angle;
|
||||
th->momx = FixedMul(FixedMul(hspeed, FINECOSINE(angle>>ANGLETOFINESHIFT)), th->scale);
|
||||
th->momy = FixedMul(FixedMul(hspeed, FINESINE(angle>>ANGLETOFINESHIFT)), th->scale);
|
||||
th->momz = FixedMul(vspeed, th->scale);
|
||||
|
||||
if (useGravity)
|
||||
th->flags &= ~MF_NOGRAVITY;
|
||||
|
||||
if (P_CheckMissileSpawn(th))
|
||||
return th;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// P_FlashPal
|
||||
// Flashes a player's palette. ARMAGEDDON BLASTS!
|
||||
|
|
Loading…
Reference in a new issue