diff --git a/src/actor.h b/src/actor.h index b3a63b0a8..066e15411 100644 --- a/src/actor.h +++ b/src/actor.h @@ -714,6 +714,8 @@ public: // Returns true if the initial item count is positive. virtual bool TakeInventory (PClassActor *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); + bool SetInventory(PClassActor *itemclass, int amount, bool beyondMax); + // Uses an item and removes it from the inventory. virtual bool UseInventory (AInventory *item); diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 4bdca624a..4d40ce66d 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -422,6 +422,25 @@ CCMD (take) Net_WriteLong (0); } +CCMD(setinv) +{ + if (CheckCheatmode() || argv.argc() < 2) + return; + + Net_WriteByte(DEM_SETINV); + Net_WriteString(argv[1]); + if (argv.argc() > 2) + Net_WriteLong(atoi(argv[2])); + else + Net_WriteLong(0); + + if (argv.argc() > 3) + Net_WriteByte(!!atoi(argv[3])); + else + Net_WriteByte(0); + +} + CCMD (gameversion) { Printf ("%s @ %s\nCommit %s\n", GetVersionString(), GetGitTime(), GetGitHash()); diff --git a/src/d_net.cpp b/src/d_net.cpp index f505285c2..80755c90e 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2207,6 +2207,12 @@ void Net_DoCommand (int type, uint8_t **stream, int player) cht_Take (&players[player], s, ReadLong (stream)); break; + case DEM_SETINV: + s = ReadString(stream); + i = ReadLong(stream); + cht_SetInv(&players[player], s, i, ReadByte(stream)); + break; + case DEM_WARPCHEAT: { int x, y, z; @@ -2727,6 +2733,10 @@ void Net_SkipCommand (int type, uint8_t **stream) skip = strlen ((char *)(*stream)) + 5; break; + case DEM_SETINV: + skip = strlen((char *)(*stream)) + 6; + break; + case DEM_NETEVENT: skip = strlen((char *)(*stream)) + 15; break; diff --git a/src/d_protocol.h b/src/d_protocol.h index 5ac1258b3..a05cef29e 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -160,7 +160,8 @@ enum EDemoCommand DEM_REMOVE, // 68 DEM_FINISHGAME, // 69 DEM_NETEVENT, // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int - DEM_MDK // 71 String: Damage type + DEM_MDK, // 71 String: Damage type + DEM_SETINV, // 72 SetInventory }; // The following are implemented by cht_DoCheat in m_cheat.cpp diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index d395d0ad2..170effaf1 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -602,6 +602,30 @@ const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo return ""; } +void cht_SetInv(player_t *player, const char *string, int amount, bool beyond) +{ + if (!stricmp(string, "health")) + { + if (amount <= 0) + { + cht_Suicide(player); + return; + } + if (!beyond) amount = MIN(amount, player->mo->GetMaxHealth(true)); + player->health = player->mo->health = amount; + } + else + { + auto item = PClass::FindActor(string); + if (item != nullptr && item->IsDescendantOf(RUNTIME_CLASS(AInventory))) + { + player->mo->SetInventory(item, amount, beyond); + return; + } + Printf("Unknown item \"%s\"\n", string); + } +} + void cht_Give (player_t *player, const char *name, int amount) { if (player->mo == nullptr) return; diff --git a/src/m_cheat.h b/src/m_cheat.h index 729c3bff6..c7417b2eb 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -35,6 +35,7 @@ void cht_DoMDK(player_t *player, const char *mod); void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); +void cht_SetInv(player_t *player, const char *item, int amount = 1, bool beyondMax = false); void cht_Suicide (player_t *player); const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo); diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 06d92cdc8..38736e033 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -2382,63 +2382,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetInventory) { mobj = mobj->player->mo; } - - AInventory *item = mobj->FindInventory(itemtype); - - if (item != nullptr) - { - // A_SetInventory sets the absolute amount. - // Subtract or set the appropriate amount as necessary. - - if (amount == item->Amount) - { - // Nothing was changed. - ACTION_RETURN_BOOL(false); - } - else if (amount <= 0) - { - //Remove it all. - res = (mobj->TakeInventory(itemtype, item->Amount, true, false)); - ACTION_RETURN_BOOL(res); - } - else if (amount < item->Amount) - { - int amt = abs(item->Amount - amount); - res = (mobj->TakeInventory(itemtype, amt, true, false)); - ACTION_RETURN_BOOL(res); - } - else - { - item->Amount = (beyondMax ? amount : clamp(amount, 0, item->MaxAmount)); - ACTION_RETURN_BOOL(true); - } - } - else - { - if (amount <= 0) - { - ACTION_RETURN_BOOL(false); - } - item = static_cast(Spawn(itemtype)); - if (item == nullptr) - { - ACTION_RETURN_BOOL(false); - } - else - { - item->Amount = amount; - item->flags |= MF_DROPPED; - item->ItemFlags |= IF_IGNORESKILL; - item->ClearCounters(); - if (!item->CallTryPickup(mobj)) - { - item->Destroy(); - ACTION_RETURN_BOOL(false); - } - ACTION_RETURN_BOOL(true); - } - } - ACTION_RETURN_BOOL(false); + ACTION_RETURN_BOOL(mobj->SetInventory(itemtype, amount, beyondMax)); } //=========================================================================== diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ca8d60376..f45a2fc86 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -920,6 +920,75 @@ DEFINE_ACTION_FUNCTION(AActor, TakeInventory) ACTION_RETURN_BOOL(self->TakeInventory(item, amount, fromdecorate, notakeinfinite)); } + + +bool AActor::SetInventory(PClassActor *itemtype, int amount, bool beyondMax) +{ + AInventory *item = FindInventory(itemtype); + + if (item != nullptr) + { + // A_SetInventory sets the absolute amount. + // Subtract or set the appropriate amount as necessary. + + if (amount == item->Amount) + { + // Nothing was changed. + return false; + } + else if (amount <= 0) + { + //Remove it all. + return TakeInventory(itemtype, item->Amount, true, false); + } + else if (amount < item->Amount) + { + int amt = abs(item->Amount - amount); + return TakeInventory(itemtype, amt, true, false); + } + else + { + item->Amount = (beyondMax ? amount : clamp(amount, 0, item->MaxAmount)); + return true; + } + } + else + { + if (amount <= 0) + { + return true; + } + item = static_cast(Spawn(itemtype)); + if (item == nullptr) + { + return false; + } + else + { + item->Amount = amount; + item->flags |= MF_DROPPED; + item->ItemFlags |= IF_IGNORESKILL; + item->ClearCounters(); + if (!item->CallTryPickup(this)) + { + item->Destroy(); + return false; + } + return true; + } + } + return false; +} + +DEFINE_ACTION_FUNCTION(AActor, SetInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS_NOT_NULL(item, AInventory); + PARAM_INT(amount); + PARAM_BOOL_DEF(beyondMax); + ACTION_RETURN_BOOL(self->SetInventory(item, amount, beyondMax)); +} + //============================================================================ // // AActor :: DestroyAllInventory diff --git a/src/version.h b/src/version.h index ee4254176..8c697d9f4 100644 --- a/src/version.h +++ b/src/version.h @@ -61,7 +61,7 @@ const char *GetVersionString(); // Version identifier for network games. // Bump it every time you do a release unless you're certain you // didn't change anything that will affect sync. -#define NETGAMEVERSION 233 +#define NETGAMEVERSION 234 // Version stored in the ini's [LastRun] section. // Bump it if you made some configuration change that you want to @@ -71,7 +71,7 @@ const char *GetVersionString(); // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. // Otherwise, it should be safe to leave it alone. -#define DEMOGAMEVERSION 0x21F +#define DEMOGAMEVERSION 0x220 // Minimum demo version we can play. // Bump it whenever you change or remove existing DEM_ commands. diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 029a38be4..7733d2ec3 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -596,6 +596,7 @@ class Actor : Thinker native native void RemoveInventory(Inventory inv); native void ClearInventory(); native bool GiveInventory(class type, int amount, bool givecheat = false); + native bool SetInventory(class itemclass, int amount, bool beyondMax = false); native bool TakeInventory(class itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); native clearscope Inventory FindInventory(class itemtype, bool subclass = false) const; native Inventory GiveInventoryType(class itemtype);