This commit is contained in:
nashmuhandes 2017-02-27 08:25:07 +08:00
commit 13c3e512d7
26 changed files with 261 additions and 78 deletions

View file

@ -197,6 +197,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
desaturation = <float>; // Color desaturation factor. 0 = none, 1 = full, default = 0.
silent = <bool>; // Actors in this sector make no sound,
nofallingdamage = <bool>; // Falling damage is disabled in this sector
noattack = <bool>; // Blocks monster attacks in this sector.
dropactors = <bool>; // Actors drop with instantly moving floors (*)
norespawn = <bool>; // Players can not respawn in this sector
soundsequence = <string>; // The sound sequence to play when this sector moves. Placing a
@ -262,8 +263,8 @@ Note: All <bool> fields default to false unless mentioned otherwise.
gravity = <float>; // Set per-actor gravity. Positive values are multiplied with the class's property,
// negative values are used as their absolute. Default = 1.0.
health = <int>; // Set per-actor health. Positive values are multiplied with the class's property,
// negative values are used as their absolute. Default = 1.
health = <int>; // Set per-actor health as an absolute value. Default = actor default.
healthfactor = <float>; // Set per-actor health as a factor to the original. Default = 1.
renderstyle = <string>; // Set per-actor render style, overriding the class default. Possible values can be "normal",
// "none", "add" or "additive", "subtract" or "subtractive", "stencil", "translucentstencil",

View file

@ -47,7 +47,7 @@ DEFINE_SPECIAL(Ceiling_CrushRaiseAndStay, 45, 3, 4, 4)
DEFINE_SPECIAL(Floor_CrushStop, 46, 1, 1, 1)
DEFINE_SPECIAL(Ceiling_MoveToValue, 47, 3, 5, 5)
DEFINE_SPECIAL(Sector_Attach3dMidtex, 48, -1, -1, 3)
DEFINE_SPECIAL(GlassBreak, 49, 0, 1, 1)
DEFINE_SPECIAL(GlassBreak, 49, 0, 1, 2)
DEFINE_SPECIAL(ExtraFloor_LightOnly, 50, -1, -1, 2)
DEFINE_SPECIAL(Sector_SetLink, 51, 4, 4, 4)
DEFINE_SPECIAL(Scroll_Wall, 52, 5, 5, 5)

View file

@ -469,6 +469,7 @@ enum ActorBounceFlag
BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag.
BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors
BOUNCE_UseBounceState = 1<<14, // Use Bounce[.*] states
BOUNCE_NotOnShootables = 1<<15, // do not bounce off shootable actors if we are a projectile. Explode instead.
BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF,

View file

@ -524,6 +524,7 @@ struct FSkillInfo
bool EasyBossBrain;
bool EasyKey;
bool NoMenu;
int RespawnCounter;
int RespawnLimit;
double Aggressiveness;

View file

@ -701,3 +701,30 @@ void AMorphedMonster::Tick ()
Super::Tick ();
}
}
DEFINE_ACTION_FUNCTION(AActor, A_Morph)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(type, AActor);
PARAM_INT_DEF(duration);
PARAM_INT_DEF(flags);
PARAM_CLASS_DEF(enter_flash, AActor);
PARAM_CLASS_DEF(exit_flash, AActor);
bool res = false;
if (self->player)
{
if (type->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
res = P_MorphPlayer(self->player, self->player, type, duration, flags, enter_flash, exit_flash);
}
}
else
{
if (type->IsKindOf(RUNTIME_CLASS(AMorphedMonster)))
{
res = P_MorphMonster(self, type, duration, flags, enter_flash, exit_flash);
}
}
ACTION_RETURN_BOOL(res);
}

View file

@ -60,6 +60,7 @@ void FMapInfoParser::ParseSkill ()
bool thisisdefault = false;
bool acsreturnisset = false;
skill.NoMenu = false;
skill.AmmoFactor = 1.;
skill.DoubleAmmoFactor = 2.;
skill.DropAmmoFactor = -1.;
@ -149,6 +150,10 @@ void FMapInfoParser::ParseSkill ()
{
skill.AutoUseHealth = true;
}
else if (sc.Compare("nomenu"))
{
skill.NoMenu = true;
}
else if (sc.Compare("respawntime"))
{
ParseAssign();
@ -508,6 +513,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other)
{
Name = other.Name;
AmmoFactor = other.AmmoFactor;
NoMenu = other.NoMenu;
DoubleAmmoFactor = other.DoubleAmmoFactor;
DropAmmoFactor = other.DropAmmoFactor;
DamageFactor = other.DamageFactor;

View file

@ -767,6 +767,13 @@ DEFINE_ACTION_FUNCTION(_DamageTypeDefinition, IgnoreArmor)
ACTION_RETURN_BOOL(DamageTypeDefinition::IgnoreArmor(type));
}
FString DamageTypeDefinition::GetObituary(FName type)
{
DamageTypeDefinition *dtd = Get(type);
if (dtd) return dtd->Obituary;
return "";
}
//==========================================================================
//
@ -859,6 +866,12 @@ void FMapInfoParser::ParseDamageDefinition()
dtd.DefaultFactor = sc.Float;
if (dtd.DefaultFactor == 0) dtd.ReplaceFactor = true;
}
if (sc.Compare("OBITUARY"))
{
sc.MustGetStringName("=");
sc.MustGetString();
dtd.Obituary = sc.String;
}
else if (sc.Compare("REPLACEFACTOR"))
{
dtd.ReplaceFactor = true;

View file

@ -214,6 +214,7 @@ struct DamageTypeDefinition
public:
DamageTypeDefinition() { Clear(); }
FString Obituary;
double DefaultFactor;
bool ReplaceFactor;
bool NoArmor;
@ -221,6 +222,7 @@ public:
void Apply(FName type);
void Clear()
{
Obituary = "";
DefaultFactor = 1.;
ReplaceFactor = false;
NoArmor = false;
@ -228,6 +230,7 @@ public:
static bool IgnoreArmor(FName type);
static int ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors);
static FString GetObituary(FName type);
private:
static double GetMobjDamageFactor(FName type, DmgFactors const * const factors);

View file

@ -68,6 +68,7 @@ IMPLEMENT_POINTERS_END
extern int NoWipe;
CVAR(Bool, nointerscrollabort, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
//==========================================================================
//
//
@ -647,7 +648,7 @@ void DIntermissionScreenScroller::Init(FIntermissionAction *desc, bool first)
int DIntermissionScreenScroller::Responder (event_t *ev)
{
int res = Super::Responder(ev);
if (res == -1)
if (res == -1 && !nointerscrollabort)
{
mBackground = mSecondPic;
mTicker = mScrollDelay + mScrollTime;

View file

@ -64,6 +64,7 @@ CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE)
CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_blockcontrollers, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE)
@ -582,6 +583,9 @@ bool M_Responder (event_t *ev)
}
else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
{
// eat blocked controller events without dispatching them.
if (ev->data1 >= KEY_FIRSTJOYBUTTON && m_blockcontrollers) return true;
keyup = ev->type == EV_KeyUp;
ch = ev->data1;

View file

@ -339,7 +339,6 @@ void M_ActivateMenu(DMenu *menu);
void M_ClearMenus ();
void M_ParseMenuDefs();
void M_StartupSkillMenu(FGameStartup *gs);
int M_GetDefaultSkill();
void M_StartControlPanel (bool makeSound);
void M_SetMenu(FName menu, int param = -1);
void M_StartMessage(const char *message, int messagemode, FName action = NAME_None);

View file

@ -1323,6 +1323,43 @@ void M_StartupSkillMenu(FGameStartup *gs)
{
static int done = -1;
bool success = false;
TArray<FSkillInfo*> MenuSkills;
TArray<int> SkillIndices;
if (MenuSkills.Size() == 0)
{
for (unsigned ind = 0; ind < AllSkills.Size(); ind++)
{
if (!AllSkills[ind].NoMenu)
{
MenuSkills.Push(&AllSkills[ind]);
SkillIndices.Push(ind);
}
}
}
if (MenuSkills.Size() == 0) I_Error("No valid skills for menu found. At least one must be defined.");
int defskill = DefaultSkill;
if ((unsigned int)defskill >= MenuSkills.Size())
{
defskill = SkillIndices[(MenuSkills.Size() - 1) / 2];
}
if (AllSkills[defskill].NoMenu)
{
for (defskill = 0; defskill < (int)AllSkills.Size(); defskill++)
{
if (!AllSkills[defskill].NoMenu) break;
}
}
int defindex = 0;
for (unsigned i = 0; i < MenuSkills.Size(); i++)
{
if (MenuSkills[i] == &AllSkills[defskill])
{
defindex = i;
break;
}
}
DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Skillmenu);
if (desc != nullptr)
{
@ -1346,12 +1383,7 @@ void M_StartupSkillMenu(FGameStartup *gs)
if (done != restart)
{
done = restart;
int defskill = DefaultSkill;
if ((unsigned int)defskill >= AllSkills.Size())
{
defskill = (AllSkills.Size() - 1) / 2;
}
ld->mSelectedItem = ld->mItems.Size() + defskill;
ld->mSelectedItem = ld->mItems.Size() + defindex;
int posy = y;
int topy = posy;
@ -1364,9 +1396,9 @@ void M_StartupSkillMenu(FGameStartup *gs)
}
// center the menu on the screen if the top space is larger than the bottom space
int totalheight = posy + AllSkills.Size() * ld->mLinespacing - topy;
int totalheight = posy + MenuSkills.Size() * ld->mLinespacing - topy;
if (totalheight < 190 || AllSkills.Size() == 1)
if (totalheight < 190 || MenuSkills.Size() == 1)
{
int newtop = (200 - totalheight + topy) / 2;
int topdelta = newtop - topy;
@ -1389,9 +1421,9 @@ void M_StartupSkillMenu(FGameStartup *gs)
}
unsigned firstitem = ld->mItems.Size();
for(unsigned int i = 0; i < AllSkills.Size(); i++)
for(unsigned int i = 0; i < MenuSkills.Size(); i++)
{
FSkillInfo &skill = AllSkills[i];
FSkillInfo &skill = *MenuSkills[i];
DMenuItemBase *li;
// Using a different name for skills that must be confirmed makes handling this easier.
FName action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ?
@ -1405,22 +1437,22 @@ void M_StartupSkillMenu(FGameStartup *gs)
if (skill.PicName.Len() != 0 && pItemText == nullptr)
{
FTextureID tex = GetMenuTexture(skill.PicName);
li = CreateListMenuItemPatch(ld->mXpos, y, ld->mLinespacing, skill.Shortcut, tex, action, i);
li = CreateListMenuItemPatch(ld->mXpos, y, ld->mLinespacing, skill.Shortcut, tex, action, SkillIndices[i]);
}
else
{
EColorRange color = (EColorRange)skill.GetTextColor();
if (color == CR_UNTRANSLATED) color = ld->mFontColor;
li = CreateListMenuItemText(x, y, ld->mLinespacing, skill.Shortcut,
pItemText? *pItemText : skill.MenuName, ld->mFont, color,ld->mFontColor2, action, i);
pItemText? *pItemText : skill.MenuName, ld->mFont, color,ld->mFontColor2, action, SkillIndices[i]);
}
ld->mItems.Push(li);
GC::WriteBarrier(*desc, li);
y += ld->mLinespacing;
}
if (AllEpisodes[gs->Episode].mNoSkill || AllSkills.Size() == 1)
if (AllEpisodes[gs->Episode].mNoSkill || MenuSkills.Size() == 1)
{
ld->mAutoselect = firstitem + M_GetDefaultSkill();
ld->mAutoselect = firstitem + defindex;
}
else
{
@ -1439,7 +1471,7 @@ fail:
MenuDescriptors[NAME_Skillmenu] = od;
od->mMenuName = NAME_Skillmenu;
od->mTitle = "$MNU_CHOOSESKILL";
od->mSelectedItem = 0;
od->mSelectedItem = defindex;
od->mScrollPos = 0;
od->mClass = nullptr;
od->mPosition = -15;
@ -1453,9 +1485,9 @@ fail:
od = static_cast<DOptionMenuDescriptor*>(*desc);
od->mItems.Clear();
}
for(unsigned int i = 0; i < AllSkills.Size(); i++)
for(unsigned int i = 0; i < MenuSkills.Size(); i++)
{
FSkillInfo &skill = AllSkills[i];
FSkillInfo &skill = *MenuSkills[i];
DMenuItemBase *li;
// Using a different name for skills that must be confirmed makes handling this easier.
const char *action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ?
@ -1466,29 +1498,13 @@ fail:
{
pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass);
}
li = CreateOptionMenuItemSubmenu(pItemText? *pItemText : skill.MenuName, action, i);
li = CreateOptionMenuItemSubmenu(pItemText? *pItemText : skill.MenuName, action, SkillIndices[i]);
od->mItems.Push(li);
GC::WriteBarrier(od, li);
if (!done)
{
done = true;
od->mSelectedItem = M_GetDefaultSkill();
od->mSelectedItem = defindex;
}
}
}
//=============================================================================
//
// Returns the default skill level.
//
//=============================================================================
int M_GetDefaultSkill()
{
int defskill = DefaultSkill;
if ((unsigned int)defskill >= AllSkills.Size())
{
defskill = (AllSkills.Size() - 1) / 2;
}
return defskill;
}

View file

@ -46,6 +46,7 @@ xx(Shadow)
xx(Subtract)
xx(Subtractive)
xx(FillColor)
xx(HealthFactor)
// Healingradius types
xx(Mana)
@ -773,6 +774,7 @@ xx(BuiltinGetDefault)
xx(BuiltinClassCast)
xx(BuiltinFormat)
xx(Damage)
xx(Noattack)
// basic type names
xx(Default)

View file

@ -350,7 +350,7 @@ bool AActor::CheckMeleeRange ()
double dist;
if (!pl)
if (!pl || (Sector->Flags & SECF_NOATTACK))
return false;
dist = Distance2D (pl);
@ -399,7 +399,7 @@ bool P_CheckMeleeRange2 (AActor *actor)
double dist;
if (!actor->target)
if (!actor->target || (actor->Sector->Flags & SECF_NOATTACK))
{
return false;
}
@ -446,6 +446,8 @@ bool P_CheckMissileRange (AActor *actor)
{
double dist;
if ((actor->Sector->Flags & SECF_NOATTACK)) return false;
if (!P_CheckSight (actor, actor->target, SF_SEEPASTBLOCKEVERYTHING))
return false;

View file

@ -217,15 +217,20 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
}
}
switch (mod)
FString obit = DamageTypeDefinition::GetObituary(mod);
if (obit.IsNotEmpty()) messagename = obit;
else
{
case NAME_Suicide: messagename = "OB_SUICIDE"; break;
case NAME_Falling: messagename = "OB_FALLING"; break;
case NAME_Crush: messagename = "OB_CRUSH"; break;
case NAME_Exit: messagename = "OB_EXIT"; break;
case NAME_Drowning: messagename = "OB_WATER"; break;
case NAME_Slime: messagename = "OB_SLIME"; break;
case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break;
switch (mod)
{
case NAME_Suicide: messagename = "OB_SUICIDE"; break;
case NAME_Falling: messagename = "OB_FALLING"; break;
case NAME_Crush: messagename = "OB_CRUSH"; break;
case NAME_Exit: messagename = "OB_EXIT"; break;
case NAME_Drowning: messagename = "OB_WATER"; break;
case NAME_Slime: messagename = "OB_SLIME"; break;
case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break;
}
}
// Check for being killed by a voodoo doll.

View file

@ -3177,7 +3177,7 @@ FUNC(LS_ClearForceField)
}
FUNC(LS_GlassBreak)
// GlassBreak (bNoJunk)
// GlassBreak (bNoJunk, junkID)
{
bool switched;
bool quest1, quest2;
@ -3197,7 +3197,6 @@ FUNC(LS_GlassBreak)
{
if (!arg0)
{ // Break some glass
AActor *glass;
DVector2 linemid((ln->v1->fX() + ln->v2->fX()) / 2, (ln->v1->fY() + ln->v2->fY()) / 2);
@ -3209,18 +3208,32 @@ FUNC(LS_GlassBreak)
y += (ln->frontsector->centerspot.y - y) / 5;
*/
auto type = SpawnableThings.CheckKey(arg1);
for (int i = 0; i < 7; ++i)
{
glass = Spawn("GlassJunk", DVector3(linemid, ONFLOORZ), ALLOW_REPLACE);
glass->AddZ(24.);
glass->SetState (glass->SpawnState + (pr_glass() % glass->health));
glass->Angles.Yaw = pr_glass() * (360 / 256.);
glass->VelFromAngle(pr_glass() & 3);
glass->Vel.Z = (pr_glass() & 7);
// [RH] Let the shards stick around longer than they did in Strife.
glass->tics += pr_glass();
AActor *glass = nullptr;
if (arg1 > 0)
{
if (type != nullptr)
{
glass = Spawn(*type, DVector3(linemid, ONFLOORZ), ALLOW_REPLACE);
glass->AddZ(24.);
}
}
else
{
glass = Spawn("GlassJunk", DVector3(linemid, ONFLOORZ), ALLOW_REPLACE);
glass->AddZ(24.);
glass->SetState(glass->SpawnState + (pr_glass() % glass->health));
}
if (glass != nullptr)
{
glass->Angles.Yaw = pr_glass() * (360 / 256.);
glass->VelFromAngle(pr_glass() & 3);
glass->Vel.Z = (pr_glass() & 7);
// [RH] Let the shards stick around longer than they did in Strife.
glass->tics += pr_glass();
}
}
}
if (quest1 || quest2)

View file

@ -3538,6 +3538,11 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop)
if ((mo->flags & MF_MISSILE) && (mo->flags2 & MF2_RIP) && BlockingMobj->flags & MF_SHOOTABLE)
return true;
if (BlockingMobj->flags & MF_SHOOTABLE && mo->BounceFlags & BOUNCE_NotOnShootables)
{
mo->bouncecount = 1; // let it explode now.
}
if (mo->bouncecount>0 && --mo->bouncecount == 0)
{
if (mo->flags & MF_MISSILE)

View file

@ -515,6 +515,7 @@ public:
FString arg0str, arg1str;
memset(th, 0, sizeof(*th));
double healthfactor = 1;
th->Gravity = 1;
th->RenderStyle = STYLE_Count;
th->Alpha = -1;
@ -738,38 +739,52 @@ public:
break;
case NAME_Alpha:
CHECK_N(Zd | Zdt)
th->Alpha = CheckFloat(key);
break;
case NAME_FillColor:
CHECK_N(Zd | Zdt)
th->fillcolor = CheckInt(key);
break;
case NAME_Health:
CHECK_N(Zd | Zdt)
th->health = CheckInt(key);
break;
case NAME_HealthFactor:
CHECK_N(Zd | Zdt)
healthfactor = CheckFloat(key);
break;
case NAME_Score:
CHECK_N(Zd | Zdt)
th->score = CheckInt(key);
break;
case NAME_Pitch:
CHECK_N(Zd | Zdt)
th->pitch = (short)CheckInt(key);
break;
case NAME_Roll:
CHECK_N(Zd | Zdt)
th->roll = (short)CheckInt(key);
break;
case NAME_ScaleX:
CHECK_N(Zd | Zdt)
th->Scale.X = CheckFloat(key);
break;
case NAME_ScaleY:
CHECK_N(Zd | Zdt)
th->Scale.Y = CheckFloat(key);
break;
case NAME_Scale:
CHECK_N(Zd | Zdt)
th->Scale.X = th->Scale.Y = CheckFloat(key);
break;
@ -793,6 +808,7 @@ public:
{
th->args[1] = -FName(arg1str);
}
th->health = int(th->health * healthfactor);
// Thing specials are only valid in namespaces with Hexen-type specials
// and in ZDoomTranslated - which will use the translator on them.
if (namespc == NAME_ZDoomTranslated)
@ -1658,6 +1674,10 @@ public:
sec->planes[sector_t::ceiling].GlowHeight = (float)CheckFloat(key);
break;
case NAME_Noattack:
Flag(sec->Flags, SECF_NOATTACK, key);
break;
case NAME_MoreIds:
// delay parsing of the tag string until parsing of the sector is complete
// This ensures that the ID is always the first tag in the list.

View file

@ -495,6 +495,7 @@ enum
SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode
SECF_ENDLEVEL = 512, // ends level when health goes below 10
SECF_HAZARD = 1024, // Change to Strife's delayed damage handling.
SECF_NOATTACK = 2048, // monsters cannot start attacks in this sector.
SECF_WASSECRET = 1 << 30, // a secret that was discovered
SECF_SECRET = 1 << 31, // a secret sector

View file

@ -217,12 +217,66 @@ bool FZipFile::Open(bool quiet)
char *dirptr = (char*)directory;
FZipLump *lump_p = Lumps;
// Check if all files have the same prefix so that this can be stripped out.
FString name0;
for (DWORD i = 0; i < NumLumps; i++)
{
FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr;
int len = LittleShort(zip_fh->NameLength);
FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len);
dirptr += sizeof(FZipCentralDirectoryInfo) +
LittleShort(zip_fh->NameLength) +
LittleShort(zip_fh->ExtraLength) +
LittleShort(zip_fh->CommentLength);
if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file.
{
free(directory);
if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", Filename);
return false;
}
name.ToLower();
if (i == 0)
{
// check for special names, if one of these gets found this must be treated as a normal zip.
bool isspecial = !name.Compare("flats/") ||
!name.Compare("textures/") ||
!name.Compare("hires/") ||
!name.Compare("sprites/") ||
!name.Compare("voxels/") ||
!name.Compare("colormaps/") ||
!name.Compare("acs/") ||
!name.Compare("voices/") ||
!name.Compare("patches/") ||
!name.Compare("graphics/") ||
!name.Compare("sounds/") ||
!name.Compare("music/");
if (isspecial) break;
name0 = name;
}
else
{
if (name.IndexOf(name0) != 0)
{
name0 = "";
break;
}
}
}
dirptr = (char*)directory;
lump_p = Lumps;
for (DWORD i = 0; i < NumLumps; i++)
{
FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr;
int len = LittleShort(zip_fh->NameLength);
FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len);
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
dirptr += sizeof(FZipCentralDirectoryInfo) +
LittleShort(zip_fh->NameLength) +
LittleShort(zip_fh->ExtraLength) +

View file

@ -356,6 +356,7 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG2(BOUNCE_MBF, MBFBOUNCER, AActor, BounceFlags),
DEFINE_FLAG2(BOUNCE_AutoOffFloorOnly, BOUNCEAUTOOFFFLOORONLY, AActor, BounceFlags),
DEFINE_FLAG2(BOUNCE_UseBounceState, USEBOUNCESTATE, AActor, BounceFlags),
DEFINE_FLAG2(BOUNCE_NotOnShootables, DONTBOUNCEONSHOOTABLES, AActor, BounceFlags),
};
// These won't be accessible through bitfield variables

View file

@ -1156,7 +1156,8 @@ public:
void WI_initShowNextLoc ()
{
if (wbs->next_ep == -1)
auto info = FindLevelInfo(wbs->next, false);
if (info == nullptr)
{
// Last map in episode - there is no next location!
WI_End();

View file

@ -1776,6 +1776,7 @@ MOUSEMNU_LOOKSTRAFE = "Lookstrafe";
JOYMNU_CONFIG = "CONFIGURE CONTROLLER";
JOYMNU_OPTIONS = "CONTROLLER OPTIONS";
JOYMNU_NOMENU = "Block controller input in menu";
// Player Setup Menu
MNU_PLAYERSETUP = "PLAYER SETUP";
@ -1895,7 +1896,7 @@ MISCMNU_DEHLOAD = "Load *.deh/*.bex lumps";
MISCMNU_CACHENODES = "Cache nodes";
MISCMNU_CACHETIME = "Time threshold for node caching";
MISCMNU_CLEARNODECACHE = "Clear node cache";
MISCMNU_INTERSCROLL = "Allow skipping of intermission scrollers";
// Automap Options
AUTOMAPMNU_TITLE = "AUTOMAP OPTIONS";
AUTOMAPMNU_COLORSET = "Map color set";

View file

@ -562,6 +562,7 @@ OptionMenu "JoystickOptionsDefaults"
{
Title "$JOYMNU_OPTIONS"
Option "$JOYMNU_ENABLE", "use_joystick", "YesNo"
Option "$JOYMNU_NOMENU", "m_blockcontrollers", "YesNo"
IfOption(Windows)
{
Option "$JOYMNU_DINPUT", "joy_dinput", "YesNo"
@ -945,6 +946,7 @@ OptionMenu "MiscOptions"
Option "$MISCMNU_SAVELOADCONFIRMATION", "saveloadconfirmation", "OnOff"
Slider "$MISCMNU_AUTOSAVECOUNT", "autosavecount", 1, 20, 1, 0
Option "$MISCMNU_DEHLOAD", "dehload", "dehopt"
Option "$MISCMNU_INTERSCROLL", "nointerscrollabort", "OffOn"
StaticText " "
Option "$MISCMNU_CACHENODES", "gl_cachenodes", "OnOff"
Slider "$MISCMNU_CACHETIME", "gl_cachetime", 0.0, 2.0, 0.1

View file

@ -796,6 +796,7 @@ class Actor : Thinker native
deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class<actor> missiletype, double missileheight);
action native bool, Actor A_ThrowGrenade(class<Actor> itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true);
native void A_Weave(int xspeed, int yspeed, double xdist, double ydist);
native bool A_Morph(class<Actor> type, int duration = 0, int flags = 0, class<Actor> enter_flash = null, class<Actor> exit_flash = null);
action native state, bool A_Teleport(statelabel teleportstate = null, class<SpecialSpot> targettype = "BossSpot", class<Actor> fogtype = "TeleportFog", int flags = 0, double mindist = 128, double maxdist = 0, int ptr = AAPTR_DEFAULT);

View file

@ -214,20 +214,23 @@ enum ESelectWeaponFlags
// Morph constants
enum EMorphFlags
{
MRF_ADDSTAMINA = 1,
MRF_FULLHEALTH = 2,
MRF_UNDOBYTOMEOFPOWER = 4,
MRF_UNDOBYCHAOSDEVICE = 8,
MRF_FAILNOTELEFRAG = 16,
MRF_FAILNOLAUGH = 32,
MRF_WHENINVULNERABLE = 64,
MRF_LOSEACTUALWEAPON = 128,
MRF_NEWTIDBEHAVIOUR = 256,
MRF_UNDOBYDEATH = 512,
MRF_UNDOBYDEATHFORCED = 1024,
MRF_UNDOBYDEATHSAVES = 2048,
MRF_UNDOALWAYS = 4096,
MRF_TRANSFERTRANSLATION = 8192,
MRF_OLDEFFECTS = 0x00000000,
MRF_ADDSTAMINA = 0x00000001,
MRF_FULLHEALTH = 0x00000002,
MRF_UNDOBYTOMEOFPOWER = 0x00000004,
MRF_UNDOBYCHAOSDEVICE = 0x00000008,
MRF_FAILNOTELEFRAG = 0x00000010,
MRF_FAILNOLAUGH = 0x00000020,
MRF_WHENINVULNERABLE = 0x00000040,
MRF_LOSEACTUALWEAPON = 0x00000080,
MRF_NEWTIDBEHAVIOUR = 0x00000100,
MRF_UNDOBYDEATH = 0x00000200,
MRF_UNDOBYDEATHFORCED = 0x00000400,
MRF_UNDOBYDEATHSAVES = 0x00000800,
MRF_UNDOBYTIMEOUT = 0x00001000,
MRF_UNDOALWAYS = 0x00002000,
MRF_TRANSFERTRANSLATION = 0x00004000,
MRF_STANDARDUNDOING = MRF_UNDOBYTOMEOFPOWER | MRF_UNDOBYCHAOSDEVICE | MRF_UNDOBYTIMEOUT,
};
// Flags for A_RailAttack and A_CustomRailgun