diff --git a/src/g_game.cpp b/src/g_game.cpp index 8dba08ccc..910025290 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1242,108 +1242,10 @@ void G_Ticker () void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags) { - AInventory *item, *next; - player_t *p; - - p = &players[player]; - - if (p->morphTics != 0) - { // Undo morph - P_UnmorphActor(p->mo, p->mo, 0, true); - } - - // Strip all current powers, unless moving in a hub and the power is okay to keep. - item = p->mo->Inventory; - auto ptype = PClass::FindActor(NAME_Powerup); - while (item != NULL) + IFVM(PlayerPawn, PlayerFinishLevel) { - next = item->Inventory; - if (item->IsKindOf (ptype)) - { - if (deathmatch || ((mode != FINISH_SameHub || !(item->ItemFlags & IF_HUBPOWER)) - && !(item->ItemFlags & IF_PERSISTENTPOWER))) // Keep persistent powers in non-deathmatch games - { - item->Destroy (); - } - } - item = next; - } - if (p->ReadyWeapon != NULL && - p->ReadyWeapon->IntVar(NAME_WeaponFlags) & WIF_POWERED_UP && - p->PendingWeapon == p->ReadyWeapon->PointerVar(NAME_SisterWeapon)) - { - // Unselect powered up weapons if the unpowered counterpart is pending - p->ReadyWeapon=p->PendingWeapon; - } - // reset invisibility to default - if (p->mo->GetDefault()->flags & MF_SHADOW) - { - p->mo->flags |= MF_SHADOW; - } - else - { - p->mo->flags &= ~MF_SHADOW; - } - p->mo->RenderStyle = p->mo->GetDefault()->RenderStyle; - p->mo->Alpha = p->mo->GetDefault()->Alpha; - p->extralight = 0; // cancel gun flashes - p->fixedcolormap = NOFIXEDCOLORMAP; // cancel ir goggles - p->fixedlightlevel = -1; - p->damagecount = 0; // no palette changes - p->bonuscount = 0; - p->poisoncount = 0; - p->inventorytics = 0; - - if (mode != FINISH_SameHub) - { - // Take away flight and keys (and anything else with IF_INTERHUBSTRIP set) - item = p->mo->Inventory; - while (item != NULL) - { - next = item->Inventory; - if (item->InterHubAmount < 1) - { - item->Destroy (); - } - item = next; - } - } - - if (mode == FINISH_NoHub && !(level.flags2 & LEVEL2_KEEPFULLINVENTORY)) - { // Reduce all owned (visible) inventory to defined maximum interhub amount - TArray todelete; - for (item = p->mo->Inventory; item != NULL; item = item->Inventory) - { - // If the player is carrying more samples of an item than allowed, reduce amount accordingly - if (item->ItemFlags & IF_INVBAR && item->Amount > item->InterHubAmount) - { - item->Amount = item->InterHubAmount; - if ((level.flags3 & LEVEL3_REMOVEITEMS) && !(item->ItemFlags & IF_UNDROPPABLE)) - { - todelete.Push(item); - } - } - } - for (auto it : todelete) - { - if (!(it->ObjectFlags & OF_EuthanizeMe)) - { - DepleteOrDestroy(item); - } - } - } - - // Resets player health to default if not dead. - if ((flags & CHANGELEVEL_RESETHEALTH) && p->playerstate != PST_DEAD) - { - p->health = p->mo->health = p->mo->SpawnHealth(); - } - - // Clears the entire inventory and gives back the defaults for starting a game - if ((flags & CHANGELEVEL_RESETINVENTORY) && p->playerstate != PST_DEAD) - { - p->mo->ClearInventory(); - p->mo->GiveDefaultInventory(); + VMValue params[] = { players[player].mo, mode, flags }; + VMCall(func, params, 3, nullptr, 0); } } diff --git a/src/g_level.cpp b/src/g_level.cpp index 392e1e63e..b29ddd072 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -2254,6 +2254,8 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN) DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT) DEFINE_FIELD_BIT(FLevelLocals, flags2, no_dlg_freeze, LEVEL2_CONV_SINGLE_UNFREEZE) +DEFINE_FIELD_BIT(FLevelLocals, flags2, keepfullinventory, LEVEL2_KEEPFULLINVENTORY) +DEFINE_FIELD_BIT(FLevelLocals, flags3, removeitems, LEVEL3_REMOVEITEMS) //========================================================================== // diff --git a/src/namedef.h b/src/namedef.h index fd876a89b..bf72bf79b 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -994,6 +994,7 @@ xx(SetMarineWeapon) xx(SetMarineSprite) xx(GiveInventory) xx(TakeInventory) +xx(ClearInventory) // Weapon member fields that need direct access xx(Ammo1) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 40a739b39..52786b2f9 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1723,30 +1723,6 @@ void P_WriteACSVars(FSerializer &arc) //---- Inventory functions --------------------------------------// // -//============================================================================ -// -// ClearInventory -// -// Clears the inventory for one or more actors. -// -//============================================================================ - -static void ClearInventory (AActor *activator) -{ - if (activator == NULL) - { - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - players[i].mo->ClearInventory(); - } - } - else - { - activator->ClearInventory(); - } -} - //============================================================================ // // DoUseInv @@ -9218,13 +9194,13 @@ scriptwait: break; case PCD_CLEARINVENTORY: - ClearInventory (activator); + ScriptUtil::Exec(NAME_ClearInventory, ScriptUtil::Pointer, activator, ScriptUtil::End); break; case PCD_CLEARACTORINVENTORY: if (STACK(1) == 0) { - ClearInventory(NULL); + ScriptUtil::Exec(NAME_ClearInventory, ScriptUtil::Pointer, nullptr, ScriptUtil::End); } else { @@ -9232,7 +9208,7 @@ scriptwait: AActor *actor; for (actor = it.Next(); actor != NULL; actor = it.Next()) { - ClearInventory(actor); + ScriptUtil::Exec(NAME_ClearInventory, ScriptUtil::Pointer, actor , ScriptUtil::End); } } sp--; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index da933dcf1..8f421dd55 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -952,6 +952,14 @@ class Actor : Thinker native BulletSlope(t, ALF_PORTALRESTRICT); return t.linetarget; } + + void RestoreRenderStyle() + { + bShadow = default.bShadow; + bGhost = default.bGhost; + RenderStyle = default.RenderStyle; + Alpha = default.Alpha; + } native void A_Face(Actor faceto, double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 2842ddc30..4b309d0a4 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -671,6 +671,8 @@ struct LevelLocals native native bool frozen; native readonly bool infinite_flight; native readonly bool no_dlg_freeze; + native readonly bool keepfullinventory; + native readonly bool removeitems; native readonly int fogdensity; native readonly int outsidefogdensity; native readonly int skyfog; diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index bcd465fc2..1212b7b76 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1276,3 +1276,22 @@ enum Bobbing Bob_Smooth, Bob_InverseSmooth }; + +enum EFinishLevelType +{ + FINISH_SameHub, + FINISH_NextHub, + FINISH_NoHub +}; + +enum EChangeLevelFlags +{ + CHANGELEVEL_KEEPFACING = 1, + CHANGELEVEL_RESETINVENTORY = 2, + CHANGELEVEL_NOMONSTERS = 4, + CHANGELEVEL_CHANGESKILL = 8, + CHANGELEVEL_NOINTERMISSION = 16, + CHANGELEVEL_RESETHEALTH = 32, + CHANGELEVEL_PRERAISEWEAPON = 64, +}; + diff --git a/wadsrc/static/zscript/scriptutil/scriptutil.txt b/wadsrc/static/zscript/scriptutil/scriptutil.txt index 43393b049..81bcb0330 100644 --- a/wadsrc/static/zscript/scriptutil/scriptutil.txt +++ b/wadsrc/static/zscript/scriptutil/scriptutil.txt @@ -86,6 +86,30 @@ class ScriptUtil play } } + //============================================================================ + // + // ClearInventory + // + // Clears the inventory for one or more actors. + // + //============================================================================ + + static void ClearInventory (Actor activator) + { + if (activator == NULL) + { + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + players[i].mo.ClearInventory(); + } + } + else + { + activator.ClearInventory(); + } + } + //========================================================================== // // diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index a213e2c0c..c4fa07484 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -1734,6 +1734,112 @@ class PlayerPawn : Actor native return TeleportFreezeTime; } + + //=========================================================================== + // + // G_PlayerFinishLevel + // Called when a player completes a level. + // + // flags is checked for RESETINVENTORY and RESETHEALTH only. + // + //=========================================================================== + + void PlayerFinishLevel (int mode, int flags) + { + Inventory item, next; + let p = player; + + if (p.morphTics != 0) + { // Undo morph + Unmorph(self, 0, true); + } + // 'self' will be no longer valid from here on in case of an unmorph + let me = p.mo; + + // Strip all current powers, unless moving in a hub and the power is okay to keep. + item = me.Inv; + while (item != NULL) + { + next = item.Inv; + if (item is 'Powerup') + { + if (deathmatch || ((mode != FINISH_SameHub || !item.bHUBPOWER) && !item.bPERSISTENTPOWER)) // Keep persistent powers in non-deathmatch games + { + item.Destroy (); + } + } + item = next; + } + let ReadyWeapon = p.ReadyWeapon; + if (ReadyWeapon != NULL && ReadyWeapon.bPOWERED_UP && p.PendingWeapon == ReadyWeapon.SisterWeapon) + { + // Unselect powered up weapons if the unpowered counterpart is pending + p.ReadyWeapon = p.PendingWeapon; + } + // reset invisibility to default + me.RestoreRenderStyle(); + p.extralight = 0; // cancel gun flashes + p.fixedcolormap = PlayerInfo.NOFIXEDCOLORMAP; // cancel ir goggles + p.fixedlightlevel = -1; + p.damagecount = 0; // no palette changes + p.bonuscount = 0; + p.poisoncount = 0; + p.inventorytics = 0; + + if (mode != FINISH_SameHub) + { + // Take away flight and keys (and anything else with IF_INTERHUBSTRIP set) + item = me.Inv; + while (item != NULL) + { + next = item.Inv; + if (item.InterHubAmount < 1) + { + item.Destroy (); + } + item = next; + } + } + + if (mode == FINISH_NoHub && !level.KEEPFULLINVENTORY) + { // Reduce all owned (visible) inventory to defined maximum interhub amount + Array todelete; + for (item = me.Inv; item != NULL; item = item.Inv) + { + // If the player is carrying more samples of an item than allowed, reduce amount accordingly + if (item.bINVBAR && item.Amount > item.InterHubAmount) + { + item.Amount = item.InterHubAmount; + if (level.REMOVEITEMS && !item.bUNDROPPABLE) + { + todelete.Push(item); + } + } + } + for (int i = 0; i < toDelete.Size(); i++) + { + let it = toDelete[i]; + if (!it.bDestroyed) + { + item.DepleteOrDestroy(); + } + } + } + + // Resets player health to default if not dead. + if ((flags & CHANGELEVEL_RESETHEALTH) && p.playerstate != PST_DEAD) + { + p.health = me.health = me.SpawnHealth(); + } + + // Clears the entire inventory and gives back the defaults for starting a game + if ((flags & CHANGELEVEL_RESETINVENTORY) && p.playerstate != PST_DEAD) + { + me.ClearInventory(); + me.GiveDefaultInventory(); + } + } + //=========================================================================== // // FWeaponSlot :: PickWeapon