- scriptified GiveInventory and made the interface a bit more configurable by mods.

Now a child type can decide for itself how to treat 'amount'.
The scripting interfaces to this function in ACS and FraggleScript have been consolidated and also scriptified.
This commit is contained in:
Christoph Oelckers 2018-12-01 17:07:09 +01:00
parent a426655d61
commit eb47fb9adc
10 changed files with 158 additions and 173 deletions

View file

@ -746,10 +746,6 @@ public:
// APlayerPawn for some specific handling for players. None of this // APlayerPawn for some specific handling for players. None of this
// should ever be overridden by custom classes. // should ever be overridden by custom classes.
// Give an item to the actor and pick it up.
// Returns true if the item pickup succeeded.
bool GiveInventory (PClassActor *type, int amount, bool givecheat = false);
// Removes the item from the inventory list. // Removes the item from the inventory list.
virtual void RemoveInventory (AInventory *item); virtual void RemoveInventory (AInventory *item);

View file

@ -2405,34 +2405,6 @@ void FParser::SF_IsPlayerObj(void)
//============================================================================ //============================================================================
//============================================================================
//
// DoGiveInv
//
// Gives an item to a single actor.
//
//============================================================================
static void FS_GiveInventory (AActor *actor, const char * type, int amount)
{
if (amount <= 0)
{
return;
}
if (strcmp (type, "Armor") == 0)
{
type = "BasicArmorPickup";
}
auto info = PClass::FindActor (type);
if (info == NULL || !info->IsDescendantOf(RUNTIME_CLASS(AInventory)))
{
Printf ("Unknown inventory item: %s\n", type);
return;
}
actor->GiveInventory(info, amount);
}
//============================================================================ //============================================================================
// //
// DoTakeInv // DoTakeInv
@ -2509,9 +2481,9 @@ static int FS_CheckInventory (AActor *activator, const char *type)
void FParser::SF_PlayerKeys(void) void FParser::SF_PlayerKeys(void)
{ {
static const char * const DoomKeys[]={"BlueCard", "YellowCard", "RedCard", "BlueSkull", "YellowSkull", "RedSkull"}; static const ENamedName DoomKeys[]={NAME_BlueCard, NAME_YellowCard, NAME_RedCard, NAME_BlueSkull, NAME_YellowSkull, NAME_RedSkull};
int playernum, keynum, givetake; int playernum, keynum, givetake;
const char * keyname; FName keyname;
if (CheckArgs(2)) if (CheckArgs(2))
{ {
@ -2535,7 +2507,7 @@ void FParser::SF_PlayerKeys(void)
else else
{ {
givetake = intvalue(t_argv[2]); givetake = intvalue(t_argv[2]);
if(givetake) FS_GiveInventory(players[playernum].mo, keyname, 1); if(givetake) ScriptUtil::Exec(NAME_GiveInventory, players[playernum].mo, keyname.GetIndex(), 1);
else FS_TakeInventory(players[playernum].mo, keyname, 1); else FS_TakeInventory(players[playernum].mo, keyname, 1);
t_return.type = svt_int; t_return.type = svt_int;
t_return.value.i = 0; t_return.value.i = 0;
@ -2745,7 +2717,7 @@ void FParser::SF_GiveInventory(void)
if(t_argc == 2) count=1; if(t_argc == 2) count=1;
else count=intvalue(t_argv[2]); else count=intvalue(t_argv[2]);
FS_GiveInventory(players[playernum].mo, stringvalue(t_argv[1]), count); ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, players[playernum].mo, FName(stringvalue(t_argv[1])).GetIndex(), count);
t_return.type = svt_int; t_return.type = svt_int;
t_return.value.i = 0; t_return.value.i = 0;
} }

View file

@ -992,6 +992,7 @@ xx(snd_resampler)
xx(ScriptUtil) xx(ScriptUtil)
xx(SetMarineWeapon) xx(SetMarineWeapon)
xx(SetMarineSprite) xx(SetMarineSprite)
xx(GiveInventory)
// Weapon member fields that need direct access // Weapon member fields that need direct access
xx(Ammo1) xx(Ammo1)
@ -1010,3 +1011,10 @@ xx(FOVScale)
xx(YAdjust) xx(YAdjust)
xx(Crosshair) xx(Crosshair)
xx(WeaponFlags) xx(WeaponFlags)
xx(BlueCard)
xx(YellowCard)
xx(RedCard)
xx(BlueSkull)
xx(YellowSkull)
xx(RedSkull)

View file

@ -1747,49 +1747,6 @@ static void ClearInventory (AActor *activator)
} }
} }
//============================================================================
//
// GiveInventory
//
// Gives an item to one or more actors.
//
//============================================================================
static void GiveInventory (AActor *activator, const char *type, int amount)
{
PClassActor *info;
if (amount <= 0 || type == NULL)
{
return;
}
if (stricmp (type, "Armor") == 0)
{
type = "BasicArmorPickup";
}
info = PClass::FindActor(type);
if (info == NULL)
{
Printf ("ACS: I don't know what %s is.\n", type);
}
else if (!info->IsDescendantOf (RUNTIME_CLASS(AInventory)))
{
Printf ("ACS: %s is not an inventory item.\n", type);
}
else if (activator == NULL)
{
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i])
players[i].mo->GiveInventory(info, amount);
}
}
else
{
activator->GiveInventory(info, amount);
}
}
//============================================================================ //============================================================================
// //
// TakeInventory // TakeInventory
@ -9325,16 +9282,20 @@ scriptwait:
break; break;
case PCD_GIVEINVENTORY: case PCD_GIVEINVENTORY:
GiveInventory (activator, FBehavior::StaticLookupString (STACK(2)), STACK(1)); {
int typeindex = FName(FBehavior::StaticLookupString(STACK(2))).GetIndex();
ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, activator, ScriptUtil::Int, typeindex, ScriptUtil::Int, STACK(1), ScriptUtil::End);
sp -= 2; sp -= 2;
break; break;
}
case PCD_GIVEACTORINVENTORY: case PCD_GIVEACTORINVENTORY:
{ {
const char *type = FBehavior::StaticLookupString(STACK(2)); int typeindex = FName(FBehavior::StaticLookupString(STACK(2))).GetIndex();
FName type = FName(FBehavior::StaticLookupString(STACK(2)));
if (STACK(3) == 0) if (STACK(3) == 0)
{ {
GiveInventory(NULL, FBehavior::StaticLookupString(STACK(2)), STACK(1)); ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, nullptr, ScriptUtil::Int, typeindex, ScriptUtil::Int, STACK(1), ScriptUtil::End);
} }
else else
{ {
@ -9342,17 +9303,20 @@ scriptwait:
AActor *actor; AActor *actor;
for (actor = it.Next(); actor != NULL; actor = it.Next()) for (actor = it.Next(); actor != NULL; actor = it.Next())
{ {
GiveInventory(actor, type, STACK(1)); ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, actor, ScriptUtil::Int, typeindex, ScriptUtil::Int, STACK(1), ScriptUtil::End);
} }
} }
sp -= 3; sp -= 3;
}
break; break;
}
case PCD_GIVEINVENTORYDIRECT: case PCD_GIVEINVENTORYDIRECT:
GiveInventory (activator, FBehavior::StaticLookupString (TAGSTR(uallong(pc[0]))), uallong(pc[1])); {
int typeindex = FName(FBehavior::StaticLookupString(TAGSTR(uallong(pc[0])))).GetIndex();
ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, activator, ScriptUtil::Int, typeindex, ScriptUtil::Int, uallong(pc[1]), ScriptUtil::End);
pc += 2; pc += 2;
break; break;
}
case PCD_TAKEINVENTORY: case PCD_TAKEINVENTORY:
TakeInventory (activator, FBehavior::StaticLookupString (STACK(2)), STACK(1)); TakeInventory (activator, FBehavior::StaticLookupString (STACK(2)), STACK(1));

View file

@ -753,81 +753,6 @@ DEFINE_ACTION_FUNCTION(AActor, SetState)
ACTION_RETURN_BOOL(self->SetState(state, nofunction)); ACTION_RETURN_BOOL(self->SetState(state, nofunction));
}; };
//============================================================================
//
// AActor :: GiveInventory
//
//============================================================================
bool AActor::GiveInventory(PClassActor *type, int amount, bool givecheat)
{
bool result = true;
if (type == nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false;
auto savedPendingWeap = player != NULL ? player->PendingWeapon : NULL;
bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true;
AInventory *item;
if (!givecheat)
{
item = static_cast<AInventory *>(Spawn (type));
}
else
{
item = static_cast<AInventory *>(Spawn (type, Pos(), NO_REPLACE));
if (item == NULL) return false;
}
// This shouldn't count for the item statistics!
item->ClearCounters();
if (!givecheat || amount > 0)
{
if (type->IsDescendantOf(NAME_BasicArmorPickup) || type->IsDescendantOf(NAME_BasicArmorBonus))
{
item->IntVar(NAME_SaveAmount) *= amount;
}
else
{
if (givecheat)
{
const AInventory *const haveitem = FindInventory(type);
item->Amount = MIN(amount, nullptr == haveitem
? static_cast<AInventory*>(GetDefaultByType(type))->MaxAmount
: haveitem->MaxAmount);
}
else
{
item->Amount = amount;
}
}
}
if (!item->CallTryPickup (this))
{
item->Destroy ();
result = false;
}
// If the item was a weapon, don't bring it up automatically
// unless the player was not already using a weapon.
// Don't bring it up automatically if this is called by the give cheat.
if (!givecheat && player != NULL && savedPendingWeap != NULL && hadweap)
{
player->PendingWeapon = savedPendingWeap;
}
return result;
}
DEFINE_ACTION_FUNCTION(AActor, GiveInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(type, AInventory);
PARAM_INT(amount);
PARAM_BOOL(givecheat);
ACTION_RETURN_BOOL(self->GiveInventory(type, amount, givecheat));
}
//============================================================================ //============================================================================
// //
// AActor :: RemoveInventory // AActor :: RemoveInventory

View file

@ -744,7 +744,6 @@ class Actor : Thinker native
native void RemoveInventory(Inventory inv); native void RemoveInventory(Inventory inv);
native void ClearInventory(); native void ClearInventory();
protected native void DestroyAllInventory(); // This is not supposed to be called by user code! protected native void DestroyAllInventory(); // This is not supposed to be called by user code!
native bool GiveInventory(class<Inventory> type, int amount, bool givecheat = false);
native bool SetInventory(class<Inventory> itemclass, int amount, bool beyondMax = false); native bool SetInventory(class<Inventory> itemclass, int amount, bool beyondMax = false);
native bool TakeInventory(class<Inventory> itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); native bool TakeInventory(class<Inventory> itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false);
native clearscope Inventory FindInventory(class<Inventory> itemtype, bool subclass = false) const; native clearscope Inventory FindInventory(class<Inventory> itemtype, bool subclass = false) const;

View file

@ -31,4 +31,53 @@ extend class Actor
Inv.InventoryID = InventoryID++; Inv.InventoryID = InventoryID++;
} }
//============================================================================
//
// AActor :: GiveInventory
//
//============================================================================
bool GiveInventory(Class<Inventory> type, int amount, bool givecheat = false)
{
bool result = true;
let player = self.player;
// This can be called from places which do not check the given item's type.
if (type == null || !(type is 'Inventory')) return false;
Weapon savedPendingWeap = player != NULL ? player.PendingWeapon : NULL;
bool hadweap = player != NULL ? player.ReadyWeapon != NULL : true;
Inventory item;
if (!givecheat)
{
item = Inventory(Spawn (type));
}
else
{
item = Inventory(Spawn (type, Pos, NO_REPLACE));
if (item == NULL) return false;
}
// This shouldn't count for the item statistics.
item.ClearCounters();
if (!givecheat || amount > 0)
{
item.SetGiveAmount(self, amount, givecheat);
}
if (!item.CallTryPickup (self))
{
item.Destroy ();
result = false;
}
// If the item was a weapon, don't bring it up automatically
// unless the player was not already using a weapon.
// Don't bring it up automatically if this is called by the give cheat.
if (!givecheat && player != NULL && savedPendingWeap != NULL && hadweap)
{
player.PendingWeapon = savedPendingWeap;
}
return result;
}
} }

View file

@ -340,6 +340,10 @@ class BasicArmorBonus : Armor
} }
override void SetGiveAmount(Actor receiver, int amount, bool bycheat)
{
SaveAmount *= amount;
}
} }
//=========================================================================== //===========================================================================
@ -440,6 +444,12 @@ class BasicArmorPickup : Armor
armor.ActualSaveAmount = SaveAmount; armor.ActualSaveAmount = SaveAmount;
return true; return true;
} }
override void SetGiveAmount(Actor receiver, int amount, bool bycheat)
{
SaveAmount *= amount;
}
} }
//=========================================================================== //===========================================================================

View file

@ -1016,6 +1016,27 @@ class Inventory : Actor native
} }
} }
//---------------------------------------------------------------------------
//
// Modifies the amount based on what an item should contain if given
//
//---------------------------------------------------------------------------
virtual void SetGiveAmount(Actor receiver, int amount, bool givecheat)
{
if (givecheat)
{
let haveitem = receiver.FindInventory(GetClass());
self.Amount = MIN(amount, haveitem == null? self.Default.MaxAmount : haveitem.MaxAmount);
}
else
{
self.Amount = amount;
}
}
} }
//=========================================================================== //===========================================================================

View file

@ -4,6 +4,47 @@
class ScriptUtil play class ScriptUtil play
{ {
//============================================================================
//
// GiveInventory
//
// Gives an item to one or more actors.
//
//============================================================================
static void GiveInventory (Actor activator, Name type, int amount)
{
if (amount <= 0 || type == 'none')
{
return;
}
if (type == 'Armor')
{
type = "BasicArmorPickup";
}
Class<Actor> info = type;
if (info == NULL)
{
Console.Printf ("GiveInventory: Unknown item type %s.\n", type);
}
else if (!(info is 'Inventory'))
{
Console.Printf ("GiveInventory: %s is not an inventory item.\n", type);
}
else if (activator == NULL)
{
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i])
players[i].mo.GiveInventory((class<Inventory>)(info), amount);
}
}
else
{
activator.GiveInventory((class<Inventory>)(info), amount);
}
}
//========================================================================== //==========================================================================
// //
// //