diff --git a/src/actor.h b/src/actor.h index 93d2834a8..a9ce18a57 100644 --- a/src/actor.h +++ b/src/actor.h @@ -380,6 +380,8 @@ enum ActorFlag7 MF7_LAXTELEFRAGDMG = 0x00100000, // [MC] Telefrag damage can be reduced. MF7_ICESHATTER = 0x00200000, // [MC] Shatters ice corpses regardless of damagetype. MF7_ALLOWTHRUFLAGS = 0x00400000, // [MC] Allow THRUACTORS and the likes on puffs to prevent mod breakage. + MF7_USEKILLSCRIPTS = 0x00800000, // [JM] Use "KILL" Script on death if not forced by GameInfo. + MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo. }; // --- mobj.renderflags --- diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index f79924b2b..29a087fac 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -921,7 +921,7 @@ static int PatchThing (int thingy) { if (stricmp (Line1, "Speed") == 0) { - info->Speed = val; // handle fixed point later. + info->Speed = (signed long)val; // handle fixed point later. } else if (stricmp (Line1, "Width") == 0) { @@ -2507,7 +2507,7 @@ static bool DoDehPatch() cont = 0; if (0 == strncmp (PatchFile, "Patch File for DeHackEd v", 25)) { - if (PatchFile[25] < '3') + if (PatchFile[25] < '3' && PatchFile[25] != '2' && PatchFile[27] != '3') { Printf (PRINT_BOLD, "\"%s\" is an old and unsupported DeHackEd patch\n", PatchName); delete[] PatchName; @@ -2544,7 +2544,7 @@ static bool DoDehPatch() {} } - if (pversion != 6) + if (pversion != 5 && pversion != 6) { Printf ("DeHackEd patch version is %d.\nUnexpected results may occur.\n", pversion); } diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index d0e807c3e..98af9ff25 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -81,6 +81,10 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp morphed = static_cast(Spawn (spawntype, actor->Pos(), NO_REPLACE)); EndAllPowerupEffects(actor->Inventory); DObject::StaticPointerSubstitution (actor, morphed); + if ((style & MORPH_TRANSFERTRANSLATION) && !(morphed->flags2 & MF2_DONTTRANSLATE)) + { + morphed->Translation = actor->Translation; + } if ((actor->tid != 0) && (style & MORPH_NEWTIDBEHAVIOUR)) { morphed->tid = actor->tid; @@ -382,6 +386,10 @@ bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int st morphed = static_cast(Spawn (spawntype, actor->Pos(), NO_REPLACE)); DObject::StaticPointerSubstitution (actor, morphed); + if ((style & MORPH_TRANSFERTRANSLATION) && !(morphed->flags2 & MF2_DONTTRANSLATE)) + { + morphed->Translation = actor->Translation; + } morphed->tid = actor->tid; morphed->Angles.Yaw = actor->Angles.Yaw; morphed->UnmorphedMe = actor; diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index f797c75e6..e770e418e 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -25,6 +25,7 @@ enum MORPH_UNDOBYDEATHSAVES = 0x00000800, // Actor (if unmorphed when killed) regains their health and doesn't die MORPH_UNDOBYTIMEOUT = 0x00001000, // Player unmorphs once countdown expires MORPH_UNDOALWAYS = 0x00002000, // Powerups must always unmorph, no matter what. + MORPH_TRANSFERTRANSLATION = 0x00004000, // Transfer translation from the original actor to the morphed one MORPH_STANDARDUNDOING = MORPH_UNDOBYTOMEOFPOWER | MORPH_UNDOBYCHAOSDEVICE | MORPH_UNDOBYTIMEOUT, }; diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 26b27e202..0023cd271 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -378,6 +378,8 @@ enum WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI. WIF_DEHAMMO = 0x00010000, // Uses Doom's original amount of ammo for the respective attack functions so that old DEHACKED patches work as intended. // AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works + WIF_NODEATHDESELECT = 0x00020000, // Don't jump to the Deselect state when the player dies + WIF_NODEATHINPUT = 0x00040000, // The weapon cannot be fired/reloaded/whatever when the player is dead WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil) // Flags used only by bot AI: diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 46cf61d54..3a8dc388c 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -539,6 +539,38 @@ static void AddAmmoToList(AWeapon * weapdef) } } +static int GetDigitCount(int value) +{ + int digits = 0; + + do + { + value /= 10; + ++digits; + } + while (0 != value); + + return digits; +} + +static void GetAmmoTextLengths(player_t *CPlayer, int& ammocur, int& ammomax) +{ + for (auto type : orderedammos) + { + AAmmo * ammoitem = static_cast(CPlayer->mo->FindInventory(type)); + AAmmo * inv = nullptr == ammoitem + ? static_cast(GetDefaultByType(type)) + : ammoitem; + assert(nullptr != inv); + + ammocur = MAX(ammocur, nullptr == ammoitem ? 0 : ammoitem->Amount); + ammomax = MAX(ammomax, inv->MaxAmount); + } + + ammocur = GetDigitCount(ammocur); + ammomax = GetDigitCount(ammomax); +} + static int DrawAmmo(player_t *CPlayer, int x, int y) { @@ -586,7 +618,13 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) // ok, we got all ammo types. Now draw the list back to front (bottom to top) - int def_width = ConFont->StringWidth("000/000"); + int ammocurlen = 0; + int ammomaxlen = 0; + GetAmmoTextLengths(CPlayer, ammocurlen, ammomaxlen); + + mysnprintf(buf, countof(buf), "%0*d/%0*d", ammocurlen, 0, ammomaxlen, 0); + + int def_width = ConFont->StringWidth(buf); int yadd = ConFont->GetHeight(); int xtext = x - def_width; @@ -618,7 +656,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) int maxammo = inv->MaxAmount; int ammo = ammoitem? ammoitem->Amount : 0; - mysnprintf(buf, countof(buf), "%3d/%3d", ammo, maxammo); + mysnprintf(buf, countof(buf), "%*d/%*d", ammocurlen, ammo, ammomaxlen, maxammo); int tex_width= clamp(ConFont->StringWidth(buf)-def_width, 0, 1000); diff --git a/src/gi.cpp b/src/gi.cpp index 313df4f0b..9d45d2724 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -354,6 +354,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_PATCH(mStatscreenFinishedFont, "statscreen_finishedpatch") GAMEINFOKEY_PATCH(mStatscreenEnteringFont, "statscreen_enteringpatch") GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass") + GAMEINFOKEY_BOOL(forcekillscripts, "forcekillscripts") // [JM] Force kill scripts on thing death. (MF7_NOKILLSCRIPTS overrides.) else { diff --git a/src/gi.h b/src/gi.h index 2786b3425..c5b8f79cf 100644 --- a/src/gi.h +++ b/src/gi.h @@ -173,6 +173,7 @@ struct gameinfo_t FGIFont mStatscreenFinishedFont; FGIFont mStatscreenEnteringFont; bool norandomplayerclass; + bool forcekillscripts; const char *GetFinalePage(unsigned int num) const; }; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 6b2f4f595..e78174a55 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -348,7 +348,7 @@ void cht_DoCheat (player_t *player, int cheat) P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetUpState()); } - if (player->morphTics > 0) + if (player->morphTics) { P_UndoPlayerMorph(player, player); } diff --git a/src/menu/menu.h b/src/menu/menu.h index aa4058f87..04ae7e3f7 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -418,7 +418,7 @@ public: class FPlayerNameBox : public FListMenuItemSelectable { - const char *mText; + FString mText; FFont *mFont; EColorRange mFontColor; int mFrameSize; @@ -447,7 +447,7 @@ public: class FValueTextItem : public FListMenuItemSelectable { TArray mSelections; - const char *mText; + FString mText; int mSelection; FFont *mFont; EColorRange mFontColor; @@ -472,7 +472,7 @@ public: class FSliderItem : public FListMenuItemSelectable { - const char *mText; + FString mText; FFont *mFont; EColorRange mFontColor; int mMinrange, mMaxrange; @@ -539,7 +539,7 @@ public: class FOptionMenuItem : public FListMenuItem { protected: - char *mLabel; + FString mLabel; bool mCentered; void drawLabel(int indent, int y, EColorRange color, bool grayed = false); @@ -548,7 +548,7 @@ public: FOptionMenuItem(const char *text, FName action = NAME_None, bool center = false) : FListMenuItem(0, 0, action) { - mLabel = copystring(text); + mLabel = text; mCentered = center; } diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 1948153e4..618189b4f 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -781,7 +781,15 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc) FString label = sc.String; sc.MustGetStringName(","); sc.MustGetString(); - FOptionMenuItem *it = new FOptionMenuItemSafeCommand(label, sc.String); + FString command = sc.String; + FString prompt; + // Check for optional custom prompt + if (sc.CheckString(",")) + { + sc.MustGetString(); + prompt = sc.String; + } + FOptionMenuItem *it = new FOptionMenuItemSafeCommand(label, command, prompt); desc->mItems.Push(it); } else if (sc.Compare("Control") || sc.Compare("MapControl")) diff --git a/src/menu/optionmenu.cpp b/src/menu/optionmenu.cpp index f6633c76a..efea7d910 100644 --- a/src/menu/optionmenu.cpp +++ b/src/menu/optionmenu.cpp @@ -479,7 +479,6 @@ void DOptionMenu::Drawer () FOptionMenuItem::~FOptionMenuItem() { - if (mLabel != NULL) delete [] mLabel; } int FOptionMenuItem::Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected) @@ -507,14 +506,14 @@ int FOptionMenuItem::GetIndent() { return 0; } - const char *label = mLabel; + const char *label = mLabel.GetChars(); if (*label == '$') label = GStrings(label+1); return SmallFont->StringWidth(label); } void FOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed) { - const char *label = mLabel; + const char *label = mLabel.GetChars(); if (*label == '$') label = GStrings(label+1); int overlay = grayed? MAKEARGB(96,48,0,0) : 0; diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index 3131e35f7..76718809e 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -103,9 +103,13 @@ public: class FOptionMenuItemSafeCommand : public FOptionMenuItemCommand { // action is a CCMD +protected: + FString mPrompt; + public: - FOptionMenuItemSafeCommand(const char *label, const char *menu) + FOptionMenuItemSafeCommand(const char *label, const char *menu, const char *prompt) : FOptionMenuItemCommand(label, menu) + , mPrompt(prompt) { } @@ -121,9 +125,13 @@ public: bool Activate() { - const char *msg = GStrings("SAFEMESSAGE"); + const char *msg = mPrompt.IsNotEmpty() ? mPrompt.GetChars() : "$SAFEMESSAGE"; + if (*msg == '$') + { + msg = GStrings(msg + 1); + } - const char *actionLabel = mLabel; + const char *actionLabel = mLabel.GetChars(); if (actionLabel != NULL) { if (*actionLabel == '$') @@ -528,7 +536,7 @@ public: int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected) { - const char *txt = mCurrent? mAltText.GetChars() : mLabel; + const char *txt = mCurrent? mAltText.GetChars() : mLabel.GetChars(); if (*txt == '$') txt = GStrings(txt + 1); int w = SmallFont->StringWidth(txt) * CleanXfac_1; int x = (screen->GetWidth() - w) / 2; diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index cf63283ba..ce542c2f2 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -64,7 +64,7 @@ EXTERN_CVAR (Bool, cl_run) FPlayerNameBox::FPlayerNameBox(int x, int y, int height, int frameofs, const char *text, FFont *font, EColorRange color, FName action) : FListMenuItemSelectable(x, y, height, action) { - mText = copystring(text); + mText = text; mFont = font; mFontColor = color; mFrameSize = frameofs; @@ -74,7 +74,6 @@ FPlayerNameBox::FPlayerNameBox(int x, int y, int height, int frameofs, const cha FPlayerNameBox::~FPlayerNameBox() { - if (mText != NULL) delete [] mText; } //============================================================================= @@ -220,7 +219,7 @@ bool FPlayerNameBox::MenuEvent(int mkey, bool fromcontroller) FValueTextItem::FValueTextItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, EColorRange valuecolor, FName action, FName values) : FListMenuItemSelectable(x, y, height, action) { - mText = copystring(text); + mText = text; mFont = font; mFontColor = color; mFontColor2 = valuecolor; @@ -240,7 +239,6 @@ FValueTextItem::FValueTextItem(int x, int y, int height, const char *text, FFont FValueTextItem::~FValueTextItem() { - if (mText != NULL) delete [] mText; } //============================================================================= @@ -341,7 +339,7 @@ void FValueTextItem::Drawer(bool selected) FSliderItem::FSliderItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, FName action, int min, int max, int step) : FListMenuItemSelectable(x, y, height, action) { - mText = copystring(text); + mText = text; mFont = font; mFontColor = color; mSelection = 0; @@ -352,7 +350,6 @@ FSliderItem::FSliderItem(int x, int y, int height, const char *text, FFont *font FSliderItem::~FSliderItem() { - if (mText != NULL) delete [] mText; } //============================================================================= diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 919834a06..01953cad9 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3719,6 +3719,7 @@ enum APROP_DamageMultiplier=43, APROP_MaxStepHeight = 44, APROP_MaxDropOffHeight= 45, + APROP_DamageType = 46, }; // These are needed for ACS's APROP_RenderStyle @@ -3978,6 +3979,9 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) actor->MaxDropOffHeight = ACSToDouble(value); break; + case APROP_DamageType: + actor->DamageType = FBehavior::StaticLookupString(value); + break; default: // do nothing. @@ -4081,6 +4085,7 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_Friction: return DoubleToACS(actor->Friction); case APROP_MaxStepHeight: return DoubleToACS(actor->MaxStepHeight); case APROP_MaxDropOffHeight: return DoubleToACS(actor->MaxDropOffHeight); + case APROP_DamageType: return GlobalACSStrings.AddString(actor->DamageType); default: return 0; } @@ -4153,6 +4158,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_ActiveSound: string = actor->ActiveSound; break; case APROP_Species: string = actor->GetSpecies(); break; case APROP_NameTag: string = actor->GetTag(); break; + case APROP_DamageType: string = actor->DamageType; break; } if (string == NULL) string = ""; return (!stricmp(string, FBehavior::StaticLookupString(value))); diff --git a/src/p_acs.h b/src/p_acs.h index 13dad4651..243e2ccf3 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -270,6 +270,8 @@ enum SCRIPT_Unloading = 13, SCRIPT_Disconnect = 14, SCRIPT_Return = 15, + SCRIPT_Event = 16, // [BB] + SCRIPT_Kill = 17, // [JM] }; // Script flags diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 8890d3592..9f50c9ab5 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -379,6 +379,12 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) target = source; } + // [JM] Fire KILL type scripts for actor. Not needed for players, since they have the "DEATH" script type. + if (!player && !(flags7 & MF7_NOKILLSCRIPTS) && ((flags7 & MF7_USEKILLSCRIPTS) || gameinfo.forcekillscripts)) + { + FBehavior::StaticStartTypedScripts(SCRIPT_Kill, this, true, 0, true); + } + flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); if (!(flags4 & MF4_DONTFALL)) flags&=~MF_NOGRAVITY; flags |= MF_DROPOFF; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index c7d801cbb..307529636 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2552,7 +2552,7 @@ FUNC(LS_Line_AlignFloor) FUNC(LS_Line_SetTextureOffset) // Line_SetTextureOffset (id, x, y, side, flags) { - const double NO_CHANGE = FLT_MAX; + const int NO_CHANGE = 32767 << 16; double farg1 = arg1 / 65536.; double farg2 = arg2 / 65536.; @@ -2607,7 +2607,7 @@ FUNC(LS_Line_SetTextureOffset) FUNC(LS_Line_SetTextureScale) // Line_SetTextureScale (id, x, y, side, flags) { - const double NO_CHANGE = FLT_MAX; + const int NO_CHANGE = 32767 << 16; double farg1 = arg1 / 65536.; double farg2 = arg2 / 65536.; diff --git a/src/p_local.h b/src/p_local.h index 42b4da7e7..4b8b40a85 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -372,6 +372,7 @@ enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags RAF_EXPLICITANGLE = 4, RAF_FULLBRIGHT = 8, RAF_CENTERZ = 16, + RAF_NORANDOMPUFFZ = 32, }; diff --git a/src/p_map.cpp b/src/p_map.cpp index 1684ee534..106c93152 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4725,6 +4725,12 @@ void P_RailAttack(FRailParams *p) } } + int puffflags = 0; + if (p->flags & RAF_NORANDOMPUFFZ) + { + puffflags |= PF_NORANDOMZ; + } + DVector2 xy = source->Vec2Angle(p->offset_xy, angle - 90.); RailData rail_data; @@ -4777,7 +4783,7 @@ void P_RailAttack(FRailParams *p) bool spawnpuff; bool bleed = false; - int puffflags = PF_HITTHING; + int actorpuffflags = puffflags | PF_HITTHING; AActor *hitactor = rail_data.RailHits[i].HitActor; DVector3 &hitpos = rail_data.RailHits[i].HitPos; DAngle hitangle = rail_data.RailHits[i].HitAngle; @@ -4790,7 +4796,7 @@ void P_RailAttack(FRailParams *p) else { spawnpuff = (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF); - puffflags |= PF_HITTHINGBLEED; // [XA] Allow for puffs to jump to XDeath state. + actorpuffflags |= PF_HITTHINGBLEED; // [XA] Allow for puffs to jump to XDeath state. if (!(puffDefaults->flags3 & MF3_BLOODLESSIMPACT)) { bleed = true; @@ -4798,7 +4804,7 @@ void P_RailAttack(FRailParams *p) } if (spawnpuff) { - P_SpawnPuff(source, puffclass, hitpos, hitangle, hitangle - 90, 1, puffflags, hitactor); + P_SpawnPuff(source, puffclass, hitpos, hitangle, hitangle - 90, 1, actorpuffflags, hitactor); } int dmgFlagPass = DMG_INFLICTOR_IS_PUFF; @@ -4827,7 +4833,7 @@ void P_RailAttack(FRailParams *p) if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 1, 0); + puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 1, puffflags); if (puff && (trace.Line != NULL) && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE)) puff->Destroy(); } @@ -4842,7 +4848,7 @@ void P_RailAttack(FRailParams *p) AActor* puff = NULL; if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 1, 0); + puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 1, puffflags); if (puff && !(puff->flags3 & MF3_SKYEXPLODE) && (((trace.HitType == TRACE_HitFloor) && (puff->floorpic == skyflatnum)) || ((trace.HitType == TRACE_HitCeiling) && (puff->ceilingpic == skyflatnum)))) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index bad9c2d73..350acc3fd 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -510,7 +510,7 @@ void P_DropWeapon (player_t *player) } // Since the weapon is dropping, stop blocking switching. player->WeaponState &= ~WF_DISABLESWITCH; - if (player->ReadyWeapon != nullptr) + if ((player->ReadyWeapon != nullptr) && (player->health > 0 || !(player->ReadyWeapon->WeaponFlags & WIF_NODEATHDESELECT))) { P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetDownState()); } @@ -1396,20 +1396,23 @@ void player_t::TickPSprites() pspr = pspr->Next; } - if (ReadyWeapon == nullptr && (health > 0 || mo->DamageType != NAME_Fire)) + if ((health > 0) || (ReadyWeapon != nullptr && !(ReadyWeapon->WeaponFlags & WIF_NODEATHINPUT))) { - if (PendingWeapon != WP_NOCHANGE) - P_BringUpWeapon(this); - } - else - { - P_CheckWeaponSwitch(this); - if (WeaponState & (WF_WEAPONREADY | WF_WEAPONREADYALT)) + if (ReadyWeapon == nullptr) { - P_CheckWeaponFire(this); + if (PendingWeapon != WP_NOCHANGE) + P_BringUpWeapon(this); + } + else + { + P_CheckWeaponSwitch(this); + if (WeaponState & (WF_WEAPONREADY | WF_WEAPONREADYALT)) + { + P_CheckWeaponFire(this); + } + // Check custom buttons + P_CheckWeaponButtons(this); } - // Check custom buttons - P_CheckWeaponButtons(this); } } diff --git a/src/p_things.cpp b/src/p_things.cpp index e19323542..6f01715ad 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -925,6 +925,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, do { caller->AddZ(reference->GetBobOffset()); } + P_TryMove(caller, caller->Pos(), false); } return true; } diff --git a/src/r_things.cpp b/src/r_things.cpp index 74707ff72..f93f34100 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -2516,7 +2516,7 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade, if (x1 >= x2) return; - yscale = xs_RoundToInt(YaspectMul * xscale); + yscale = YaspectMul * xscale; ty = particle->Pos.Z - ViewPos.Z; y1 = xs_RoundToInt(CenterY - (ty + psize) * yscale); y2 = xs_RoundToInt(CenterY - (ty - psize) * yscale); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 63ba6ec30..d1933e142 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -6129,6 +6129,7 @@ enum DMSS DMSS_EXFILTER = 64, //Changes filter into a blacklisted class instead of whitelisted. DMSS_EXSPECIES = 128, // ^ but with species instead. DMSS_EITHER = 256, //Allow either type or species to be affected. + DMSS_INFLICTORDMGTYPE = 512, //Ignore the passed damagetype and use the inflictor's instead. }; static void DoDamage(AActor *dmgtarget, AActor *inflictor, AActor *source, int amount, FName DamageType, int flags, PClassActor *filter, FName species) @@ -6153,6 +6154,9 @@ static void DoDamage(AActor *dmgtarget, AActor *inflictor, AActor *source, int a if (amount > 0) { //Should wind up passing them through just fine. + if (flags & DMSS_INFLICTORDMGTYPE) + DamageType = inflictor->DamageType; + P_DamageMobj(dmgtarget, inflictor, source, amount, DamageType, dmgFlags); } else if (amount < 0) @@ -7184,3 +7188,34 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) ACTION_RETURN_BOOL(true); } +//========================================================================== +// +// A_CopySpriteFrame(from, to, flags) +// +// Copies the sprite and/or frame from one pointer to another. +//========================================================================== +enum CPSFFlags +{ + CPSF_NOSPRITE = 1, + CPSF_NOFRAME = 1 << 1, +}; + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(from); + PARAM_INT(to); + PARAM_INT_OPT(flags) { flags = 0; } + + AActor *copyfrom = COPY_AAPTR(self, from); + AActor *copyto = COPY_AAPTR(self, to); + + if (copyfrom == copyto || copyfrom == nullptr || copyto == nullptr || ((flags & CPSF_NOSPRITE) && (flags & CPSF_NOFRAME))) + { + ACTION_RETURN_BOOL(false); + } + + if (!(flags & CPSF_NOSPRITE)) copyto->sprite = copyfrom->sprite; + if (!(flags & CPSF_NOFRAME)) copyto->frame = copyfrom->frame; + ACTION_RETURN_BOOL(true); +} diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index a86e98566..0768f80c8 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -257,6 +257,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, LAXTELEFRAGDMG, AActor, flags7), DEFINE_FLAG(MF7, ICESHATTER, AActor, flags7), DEFINE_FLAG(MF7, ALLOWTHRUFLAGS, AActor, flags7), + DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7), + DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), @@ -362,6 +364,8 @@ static FFlagDef WeaponFlagDefs[] = DEFINE_FLAG(WIF, NO_AUTO_SWITCH, AWeapon, WeaponFlags), DEFINE_FLAG(WIF, AMMO_CHECKBOTH, AWeapon, WeaponFlags), DEFINE_FLAG(WIF, NOAUTOAIM, AWeapon, WeaponFlags), + DEFINE_FLAG(WIF, NODEATHDESELECT, AWeapon, WeaponFlags), + DEFINE_FLAG(WIF, NODEATHINPUT, AWeapon, WeaponFlags), DEFINE_DUMMY_FLAG(NOLMS), DEFINE_FLAG(WIF, ALT_USES_BOTH, AWeapon, WeaponFlags), diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index c97930277..f4bad69bb 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -710,6 +710,7 @@ static int ParseMorphStyle (FScanner &sc) { "MRF_UNDOBYDEATHFORCED", MORPH_UNDOBYDEATHFORCED}, { "MRF_UNDOBYDEATHSAVES", MORPH_UNDOBYDEATHSAVES}, { "MRF_UNDOALWAYS", MORPH_UNDOALWAYS }, + { "MRF_TRANSFERTRANSLATION", MORPH_TRANSFERTRANSLATION }, { NULL, 0 } }; diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 8c35df21b..77250b3df 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -330,6 +330,7 @@ ACTOR Actor native //: Thinker native state A_CheckRange(float distance, state label, bool two_dimension = false); action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); action native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); + action native bool A_CopySpriteFrame(int from, int to, int flags = 0); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 05049e598..76bdcf9eb 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -164,6 +164,7 @@ const int MRF_UNDOBYDEATH = 512; const int MRF_UNDOBYDEATHFORCED = 1024; const int MRF_UNDOBYDEATHSAVES = 2048; const int MRF_UNDOALWAYS = 4096; +const int MRF_TRANSFERTRANSLATION = 8192; // Flags for A_RailAttack and A_CustomRailgun const int RGF_SILENT = 1; @@ -171,6 +172,7 @@ const int RGF_NOPIERCING = 2; const int RGF_EXPLICITANGLE = 4; const int RGF_FULLBRIGHT = 8; const int RGF_CENTERZ = 16; +const int RGF_NORANDOMPUFFZ = 32; // Flags for A_Mushroom const int MSF_Standard = 0; @@ -466,6 +468,7 @@ enum DMSS_EXFILTER = 0x00000040, DMSS_EXSPECIES = 0x00000080, DMSS_EITHER = 0x00000100, + DMSS_INFLICTORDMGTYPE = 0x00000200, }; // Flags for A_AlertMonsters @@ -663,4 +666,11 @@ enum { GAF_RELATIVE = 1, GAF_SWITCH = 1 << 1, +}; + +//Flags for A_CopySpriteFrame +enum +{ + CPSF_NOSPRITE = 1, + CPSF_NOFRAME = 1 << 1, }; \ No newline at end of file