- scriptified A_SpawnItem(Ex) and A_ThrowGrenade.
These were the last native functions referencing AWeapon::DepleteAmmo, so that function is now exclusively on the scripting side.
This commit is contained in:
parent
6be7fc33f3
commit
b4c272ddff
5 changed files with 361 additions and 474 deletions
|
|
@ -1960,452 +1960,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_TakeFromSiblings)
|
|||
ACTION_RETURN_INT(count);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Common code for A_SpawnItem and A_SpawnItemEx
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
enum SIX_Flags
|
||||
{
|
||||
SIXF_TRANSFERTRANSLATION = 0x00000001,
|
||||
SIXF_ABSOLUTEPOSITION = 0x00000002,
|
||||
SIXF_ABSOLUTEANGLE = 0x00000004,
|
||||
SIXF_ABSOLUTEVELOCITY = 0x00000008,
|
||||
SIXF_SETMASTER = 0x00000010,
|
||||
SIXF_NOCHECKPOSITION = 0x00000020,
|
||||
SIXF_TELEFRAG = 0x00000040,
|
||||
SIXF_CLIENTSIDE = 0x00000080, // only used by Skulldronum
|
||||
SIXF_TRANSFERAMBUSHFLAG = 0x00000100,
|
||||
SIXF_TRANSFERPITCH = 0x00000200,
|
||||
SIXF_TRANSFERPOINTERS = 0x00000400,
|
||||
SIXF_USEBLOODCOLOR = 0x00000800,
|
||||
SIXF_CLEARCALLERTID = 0x00001000,
|
||||
SIXF_MULTIPLYSPEED = 0x00002000,
|
||||
SIXF_TRANSFERSCALE = 0x00004000,
|
||||
SIXF_TRANSFERSPECIAL = 0x00008000,
|
||||
SIXF_CLEARCALLERSPECIAL = 0x00010000,
|
||||
SIXF_TRANSFERSTENCILCOL = 0x00020000,
|
||||
SIXF_TRANSFERALPHA = 0x00040000,
|
||||
SIXF_TRANSFERRENDERSTYLE = 0x00080000,
|
||||
SIXF_SETTARGET = 0x00100000,
|
||||
SIXF_SETTRACER = 0x00200000,
|
||||
SIXF_NOPOINTERS = 0x00400000,
|
||||
SIXF_ORIGINATOR = 0x00800000,
|
||||
SIXF_TRANSFERSPRITEFRAME = 0x01000000,
|
||||
SIXF_TRANSFERROLL = 0x02000000,
|
||||
SIXF_ISTARGET = 0x04000000,
|
||||
SIXF_ISMASTER = 0x08000000,
|
||||
SIXF_ISTRACER = 0x10000000,
|
||||
};
|
||||
|
||||
static bool InitSpawnedItem(AActor *self, AActor *mo, int flags)
|
||||
{
|
||||
if (mo == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
AActor *originator = self;
|
||||
|
||||
if (!(mo->flags2 & MF2_DONTTRANSLATE))
|
||||
{
|
||||
if (flags & SIXF_TRANSFERTRANSLATION)
|
||||
{
|
||||
mo->Translation = self->Translation;
|
||||
}
|
||||
else if (flags & SIXF_USEBLOODCOLOR)
|
||||
{
|
||||
// [XA] Use the spawning actor's BloodColor to translate the newly-spawned object.
|
||||
mo->Translation = self->BloodTranslation;
|
||||
}
|
||||
}
|
||||
if (flags & SIXF_TRANSFERPOINTERS)
|
||||
{
|
||||
mo->target = self->target;
|
||||
mo->master = self->master; // This will be overridden later if SIXF_SETMASTER is set
|
||||
mo->tracer = self->tracer;
|
||||
}
|
||||
|
||||
mo->Angles.Yaw = self->Angles.Yaw;
|
||||
if (flags & SIXF_TRANSFERPITCH)
|
||||
{
|
||||
mo->Angles.Pitch = self->Angles.Pitch;
|
||||
}
|
||||
if (!(flags & SIXF_ORIGINATOR))
|
||||
{
|
||||
while (originator && originator->isMissile())
|
||||
{
|
||||
originator = originator->target;
|
||||
}
|
||||
}
|
||||
if (flags & SIXF_TELEFRAG)
|
||||
{
|
||||
P_TeleportMove(mo, mo->Pos(), true);
|
||||
// This is needed to ensure consistent behavior.
|
||||
// Otherwise it will only spawn if nothing gets telefragged
|
||||
flags |= SIXF_NOCHECKPOSITION;
|
||||
}
|
||||
if (mo->flags3 & MF3_ISMONSTER)
|
||||
{
|
||||
if (!(flags & SIXF_NOCHECKPOSITION) && !P_TestMobjLocation(mo))
|
||||
{
|
||||
// The monster is blocked so don't spawn it at all!
|
||||
mo->ClearCounters();
|
||||
mo->Destroy();
|
||||
return false;
|
||||
}
|
||||
else if (originator && !(flags & SIXF_NOPOINTERS))
|
||||
{
|
||||
if (originator->flags3 & MF3_ISMONSTER)
|
||||
{
|
||||
// If this is a monster transfer all friendliness information
|
||||
mo->CopyFriendliness(originator, true);
|
||||
}
|
||||
else if (originator->player)
|
||||
{
|
||||
// A player always spawns a monster friendly to him
|
||||
mo->flags |= MF_FRIENDLY;
|
||||
mo->SetFriendPlayer(originator->player);
|
||||
|
||||
AActor * attacker=originator->player->attacker;
|
||||
if (attacker)
|
||||
{
|
||||
if (!(attacker->flags&MF_FRIENDLY) ||
|
||||
(deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=mo->FriendPlayer))
|
||||
{
|
||||
// Target the monster which last attacked the player
|
||||
mo->LastHeard = mo->target = attacker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(flags & SIXF_TRANSFERPOINTERS))
|
||||
{
|
||||
// If this is a missile or something else set the target to the originator
|
||||
mo->target = originator ? originator : self;
|
||||
}
|
||||
if (flags & SIXF_NOPOINTERS)
|
||||
{
|
||||
//[MC]Intentionally eliminate pointers. Overrides TRANSFERPOINTERS, but is overridden by SETMASTER/TARGET/TRACER.
|
||||
mo->LastHeard = NULL; //Sanity check.
|
||||
mo->target = NULL;
|
||||
mo->master = NULL;
|
||||
mo->tracer = NULL;
|
||||
}
|
||||
if (flags & SIXF_SETMASTER)
|
||||
{ // don't let it attack you (optional)!
|
||||
mo->master = originator;
|
||||
}
|
||||
if (flags & SIXF_SETTARGET)
|
||||
{
|
||||
mo->target = originator;
|
||||
}
|
||||
if (flags & SIXF_SETTRACER)
|
||||
{
|
||||
mo->tracer = originator;
|
||||
}
|
||||
if (flags & SIXF_TRANSFERSCALE)
|
||||
{
|
||||
mo->Scale = self->Scale;
|
||||
}
|
||||
if (flags & SIXF_TRANSFERAMBUSHFLAG)
|
||||
{
|
||||
mo->flags = (mo->flags & ~MF_AMBUSH) | (self->flags & MF_AMBUSH);
|
||||
}
|
||||
if (flags & SIXF_CLEARCALLERTID)
|
||||
{
|
||||
self->RemoveFromHash();
|
||||
self->tid = 0;
|
||||
}
|
||||
if (flags & SIXF_TRANSFERSPECIAL)
|
||||
{
|
||||
mo->special = self->special;
|
||||
memcpy(mo->args, self->args, sizeof(self->args));
|
||||
}
|
||||
if (flags & SIXF_CLEARCALLERSPECIAL)
|
||||
{
|
||||
self->special = 0;
|
||||
memset(self->args, 0, sizeof(self->args));
|
||||
}
|
||||
if (flags & SIXF_TRANSFERSTENCILCOL)
|
||||
{
|
||||
mo->fillcolor = self->fillcolor;
|
||||
}
|
||||
if (flags & SIXF_TRANSFERALPHA)
|
||||
{
|
||||
mo->Alpha = self->Alpha;
|
||||
}
|
||||
if (flags & SIXF_TRANSFERRENDERSTYLE)
|
||||
{
|
||||
mo->RenderStyle = self->RenderStyle;
|
||||
}
|
||||
|
||||
if (flags & SIXF_TRANSFERSPRITEFRAME)
|
||||
{
|
||||
mo->sprite = self->sprite;
|
||||
mo->frame = self->frame;
|
||||
}
|
||||
|
||||
if (flags & SIXF_TRANSFERROLL)
|
||||
{
|
||||
mo->Angles.Roll = self->Angles.Roll;
|
||||
}
|
||||
|
||||
if (flags & SIXF_ISTARGET)
|
||||
{
|
||||
self->target = mo;
|
||||
}
|
||||
if (flags & SIXF_ISMASTER)
|
||||
{
|
||||
self->master = mo;
|
||||
}
|
||||
if (flags & SIXF_ISTRACER)
|
||||
{
|
||||
self->tracer = mo;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_SpawnItem
|
||||
//
|
||||
// Spawns an item in front of the caller like Heretic's time bomb
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SpawnItem)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
PARAM_CLASS (missile, AActor)
|
||||
PARAM_FLOAT (distance)
|
||||
PARAM_FLOAT (zheight)
|
||||
PARAM_BOOL (useammo)
|
||||
PARAM_BOOL (transfer_translation);
|
||||
|
||||
if (numret > 1) ret[1].SetObject(nullptr);
|
||||
|
||||
if (missile == NULL)
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(false);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
|
||||
// Don't spawn monsters if this actor has been massacred
|
||||
if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER))
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
|
||||
if (ACTION_CALL_FROM_PSPRITE())
|
||||
{
|
||||
// Used from a weapon, so use some ammo
|
||||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
|
||||
if (weapon == NULL)
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
if (useammo && !weapon->DepleteAmmo(weapon->bAltFire))
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
}
|
||||
|
||||
AActor *mo = Spawn( missile, self->Vec3Angle(distance, self->Angles.Yaw, -self->Floorclip + self->GetBobOffset() + zheight), ALLOW_REPLACE);
|
||||
|
||||
int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0);
|
||||
bool res = InitSpawnedItem(self, mo, flags); // for an inventory item's use state
|
||||
if (numret > 0) ret[0].SetInt(res);
|
||||
if (numret > 1) ret[1].SetObject(mo);
|
||||
return MIN(numret, 2);
|
||||
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_SpawnItemEx
|
||||
//
|
||||
// Enhanced spawning function
|
||||
//
|
||||
//===========================================================================
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SpawnItemEx)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_CLASS (missile, AActor);
|
||||
PARAM_FLOAT (xofs)
|
||||
PARAM_FLOAT (yofs)
|
||||
PARAM_FLOAT (zofs)
|
||||
PARAM_FLOAT (xvel)
|
||||
PARAM_FLOAT (yvel)
|
||||
PARAM_FLOAT (zvel)
|
||||
PARAM_ANGLE (angle)
|
||||
PARAM_INT (flags)
|
||||
PARAM_INT (chance)
|
||||
PARAM_INT (tid)
|
||||
|
||||
if (numret > 1) ret[1].SetObject(nullptr);
|
||||
|
||||
if (missile == NULL)
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(false);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
if (chance > 0 && pr_spawnitemex() < chance)
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
// Don't spawn monsters if this actor has been massacred
|
||||
if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER))
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
|
||||
DVector2 pos;
|
||||
|
||||
if (!(flags & SIXF_ABSOLUTEANGLE))
|
||||
{
|
||||
angle += self->Angles.Yaw;
|
||||
}
|
||||
double s = angle.Sin();
|
||||
double c = angle.Cos();
|
||||
|
||||
if (flags & SIXF_ABSOLUTEPOSITION)
|
||||
{
|
||||
pos = self->Vec2Offset(xofs, yofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// in relative mode negative y values mean 'left' and positive ones mean 'right'
|
||||
// This is the inverse orientation of the absolute mode!
|
||||
pos = self->Vec2Offset(xofs * c + yofs * s, xofs * s - yofs*c);
|
||||
}
|
||||
|
||||
if (!(flags & SIXF_ABSOLUTEVELOCITY))
|
||||
{
|
||||
// Same orientation issue here!
|
||||
double newxvel = xvel * c + yvel * s;
|
||||
yvel = xvel * s - yvel * c;
|
||||
xvel = newxvel;
|
||||
}
|
||||
|
||||
AActor *mo = Spawn(missile, DVector3(pos, self->Z() - self->Floorclip + self->GetBobOffset() + zofs), ALLOW_REPLACE);
|
||||
bool res = InitSpawnedItem(self, mo, flags);
|
||||
if (res)
|
||||
{
|
||||
if (tid != 0)
|
||||
{
|
||||
assert(mo->tid == 0);
|
||||
mo->tid = tid;
|
||||
mo->AddToHash();
|
||||
}
|
||||
mo->Vel = {xvel, yvel, zvel};
|
||||
if (flags & SIXF_MULTIPLYSPEED)
|
||||
{
|
||||
mo->Vel *= mo->Speed;
|
||||
}
|
||||
mo->Angles.Yaw = angle;
|
||||
}
|
||||
if (numret > 0) ret[0].SetInt(res);
|
||||
if (numret > 1) ret[1].SetObject(mo);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_ThrowGrenade
|
||||
//
|
||||
// Throws a grenade (like Hexen's fighter flechette)
|
||||
//
|
||||
//===========================================================================
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_ThrowGrenade)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
PARAM_CLASS (missile, AActor);
|
||||
PARAM_FLOAT (zheight)
|
||||
PARAM_FLOAT (xyvel)
|
||||
PARAM_FLOAT (zvel)
|
||||
PARAM_BOOL (useammo)
|
||||
|
||||
if (numret > 1) ret[1].SetObject(nullptr);
|
||||
|
||||
if (missile == NULL)
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(false);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
if (ACTION_CALL_FROM_PSPRITE())
|
||||
{
|
||||
// Used from a weapon, so use some ammo
|
||||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
|
||||
if (weapon == NULL)
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
if (useammo && !weapon->DepleteAmmo(weapon->bAltFire))
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
}
|
||||
|
||||
AActor *bo;
|
||||
|
||||
bo = Spawn(missile,
|
||||
self->PosPlusZ(-self->Floorclip + self->GetBobOffset() + zheight + 35 + (self->player? self->player->crouchoffset : 0.)),
|
||||
ALLOW_REPLACE);
|
||||
if (bo)
|
||||
{
|
||||
P_PlaySpawnSound(bo, self);
|
||||
if (xyvel != 0)
|
||||
bo->Speed = xyvel;
|
||||
bo->Angles.Yaw = self->Angles.Yaw + (((pr_grenade()&7) - 4) * (360./256.));
|
||||
|
||||
DAngle pitch = -self->Angles.Pitch;
|
||||
DAngle angle = bo->Angles.Yaw;
|
||||
|
||||
// There are two vectors we are concerned about here: xy and z. We rotate
|
||||
// them separately according to the shooter's pitch and then sum them to
|
||||
// get the final velocity vector to shoot with.
|
||||
|
||||
double xy_xyscale = bo->Speed * pitch.Cos();
|
||||
double xy_velz = bo->Speed * pitch.Sin();
|
||||
double xy_velx = xy_xyscale * angle.Cos();
|
||||
double xy_vely = xy_xyscale * angle.Sin();
|
||||
|
||||
pitch = self->Angles.Pitch;
|
||||
double z_xyscale = zvel * pitch.Sin();
|
||||
double z_velz = zvel * pitch.Cos();
|
||||
double z_velx = z_xyscale * angle.Cos();
|
||||
double z_vely = z_xyscale * angle.Sin();
|
||||
|
||||
bo->Vel.X = xy_velx + z_velx + self->Vel.X / 2;
|
||||
bo->Vel.Y = xy_vely + z_vely + self->Vel.Y / 2;
|
||||
bo->Vel.Z = xy_velz + z_velz;
|
||||
|
||||
bo->target = self;
|
||||
if (!P_CheckMissileSpawn(bo, self->radius)) bo = nullptr;
|
||||
|
||||
if (numret > 0) ret[0].SetInt(true);
|
||||
if (numret > 1) ret[1].SetObject(bo);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numret > 0) ret[0].SetInt(false);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_Recoil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue