diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..d12f3a703 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,26 @@ +* text=auto + +*.h text +*.c text +*.cc text +*.cpp text +*.mm text +*.lemon text +*.y text +*.re text +*.i text +*.asm text +*.S text + +*.vcproj text eol=crlf +*.sln text eol=crlf +*.bat text eol=crlf + +*.txt text +language.* text + +*.png binary +*.imgz binary +*.lmp binary +*.flac binary +*.dat binary diff --git a/.gitignore b/.gitignore index df5c6663b..1b078ed63 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.pdb *.ilk *.aps +/fmodapi*/ /Release /wadsrc_wad *.user @@ -45,3 +46,4 @@ /build_vc2015 /build_vc2015-32 /build_vc2015-64 +/build diff --git a/bzip2/bzip2.vcproj b/bzip2/bzip2.vcproj deleted file mode 100644 index 4b8aef564..000000000 --- a/bzip2/bzip2.vcproj +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dumb/vc6/dumb/dumb.vcproj b/dumb/vc6/dumb/dumb.vcproj deleted file mode 100644 index 525bc56fc..000000000 --- a/dumb/vc6/dumb/dumb.vcproj +++ /dev/null @@ -1,2007 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dumb/vc6/dumb_static/dumb_static.vcproj b/dumb/vc6/dumb_static/dumb_static.vcproj deleted file mode 100644 index 6d6736259..000000000 --- a/dumb/vc6/dumb_static/dumb_static.vcproj +++ /dev/null @@ -1,2069 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/game-music-emu/game-music-emu.vcproj b/game-music-emu/game-music-emu.vcproj deleted file mode 100644 index e521ab01d..000000000 --- a/game-music-emu/game-music-emu.vcproj +++ /dev/null @@ -1,874 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gdtoa/gdtoa.vcproj b/gdtoa/gdtoa.vcproj deleted file mode 100644 index 12a3e40b3..000000000 --- a/gdtoa/gdtoa.vcproj +++ /dev/null @@ -1,1728 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jpeg-6b/jpeg-6b.vcproj b/jpeg-6b/jpeg-6b.vcproj deleted file mode 100644 index b46f4150d..000000000 --- a/jpeg-6b/jpeg-6b.vcproj +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lzma/lzmalib.vcproj b/lzma/lzmalib.vcproj deleted file mode 100644 index f1e085f3d..000000000 --- a/lzma/lzmalib.vcproj +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/actor.h b/src/actor.h index 2de96d84c..8695986b2 100644 --- a/src/actor.h +++ b/src/actor.h @@ -743,6 +743,7 @@ public: inline bool IsNoClip2() const; void CheckPortalTransition(bool islinked); + fixedvec3 GetPortalTransition(fixed_t byoffset); // What species am I? virtual FName GetSpecies(); @@ -893,7 +894,7 @@ public: fixedvec2 ret = { X() + dx, Y() + dy }; return ret; } - else return P_GetOffsetPosition(this, dx, dy); + else return P_GetOffsetPosition(X(), Y(), dx, dy); } @@ -905,7 +906,7 @@ public: Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) }; return ret; } - else return P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT])); + else return P_GetOffsetPosition(X(), Y(), FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT])); } fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) @@ -917,7 +918,7 @@ public: } else { - fixedvec2 op = P_GetOffsetPosition(this, dx, dy); + fixedvec2 op = P_GetOffsetPosition(X(), Y(), dx, dy); fixedvec3 pos = { op.x, op.y, Z() + dz }; return pos; } @@ -933,7 +934,7 @@ public: } else { - fixedvec2 op = P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT])); + fixedvec2 op = P_GetOffsetPosition(X(), Y(), FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT])); fixedvec3 pos = { op.x, op.y, Z() + dz }; return pos; } @@ -1404,6 +1405,28 @@ inline fixedvec2 Vec2Angle(fixed_t length, angle_t angle) void PrintMiscActorInfo(AActor * query); AActor *P_LinePickActor(AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); +// If we want to make P_AimLineAttack capable of handling arbitrary portals, it needs to pass a lot more info than just the linetarget actor. +struct FTranslatedLineTarget +{ + AActor *linetarget; + angle_t hitangle; + fixedvec3 targetPosFromSrc; + angle_t targetAngleFromSrc; + fixedvec3 sourcePosFromTarget; + angle_t sourceAngleFromTarget; + bool unlinked; // found by a trace that went through an unlinked portal. + + angle_t SourceAngleToTarget() const + { + return R_PointToAngle2(sourcePosFromTarget.x, sourcePosFromTarget.y, linetarget->X(), linetarget->Y()); + } + angle_t TargetAngleToSource() const + { + return R_PointToAngle2(linetarget->X(), linetarget->Y(), sourcePosFromTarget.x, sourcePosFromTarget.y); + } +}; + + #define S_FREETARGMOBJ 1 #endif // __P_MOBJ_H__ diff --git a/src/actorptrselect.cpp b/src/actorptrselect.cpp index 54c41e6ba..a93ecd6a1 100644 --- a/src/actorptrselect.cpp +++ b/src/actorptrselect.cpp @@ -2,6 +2,7 @@ #include "actor.h" #include "d_player.h" #include "p_pspr.h" +#include "p_local.h" //========================================================================== // @@ -34,6 +35,8 @@ AActor *COPY_AAPTR(AActor *origin, int selector) { if (selector == AAPTR_DEFAULT) return origin; + FTranslatedLineTarget t; + if (origin) { if (origin->player) @@ -41,11 +44,9 @@ AActor *COPY_AAPTR(AActor *origin, int selector) switch (selector & AAPTR_PLAYER_SELECTORS) { case AAPTR_PLAYER_GETTARGET: - { - AActor *gettarget = NULL; - P_BulletSlope(origin, &gettarget); - return gettarget; - } + P_BulletSlope(origin, &t, ALF_PORTALRESTRICT); + return t.linetarget; + case AAPTR_PLAYER_GETCONVERSATION: return origin->player->ConversationNPC; } @@ -60,11 +61,8 @@ AActor *COPY_AAPTR(AActor *origin, int selector) return origin->FriendPlayer ? AAPTR_RESOLVE_PLAYERNUM(origin->FriendPlayer - 1) : NULL; case AAPTR_GET_LINETARGET: - { - AActor *gettarget = NULL; - P_BulletSlope(origin, &gettarget); - return gettarget; - } + P_BulletSlope(origin, &t, ALF_PORTALRESTRICT); + return t.linetarget; } } diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 70f36bea9..1e4516b27 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -872,16 +872,16 @@ CCMD (wdir) //----------------------------------------------------------------------------- CCMD(linetarget) { - AActor *linetarget; + FTranslatedLineTarget t; if (CheckCheatmode () || players[consoleplayer].mo == NULL) return; - P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, &linetarget, 0); - if (linetarget) + P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, &t, 0); + if (t.linetarget) { Printf("Target=%s, Health=%d, Spawnhealth=%d\n", - linetarget->GetClass()->TypeName.GetChars(), - linetarget->health, - linetarget->SpawnHealth()); + t.linetarget->GetClass()->TypeName.GetChars(), + t.linetarget->health, + t.linetarget->SpawnHealth()); } else Printf("No target found\n"); } @@ -889,18 +889,18 @@ CCMD(linetarget) // As linetarget, but also give info about non-shootable actors CCMD(info) { - AActor *linetarget; + FTranslatedLineTarget t; if (CheckCheatmode () || players[consoleplayer].mo == NULL) return; P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, - &linetarget, 0, ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART); - if (linetarget) + &t, 0, ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART); + if (t.linetarget) { Printf("Target=%s, Health=%d, Spawnhealth=%d\n", - linetarget->GetClass()->TypeName.GetChars(), - linetarget->health, - linetarget->SpawnHealth()); - PrintMiscActorInfo(linetarget); + t.linetarget->GetClass()->TypeName.GetChars(), + t.linetarget->health, + t.linetarget->SpawnHealth()); + PrintMiscActorInfo(t.linetarget); } else Printf("No target found. Info cannot find actors that have " "the NOBLOCKMAP flag or have height/radius of 0.\n"); diff --git a/src/dobjtype.h b/src/dobjtype.h index 1e982e74b..ba2634f08 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -5,7 +5,6 @@ #error You must #include "dobject.h" to get dobjtype.h #endif -#include "thingdef/thingdef_type.h" #include "vm.h" // Variable/parameter/field flags ------------------------------------------- diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 73fda96b3..08eb018f9 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -33,7 +33,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) angle_t angle; int damage; int pitch; - AActor *linetarget; + FTranslatedLineTarget t; if (self->player != NULL) { @@ -53,15 +53,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) angle = self->angle; angle += pr_punch.Random2() << 18; - pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); + pitch = P_AimLineAttack (self, angle, MELEERANGE); - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &linetarget); + P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &t); // turn to face target - if (linetarget) + if (t.linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = self->AngleTo(linetarget); + self->angle = t.SourceAngleToTarget(); } return 0; } @@ -133,7 +133,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) angle_t angle; angle_t slope; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; int actualdamage; if (NULL == (player = self->player)) @@ -159,18 +159,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) } angle = self->angle + (pr_saw.Random2() * (spread_xy / 255)); - slope = P_AimLineAttack (self, angle, range, &linetarget) + (pr_saw.Random2() * (spread_z / 255)); + slope = P_AimLineAttack (self, angle, range, &t) + (pr_saw.Random2() * (spread_z / 255)); AWeapon *weapon = self->player->ReadyWeapon; - if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON()) + if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &linetarget, &actualdamage); + P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage); - if (!linetarget) + if (!t.linetarget) { if ((flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64)) { @@ -197,7 +197,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) } } - if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN)) + if (lifesteal && !(t.linetarget->flags5 & MF5_DONTDRAIN)) { if (flags & SF_STEALARMOR) { @@ -232,7 +232,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) // turn to face target if (!(flags & SF_NOTURN)) { - angle = self->AngleTo(linetarget); + angle = t.SourceAngleToTarget(); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90 / 20)) @@ -643,7 +643,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) int j; int damage; angle_t an; - AActor *linetarget; + FTranslatedLineTarget t; if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra"); if (numrays <= 0) numrays = 40; @@ -662,18 +662,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) an = self->angle - angle / 2 + angle / numrays*i; // self->target is the originator (player) of the missile - P_AimLineAttack(self->target, an, distance, &linetarget, vrange); + P_AimLineAttack(self->target, an, distance, &t, vrange); - if (linetarget != NULL) + if (t.linetarget != NULL) { - AActor *spray = Spawn(spraytype, linetarget->PosPlusZ(linetarget->height >> 2), ALLOW_REPLACE); + AActor *spray = Spawn(spraytype, t.linetarget->PosPlusZ(t.linetarget->height >> 2), ALLOW_REPLACE); int dmgFlags = 0; FName dmgType = NAME_BFGSplash; if (spray != NULL) { - if (spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == linetarget->GetSpecies()) + if (spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == t.linetarget->GetSpecies()) { spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. continue; @@ -696,8 +696,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) damage = defdamage; } - int newdam = P_DamageMobj(linetarget, self->target, self->target, damage, dmgType, dmgFlags); - P_TraceBleed(newdam > 0 ? newdam : damage, linetarget, self->target); + int newdam = P_DamageMobj(t.linetarget, self->target, self->target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.SourceAngleToTarget()); + P_TraceBleed(newdam > 0 ? newdam : damage, &t, self); } } return 0; diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index 43eec76e1..5051a4b94 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -276,16 +276,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) if (self->CheckMeleeRange ()) { angle_t angle; - AActor *linetarget; + FTranslatedLineTarget t; damage *= (pr_m_saw()%10+1); angle = self->angle + (pr_m_saw.Random2() << 18); P_LineAttack (self, angle, MELEERANGE+1, - P_AimLineAttack (self, angle, MELEERANGE+1, &linetarget), damage, - NAME_Melee, pufftype, false, &linetarget); + P_AimLineAttack (self, angle, MELEERANGE+1), damage, + NAME_Melee, pufftype, false, &t); - if (!linetarget) + if (!t.linetarget) { S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); return 0; @@ -293,7 +293,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); // turn to face target - angle = self->AngleTo(linetarget); + angle = t.SourceAngleToTarget(); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90/20)) @@ -328,7 +328,7 @@ static void MarinePunch(AActor *self, int damagemul) angle_t angle; int damage; int pitch; - AActor *linetarget; + FTranslatedLineTarget t; if (self->target == NULL) return; @@ -337,15 +337,14 @@ static void MarinePunch(AActor *self, int damagemul) A_FaceTarget (self); angle = self->angle + (pr_m_punch.Random2() << 18); - pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &linetarget); + pitch = P_AimLineAttack (self, angle, MELEERANGE); + P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &t); // turn to face target - if (linetarget) + if (t.linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = self->AngleTo(linetarget); - + self->angle = t.SourceAngleToTarget(); } } diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index dcc3e1774..9ebdaf169 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -176,7 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) int damage; int slope; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -185,11 +185,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) damage = 1 + (pr_beakatkpl1()&3); angle = player->mo->angle; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); - if (linetarget) + slope = P_AimLineAttack (player->mo, angle, MELEERANGE); + P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t); + if (t.linetarget) { - player->mo->angle = player->mo->AngleTo(linetarget); + player->mo->angle = t.SourceAngleToTarget(); } P_PlayPeck (player->mo); player->chickenPeck = 12; @@ -211,7 +211,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) int damage; int slope; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -220,11 +220,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) damage = pr_beakatkpl2.HitDice (4); angle = player->mo->angle; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); - if (linetarget) + slope = P_AimLineAttack (player->mo, angle, MELEERANGE); + P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t); + if (t.linetarget) { - player->mo->angle = player->mo->AngleTo(linetarget); + player->mo->angle = t.SourceAngleToTarget(); } P_PlayPeck (player->mo); player->chickenPeck = 12; diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index f51de13e1..4ff89d9d2 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -66,7 +66,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) angle_t angle; int slope; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -88,13 +88,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) } angle = self->angle; angle += pr_sap.Random2() << 18; - slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); - P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true, &linetarget); - if (linetarget) + slope = P_AimLineAttack (self, angle, MELEERANGE); + P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true, &t); + if (t.linetarget) { //S_StartSound(player->mo, sfx_stfhit); // turn to face target - self->angle = self->AngleTo(linetarget); + self->angle = t.SourceAngleToTarget(); } return 0; } @@ -257,7 +257,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) fixed_t dist; player_t *player; PClassActor *pufftype; - AActor *linetarget; + FTranslatedLineTarget t; int actualdamage = 0; if (NULL == (player = self->player)) @@ -290,9 +290,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) angle += pr_gatk.Random2() << 18; pufftype = PClass::FindActor("GauntletPuff1"); } - slope = P_AimLineAttack (self, angle, dist, &linetarget); - P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype, false, &linetarget, &actualdamage); - if (!linetarget) + slope = P_AimLineAttack (self, angle, dist); + P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage); + if (!t.linetarget) { if (pr_gatk() > 64) { @@ -316,7 +316,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) } if (power) { - if (!(linetarget->flags5 & MF5_DONTDRAIN)) P_GiveBody (self, actualdamage>>1); + if (!(t.linetarget->flags5 & MF5_DONTDRAIN)) P_GiveBody (self, actualdamage>>1); S_Sound (self, CHAN_AUTO, "weapons/gauntletspowhit", 1, ATTN_NORM); } else @@ -324,7 +324,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM); } // turn to face target - angle = self->AngleTo(linetarget); + angle = t.SourceAngleToTarget(); if (angle-self->angle > ANG180) { if ((int)(angle-self->angle) < -ANG90/20) @@ -594,7 +594,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) AActor *mo; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -607,16 +607,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->angle, &linetarget); + mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->angle, &t); if (mo) { mo->velx += self->velx; mo->vely += self->vely; mo->velz = 2*FRACUNIT+ clamp(finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)], -5*FRACUNIT, 5*FRACUNIT); - if (linetarget) + if (t.linetarget && !t.unlinked) { - mo->tracer = linetarget; + mo->tracer = t.linetarget; } } S_Sound (self, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM); @@ -637,7 +637,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) AActor *target; angle_t angle = 0; bool newAngle; - AActor *linetarget; + FTranslatedLineTarget t; if ((self->Z() <= self->floorz) && P_HitFloor (self)) { // Landed in some sort of liquid @@ -671,11 +671,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) angle = 0; for (i = 0; i < 16; i++) { - P_AimLineAttack (self, angle, 10*64*FRACUNIT, &linetarget, 0, ALF_NOFRIENDS, NULL, self->target); - if (linetarget && self->target != linetarget) + P_AimLineAttack (self, angle, 10*64*FRACUNIT, &t, 0, ALF_NOFRIENDS|ALF_PORTALRESTRICT, NULL, self->target); + if (t.linetarget && self->target != t.linetarget) { - self->tracer = linetarget; - angle = self->AngleTo(linetarget); + self->tracer = t.linetarget; + angle = t.SourceAngleToTarget(); newAngle = true; break; } @@ -943,7 +943,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) player_t *player; AActor *MissileActor; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -955,16 +955,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->angle, &linetarget, &MissileActor); + P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->angle, &t, &MissileActor); // Use MissileActor instead of the return value from // P_SpawnPlayerMissile because we need to give info to the mobj // even if it exploded immediately. if (MissileActor != NULL) { MissileActor->special2 = (int)(player - players); - if (linetarget) + if (t.linetarget && !t.unlinked) { - MissileActor->tracer = linetarget; + MissileActor->tracer = t.linetarget; } S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM); } diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index c83211585..bfaec55d0 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -151,6 +151,11 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) { // Out of range continue; } + if (mo->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, mo)) + { + // in another region and cannot be seen. + continue; + } BlastActor (mo, strength, speed, self, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE)); } return 0; diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 466c0f7c8..f87c2dd7d 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -213,7 +213,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) PARAM_ACTION_PROLOGUE; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -225,10 +225,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->angle, &linetarget); - if (missile != NULL) + AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->angle, &t); + if (missile != NULL && !t.unlinked) { - missile->tracer = linetarget; + missile->tracer = t.linetarget; } weapon->CHolyCount = 3; diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp index ecd28da4f..05698c086 100644 --- a/src/g_hexen/a_clericmace.cpp +++ b/src/g_hexen/a_clericmace.cpp @@ -5,8 +5,6 @@ #include "thingdef/thingdef.h" */ -extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget); - static FRandom pr_maceatk ("CMaceAttack"); //=========================================================================== @@ -24,7 +22,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) int slope; int i; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -36,26 +34,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) damage = 25+(pr_maceatk()&15); for (i = 0; i < 16; i++) { - angle = player->mo->angle+i*(ANG45/16); - slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); - if (linetarget) + for (int j = 1; j >= -1; j -= 2) { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); - if (linetarget != NULL) + angle = player->mo->angle + j*i*(ANG45 / 16); + slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE, &t); + if (t.linetarget) { - AdjustPlayerAngle (player->mo, linetarget); - goto macedone; - } - } - angle = player->mo->angle-i*(ANG45/16); - slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); - if (linetarget) - { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); - if (linetarget != NULL) - { - AdjustPlayerAngle (player->mo, linetarget); - goto macedone; + P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &t); + if (t.linetarget != NULL) + { + AdjustPlayerAngle(player->mo, &t); + goto macedone; + } } } } @@ -63,7 +53,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) player->mo->weaponspecial = 0; angle = player->mo->angle; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); + slope = P_AimLineAttack (player->mo, angle, MELEERANGE); P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, hammertime); macedone: return 0; diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index 964a78503..2644b29b0 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -55,7 +55,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) int slope; int i; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; PClassActor *puff; if (NULL == (player = self->player)) @@ -70,57 +70,38 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) puff = PClass::FindActor("CStaffPuff"); for (i = 0; i < 3; i++) { - angle = pmo->angle + i*(ANG45 / 16); - slope = P_AimLineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); - if (linetarget) + for (int j = 1; j >= -1; j -= 2) { - P_LineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget); - if (linetarget != NULL) + angle = pmo->angle + j*i*(ANG45 / 16); + slope = P_AimLineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), &t, 0, ALF_CHECK3D); + if (t.linetarget) { - pmo->angle = pmo->AngleTo(linetarget); - if (((linetarget->player && (!linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) - && (!(linetarget->flags2&(MF2_DORMANT | MF2_INVULNERABLE)))) + P_LineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &t); + if (t.linetarget != NULL) { - newLife = player->health + (damage >> 3); - newLife = newLife > max ? max : newLife; - if (newLife > player->health) + pmo->angle = t.SourceAngleToTarget(); + if (((t.linetarget->player && (!t.linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || t.linetarget->flags3&MF3_ISMONSTER) + && (!(t.linetarget->flags2&(MF2_DORMANT | MF2_INVULNERABLE)))) { - pmo->health = player->health = newLife; + newLife = player->health + (damage >> 3); + newLife = newLife > max ? max : newLife; + if (newLife > player->health) + { + pmo->health = player->health = newLife; + } + if (weapon != NULL) + { + FState * newstate = weapon->FindState("Drain"); + if (newstate != NULL) P_SetPsprite(player, ps_weapon, newstate); + } } if (weapon != NULL) { - FState * newstate = weapon->FindState("Drain"); - if (newstate != NULL) P_SetPsprite(player, ps_weapon, newstate); + weapon->DepleteAmmo(weapon->bAltFire, false); } } - if (weapon != NULL) - { - weapon->DepleteAmmo(weapon->bAltFire, false); - } + return 0; } - break; - } - angle = pmo->angle - i*(ANG45 / 16); - slope = P_AimLineAttack(player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); - if (linetarget) - { - P_LineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget); - if (linetarget != NULL) - { - pmo->angle = pmo->AngleTo(linetarget); - if ((linetarget->player && (!linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) - { - newLife = player->health + (damage >> 4); - newLife = newLife > max ? max : newLife; - pmo->health = player->health = newLife; - P_SetPsprite(player, ps_weapon, weapon->FindState("Drain")); - } - if (weapon != NULL) - { - weapon->DepleteAmmo(weapon->bAltFire, false); - } - } - break; } } return 0; diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 575b8d8c1..1681efe9f 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -24,8 +24,6 @@ void A_FAxeCheckReadyG (AActor *actor); void A_FAxeCheckUpG (AActor *actor); void A_FAxeAttack (AActor *actor); -extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget); - // The Fighter's Axe -------------------------------------------------------- class AFWeapAxe : public AFighterWeapon @@ -210,7 +208,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) player_t *player; AWeapon *weapon; PClassActor *pufftype; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -236,36 +234,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) } for (i = 0; i < 16; i++) { - angle = pmo->angle+i*(ANG45/16); - slope = P_AimLineAttack (pmo, angle, AXERANGE, &linetarget); - if (linetarget) + for (int j = 1; j >= -1; j -= 2) { - P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); - if (linetarget != NULL) + angle = pmo->angle + j*i*(ANG45 / 16); + slope = P_AimLineAttack(pmo, angle, AXERANGE, &t); + if (t.linetarget) { - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + P_LineAttack(pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &t); + if (t.linetarget != NULL) { - P_ThrustMobj (linetarget, angle, power); + if (t.linetarget->flags3&MF3_ISMONSTER || t.linetarget->player) + { + P_ThrustMobj(t.linetarget, t.hitangle, power); + } + AdjustPlayerAngle(pmo, &t); + useMana++; + goto axedone; } - AdjustPlayerAngle (pmo, linetarget); - useMana++; - goto axedone; - } - } - angle = pmo->angle-i*(ANG45/16); - slope = P_AimLineAttack (pmo, angle, AXERANGE, &linetarget); - if (linetarget) - { - P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); - if (linetarget != NULL) - { - if (linetarget->flags3&MF3_ISMONSTER) - { - P_ThrustMobj (linetarget, angle, power); - } - AdjustPlayerAngle (pmo, linetarget); - useMana++; - goto axedone; } } } @@ -273,7 +258,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) pmo->weaponspecial = 0; angle = pmo->angle; - slope = P_AimLineAttack (pmo, angle, MELEERANGE, &linetarget); + slope = P_AimLineAttack (pmo, angle, MELEERANGE); P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true); axedone: diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index 2980dec7a..836f6e4b7 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -17,8 +17,6 @@ const fixed_t HAMMER_RANGE = MELEERANGE+MELEERANGE/2; static FRandom pr_hammeratk ("FHammerAtk"); -extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget); - //============================================================================ // // A_FHammerAttack @@ -35,7 +33,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) int slope; int i; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; PClassActor *hammertime; if (NULL == (player = self->player)) @@ -50,32 +48,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) for (i = 0; i < 16; i++) { angle = pmo->angle + i*(ANG45/32); - slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); - if (linetarget != NULL) + slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &t, 0, ALF_CHECK3D); + if (t.linetarget != NULL) { - P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); - if (linetarget != NULL) + P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &t); + if (t.linetarget != NULL) { - AdjustPlayerAngle(pmo, linetarget); - if (linetarget->flags3 & MF3_ISMONSTER || linetarget->player) + AdjustPlayerAngle(pmo, &t); + if (t.linetarget->flags3 & MF3_ISMONSTER || t.linetarget->player) { - P_ThrustMobj(linetarget, angle, power); + P_ThrustMobj(t.linetarget, t.hitangle, power); } pmo->weaponspecial = false; // Don't throw a hammer goto hammerdone; } } angle = pmo->angle-i*(ANG45/32); - slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); - if (linetarget != NULL) + slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &t, 0, ALF_CHECK3D); + if (t.linetarget != NULL) { - P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); - if (linetarget != NULL) + P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &t); + if (t.linetarget != NULL) { - AdjustPlayerAngle(pmo, linetarget); - if (linetarget->flags3 & MF3_ISMONSTER || linetarget->player) + AdjustPlayerAngle(pmo, &t); + if (t.linetarget->flags3 & MF3_ISMONSTER || t.linetarget->player) { - P_ThrustMobj(linetarget, angle, power); + P_ThrustMobj(t.linetarget, t.hitangle, power); } pmo->weaponspecial = false; // Don't throw a hammer goto hammerdone; @@ -84,7 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) } // didn't find any targets in meleerange, so set to throw out a hammer angle = pmo->angle; - slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); + slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, NULL, 0, ALF_CHECK3D); if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL) { pmo->weaponspecial = false; diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 944a4aa45..dfbc43be2 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -25,12 +25,12 @@ static FRandom pr_fpatk ("FPunchAttack"); #define MAX_ANGLE_ADJUST (5*ANGLE_1) -void AdjustPlayerAngle (AActor *pmo, AActor *linetarget) +void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t) { angle_t angle; int difference; - angle = pmo->AngleTo(linetarget); + angle = t->SourceAngleToTarget(); difference = (int)angle - (int)pmo->angle; if (abs(difference) > MAX_ANGLE_ADJUST) { @@ -60,11 +60,11 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget) static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power) { PClassActor *pufftype; - AActor *linetarget; + FTranslatedLineTarget t; int slope; - slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &linetarget); - if (linetarget != NULL) + slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &t); + if (t.linetarget != NULL) { if (++pmo->weaponspecial >= 3) { @@ -76,15 +76,15 @@ static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power) { pufftype = PClass::FindActor("PunchPuff"); } - P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); - if (linetarget != NULL) + P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &t); + if (t.linetarget != NULL) { - if (linetarget->player != NULL || - (linetarget->Mass != INT_MAX && (linetarget->flags3 & MF3_ISMONSTER))) + if (t.linetarget->player != NULL || + (t.linetarget->Mass != INT_MAX && (t.linetarget->flags3 & MF3_ISMONSTER))) { - P_ThrustMobj (linetarget, angle, power); + P_ThrustMobj (t.linetarget, t.hitangle, power); } - AdjustPlayerAngle (pmo, linetarget); + AdjustPlayerAngle (pmo, &t); return true; } } @@ -131,8 +131,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) // didn't find any creatures, so try to strike any walls pmo->weaponspecial = 0; - AActor *linetarget; - int slope = P_AimLineAttack (pmo, pmo->angle, MELEERANGE, &linetarget); + int slope = P_AimLineAttack (pmo, pmo->angle, MELEERANGE); P_LineAttack (pmo, pmo->angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("PunchPuff"), true); return 0; } diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h index ba68a9988..94b03d45d 100644 --- a/src/g_hexen/a_hexenglobal.h +++ b/src/g_hexen/a_hexenglobal.h @@ -3,6 +3,8 @@ #include "d_player.h" +void AdjustPlayerAngle(AActor *pmo, FTranslatedLineTarget *t); + class AHolySpirit : public AActor { DECLARE_CLASS (AHolySpirit, AActor) diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 86addb2cb..302048998 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -350,7 +350,7 @@ void AZBell::Activate (AActor *activator) { if (health > 0) { - P_DamageMobj (this, activator, activator, 10, NAME_Melee); // 'ring' the bell + P_DamageMobj (this, activator, activator, 10, NAME_Melee, DMG_THRUSTLESS); // 'ring' the bell } } diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp index 154c76524..c157c02c0 100644 --- a/src/g_hexen/a_magecone.cpp +++ b/src/g_hexen/a_magecone.cpp @@ -60,7 +60,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) AActor *mo; bool conedone=false; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -79,10 +79,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) for (i = 0; i < 16; i++) { angle = self->angle+i*(ANG45/16); - slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget, 0, ALF_CHECK3D); - if (linetarget) + slope = P_AimLineAttack (self, angle, MELEERANGE, &t, 0, ALF_CHECK3D); + if (t.linetarget) { - P_DamageMobj (linetarget, self, self, damage, NAME_Ice); + P_DamageMobj (t.linetarget, self, self, damage, NAME_Ice, DMG_USEANGLE, t.SourceAngleToTarget()); conedone = true; break; } diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index d1ca7e75c..832ae96d1 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -97,17 +97,20 @@ bool AMageStaffFX2::SpecialBlastHandling (AActor *source, fixed_t strength) // //============================================================================ -void MStaffSpawn (AActor *pmo, angle_t angle) +void MStaffSpawn (AActor *pmo, angle_t angle, AActor *alttarget) { AActor *mo; - AActor *linetarget; + FTranslatedLineTarget t; mo = P_SpawnPlayerMissile (pmo, 0, 0, 8*FRACUNIT, - RUNTIME_CLASS(AMageStaffFX2), angle, &linetarget); + RUNTIME_CLASS(AMageStaffFX2), angle, &t); if (mo) { mo->target = pmo; - mo->tracer = linetarget; + if (t.linetarget && !t.unlinked) + mo->tracer = t.linetarget; + else + mo->tracer = alttarget; } } @@ -123,7 +126,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) angle_t angle; player_t *player; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -139,18 +142,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) angle = self->angle; // [RH] Let's try and actually track what the player aimed at - P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &linetarget, ANGLE_1*32); - if (linetarget == NULL) + P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &t, ANGLE_1*32); + if (t.linetarget == NULL) { BlockCheckLine.x = self->X(); BlockCheckLine.y = self->Y(); BlockCheckLine.dx = -finesine[angle >> ANGLETOFINESHIFT]; BlockCheckLine.dy = -finecosine[angle >> ANGLETOFINESHIFT]; - linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck); + t.linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck); } - MStaffSpawn (self, angle); - MStaffSpawn (self, angle-ANGLE_1*5); - MStaffSpawn (self, angle+ANGLE_1*5); + MStaffSpawn (self, angle, t.linetarget); + MStaffSpawn (self, angle-ANGLE_1*5, t.linetarget); + MStaffSpawn (self, angle+ANGLE_1*5, t.linetarget); S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); weapon->MStaffCount = 3; return 0; diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp index 8ce394a28..b07bfc4a0 100644 --- a/src/g_hexen/a_pig.cpp +++ b/src/g_hexen/a_pig.cpp @@ -18,8 +18,6 @@ static FRandom pr_snoutattack ("SnoutAttack"); static FRandom pr_pigattack ("PigAttack"); static FRandom pr_pigplayerthink ("PigPlayerThink"); -extern void AdjustPlayerAngle (AActor *, AActor *); - // Pig player --------------------------------------------------------------- class APigPlayer : public APlayerPawn @@ -67,7 +65,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) int slope; player_t *player; AActor *puff; - AActor *linetarget; + FTranslatedLineTarget t; if (NULL == (player = self->player)) { @@ -76,12 +74,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) damage = 3+(pr_snoutattack()&3); angle = player->mo->angle; - slope = P_AimLineAttack(player->mo, angle, MELEERANGE, &linetarget); - puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &linetarget); + slope = P_AimLineAttack(player->mo, angle, MELEERANGE); + puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &t); S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM); - if(linetarget) + if(t.linetarget) { - AdjustPlayerAngle(player->mo, linetarget); + AdjustPlayerAngle(player->mo, &t); if(puff != NULL) { // Bit something S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM); diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index f1538d3d9..4af4e2d54 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -154,6 +154,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) PARAM_ACTION_PROLOGUE; AActor *thing; + // This doesn't need to iterate through portals. FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius)); while ((thing = it.Next())) { diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 561f52746..60e86a34b 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -100,7 +100,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) int damage; int pitch; int power; - AActor *linetarget; + FTranslatedLineTarget t; power = MIN(10, self->player->mo->stamina / 10); damage = (pr_jabdagger() % (power + 8)) * (power + 2); @@ -111,18 +111,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) } angle = self->angle + (pr_jabdagger.Random2() << 18); - pitch = P_AimLineAttack (self, angle, 80*FRACUNIT, &linetarget); - P_LineAttack (self, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, "StrifeSpark", true, &linetarget); + pitch = P_AimLineAttack (self, angle, 80*FRACUNIT); + P_LineAttack (self, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, "StrifeSpark", true, &t); // turn to face target - if (linetarget) + if (t.linetarget) { S_Sound (self, CHAN_WEAPON, - linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit", + t.linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit", 1, ATTN_NORM); - self->angle = self->AngleTo(linetarget); + self->angle = t.SourceAngleToTarget(); self->flags |= MF_JUSTATTACKED; - P_DaggerAlert (self, linetarget); + P_DaggerAlert (self, t.linetarget); } else { @@ -978,7 +978,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) AActor *spot; player_t *player = self->player; - AActor *linetarget; + FTranslatedLineTarget t; if (player == NULL || player->ReadyWeapon == NULL) return 0; @@ -986,13 +986,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) P_DamageMobj (self, self, NULL, 1*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - P_BulletSlope (self, &linetarget); - if (linetarget != NULL) + P_BulletSlope (self, &t, ALF_PORTALRESTRICT); + if (t.linetarget != NULL) { - spot = Spawn("SpectralLightningSpot", linetarget->X(), linetarget->Y(), linetarget->floorz, ALLOW_REPLACE); + spot = Spawn("SpectralLightningSpot", t.linetarget->X(), t.linetarget->Y(), t.linetarget->floorz, ALLOW_REPLACE); if (spot != NULL) { - spot->tracer = linetarget; + spot->tracer = t.linetarget; } } else @@ -1080,7 +1080,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) AActor *spot; player_t *player = self->player; - AActor *linetarget; + FTranslatedLineTarget t; if (player == NULL || player->ReadyWeapon == NULL) return 0; @@ -1088,13 +1088,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) P_DamageMobj (self, self, NULL, 4*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - P_BulletSlope (self, &linetarget); - if (linetarget != NULL) + P_BulletSlope (self, &t, ALF_PORTALRESTRICT); + if (t.linetarget != NULL) { - spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->angle, &linetarget); + spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->angle, &t, NULL, false, false, ALF_PORTALRESTRICT); if (spot != NULL) { - spot->tracer = linetarget; + spot->tracer = t.linetarget; } } else diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 04c10760e..ebd002b4e 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -60,6 +60,7 @@ static FListMenuDescriptor DefaultListMenuSettings; // contains common settings static FOptionMenuDescriptor DefaultOptionMenuSettings; // contains common settings for all Option menus FOptionMenuSettings OptionSettings; FOptionMap OptionValues; +bool mustPrintErrors; void I_BuildALDeviceList(FOptionValues *opt); @@ -99,7 +100,7 @@ static FTextureID GetMenuTexture(const char* const name) { const FTextureID texture = TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch); - if (!texture.Exists()) + if (!texture.Exists() && mustPrintErrors) { Printf("Missing menu texture: \"%s\"\n", name); } @@ -956,10 +957,14 @@ void M_ParseMenuDefs() atterm( DeinitMenus); DeinitMenus(); + + int IWADMenu = Wads.CheckNumForName("MENUDEF", ns_global, FWadCollection::IWAD_FILENUM); + while ((lump = Wads.FindLump ("MENUDEF", &lastlump)) != -1) { FScanner sc(lump); + mustPrintErrors = lump >= IWADMenu; sc.SetCMode(true); while (sc.GetString()) { diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 52e11ee8b..b6a718f65 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4939,7 +4939,9 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) { if (actor->player != NULL && actor->player->playerstate == PST_LIVE) { - P_BulletSlope(actor, &actor); + FTranslatedLineTarget t; + P_BulletSlope(actor, &t, ALF_PORTALRESTRICT); + actor = t.linetarget; } else { diff --git a/src/p_effect.cpp b/src/p_effect.cpp index ffd1f303c..0b4fe0e55 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -205,9 +205,9 @@ void P_FindParticleSubsectors () } for (WORD i = ActiveParticles; i != NO_PARTICLE; i = Particles[i].tnext) { - subsector_t *ssec = R_PointInSubsector (Particles[i].x, Particles[i].y); - int ssnum = int(ssec-subsectors); - Particles[i].subsector = ssec; + // Try to reuse the subsector from the last portal check, if still valid. + if (Particles[i].subsector == NULL) Particles[i].subsector = R_PointInSubsector(Particles[i].x, Particles[i].y); + int ssnum = int(Particles[i].subsector - subsectors); Particles[i].snext = ParticlesInSubsec[ssnum]; ParticlesInSubsec[ssnum] = i; } @@ -278,12 +278,37 @@ void P_ThinkParticles () InactiveParticles = (int)(particle - Particles); continue; } - particle->x += particle->velx; - particle->y += particle->vely; + + fixedvec2 newxy = P_GetOffsetPosition(particle->x, particle->y, particle->velx, particle->vely); + particle->x = newxy.x; + particle->y = newxy.y; + //particle->x += particle->velx; + //particle->y += particle->vely; particle->z += particle->velz; particle->velx += particle->accx; particle->vely += particle->accy; particle->velz += particle->accz; + particle->subsector = R_PointInSubsector(particle->x, particle->y); + if (!particle->subsector->sector->PortalBlocksMovement(sector_t::ceiling)) + { + AActor *skybox = particle->subsector->sector->SkyBoxes[sector_t::ceiling]; + if (particle->z > skybox->threshold) + { + particle->x += skybox->scaleX; + particle->y += skybox->scaleY; + particle->subsector = NULL; + } + } + else if (!particle->subsector->sector->PortalBlocksMovement(sector_t::floor)) + { + AActor *skybox = particle->subsector->sector->SkyBoxes[sector_t::floor]; + if (particle->z < skybox->threshold) + { + particle->x += skybox->scaleX; + particle->y += skybox->scaleY; + particle->subsector = NULL; + } + } prev = particle; } } diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index ed9abdcb9..af4a9042d 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -150,9 +150,40 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun } } + bool checkabove = !sec->PortalBlocksSound(sector_t::ceiling); + bool checkbelow = !sec->PortalBlocksSound(sector_t::floor); + for (i = 0; i < sec->linecount; i++) { check = sec->lines[i]; + + // I wish there was a better method to do this than randomly looking through the portal at a few places... + if (checkabove) + { + sector_t *upper = + P_PointInSector(check->v1->x + check->dx / 2 + sec->SkyBoxes[sector_t::ceiling]->scaleX, + check->v1->y + check->dy / 2 + sec->SkyBoxes[sector_t::ceiling]->scaleY); + + P_RecursiveSound(upper, soundtarget, splash, soundblocks, emitter, maxdist); + } + if (checkbelow) + { + sector_t *lower = + P_PointInSector(check->v1->x + check->dx / 2 + sec->SkyBoxes[sector_t::floor]->scaleX, + check->v1->y + check->dy / 2 + sec->SkyBoxes[sector_t::floor]->scaleY); + + P_RecursiveSound(lower, soundtarget, splash, soundblocks, emitter, maxdist); + } + FLinePortal *port = check->getPortal(); + if (port && (port->mFlags & PORTF_SOUNDTRAVERSE)) + { + if (port->mDestination) + { + P_RecursiveSound(port->mDestination->frontsector, soundtarget, splash, soundblocks, emitter, maxdist); + } + } + + if (check->sidedef[1] == NULL || !(check->flags & ML_TWOSIDED)) { @@ -394,16 +425,16 @@ bool AActor::SuggestMissileAttack (fixed_t dist) bool P_HitFriend(AActor * self) { - AActor *linetarget; + FTranslatedLineTarget t; if (self->flags&MF_FRIENDLY && self->target != NULL) { angle_t angle = self->AngleTo(self->target); fixed_t dist = self->AproxDistance (self->target); - P_AimLineAttack (self, angle, dist, &linetarget, 0, true); - if (linetarget != NULL && linetarget != self->target) + P_AimLineAttack (self, angle, dist, &t, 0, true); + if (t.linetarget != NULL && t.linetarget != self->target) { - return self->IsFriend (linetarget); + return self->IsFriend (t.linetarget); } } return false; @@ -2573,40 +2604,48 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) fixedvec2 viletry = self->Vec2Offset( FixedMul (absSpeed, xspeed[self->movedir]), FixedMul (absSpeed, yspeed[self->movedir]), true); - AActor *corpsehit; - FBlockThingsIterator it(FBoundingBox(viletry.x, viletry.y, 32*FRACUNIT)); - while ((corpsehit = it.Next())) + FPortalGroupArray check(FPortalGroupArray::PGA_Full3d); + + FMultiBlockThingsIterator it(check, viletry.x, viletry.y, self->Z() - 64* FRACUNIT, self->Top() + 64 * FRACUNIT, 32 * FRACUNIT); + FMultiBlockThingsIterator::CheckResult cres; + while (it.Next(&cres)) { + AActor *corpsehit = cres.thing; FState *raisestate = corpsehit->GetRaiseState(); if (raisestate != NULL) { // use the current actor's radius instead of the Arch Vile's default. fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; - if (abs(corpsehit->X() - viletry.x) > maxdist || - abs(corpsehit->Y() - viletry.y) > maxdist) + if (abs(cres.position.x - viletry.x) > maxdist || + abs(cres.position.y - viletry.y) > maxdist) continue; // not actually touching // Let's check if there are floors in between the archvile and its target - // if in a different section of the map, only consider possible if a line of sight exists. - if (corpsehit->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, corpsehit)) - continue; - - sector_t *vilesec = self->Sector; - sector_t *corpsec = corpsehit->Sector; - // We only need to test if at least one of the sectors has a 3D floor. - sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec : - (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL; - if (testsec) + if (corpsehit->Sector->PortalGroup != self->Sector->PortalGroup) { - fixed_t zdist1, zdist2; - if (P_Find3DFloor(testsec, corpsehit->Pos(), false, true, zdist1) - != P_Find3DFloor(testsec, self->Pos(), false, true, zdist2)) + // if in a different section of the map, only consider possible if a line of sight exists. + if (!P_CheckSight(self, corpsehit)) + continue; + } + else + { + sector_t *vilesec = self->Sector; + sector_t *corpsec = corpsehit->Sector; + // We only need to test if at least one of the sectors has a 3D floor. + sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec : + (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL; + if (testsec) { - // Not on same floor - if (vilesec == corpsec || abs(zdist1 - self->Z()) > self->height) - continue; + fixed_t zdist1, zdist2; + if (P_Find3DFloor(testsec, corpsehit->Pos(), false, true, zdist1) + != P_Find3DFloor(testsec, self->Pos(), false, true, zdist2)) + { + // Not on same floor + if (vilesec == corpsec || abs(zdist1 - self->Z()) > self->height) + continue; + } } } @@ -2951,7 +2990,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) return 0; fixed_t saved_pitch = self->pitch; - AActor *linetarget; + FTranslatedLineTarget t; // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) @@ -2963,8 +3002,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) self->angle = self->AngleTo(self->target); - self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target); - if (linetarget == NULL) + self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &t, ANGLE_1*60, 0, self->target); + if (t.linetarget == NULL) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. fixedvec2 pos = self->Vec2To(self->target); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 98d08832e..313531425 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -927,7 +927,7 @@ static inline bool isFakePain(AActor *target, AActor *inflictor, int damage) // Returns the amount of damage actually inflicted upon the target, or -1 if // the damage was cancelled. -int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags) +int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, angle_t angle) { unsigned ang; player_t *player = NULL; @@ -1151,11 +1151,15 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, { AActor *origin = (source && (flags & DMG_INFLICTOR_IS_PUFF))? source : inflictor; - // If the origin and target are in exactly the same spot, choose a random direction. - // (Most likely cause is from telefragging somebody during spawning because they - // haven't moved from their spawn spot at all.) - if (origin->X() == target->X() && origin->Y() == target->Y()) + if (flags & DMG_USEANGLE) { + ang = angle; + } + else if (origin->X() == target->X() && origin->Y() == target->Y()) + { + // If the origin and target are in exactly the same spot, choose a random direction. + // (Most likely cause is from telefragging somebody during spawning because they + // haven't moved from their spawn spot at all.) ang = pr_kickbackdir.GenRand32(); } else diff --git a/src/p_local.h b/src/p_local.h index 7e11010c5..75ee1e695 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -37,6 +37,7 @@ struct sector_t; struct msecnode_t; struct secplane_t; struct FCheckPosition; +struct FTranslatedLineTarget; #include @@ -173,7 +174,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassAct AActor *P_SpawnPlayerMissile (AActor* source, PClassActor *type); AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle); AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, PClassActor *type, angle_t angle, - AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false); + FTranslatedLineTarget *pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); @@ -304,7 +305,7 @@ void P_FindFloorCeiling (AActor *actor, int flags=0); bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); -fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL); +fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, FTranslatedLineTarget *pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL); enum // P_AimLineAttack flags { @@ -313,6 +314,7 @@ enum // P_AimLineAttack flags ALF_CHECKNONSHOOTABLE = 4, ALF_CHECKCONVERSATION = 8, ALF_NOFRIENDS = 16, + ALF_PORTALRESTRICT = 32, // only work through portals with a global offset (to be used for stuff that cannot remember the calculated FTranslatedLineTarget info) }; enum // P_LineAttack flags @@ -322,11 +324,12 @@ enum // P_LineAttack flags LAF_NOIMPACTDECAL = 4 }; -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version +void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff); // hitscan version void P_TraceBleed (int damage, AActor *target); // random direction version bool P_HitFloor (AActor *thing); bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false); @@ -382,7 +385,7 @@ extern BYTE* rejectmatrix; // for fast sight rejection // P_INTER // void P_TouchSpecialThing (AActor *special, AActor *toucher); -int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); +int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0, angle_t angle = 0); void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type); bool P_GiveBody (AActor *actor, int num, int max=0); bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); @@ -399,6 +402,7 @@ enum EDmgFlags DMG_FOILINVUL = 64, DMG_FOILBUDDHA = 128, DMG_NO_PROTECT = 256, + DMG_USEANGLE = 512, }; diff --git a/src/p_map.cpp b/src/p_map.cpp index 7908ce4a9..150348fc3 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -162,11 +162,22 @@ static inline fixed_t GetCoefficientClosestPointInLine24(line_t *ld, fixedvec2 p static inline fixedvec2 FindRefPoint(line_t *ld, fixedvec2 pos) { - if (!((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) | - (ld->backsector->floorplane.a | ld->backsector->floorplane.b) | - (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | - (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0) - && ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0)) + // If there's any chance of slopes getting in the way we need to get a proper refpoint, otherwise we can save the work. + // Slopes can get in here when: + // - the actual sector planes are sloped + // - there's 3D floors in this sector + // - there's a crossable floor portal (for which the dropoff needs to be calculated within P_LineOpening, and the lower sector can easily have slopes) + if ( + (((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) | + (ld->backsector->floorplane.a | ld->backsector->floorplane.b) | + (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | + (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) != 0) + || + ld->backsector->e->XFloor.ffloors.Size() != 0 + || + ld->frontsector->e->XFloor.ffloors.Size() != 0 + || + !ld->frontsector->PortalBlocksMovement(sector_t::floor)) { fixed_t r = GetCoefficientClosestPointInLine24(ld, pos); if (r <= 0) @@ -809,8 +820,8 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec if (!ld->backsector) { // One sided line - // Needed for polyobject portals. Having two-sided lines just for portals on otherwise solid polyobjects is a messy subject. - if ((cres.line->sidedef[0]->Flags & WALLF_POLYOBJ) && cres.line->isLinePortal()) + // Needed for polyobject portals. + if (cres.line->isLinePortal()) { spechit_t spec; spec.line = ld; @@ -921,7 +932,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec // If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking // This is to avoid bumpy movement when crossing a linedef with the same slope on both sides. - if (open.frontfloorplane == open.backfloorplane) + if (open.frontfloorplane == open.backfloorplane && open.bottom > FIXED_MIN) { open.bottom = open.frontfloorplane.ZatPoint(cres.position.x, cres.position.y); } @@ -972,7 +983,9 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec } if (open.lowfloor < tm.dropoffz) + { tm.dropoffz = open.lowfloor; + } } // if contacted a special line, add it to the list @@ -3774,7 +3787,7 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en // //============================================================================ -fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget, fixed_t vrange, +fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, FTranslatedLineTarget *pLineTarget, fixed_t vrange, int flags, AActor *target, AActor *friender) { fixed_t x2; @@ -3868,7 +3881,18 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pL } if (pLineTarget) { - *pLineTarget = aim.linetarget; + if (aim.linetarget) + { + pLineTarget->linetarget = aim.linetarget; + pLineTarget->hitangle = angle; + pLineTarget->targetPosFromSrc = aim.linetarget->Pos(); + pLineTarget->targetAngleFromSrc = aim.linetarget->angle; + pLineTarget->sourcePosFromTarget = t1->Pos(); + pLineTarget->sourceAngleFromTarget = t1->angle; + pLineTarget->unlinked = false; + } + else + memset(pLineTarget, 0, sizeof(*pLineTarget)); } return aim.linetarget ? aim.aimpitch : t1->pitch; } @@ -3923,7 +3947,7 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata) //========================================================================== AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, - int pitch, int damage, FName damageType, PClassActor *pufftype, int flags, AActor **victim, int *actualdamage) + int pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage) { fixed_t vx, vy, vz, shootz; FTraceResults trace; @@ -3940,7 +3964,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, if (victim != NULL) { - *victim = NULL; + memset(victim, 0, sizeof(*victim)); } if (actualdamage != NULL) { @@ -4123,6 +4147,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING | PF_TEMPORARY); killPuff = true; } +#pragma message("damage angle") newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags); if (actualdamage != NULL) { @@ -4162,7 +4187,13 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, } if (victim != NULL) { - *victim = trace.Actor; + victim->linetarget = trace.Actor; + victim->hitangle = angle; + victim->targetPosFromSrc = trace.Actor->Pos(); + victim->targetAngleFromSrc = trace.Actor->angle; + victim->sourcePosFromTarget = t1->Pos(); + victim->sourceAngleFromTarget = t1->angle; + victim->unlinked = false; } } if (trace.Crossed3DWater || trace.CrossedWater) @@ -4185,22 +4216,22 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, } AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, - int pitch, int damage, FName damageType, FName pufftype, int flags, AActor **victim, int *actualdamage) + int pitch, int damage, FName damageType, FName pufftype, int flags, FTranslatedLineTarget *victim, int *actualdamage) { PClassActor *type = PClass::FindActor(pufftype); - if (victim != NULL) - { - *victim = NULL; - } if (type == NULL) { + if (victim != NULL) + { + memset(victim, 0, sizeof(*victim)); + } Printf("Attempt to spawn unknown actor type '%s'\n", pufftype.GetChars()); + return NULL; } else { return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, flags, victim, actualdamage); } - return NULL; } //========================================================================== @@ -4382,6 +4413,24 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile) // //========================================================================== +void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff) +{ + if (t->linetarget == NULL || puff->flags3 & MF3_BLOODLESSIMPACT) + { + return; + } + + fixed_t randpitch = (pr_tracebleed() - 128) << 16; + P_TraceBleed(damage, t->linetarget->X(), t->linetarget->Y(), t->linetarget->Z() + t->linetarget->height / 2, + t->linetarget, t->SourceAngleToTarget(), 0); +} + +//========================================================================== +// +// +// +//========================================================================== + void P_TraceBleed(int damage, AActor *target) { if (target != NULL) @@ -4560,6 +4609,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL; if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA; } +#pragma message("damage angle") int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass); if (bleed) @@ -4677,38 +4727,26 @@ void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &Camera bool P_TalkFacing(AActor *player) { - AActor *linetarget; + static const int angleofs[] = { 0, ANGLE_90 >> 4, - ANGLE_90 >> 4 }; + FTranslatedLineTarget t; - P_AimLineAttack(player, player->angle, TALKRANGE, &linetarget, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION); - if (linetarget == NULL) + for (int angle : angleofs) { - P_AimLineAttack(player, player->angle + (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION); - if (linetarget == NULL) + P_AimLineAttack(player, player->angle + angle, TALKRANGE, &t, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION | ALF_PORTALRESTRICT); + if (t.linetarget != NULL) { - P_AimLineAttack(player, player->angle - (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION); - if (linetarget == NULL) + if (t.linetarget->health > 0 && // Dead things can't talk. + t.linetarget->flags4 & MF4_INCOMBAT && // Fighting things don't talk either. + t.linetarget->Conversation != NULL) { - return false; + // Give the NPC a chance to play a brief animation + t.linetarget->ConversationAnimation(0); + P_StartConversation(t.linetarget, player, true, true); + return true; } + return false; } } - // Dead things can't talk. - if (linetarget->health <= 0) - { - return false; - } - // Fighting things don't talk either. - if (linetarget->flags4 & MF4_INCOMBAT) - { - return false; - } - if (linetarget->Conversation != NULL) - { - // Give the NPC a chance to play a brief animation - linetarget->ConversationAnimation(0); - P_StartConversation(linetarget, player, true, true); - return true; - } return false; } @@ -4718,10 +4756,11 @@ bool P_TalkFacing(AActor *player) // //========================================================================== -bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline) +bool P_UseTraverse(AActor *usething, fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, bool &foundline) { - FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES | PT_ADDTHINGS); + FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES | PT_ADDTHINGS); intercept_t *in; + fixedvec3 xpos = { startx, starty, usething->Z() }; while ((in = it.Next())) { @@ -4741,6 +4780,10 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline } continue; } + if (it.PortalRelocate(in, PT_ADDLINES | PT_ADDTHINGS, &xpos)) + { + continue; + } FLineOpening open; if (in->d.line->special == 0 || !(in->d.line->activation & (SPAC_Use | SPAC_UseThrough | SPAC_UseBack))) @@ -4769,7 +4812,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline return true; } - sec = P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 0 ? + sec = P_PointOnLineSide(xpos.x, xpos.y, in->d.line) == 0 ? in->d.line->frontsector : in->d.line->backsector; if (sec != NULL && sec->SecActTarget && @@ -4788,7 +4831,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline continue; // not a special line, but keep checking } - if (P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 1) + if (P_PointOnLineSide(xpos.x, xpos.y, in->d.line) == 1) { if (!(in->d.line->activation & SPAC_UseBack)) { @@ -4798,7 +4841,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline } else { - P_ActivateLine(in->d.line, usething, 1, SPAC_UseBack); + P_ActivateLine(in->d.line, usething, 1, SPAC_UseBack, &xpos); return true; } } @@ -4809,7 +4852,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline goto blocked; // Line cannot be used from front side so treat it as a non-trigger line } - P_ActivateLine(in->d.line, usething, 0, SPAC_Use); + P_ActivateLine(in->d.line, usething, 0, SPAC_Use, &xpos); //WAS can't use more than one special line in a row //jff 3/21/98 NOW multiple use allowed with enabling line flag @@ -4846,9 +4889,9 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline // //========================================================================== -bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy) +bool P_NoWayTraverse(AActor *usething, fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy) { - FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES); + FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES); intercept_t *in; while ((in = it.Next())) @@ -4859,6 +4902,7 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy) // [GrafZahl] de-obfuscated. Was I the only one who was unable to make sense out of // this convoluted mess? if (ld->special) continue; + if (ld->isLinePortal()) return false; if (ld->flags&(ML_BLOCKING | ML_BLOCKEVERYTHING | ML_BLOCK_PLAYERS)) return true; P_LineOpening(open, NULL, ld, it.Trace().x + FixedMul(it.Trace().dx, in->frac), it.Trace().y + FixedMul(it.Trace().dy, in->frac)); @@ -4877,12 +4921,16 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy) // //========================================================================== +CVAR(Int, userange, 0, 0); + void P_UseLines(player_t *player) { bool foundline = false; + // If the player is transitioning a portal, use the group that is at its vertical center. + fixedvec2 start = player->mo->GetPortalTransition(player->mo->height / 2); // [NS] Now queries the Player's UseRange. - fixedvec2 end = player->mo->Vec2Angle(player->mo->UseRange, player->mo->angle, true); + fixedvec2 end = start + Vec2Angle(userange > 0? fixed_t(userange<mo->UseRange, player->mo->angle); // old code: // @@ -4890,13 +4938,13 @@ void P_UseLines(player_t *player) // // This added test makes the "oof" sound work on 2s lines -- killough: - if (!P_UseTraverse(player->mo, end.x, end.y, foundline)) + if (!P_UseTraverse(player->mo, start.x, start.y, end.x, end.y, foundline)) { // [RH] Give sector a chance to eat the use sector_t *sec = player->mo->Sector; int spac = SECSPAC_Use; if (foundline) spac |= SECSPAC_UseWall; if ((!sec->SecActTarget || !sec->SecActTarget->TriggerAction(player->mo, spac)) && - P_NoWayTraverse(player->mo, end.x, end.y)) + P_NoWayTraverse(player->mo, start.x, start.y, end.x, end.y)) { S_Sound(player->mo, CHAN_VOICE, "*usefail", 1, ATTN_IDLE); } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 057c4329c..c84d6d5e2 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -150,7 +150,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, if (!(flags & FFCF_ONLY3DFLOORS)) { sector_t *front, *back; - fixed_t fc, ff, bc, bf; + fixed_t fc = 0, ff = 0, bc = 0, bf = 0; if (linedef->backsector == NULL) { @@ -162,29 +162,20 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, front = linedef->frontsector; back = linedef->backsector; - if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::ceiling) && - linedef->backsector->SkyBoxes[sector_t::ceiling] && - linedef->frontsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup) + if (!(flags & FFCF_NOPORTALS)) { - fc = bc = FIXED_MAX; - } - else - { - fc = front->ceilingplane.ZatPoint(x, y); - bc = back->ceilingplane.ZatPoint(x, y); - } - if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::floor) && - linedef->backsector->SkyBoxes[sector_t::floor] && - linedef->frontsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup) - { - ff = bf = FIXED_MIN; - } - else - { - ff = front->floorplane.ZatPoint(x, y); - bf = back->floorplane.ZatPoint(x, y); + if (!linedef->frontsector->PortalBlocksMovement(sector_t::ceiling)) fc = FIXED_MAX; + if (!linedef->backsector->PortalBlocksMovement(sector_t::ceiling)) bc = FIXED_MAX; + if (!linedef->frontsector->PortalBlocksMovement(sector_t::floor)) ff = FIXED_MIN; + if (!linedef->backsector->PortalBlocksMovement(sector_t::floor)) bf = FIXED_MIN; } + if (fc == 0) fc = front->ceilingplane.ZatPoint(x, y); + if (bc == 0) bc = back->ceilingplane.ZatPoint(x, y); + if (ff == 0) ff = front->floorplane.ZatPoint(x, y); + if (bf == 0) bf = back->floorplane.ZatPoint(x, y); + + /*Printf ("]]]]]] %d %d\n", ff, bf);*/ open.topsec = fc < bc? front : back; @@ -198,8 +189,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, // that imprecisions in the plane equation mean there is a // good chance that even if a slope and non-slope look like // they line up, they won't be perfectly aligned. - if (refx == FIXED_MIN || - abs (ff-bf) > 256) + if (ff == FIXED_MIN || bf == FIXED_MIN || (refx == FIXED_MIN || abs (ff-bf) > 256)) { usefront = (ff > bf); } @@ -219,7 +209,13 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.bottomsec = front; open.floorpic = front->GetTexture(sector_t::floor); open.floorterrain = front->GetTerrain(sector_t::floor); - open.lowfloor = bf; + if (bf != FIXED_MIN) open.lowfloor = bf; + else + { + // We must check through the portal for the actual dropoff. + // If there's no lines in the lower sections we'd never get a usable value otherwise. + open.lowfloor = back->NextLowestFloorAt(refx, refy, back->SkyBoxes[sector_t::floor]->threshold-1); + } } else { @@ -227,7 +223,13 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.bottomsec = back; open.floorpic = back->GetTexture(sector_t::floor); open.floorterrain = back->GetTerrain(sector_t::floor); - open.lowfloor = ff; + if (ff != FIXED_MIN) open.lowfloor = ff; + else + { + // We must check through the portal for the actual dropoff. + // If there's no lines in the lower sections we'd never get a usable value otherwise. + open.lowfloor = front->NextLowestFloorAt(refx, refy, front->SkyBoxes[sector_t::floor]->threshold - 1); + } } open.frontfloorplane = front->floorplane; open.backfloorplane = back->floorplane; @@ -1201,7 +1203,7 @@ void FPathTraverse::AddLineIntercepts(int bx, int by) P_MakeDivline (ld, &dl); frac = P_InterceptVector (&trace, &dl); - if (frac < 0 || frac > FRACUNIT) continue; // behind source or beyond end point + if (frac < startfrac || frac > FRACUNIT) continue; // behind source or beyond end point intercept_t newintercept; @@ -1282,7 +1284,7 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it { // It's a hit fixed_t frac = P_InterceptVector (&trace, &line); - if (frac < 0) + if (frac < startfrac) { // behind source continue; } @@ -1350,7 +1352,7 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it frac = P_InterceptVector (&trace, &dl); - if (frac >= 0) + if (frac >= startfrac) { intercept_t newintercept; newintercept.frac = frac; @@ -1398,7 +1400,7 @@ intercept_t *FPathTraverse::Next() // //=========================================================================== -void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags) +void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, fixed_t startfrac) { fixed_t xt1, xt2; fixed_t yt1, yt2; @@ -1422,6 +1424,7 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl validcount++; intercept_index = intercepts.Size(); + this->startfrac = startfrac; if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) x1 += FRACUNIT; // don't side exactly on a line @@ -1442,8 +1445,8 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl trace.dy = y2 - y1; } - _x1 = (long long)x1 - bmaporgx; - _y1 = (long long)y1 - bmaporgy; + _x1 = (long long)x1 + FixedMul(trace.dx, startfrac) - bmaporgx; + _y1 = (long long)y1 + FixedMul(trace.dy, startfrac) - bmaporgy; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = int(_x1 >> MAPBLOCKSHIFT); @@ -1606,6 +1609,41 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl } } +//=========================================================================== +// +// Relocates the trace when going through a line portal +// +//=========================================================================== + +bool FPathTraverse::PortalRelocate(intercept_t *in, int flags, fixedvec3 *optpos) +{ + if (!in->isaline || !in->d.line->isLinePortal()) return false; + if (P_PointOnLineSidePrecise(trace.x, trace.y, in->d.line) == 1) return false; + + fixed_t hitx = trace.x; + fixed_t hity = trace.y; + fixed_t endx = trace.x + trace.dx; + fixed_t endy = trace.y + trace.dy; + line_t *out = in->d.line->getPortalDestination(); + + P_TranslatePortalXY(in->d.line, out, hitx, hity); + P_TranslatePortalXY(in->d.line, out, endx, endy); + if (optpos != NULL) + { + P_TranslatePortalXY(in->d.line, out, optpos->x, optpos->y); + P_TranslatePortalZ(in->d.line, out, optpos->z); + } + intercepts.Resize(intercept_index); + init(hitx, hity, endx, endy, flags, in->frac); + return true; +} + +//=========================================================================== +// +// +// +//=========================================================================== + FPathTraverse::~FPathTraverse() { intercepts.Resize(intercept_index); diff --git a/src/p_maputl.h b/src/p_maputl.h index 838c4e775..b4155995f 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -129,6 +129,14 @@ struct polyblock_t; struct FPortalGroupArray { + // Controls how groups are connected + enum + { + PGA_NoSectorPortals,// only collect line portals + PGA_CheckPosition, // only collects sector portals at the actual position + PGA_Full3d, // Goes up and down sector portals at any linedef within the bounding box (this is a lot slower and should only be done if really needed.) + }; + enum { LOWER = 0x4000, @@ -141,8 +149,9 @@ struct FPortalGroupArray MAX_STATIC = 4 }; - FPortalGroupArray() + FPortalGroupArray(int collectionmethod = PGA_CheckPosition) { + method = collectionmethod; varused = 0; inited = false; } @@ -171,6 +180,7 @@ struct FPortalGroupArray } bool inited; + int method; private: WORD entry[MAX_STATIC]; @@ -329,6 +339,7 @@ protected: static TArray intercepts; divline_t trace; + fixed_t startfrac; unsigned int intercept_index; unsigned int intercept_count; unsigned int count; @@ -344,7 +355,8 @@ public: { init(x1, y1, x2, y2, flags); } - void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); + void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, fixed_t startfrac = 0); + bool PortalRelocate(intercept_t *in, int flags, fixedvec3 *optpos = NULL); virtual ~FPathTraverse(); const divline_t &Trace() const { return trace; } }; @@ -384,5 +396,4 @@ fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1); #define PT_COMPATIBLE 4 #define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint - #endif \ No newline at end of file diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 51a671369..fbceb5d3f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3286,6 +3286,42 @@ void AActor::SetRoll(angle_t r, bool interpolate) } +fixedvec3 AActor::GetPortalTransition(fixed_t byoffset) +{ + bool moved = false; + sector_t *sec = Sector; + fixed_t testz = Z() + byoffset; + fixedvec3 pos = Pos(); + + while (!sec->PortalBlocksMovement(sector_t::ceiling)) + { + AActor *port = sec->SkyBoxes[sector_t::ceiling]; + if (testz > port->threshold) + { + pos = PosRelative(port->Sector); + sec = P_PointInSector(pos.x, pos.y); + moved = true; + } + else break; + } + if (!moved) + { + while (!sec->PortalBlocksMovement(sector_t::floor)) + { + AActor *port = sec->SkyBoxes[sector_t::floor]; + if (testz <= port->threshold) + { + pos = PosRelative(port->Sector); + sec = P_PointInSector(pos.x, pos.y); + } + else break; + } + } + return pos; +} + + + void AActor::CheckPortalTransition(bool islinked) { bool moved = false; @@ -6128,13 +6164,13 @@ AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle) } AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, - PClassActor *type, angle_t angle, AActor **pLineTarget, AActor **pMissileActor, - bool nofreeaim, bool noautoaim) + PClassActor *type, angle_t angle, FTranslatedLineTarget *pLineTarget, AActor **pMissileActor, + bool nofreeaim, bool noautoaim, int aimflags) { static const int angdiff[3] = { -(1<<26), 1<<26, 0 }; angle_t an = angle; angle_t pitch; - AActor *linetarget; + FTranslatedLineTarget scratch; AActor *defaultobject = GetDefaultByType(type); int vrange = nofreeaim ? ANGLE_1*35 : 0; @@ -6142,12 +6178,13 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, { return NULL; } + if (!pLineTarget) pLineTarget = &scratch; if (source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM) || noautoaim)) { // Keep exactly the same angle and pitch as the player's own aim an = angle; pitch = source->pitch; - linetarget = NULL; + pLineTarget->linetarget = NULL; } else // see which target is to be aimed at { @@ -6160,7 +6197,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, do { an = angle + angdiff[i]; - pitch = P_AimLineAttack (source, an, linetargetrange, &linetarget, vrange); + pitch = P_AimLineAttack (source, an, linetargetrange, pLineTarget, vrange, aimflags); if (source->player != NULL && !nofreeaim && @@ -6169,9 +6206,9 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, { break; } - } while (linetarget == NULL && --i >= 0); + } while (pLineTarget->linetarget == NULL && --i >= 0); - if (linetarget == NULL) + if (pLineTarget->linetarget == NULL) { an = angle; if (nofreeaim || !level.IsFreelookAllowed()) @@ -6180,7 +6217,6 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, } } } - if (pLineTarget) *pLineTarget = linetarget; if (z != ONFLOORZ && z != ONCEILINGZ) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index ec6c38f77..2f2af36c3 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -919,20 +919,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash) // the height of the intended target // -angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget) +angle_t P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget, int aimflags) { static const int angdiff[3] = { -(1<<26), 1<<26, 0 }; int i; angle_t an; angle_t pitch; - AActor *linetarget; + FTranslatedLineTarget scratch; + if (pLineTarget == NULL) pLineTarget = &scratch; // see which target is to be aimed at i = 2; do { an = mo->angle + angdiff[i]; - pitch = P_AimLineAttack (mo, an, 16*64*FRACUNIT, &linetarget); + pitch = P_AimLineAttack (mo, an, 16*64*FRACUNIT, pLineTarget, 0, aimflags); if (mo->player != NULL && level.IsFreelookAllowed() && @@ -940,11 +941,8 @@ angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget) { break; } - } while (linetarget == NULL && --i >= 0); - if (pLineTarget != NULL) - { - *pLineTarget = linetarget; - } + } while (pLineTarget->linetarget == NULL && --i >= 0); + return pitch; } diff --git a/src/p_pspr.h b/src/p_pspr.h index a9eec48b6..8fb6d455b 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -88,7 +88,7 @@ void P_BringUpWeapon (player_t *player); void P_FireWeapon (player_t *player); void P_DropWeapon (player_t *player); void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y); -angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget = NULL); +angle_t P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0); void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, angle_t pitch); void DoReadyWeapon(AActor *self); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 9252abe1d..76c5036a0 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1,2494 +1,2497 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ -// -// DESCRIPTION: -// Implements special effects: -// Texture animation, height or lighting changes -// according to adjacent sectors, respective -// utility functions, etc. -// Line Tag handling. Line and Sector triggers. -// Implements donut linedef triggers -// Initializes and implements BOOM linedef triggers for -// Scrollers/Conveyors -// Friction -// Wind/Current -// -//----------------------------------------------------------------------------- - - -#include - -#include "templates.h" -#include "doomdef.h" -#include "doomstat.h" -#include "d_event.h" -#include "gstrings.h" - -#include "i_system.h" -#include "m_argv.h" -#include "m_random.h" -#include "m_bbox.h" -#include "w_wad.h" - -#include "p_local.h" -#include "p_spec.h" -#include "p_blockmap.h" -#include "p_lnspec.h" -#include "p_terrain.h" -#include "p_acs.h" -#include "p_3dmidtex.h" - -#include "g_game.h" - -#include "s_sound.h" -#include "sc_man.h" -#include "gi.h" -#include "statnums.h" -#include "g_level.h" -#include "v_font.h" -#include "a_sharedglobal.h" -#include "farchive.h" -#include "a_keys.h" -#include "c_dispatch.h" -#include "r_sky.h" -#include "d_player.h" -#include "p_maputl.h" -#include "p_blockmap.h" -#ifndef NO_EDATA -#include "edata.h" -#endif - -// State. -#include "r_state.h" - -#include "c_console.h" - -#include "r_data/r_interpolate.h" - -static FRandom pr_playerinspecialsector ("PlayerInSpecialSector"); - -EXTERN_CVAR(Bool, cl_predict_specials) - -IMPLEMENT_POINTY_CLASS (DScroller) - DECLARE_POINTER (m_Interpolations[0]) - DECLARE_POINTER (m_Interpolations[1]) - DECLARE_POINTER (m_Interpolations[2]) -END_POINTERS - -IMPLEMENT_POINTY_CLASS (DPusher) - DECLARE_POINTER (m_Source) -END_POINTERS - -inline FArchive &operator<< (FArchive &arc, DScroller::EScrollType &type) -{ - BYTE val = (BYTE)type; - arc << val; - type = (DScroller::EScrollType)val; - return arc; -} - -DScroller::DScroller () -{ -} - -void DScroller::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - arc << m_Type - << m_dx << m_dy - << m_Affectee - << m_Control - << m_LastHeight - << m_vdx << m_vdy - << m_Accel - << m_Parts - << m_Interpolations[0] - << m_Interpolations[1] - << m_Interpolations[2]; -} - -DPusher::DPusher () -{ -} - -inline FArchive &operator<< (FArchive &arc, DPusher::EPusher &type) -{ - BYTE val = (BYTE)type; - arc << val; - type = (DPusher::EPusher)val; - return arc; -} - -void DPusher::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - arc << m_Type - << m_Source - << m_Xmag - << m_Ymag - << m_Magnitude - << m_Radius - << m_X - << m_Y - << m_Affectee; -} - -// killough 3/7/98: Initialize generalized scrolling -static void P_SpawnScrollers(); -static void P_SpawnFriction (); // phares 3/16/98 -static void P_SpawnPushers (); // phares 3/20/98 - - -// [RH] Check dmflags for noexit and respond accordingly -bool CheckIfExitIsGood (AActor *self, level_info_t *info) -{ - cluster_info_t *cluster; - - // The world can always exit itself. - if (self == NULL) - return true; - - // We must kill all monsters to exit the level. - if ((dmflags2 & DF2_KILL_MONSTERS) && level.killed_monsters != level.total_monsters) - return false; - - // Is this a deathmatch game and we're not allowed to exit? - if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT)) - { - P_DamageMobj (self, self, self, TELEFRAG_DAMAGE, NAME_Exit); - return false; - } - // Is this a singleplayer game and the next map is part of the same hub and we're dead? - if (self->health <= 0 && - !multiplayer && - info != NULL && - info->cluster == level.cluster && - (cluster = FindClusterInfo(level.cluster)) != NULL && - cluster->flags & CLUSTER_HUB) - { - return false; - } - if (deathmatch && gameaction != ga_completed) - { - Printf ("%s exited the level.\n", self->player->userinfo.GetName()); - } - return true; -} - - -// -// UTILITIES -// - -//============================================================================ -// -// P_ActivateLine -// -//============================================================================ - -bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType) -{ - int lineActivation; - INTBOOL repeat; - INTBOOL buttonSuccess; - BYTE special; - - if (!P_TestActivateLine (line, mo, side, activationType)) - { - return false; - } - bool remote = (line->special != 7 && line->special != 8 && (line->special < 11 || line->special > 14)); - if (line->locknumber > 0 && !P_CheckKeys (mo, line->locknumber, remote)) return false; - lineActivation = line->activation; - repeat = line->flags & ML_REPEAT_SPECIAL; - buttonSuccess = false; - buttonSuccess = P_ExecuteSpecial(line->special, - line, mo, side == 1, line->args[0], - line->args[1], line->args[2], - line->args[3], line->args[4]); - - special = line->special; - if (!repeat && buttonSuccess) - { // clear the special on non-retriggerable lines - line->special = 0; - } - - if (buttonSuccess) - { - if (activationType == SPAC_Use || activationType == SPAC_Impact || activationType == SPAC_Push) - { - P_ChangeSwitchTexture (line->sidedef[0], repeat, special); - } - } - // some old WADs use this method to create walls that change the texture when shot. - else if (activationType == SPAC_Impact && // only for shootable triggers - (level.flags2 & LEVEL2_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack! - !repeat && // only non-repeatable triggers - (specialGeneric_Crusher) && // not for Boom's generalized linedefs - special && // not for lines without a special - tagManager.LineHasID(line, line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0] - line->args[0] && // only if there's a tag (which is stored in the first arg) - P_FindFirstSectorFromTag (line->args[0]) == -1) // only if no sector is tagged to this linedef - { - P_ChangeSwitchTexture (line->sidedef[0], repeat, special); - line->special = 0; - } -// end of changed code - if (developer && buttonSuccess) - { - Printf ("Line special %d activated on line %i\n", special, int(line - lines)); - } - return true; -} - -//============================================================================ -// -// P_TestActivateLine -// -//============================================================================ - -bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType) -{ - int lineActivation = line->activation; - - if (line->flags & ML_FIRSTSIDEONLY && side == 1) - { - return false; - } - - if (lineActivation & SPAC_UseThrough) - { - lineActivation |= SPAC_Use; - } - else if (line->special == Teleport && - (lineActivation & SPAC_Cross) && - activationType == SPAC_PCross && - mo != NULL && - mo->flags & MF_MISSILE) - { // Let missiles use regular player teleports - lineActivation |= SPAC_PCross; - } - // BOOM's generalized line types that allow monster use can actually be - // activated by anything except projectiles. - if (lineActivation & SPAC_AnyCross) - { - lineActivation |= SPAC_Cross|SPAC_MCross; - } - if (activationType == SPAC_Use || activationType == SPAC_UseBack) - { - if (!P_CheckSwitchRange(mo, line, side)) - { - return false; - } - } - - if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS) - { - return true; - } - if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL) - { - return true; - } - if ((lineActivation & activationType) == 0) - { - if (activationType != SPAC_MCross || lineActivation != SPAC_Cross) - { - return false; - } - } - if (activationType == SPAC_AnyCross && (lineActivation & activationType)) - { - return true; - } - if (mo && !mo->player && - !(mo->flags & MF_MISSILE) && - !(line->flags & ML_MONSTERSCANACTIVATE) && - (activationType != SPAC_MCross || (!(lineActivation & SPAC_MCross)))) - { - // [RH] monsters' ability to activate this line depends on its type - // In Hexen, only MCROSS lines could be activated by monsters. With - // lax activation checks, monsters can also activate certain lines - // even without them being marked as monster activate-able. This is - // the default for non-Hexen maps in Hexen format. - if (!(level.flags2 & LEVEL2_LAXMONSTERACTIVATION)) - { - return false; - } - if ((activationType == SPAC_Use || activationType == SPAC_Push) - && (line->flags & ML_SECRET)) - return false; // never open secret doors - - bool noway = true; - - switch (activationType) - { - case SPAC_Use: - case SPAC_Push: - switch (line->special) - { - case Door_Raise: - if (line->args[0] == 0 && line->args[1] < 64) - noway = false; - break; - case Teleport: - case Teleport_NoFog: - noway = false; - } - break; - - case SPAC_MCross: - if (!(lineActivation & SPAC_MCross)) - { - switch (line->special) - { - case Door_Raise: - if (line->args[1] >= 64) - { - break; - } - case Teleport: - case Teleport_NoFog: - case Teleport_Line: - case Plat_DownWaitUpStayLip: - case Plat_DownWaitUpStay: - noway = false; - } - } - else noway = false; - break; - - default: - noway = false; - } - return !noway; - } - if (activationType == SPAC_MCross && !(lineActivation & SPAC_MCross) && - !(line->flags & ML_MONSTERSCANACTIVATE)) - { - return false; - } - return true; -} - -//============================================================================ -// -// P_PredictLine -// -//============================================================================ - -bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType) -{ - int lineActivation; - INTBOOL buttonSuccess; - BYTE special; - - // Only predict a very specifc section of specials - if (line->special != Teleport_Line && - line->special != Teleport) - { - return false; - } - - if (!P_TestActivateLine(line, mo, side, activationType) || !cl_predict_specials) - { - return false; - } - - if (line->locknumber > 0) return false; - lineActivation = line->activation; - buttonSuccess = false; - buttonSuccess = P_ExecuteSpecial(line->special, - line, mo, side == 1, line->args[0], - line->args[1], line->args[2], - line->args[3], line->args[4]); - - special = line->special; - - // end of changed code - if (developer && buttonSuccess) - { - Printf("Line special %d predicted on line %i\n", special, int(line - lines)); - } - return true; -} - -// -// P_PlayerInSpecialSector -// Called every tic frame -// that the player origin is in a special sector -// -void P_PlayerInSpecialSector (player_t *player, sector_t * sector) -{ - if (sector == NULL) - { - // Falling, not all the way down yet? - sector = player->mo->Sector; - if (player->mo->Z() != sector->LowestFloorAt(player->mo) - && !player->mo->waterlevel) - { - return; - } - } - - // Has hit ground. - AInventory *ironfeet; - - // [RH] Apply any customizable damage - if (sector->damageamount > 0) - { - // Allow subclasses. Better would be to implement it as armor and let that reduce - // the damage as part of the normal damage procedure. Unfortunately, I don't have - // different damage types yet, so that's not happening for now. - for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) - { - if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) - break; - } - - if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE; - if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) - { - if (sector->Flags & SECF_HAZARD) - { - player->hazardcount += sector->damageamount; - player->hazardtype = sector->damagetype; - player->hazardinterval = sector->damageinterval; - } - else if (level.time % sector->damageinterval == 0) - { - if (!(player->cheats & (CF_GODMODE|CF_GODMODE2))) P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); - if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) - { - G_ExitLevel(0, false); - } - if (sector->Flags & SECF_DMGTERRAINFX) - { - P_HitWater(player->mo, player->mo->Sector, INT_MIN, INT_MIN, INT_MIN, false, true, true); - } - } - } - } - else if (sector->damageamount < 0) - { - if (level.time % sector->damageinterval == 0) - { - P_GiveBody(player->mo, -sector->damageamount, 100); - } - } - - if (sector->isSecret()) - { - sector->ClearSecret(); - P_GiveSecret(player->mo, true, true, int(sector - sectors)); - } -} - -//============================================================================ -// -// P_SectorDamage -// -//============================================================================ - -static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, PClassActor *protectClass, int flags) -{ - if (!(actor->flags & MF_SHOOTABLE)) - return; - - if (!(flags & DAMAGE_NONPLAYERS) && actor->player == NULL) - return; - - if (!(flags & DAMAGE_PLAYERS) && actor->player != NULL) - return; - - if (!(flags & DAMAGE_IN_AIR) && actor->Z() != sec->floorplane.ZatPoint(actor) && !actor->waterlevel) - return; - - if (protectClass != NULL) - { - if (actor->FindInventory(protectClass, !!(flags & DAMAGE_SUBCLASSES_PROTECT))) - return; - } - - P_DamageMobj (actor, NULL, NULL, amount, type); -} - -void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass, int flags) -{ - FSectorTagIterator itr(tag); - int secnum; - while ((secnum = itr.Next()) >= 0) - { - AActor *actor, *next; - sector_t *sec = §ors[secnum]; - - // Do for actors in this sector. - for (actor = sec->thinglist; actor != NULL; actor = next) - { - next = actor->snext; - DoSectorDamage(actor, sec, amount, type, protectClass, flags); - } - // If this is a 3D floor control sector, also do for anything in/on - // those 3D floors. - for (unsigned i = 0; i < sec->e->XFloor.attached.Size(); ++i) - { - sector_t *sec2 = sec->e->XFloor.attached[i]; - - for (actor = sec2->thinglist; actor != NULL; actor = next) - { - next = actor->snext; - // Only affect actors touching the 3D floor - fixed_t z1 = sec->floorplane.ZatPoint(actor); - fixed_t z2 = sec->ceilingplane.ZatPoint(actor); - if (z2 < z1) - { - // Account for Vavoom-style 3D floors - fixed_t zz = z1; - z1 = z2; - z2 = zz; - } - if (actor->Z() + actor->height > z1) - { - // If DAMAGE_IN_AIR is used, anything not beneath the 3D floor will be - // damaged (so, anything touching it or above it). Other 3D floors between - // the actor and this one will not stop this effect. - if ((flags & DAMAGE_IN_AIR) || actor->Z() <= z2) - { - // Here we pass the DAMAGE_IN_AIR flag to disable the floor check, since it - // only works with the real sector's floor. We did the appropriate height checks - // for 3D floors already. - DoSectorDamage(actor, NULL, amount, type, protectClass, flags | DAMAGE_IN_AIR); - } - } - } - } - } -} - -//============================================================================ -// -// P_GiveSecret -// -//============================================================================ - -CVAR(Bool, showsecretsector, false, 0) -CVAR(Bool, cl_showsecretmessage, true, CVAR_ARCHIVE) - -void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum) -{ - if (actor != NULL) - { - if (actor->player != NULL) - { - actor->player->secretcount++; - } - if (cl_showsecretmessage && actor->CheckLocalView(consoleplayer)) - { - if (printmessage) - { - if (!showsecretsector || sectornum < 0) C_MidPrint(SmallFont, GStrings["SECRETMESSAGE"]); - else - { - FString s = GStrings["SECRETMESSAGE"]; - s.AppendFormat(" (Sector %d)", sectornum); - C_MidPrint(SmallFont, s); - } - } - if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM); - } - } - level.found_secrets++; -} - -//============================================================================ -// -// P_PlayerOnSpecialFlat -// -//============================================================================ - -void P_PlayerOnSpecialFlat (player_t *player, int floorType) -{ - if (Terrains[floorType].DamageAmount && - !(level.time & Terrains[floorType].DamageTimeMask)) - { - AInventory *ironfeet = NULL; - - if (Terrains[floorType].AllowProtection) - { - for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) - { - if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) - break; - } - } - - int damage = 0; - if (ironfeet == NULL) - { - damage = P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount, - Terrains[floorType].DamageMOD); - } - if (damage > 0 && Terrains[floorType].Splash != -1) - { - S_Sound (player->mo, CHAN_AUTO, - Splashes[Terrains[floorType].Splash].NormalSplashSound, 1, - ATTN_IDLE); - } - } -} - - - -// -// P_UpdateSpecials -// Animate planes, scroll walls, etc. -// -EXTERN_CVAR (Float, timelimit) - -void P_UpdateSpecials () -{ - // LEVEL TIMER - if (deathmatch && timelimit) - { - if (level.maptime >= (int)(timelimit * TICRATE * 60)) - { - Printf ("%s\n", GStrings("TXT_TIMELIMIT")); - G_ExitLevel(0, false); - } - } -} - - - -// -// SPECIAL SPAWNING -// - -CUSTOM_CVAR (Bool, forcewater, false, CVAR_ARCHIVE|CVAR_SERVERINFO) -{ - if (gamestate == GS_LEVEL) - { - int i; - - for (i = 0; i < numsectors; i++) - { - sector_t *hsec = sectors[i].GetHeightSec(); - if (hsec && - !(sectors[i].heightsec->MoreFlags & SECF_UNDERWATER)) - { - if (self) - { - hsec->MoreFlags |= SECF_FORCEDUNDERWATER; - } - else - { - hsec->MoreFlags &= ~SECF_FORCEDUNDERWATER; - } - } - } - } -} - -class DLightTransfer : public DThinker -{ - DECLARE_CLASS (DLightTransfer, DThinker) - - DLightTransfer() {} -public: - DLightTransfer (sector_t *srcSec, int target, bool copyFloor); - void Serialize (FArchive &arc); - void Tick (); - -protected: - static void DoTransfer (int level, int target, bool floor); - - sector_t *Source; - int TargetTag; - bool CopyFloor; - short LastLight; -}; - -IMPLEMENT_CLASS (DLightTransfer) - -void DLightTransfer::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - if (SaveVersion < 3223) - { - BYTE bytelight; - arc << bytelight; - LastLight = bytelight; - } - else - { - arc << LastLight; - } - arc << Source << TargetTag << CopyFloor; -} - -DLightTransfer::DLightTransfer (sector_t *srcSec, int target, bool copyFloor) -{ - int secnum; - - Source = srcSec; - TargetTag = target; - CopyFloor = copyFloor; - DoTransfer (LastLight = srcSec->lightlevel, target, copyFloor); - - if (copyFloor) - { - FSectorTagIterator itr(target); - while ((secnum = itr.Next()) >= 0) - sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING); - } - else - { - FSectorTagIterator itr(target); - while ((secnum = itr.Next()) >= 0) - sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING); - } - ChangeStatNum (STAT_LIGHTTRANSFER); -} - -void DLightTransfer::Tick () -{ - int light = Source->lightlevel; - - if (light != LastLight) - { - LastLight = light; - DoTransfer (light, TargetTag, CopyFloor); - } -} - -void DLightTransfer::DoTransfer (int level, int target, bool floor) -{ - int secnum; - - if (floor) - { - FSectorTagIterator itr(target); - while ((secnum = itr.Next()) >= 0) - sectors[secnum].SetPlaneLight(sector_t::floor, level); - } - else - { - FSectorTagIterator itr(target); - while ((secnum = itr.Next()) >= 0) - sectors[secnum].SetPlaneLight(sector_t::ceiling, level); - } -} - - -class DWallLightTransfer : public DThinker -{ - enum - { - WLF_SIDE1=1, - WLF_SIDE2=2, - WLF_NOFAKECONTRAST=4 - }; - - DECLARE_CLASS (DWallLightTransfer, DThinker) - DWallLightTransfer() {} -public: - DWallLightTransfer (sector_t *srcSec, int target, BYTE flags); - void Serialize (FArchive &arc); - void Tick (); - -protected: - static void DoTransfer (short level, int target, BYTE flags); - - sector_t *Source; - int TargetID; - short LastLight; - BYTE Flags; -}; - -IMPLEMENT_CLASS (DWallLightTransfer) - -void DWallLightTransfer::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - if (SaveVersion < 3223) - { - BYTE bytelight; - arc << bytelight; - LastLight = bytelight; - } - else - { - arc << LastLight; - } - arc << Source << TargetID << Flags; -} - -DWallLightTransfer::DWallLightTransfer (sector_t *srcSec, int target, BYTE flags) -{ - int linenum; - int wallflags; - - Source = srcSec; - TargetID = target; - Flags = flags; - DoTransfer (LastLight = srcSec->GetLightLevel(), target, Flags); - - if (!(flags & WLF_NOFAKECONTRAST)) - { - wallflags = WALLF_ABSLIGHTING; - } - else - { - wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST; - } - - FLineIdIterator itr(target); - while ((linenum = itr.Next()) >= 0) - { - if (flags & WLF_SIDE1 && lines[linenum].sidedef[0] != NULL) - { - lines[linenum].sidedef[0]->Flags |= wallflags; - } - - if (flags & WLF_SIDE2 && lines[linenum].sidedef[1] != NULL) - { - lines[linenum].sidedef[1]->Flags |= wallflags; - } - } - ChangeStatNum(STAT_LIGHTTRANSFER); -} - -void DWallLightTransfer::Tick () -{ - short light = sector_t::ClampLight(Source->lightlevel); - - if (light != LastLight) - { - LastLight = light; - DoTransfer (light, TargetID, Flags); - } -} - -void DWallLightTransfer::DoTransfer (short lightlevel, int target, BYTE flags) -{ - int linenum; - - FLineIdIterator itr(target); - while ((linenum = itr.Next()) >= 0) - { - line_t *line = &lines[linenum]; - - if (flags & WLF_SIDE1 && line->sidedef[0] != NULL) - { - line->sidedef[0]->SetLight(lightlevel); - } - - if (flags & WLF_SIDE2 && line->sidedef[1] != NULL) - { - line->sidedef[1]->SetLight(lightlevel); - } - } -} - -//----------------------------------------------------------------------------- -// -// Portals -// -//----------------------------------------------------------------------------- - -//--------------------------------------------------------------------------- -// Upper stacks go in the top sector. Lower stacks go in the bottom sector. - -static void SetupFloorPortal (AStackPoint *point) -{ - NActorIterator it (NAME_LowerStackLookOnly, point->tid); - sector_t *Sector = point->Sector; - ASkyViewpoint *skyv = static_cast(it.Next()); - Sector->SkyBoxes[sector_t::floor] = skyv; - if (skyv != NULL && skyv->bAlways) - { - skyv->Mate = point; - if (Sector->GetAlpha(sector_t::floor) == OPAQUE) - Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255)); - } -} - -static void SetupCeilingPortal (AStackPoint *point) -{ - NActorIterator it (NAME_UpperStackLookOnly, point->tid); - sector_t *Sector = point->Sector; - ASkyViewpoint *skyv = static_cast(it.Next()); - Sector->SkyBoxes[sector_t::ceiling] = skyv; - if (skyv != NULL && skyv->bAlways) - { - skyv->Mate = point; - if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE) - Sector->SetAlpha(sector_t::ceiling, Scale(point->args[0], OPAQUE, 255)); - } -} - -void P_SetupPortals() -{ - TThinkerIterator it; - AStackPoint *pt; - TArray points; - - while ((pt = it.Next())) - { - FName nm = pt->GetClass()->TypeName; - if (nm == NAME_UpperStackLookOnly) - { - SetupFloorPortal(pt); - } - else if (nm == NAME_LowerStackLookOnly) - { - SetupCeilingPortal(pt); - } - pt->special1 = 0; - points.Push(pt); - } -} - -static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_t alpha) -{ - // plane: 0=floor, 1=ceiling, 2=both - if (plane > 0) - { - if (sector->SkyBoxes[sector_t::ceiling] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::ceiling])->bAlways) - { - sector->SkyBoxes[sector_t::ceiling] = portal; - if (sector->GetAlpha(sector_t::ceiling) == OPAQUE) - sector->SetAlpha(sector_t::ceiling, alpha); - - if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum); - } - } - if (plane == 2 || plane == 0) - { - if (sector->SkyBoxes[sector_t::floor] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::floor])->bAlways) - { - sector->SkyBoxes[sector_t::floor] = portal; - } - if (sector->GetAlpha(sector_t::floor) == OPAQUE) - sector->SetAlpha(sector_t::floor, alpha); - - if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum); - } -} - -static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t alpha, bool tolines) -{ - int s; - FSectorTagIterator itr(sectortag); - while ((s = itr.Next()) >= 0) - { - SetPortal(§ors[s], plane, origin, alpha); - } - - for (int j=0;j= 0) - { - SetPortal(§ors[s], plane, origin, alpha); - } - } - } - if (tolines && lines[j].special == Sector_SetPortal && - lines[j].args[1] == 5 && - lines[j].args[3] == sectortag) - { - if (lines[j].args[0] == 0) - { - lines[j].skybox = origin; - } - else - { - FLineIdIterator itr(lines[j].args[0]); - while ((s = itr.Next()) >= 0) - { - lines[s].skybox = origin; - } - } - } - } -} - -void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha, int linked) -{ - if (plane < 0 || plane > 2 || (linked && plane == 2)) return; - for (int i=0;iv1->x) + SQWORD(line->v2->x)) >> 1); - fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1); - fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1); - fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1); - fixed_t z = linked ? line->frontsector->planes[plane].TexZ : 0; // the map's sector height defines the portal plane for linked portals - - fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255); - - AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE); - AStackPoint *reference = Spawn(x2, y2, 0, NO_REPLACE); - reference->special1 = linked ? SKYBOX_LINKEDPORTAL : SKYBOX_PORTAL; - anchor->special1 = SKYBOX_ANCHOR; - // store the portal displacement in the unused scaleX/Y members of the portal reference actor. - anchor->scaleX = -(reference->scaleX = x2 - x1); - anchor->scaleY = -(reference->scaleY = y2 - y1); - anchor->threshold = reference->threshold = z; - - reference->Mate = anchor; - anchor->Mate = reference; - - // This is so that the renderer can distinguish these portals from - // the ones spawned with the '*StackLookOnly' things. - reference->flags |= MF_JUSTATTACKED; - anchor->flags |= MF_JUSTATTACKED; - - CopyPortal(sectortag, plane, reference, alpha, false); - return; - } - } -} - -// This searches the viewpoint's sector -// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors. -void P_SpawnSkybox(ASkyViewpoint *origin) -{ - sector_t *Sector = origin->Sector; - if (Sector == NULL) - { - Printf("Sector not initialized for SkyCamCompat\n"); - origin->Sector = Sector = P_PointInSector(origin->X(), origin->Y()); - } - if (Sector) - { - line_t * refline = NULL; - for (short i = 0; i < Sector->linecount; i++) - { - refline = Sector->lines[i]; - if (refline->special == Sector_SetPortal && refline->args[1] == 2) - { - // We found the setup linedef for this skybox, so let's use it for our init. - CopyPortal(refline->args[0], refline->args[2], origin, 0, true); - return; - } - } - } -} - - - -// -// P_SetSectorDamage -// -// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties -// - -static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags) -{ - // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials. - if (sector->damageamount == 0) - { - sector->damageamount = damage; - sector->damageinterval = MAX(1, interval); - sector->leakydamage = leakchance; - sector->damagetype = type; - sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS); - } -} - -// -// P_InitSectorSpecial -// -// Sets up everything derived from 'sector->special' for one sector -// ('fromload' is necessary to allow conversion upon savegame load.) -// - -void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) -{ - // [RH] All secret sectors are marked with a BOOM-ish bitfield - if (sector->special & SECRET_MASK) - { - sector->Flags |= SECF_SECRET | SECF_WASSECRET; - level.total_secrets++; - } - if (sector->special & FRICTION_MASK) - { - sector->Flags |= SECF_FRICTION; - } - if (sector->special & PUSH_MASK) - { - sector->Flags |= SECF_PUSH; - } - if ((sector->special & DAMAGE_MASK) == 0x100) - { - P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); - } - else if ((sector->special & DAMAGE_MASK) == 0x200) - { - P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); - } - else if ((sector->special & DAMAGE_MASK) == 0x300) - { - P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); - } - sector->special &= 0xff; - - // [RH] Normal DOOM special or BOOM specialized? - bool keepspecial = false; - switch (sector->special) - { - case Light_Phased: - if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); - break; - - // [RH] Hexen-like phased lighting - case LightSequenceStart: - if (!nothinkers) new DPhased (sector); - break; - - case dLight_Flicker: - if (!nothinkers) new DLightFlash (sector); - break; - - case dLight_StrobeFast: - if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - break; - - case dLight_StrobeSlow: - if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); - break; - - case dLight_Strobe_Hurt: - if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); - break; - - case dDamage_Hellslime: - P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); - break; - - case dDamage_Nukage: - P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); - break; - - case dLight_Glow: - if (!nothinkers) new DGlow (sector); - break; - - case dSector_DoorCloseIn30: - new DDoor(sector, DDoor::doorWaitClose, FRACUNIT * 2, 0, 0, 30 * TICRATE); - break; - - case dDamage_End: - P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL); - break; - - case dLight_StrobeSlowSync: - if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); - break; - - case dLight_StrobeFastSync: - if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); - break; - - case dSector_DoorRaiseIn5Mins: - new DDoor (sector, DDoor::doorWaitRaise, 2*FRACUNIT, TICRATE*30/7, 5*60*TICRATE, 0); - break; - - case dFriction_Low: - sector->friction = FRICTION_LOW; - sector->movefactor = 0x269; - sector->Flags |= SECF_FRICTION; - break; - - case dDamage_SuperHellslime: - P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); - break; - - case dLight_FireFlicker: - if (!nothinkers) new DFireFlicker (sector); - break; - - case dDamage_LavaWimpy: - P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); - break; - - case dDamage_LavaHefty: - P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); - break; - - case dScroll_EastLavaDamage: - P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); - if (!nothinkers) - { - new DStrobe(sector, STROBEBRIGHT, FASTDARK, false); - new DScroller(DScroller::sc_floor, -((FRACUNIT / 2) << 3), - 0, -1, int(sector - sectors), 0); - } - keepspecial = true; - break; - - case hDamage_Sludge: - P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0); - break; - - case sLight_Strobe_Hurt: - P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); - if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - break; - - case sDamage_Hellslime: - P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD); - break; - - case Damage_InstantDeath: - // Strife's instant death sector - P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0); - break; - - case sDamage_SuperHellslime: - P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD); - break; - - case Sector_Hidden: - sector->MoreFlags |= SECF_HIDDEN; - break; - - case Sector_Heal: - // CoD's healing sector - P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0); - break; - - case Sky2: - sector->sky = PL_SKYFLAT; - break; - - default: - if (sector->special >= Scroll_North_Slow && - sector->special <= Scroll_SouthWest_Fast) - { // Hexen scroll special - static const char hexenScrollies[24][2] = - { - { 0, 1 }, { 0, 2 }, { 0, 4 }, - { -1, 0 }, { -2, 0 }, { -4, 0 }, - { 0, -1 }, { 0, -2 }, { 0, -4 }, - { 1, 0 }, { 2, 0 }, { 4, 0 }, - { 1, 1 }, { 2, 2 }, { 4, 4 }, - { -1, 1 }, { -2, 2 }, { -4, 4 }, - { -1, -1 }, { -2, -2 }, { -4, -4 }, - { 1, -1 }, { 2, -2 }, { 4, -4 } - }; - - - int i = sector->special - Scroll_North_Slow; - fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); - fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); - if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); - } - else if (sector->special >= Carry_East5 && - sector->special <= Carry_East35) - { // Heretic scroll special - // Only east scrollers also scroll the texture - if (!nothinkers) new DScroller (DScroller::sc_floor, - (-FRACUNIT/2)<<(sector->special - Carry_East5), - 0, -1, int(sector-sectors), 0); - } - keepspecial = true; - break; - } - if (!keepspecial) sector->special = 0; -} - -// -// P_SpawnSpecials -// -// After the map has been loaded, scan for specials that spawn thinkers -// - -void P_SpawnSpecials (void) -{ - sector_t *sector; - int i; - - P_SetupPortals(); - - // Init special SECTORs. - sector = sectors; - - for (i = 0; i < numsectors; i++, sector++) - { - if (sector->special == 0) - continue; - - P_InitSectorSpecial(sector, sector->special, false); - } - -#ifndef NO_EDATA - ProcessEDSectors(); -#endif - - - // Init other misc stuff - - P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers - P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs - P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs - - TThinkerIterator it2; - ASkyCamCompat *pt2; - while ((pt2 = it2.Next())) - { - P_SpawnSkybox(pt2); - } - - for (i = 0; i < numlines; i++) - { - switch (lines[i].special) - { - int s; - sector_t *sec; - - // killough 3/7/98: - // support for drawn heights coming from different sector - case Transfer_Heights: - { - sec = lines[i].frontsector; - if (lines[i].args[1] & 2) - { - sec->MoreFlags |= SECF_FAKEFLOORONLY; - } - if (lines[i].args[1] & 4) - { - sec->MoreFlags |= SECF_CLIPFAKEPLANES; - } - if (lines[i].args[1] & 8) - { - sec->MoreFlags |= SECF_UNDERWATER; - } - else if (forcewater) - { - sec->MoreFlags |= SECF_FORCEDUNDERWATER; - } - if (lines[i].args[1] & 16) - { - sec->MoreFlags |= SECF_IGNOREHEIGHTSEC; - } - if (lines[i].args[1] & 32) - { - sec->MoreFlags |= SECF_NOFAKELIGHT; - } - FSectorTagIterator itr(lines[i].args[0]); - while ((s = itr.Next()) >= 0) - { - sectors[s].heightsec = sec; - sec->e->FakeFloor.Sectors.Push(§ors[s]); - sectors[s].AdjustFloorClip(); - } - break; - } - - // killough 3/16/98: Add support for setting - // floor lighting independently (e.g. lava) - case Transfer_FloorLight: - new DLightTransfer (lines[i].frontsector, lines[i].args[0], true); - break; - - // killough 4/11/98: Add support for setting - // ceiling lighting independently - case Transfer_CeilingLight: - new DLightTransfer (lines[i].frontsector, lines[i].args[0], false); - break; - - // [Graf Zahl] Add support for setting lighting - // per wall independently - case Transfer_WallLight: - new DWallLightTransfer (lines[i].frontsector, lines[i].args[0], lines[i].args[1]); - break; - - case Sector_Attach3dMidtex: - P_Attach3dMidtexLinesToSector(lines[i].frontsector, lines[i].args[0], lines[i].args[1], !!lines[i].args[2]); - break; - - case Sector_SetLink: - if (lines[i].args[0] == 0) - { - P_AddSectorLinks(lines[i].frontsector, lines[i].args[1], lines[i].args[2], lines[i].args[3]); - } - break; - - case Sector_SetPortal: - // arg 0 = sector tag - // arg 1 = type - // - 0: normal (handled here) - // - 1: copy (handled by the portal they copy) - // - 2: EE-style skybox (handled by the camera object) - // - 3: EE-style flat portal (GZDoom HW renderer only for now) - // - 4: EE-style horizon portal (GZDoom HW renderer only for now) - // - 5: copy portal to line (GZDoom HW renderer only for now) - // - 6: linked portal - // other values reserved for later use - // arg 2 = 0:floor, 1:ceiling, 2:both - // arg 3 = 0: anchor, 1: reference line - // arg 4 = for the anchor only: alpha - if ((lines[i].args[1] == 0 || lines[i].args[1] == 6) && lines[i].args[3] == 0) - { - P_SpawnPortal(&lines[i], lines[i].args[0], lines[i].args[2], lines[i].args[4], lines[i].args[1]); - } - else if (lines[i].args[1] == 3 || lines[i].args[1] == 4) - { - line_t *line = &lines[i]; - ASkyViewpoint *origin = Spawn(0, 0, 0, NO_REPLACE); - origin->Sector = line->frontsector; - origin->special1 = line->args[1] == 3? SKYBOX_PLANE:SKYBOX_HORIZON; - - CopyPortal(line->args[0], line->args[2], origin, 0, true); - } - break; - - case Line_SetPortal: - P_SpawnLinePortal(&lines[i]); - break; - - // [RH] ZDoom Static_Init settings - case Static_Init: - switch (lines[i].args[1]) - { - case Init_Gravity: - { - float grav = ((float)P_AproxDistance (lines[i].dx, lines[i].dy)) / (FRACUNIT * 100.0f); - FSectorTagIterator itr(lines[i].args[0]); - while ((s = itr.Next()) >= 0) - sectors[s].gravity = grav; - } - break; - - //case Init_Color: - // handled in P_LoadSideDefs2() - - case Init_Damage: - { - int damage = P_AproxDistance (lines[i].dx, lines[i].dy) >> FRACBITS; - FSectorTagIterator itr(lines[i].args[0]); - while ((s = itr.Next()) >= 0) - { - sector_t *sec = §ors[s]; - sec->damageamount = damage; - sec->damagetype = NAME_None; - if (sec->damageamount < 20) - { - sec->leakydamage = 0; - sec->damageinterval = 32; - } - else if (sec->damageamount < 50) - { - sec->leakydamage = 5; - sec->damageinterval = 32; - } - else - { - sec->leakydamage = 256; - sec->damageinterval = 1; - } - } - } - break; - - case Init_SectorLink: - if (lines[i].args[3] == 0) - P_AddSectorLinksByID(lines[i].frontsector, lines[i].args[0], lines[i].args[2]); - break; - - // killough 10/98: - // - // Support for sky textures being transferred from sidedefs. - // Allows scrolling and other effects (but if scrolling is - // used, then the same sector tag needs to be used for the - // sky sector, the sky-transfer linedef, and the scroll-effect - // linedef). Still requires user to use F_SKY1 for the floor - // or ceiling texture, to distinguish floor and ceiling sky. - - case Init_TransferSky: - { - FSectorTagIterator itr(lines[i].args[0]); - while ((s = itr.Next()) >= 0) - sectors[s].sky = (i + 1) | PL_SKYFLAT; - break; - } - } - break; - } - } - // [RH] Start running any open scripts on this map - FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); -} - -// killough 2/28/98: -// -// This function, with the help of r_plane.c and r_bsp.c, supports generalized -// scrolling floors and walls, with optional mobj-carrying properties, e.g. -// conveyor belts, rivers, etc. A linedef with a special type affects all -// tagged sectors the same way, by creating scrolling and/or object-carrying -// properties. Multiple linedefs may be used on the same sector and are -// cumulative, although the special case of scrolling a floor and carrying -// things on it, requires only one linedef. The linedef's direction determines -// the scrolling direction, and the linedef's length determines the scrolling -// speed. This was designed so that an edge around the sector could be used to -// control the direction of the sector's scrolling, which is usually what is -// desired. -// -// Process the active scrollers. -// -// This is the main scrolling code -// killough 3/7/98 - -// [RH] Compensate for rotated sector textures by rotating the scrolling -// in the opposite direction. -static void RotationComp(const sector_t *sec, int which, fixed_t dx, fixed_t dy, fixed_t &tdx, fixed_t &tdy) -{ - angle_t an = sec->GetAngle(which); - if (an == 0) - { - tdx = dx; - tdy = dy; - } - else - { - an = an >> ANGLETOFINESHIFT; - fixed_t ca = -finecosine[an]; - fixed_t sa = -finesine[an]; - tdx = DMulScale16(dx, ca, -dy, sa); - tdy = DMulScale16(dy, ca, dx, sa); - } -} - -void DScroller::Tick () -{ - fixed_t dx = m_dx, dy = m_dy, tdx, tdy; - - if (m_Control != -1) - { // compute scroll amounts based on a sector's height changes - fixed_t height = sectors[m_Control].CenterFloor () + - sectors[m_Control].CenterCeiling (); - fixed_t delta = height - m_LastHeight; - m_LastHeight = height; - dx = FixedMul(dx, delta); - dy = FixedMul(dy, delta); - } - - // killough 3/14/98: Add acceleration - if (m_Accel) - { - m_vdx = dx += m_vdx; - m_vdy = dy += m_vdy; - } - - if (!(dx | dy)) // no-op if both (x,y) offsets are 0 - return; - - switch (m_Type) - { - case sc_side: // killough 3/7/98: Scroll wall texture - if (m_Parts & scw_top) - { - sides[m_Affectee].AddTextureXOffset(side_t::top, dx); - sides[m_Affectee].AddTextureYOffset(side_t::top, dy); - } - if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL || - !(sides[m_Affectee].linedef->flags&ML_3DMIDTEX))) - { - sides[m_Affectee].AddTextureXOffset(side_t::mid, dx); - sides[m_Affectee].AddTextureYOffset(side_t::mid, dy); - } - if (m_Parts & scw_bottom) - { - sides[m_Affectee].AddTextureXOffset(side_t::bottom, dx); - sides[m_Affectee].AddTextureYOffset(side_t::bottom, dy); - } - break; - - case sc_floor: // killough 3/7/98: Scroll floor texture - RotationComp(§ors[m_Affectee], sector_t::floor, dx, dy, tdx, tdy); - sectors[m_Affectee].AddXOffset(sector_t::floor, tdx); - sectors[m_Affectee].AddYOffset(sector_t::floor, tdy); - break; - - case sc_ceiling: // killough 3/7/98: Scroll ceiling texture - RotationComp(§ors[m_Affectee], sector_t::ceiling, dx, dy, tdx, tdy); - sectors[m_Affectee].AddXOffset(sector_t::ceiling, tdx); - sectors[m_Affectee].AddYOffset(sector_t::ceiling, tdy); - break; - - // [RH] Don't actually carry anything here. That happens later. - case sc_carry: - level.Scrolls[m_Affectee].ScrollX += dx; - level.Scrolls[m_Affectee].ScrollY += dy; - break; - - case sc_carry_ceiling: // to be added later - break; - } -} - -// -// Add_Scroller() -// -// Add a generalized scroller to the thinker list. -// -// type: the enumerated type of scrolling: floor, ceiling, floor carrier, -// wall, floor carrier & scroller -// -// (dx,dy): the direction and speed of the scrolling or its acceleration -// -// control: the sector whose heights control this scroller's effect -// remotely, or -1 if no control sector -// -// affectee: the index of the affected object (sector or sidedef) -// -// accel: non-zero if this is an accelerative effect -// - -DScroller::DScroller (EScrollType type, fixed_t dx, fixed_t dy, - int control, int affectee, int accel, int scrollpos) - : DThinker (STAT_SCROLLER) -{ - m_Type = type; - m_dx = dx; - m_dy = dy; - m_Accel = accel; - m_Parts = scrollpos; - m_vdx = m_vdy = 0; - if ((m_Control = control) != -1) - m_LastHeight = - sectors[control].CenterFloor () + sectors[control].CenterCeiling (); - m_Affectee = affectee; - m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL; - - switch (type) - { - case sc_carry: - level.AddScroller (this, affectee); - break; - - case sc_side: - sides[affectee].Flags |= WALLF_NOAUTODECALS; - if (m_Parts & scw_top) - { - m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top); - } - if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL || - !(sides[m_Affectee].linedef->flags&ML_3DMIDTEX))) - { - m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid); - } - if (m_Parts & scw_bottom) - { - m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom); - } - break; - - case sc_floor: - m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::FloorScroll, false); - break; - - case sc_ceiling: - m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::CeilingScroll, false); - break; - - default: - break; - } -} - -void DScroller::Destroy () -{ - for(int i=0;i<3;i++) - { - if (m_Interpolations[i] != NULL) - { - m_Interpolations[i]->DelRef(); - m_Interpolations[i] = NULL; - } - } - Super::Destroy(); -} - -// Adds wall scroller. Scroll amount is rotated with respect to wall's -// linedef first, so that scrolling towards the wall in a perpendicular -// direction is translated into vertical motion, while scrolling along -// the wall in a parallel direction is translated into horizontal motion. -// -// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff - -DScroller::DScroller (fixed_t dx, fixed_t dy, const line_t *l, - int control, int accel, int scrollpos) - : DThinker (STAT_SCROLLER) -{ - fixed_t x = abs(l->dx), y = abs(l->dy), d; - if (y > x) - d = x, x = y, y = d; - d = FixedDiv (x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90) - >> ANGLETOFINESHIFT]); - x = -FixedDiv (FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d); - y = -FixedDiv (FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d); - - m_Type = sc_side; - m_dx = x; - m_dy = y; - m_vdx = m_vdy = 0; - m_Accel = accel; - m_Parts = scrollpos; - if ((m_Control = control) != -1) - m_LastHeight = sectors[control].CenterFloor() + sectors[control].CenterCeiling(); - m_Affectee = int(l->sidedef[0] - sides); - sides[m_Affectee].Flags |= WALLF_NOAUTODECALS; - m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL; - - if (m_Parts & scw_top) - { - m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top); - } - if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL || - !(sides[m_Affectee].linedef->flags&ML_3DMIDTEX))) - { - m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid); - } - if (m_Parts & scw_bottom) - { - m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom); - } -} - -// Amount (dx,dy) vector linedef is shifted right to get scroll amount -#define SCROLL_SHIFT 5 -#define SCROLLTYPE(i) (((i) <= 0) || ((i) & ~7) ? 7 : (i)) - -// Initialize the scrollers -static void P_SpawnScrollers(void) -{ - int i; - line_t *l = lines; - TArray copyscrollers; - - for (i = 0; i < numlines; i++) - { - if (lines[i].special == Sector_CopyScroller) - { - // don't allow copying the scroller if the sector has the same tag as it would just duplicate it. - if (!tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0])) - { - copyscrollers.Push(i); - } - lines[i].special = 0; - } - } - - for (i = 0; i < numlines; i++, l++) - { - fixed_t dx; // direction and speed of scrolling - fixed_t dy; - int control = -1, accel = 0; // no control sector or acceleration - int special = l->special; - - // Check for undefined parameters that are non-zero and output messages for them. - // We don't report for specials we don't understand. - FLineSpecial *spec = P_GetLineSpecialInfo(special); - if (spec != NULL) - { - int max = spec->map_args; - for (unsigned arg = max; arg < countof(l->args); ++arg) - { - if (l->args[arg] != 0) - { - Printf("Line %d (type %d:%s), arg %u is %d (should be 0)\n", - i, special, spec->name, arg+1, l->args[arg]); - } - } - } - - // killough 3/7/98: Types 245-249 are same as 250-254 except that the - // first side's sector's heights cause scrolling when they change, and - // this linedef controls the direction and speed of the scrolling. The - // most complicated linedef since donuts, but powerful :) - // - // killough 3/15/98: Add acceleration. Types 214-218 are the same but - // are accelerative. - - // [RH] Assume that it's a scroller and zero the line's special. - l->special = 0; - - dx = dy = 0; // Shut up, GCC - - if (special == Scroll_Ceiling || - special == Scroll_Floor || - special == Scroll_Texture_Model) - { - if (l->args[1] & 3) - { - // if 1, then displacement - // if 2, then accelerative (also if 3) - control = int(l->sidedef[0]->sector - sectors); - if (l->args[1] & 2) - accel = 1; - } - if (special == Scroll_Texture_Model || - l->args[1] & 4) - { - // The line housing the special controls the - // direction and speed of scrolling. - dx = l->dx >> SCROLL_SHIFT; - dy = l->dy >> SCROLL_SHIFT; - } - else - { - // The speed and direction are parameters to the special. - dx = (l->args[3] - 128) * (FRACUNIT / 32); - dy = (l->args[4] - 128) * (FRACUNIT / 32); - } - } - - switch (special) - { - int s; - - case Scroll_Ceiling: - { - FSectorTagIterator itr(l->args[0]); - while ((s = itr.Next()) >= 0) - { - new DScroller(DScroller::sc_ceiling, -dx, dy, control, s, accel); - } - for (unsigned j = 0; j < copyscrollers.Size(); j++) - { - line_t *line = &lines[copyscrollers[j]]; - - if (line->args[0] == l->args[0] && (line->args[1] & 1)) - { - new DScroller(DScroller::sc_ceiling, -dx, dy, control, int(line->frontsector - sectors), accel); - } - } - break; - } - - case Scroll_Floor: - if (l->args[2] != 1) - { // scroll the floor texture - FSectorTagIterator itr(l->args[0]); - while ((s = itr.Next()) >= 0) - { - new DScroller (DScroller::sc_floor, -dx, dy, control, s, accel); - } - for(unsigned j = 0;j < copyscrollers.Size(); j++) - { - line_t *line = &lines[copyscrollers[j]]; - - if (line->args[0] == l->args[0] && (line->args[1] & 2)) - { - new DScroller (DScroller::sc_floor, -dx, dy, control, int(line->frontsector-sectors), accel); - } - } - } - - if (l->args[2] > 0) - { // carry objects on the floor - FSectorTagIterator itr(l->args[0]); - while ((s = itr.Next()) >= 0) - { - new DScroller (DScroller::sc_carry, dx, dy, control, s, accel); - } - for(unsigned j = 0;j < copyscrollers.Size(); j++) - { - line_t *line = &lines[copyscrollers[j]]; - - if (line->args[0] == l->args[0] && (line->args[1] & 4)) - { - new DScroller (DScroller::sc_carry, dx, dy, control, int(line->frontsector-sectors), accel); - } - } - } - break; - - // killough 3/1/98: scroll wall according to linedef - // (same direction and speed as scrolling floors) - case Scroll_Texture_Model: - { - FLineIdIterator itr(l->args[0]); - while ((s = itr.Next()) >= 0) - { - if (s != i) - new DScroller(dx, dy, lines + s, control, accel); - } - break; - } - - case Scroll_Texture_Offsets: - // killough 3/2/98: scroll according to sidedef offsets - s = int(lines[i].sidedef[0] - sides); - new DScroller (DScroller::sc_side, -sides[s].GetTextureXOffset(side_t::mid), - sides[s].GetTextureYOffset(side_t::mid), -1, s, accel, SCROLLTYPE(l->args[0])); - break; - - case Scroll_Texture_Left: - l->special = special; // Restore the special, for compat_useblocking's benefit. - s = int(lines[i].sidedef[0] - sides); - new DScroller (DScroller::sc_side, l->args[0] * (FRACUNIT/64), 0, - -1, s, accel, SCROLLTYPE(l->args[1])); - break; - - case Scroll_Texture_Right: - l->special = special; - s = int(lines[i].sidedef[0] - sides); - new DScroller (DScroller::sc_side, l->args[0] * (-FRACUNIT/64), 0, - -1, s, accel, SCROLLTYPE(l->args[1])); - break; - - case Scroll_Texture_Up: - l->special = special; - s = int(lines[i].sidedef[0] - sides); - new DScroller (DScroller::sc_side, 0, l->args[0] * (FRACUNIT/64), - -1, s, accel, SCROLLTYPE(l->args[1])); - break; - - case Scroll_Texture_Down: - l->special = special; - s = int(lines[i].sidedef[0] - sides); - new DScroller (DScroller::sc_side, 0, l->args[0] * (-FRACUNIT/64), - -1, s, accel, SCROLLTYPE(l->args[1])); - break; - - case Scroll_Texture_Both: - s = int(lines[i].sidedef[0] - sides); - if (l->args[0] == 0) { - dx = (l->args[1] - l->args[2]) * (FRACUNIT/64); - dy = (l->args[4] - l->args[3]) * (FRACUNIT/64); - new DScroller (DScroller::sc_side, dx, dy, -1, s, accel); - } - break; - - default: - // [RH] It wasn't a scroller after all, so restore the special. - l->special = special; - break; - } - } -} - -// killough 3/7/98 -- end generalized scroll effects - -//////////////////////////////////////////////////////////////////////////// -// -// FRICTION EFFECTS -// -// phares 3/12/98: Start of friction effects - -// As the player moves, friction is applied by decreasing the x and y -// velocity values on each tic. By varying the percentage of decrease, -// we can simulate muddy or icy conditions. In mud, the player slows -// down faster. In ice, the player slows down more slowly. -// -// The amount of friction change is controlled by the length of a linedef -// with type 223. A length < 100 gives you mud. A length > 100 gives you ice. -// -// Also, each sector where these effects are to take place is given a -// new special type _______. Changing the type value at runtime allows -// these effects to be turned on or off. -// -// Sector boundaries present problems. The player should experience these -// friction changes only when his feet are touching the sector floor. At -// sector boundaries where floor height changes, the player can find -// himself still 'in' one sector, but with his feet at the floor level -// of the next sector (steps up or down). To handle this, Thinkers are used -// in icy/muddy sectors. These thinkers examine each object that is touching -// their sectors, looking for players whose feet are at the same level as -// their floors. Players satisfying this condition are given new friction -// values that are applied by the player movement code later. - -// -// killough 8/28/98: -// -// Completely redid code, which did not need thinkers, and which put a heavy -// drag on CPU. Friction is now a property of sectors, NOT objects inside -// them. All objects, not just players, are affected by it, if they touch -// the sector's floor. Code simpler and faster, only calling on friction -// calculations when an object needs friction considered, instead of doing -// friction calculations on every sector during every tic. -// -// Although this -might- ruin Boom demo sync involving friction, it's the only -// way, short of code explosion, to fix the original design bug. Fixing the -// design bug in Boom's original friction code, while maintaining demo sync -// under every conceivable circumstance, would double or triple code size, and -// would require maintenance of buggy legacy code which is only useful for old -// demos. Doom demos, which are more important IMO, are not affected by this -// change. -// -// [RH] On the other hand, since I've given up on trying to maintain demo -// sync between versions, these considerations aren't a big deal to me. -// -///////////////////////////// -// -// Initialize the sectors where friction is increased or decreased - -static void P_SpawnFriction(void) -{ - int i; - line_t *l = lines; - - for (i = 0 ; i < numlines ; i++,l++) - { - if (l->special == Sector_SetFriction) - { - int length; - - if (l->args[1]) - { // [RH] Allow setting friction amount from parameter - length = l->args[1] <= 200 ? l->args[1] : 200; - } - else - { - length = P_AproxDistance(l->dx,l->dy)>>FRACBITS; - } - - P_SetSectorFriction (l->args[0], length, false); - l->special = 0; - } - } -} - -void P_SetSectorFriction (int tag, int amount, bool alterFlag) -{ - int s; - fixed_t friction, movefactor; - - // An amount of 100 should result in a friction of - // ORIG_FRICTION (0xE800) - friction = (0x1EB8*amount)/0x80 + 0xD001; - - // killough 8/28/98: prevent odd situations - friction = clamp(friction, 0, FRACUNIT); - - // The following check might seem odd. At the time of movement, - // the move distance is multiplied by 'friction/0x10000', so a - // higher friction value actually means 'less friction'. - movefactor = FrictionToMoveFactor(friction); - - FSectorTagIterator itr(tag); - while ((s = itr.Next()) >= 0) - { - // killough 8/28/98: - // - // Instead of spawning thinkers, which are slow and expensive, - // modify the sector's own friction values. Friction should be - // a property of sectors, not objects which reside inside them. - // Original code scanned every object in every friction sector - // on every tic, adjusting its friction, putting unnecessary - // drag on CPU. New code adjusts friction of sector only once - // at level startup, and then uses this friction value. - - sectors[s].friction = friction; - sectors[s].movefactor = movefactor; - if (alterFlag) - { - // When used inside a script, the sectors' friction flags - // can be enabled and disabled at will. - if (friction == ORIG_FRICTION) - { - sectors[s].Flags &= ~SECF_FRICTION; - } - else - { - sectors[s].Flags |= SECF_FRICTION; - } - } - } -} - -// -// phares 3/12/98: End of friction effects -// -//////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////// -// -// PUSH/PULL EFFECT -// -// phares 3/20/98: Start of push/pull effects -// -// This is where push/pull effects are applied to objects in the sectors. -// -// There are four kinds of push effects -// -// 1) Pushing Away -// -// Pushes you away from a point source defined by the location of an -// MT_PUSH Thing. The force decreases linearly with distance from the -// source. This force crosses sector boundaries and is felt w/in a circle -// whose center is at the MT_PUSH. The force is felt only if the point -// MT_PUSH can see the target object. -// -// 2) Pulling toward -// -// Same as Pushing Away except you're pulled toward an MT_PULL point -// source. This force crosses sector boundaries and is felt w/in a circle -// whose center is at the MT_PULL. The force is felt only if the point -// MT_PULL can see the target object. -// -// 3) Wind -// -// Pushes you in a constant direction. Full force above ground, half -// force on the ground, nothing if you're below it (water). -// -// 4) Current -// -// Pushes you in a constant direction. No force above ground, full -// force if on the ground or below it (water). -// -// The magnitude of the force is controlled by the length of a controlling -// linedef. The force vector for types 3 & 4 is determined by the angle -// of the linedef, and is constant. -// -// For each sector where these effects occur, the sector special type has -// to have the PUSH_MASK bit set. If this bit is turned off by a switch -// at run-time, the effect will not occur. The controlling sector for -// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing. - - -#define PUSH_FACTOR 7 - -///////////////////////////// -// -// Add a push thinker to the thinker list - -DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle, - AActor *source, int affectee) -{ - m_Source = source; - m_Type = type; - if (l) - { - m_Xmag = l->dx>>FRACBITS; - m_Ymag = l->dy>>FRACBITS; - m_Magnitude = P_AproxDistance (m_Xmag, m_Ymag); - } - else - { // [RH] Allow setting magnitude and angle with parameters - ChangeValues (magnitude, angle); - } - if (source) // point source exist? - { - m_Radius = (m_Magnitude) << (FRACBITS+1); // where force goes to zero - m_X = m_Source->X(); - m_Y = m_Source->Y(); - } - m_Affectee = affectee; -} - -int DPusher::CheckForSectorMatch (EPusher type, int tag) -{ - if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag)) - return m_Affectee; - else - return -1; -} - - -///////////////////////////// -// -// T_Pusher looks for all objects that are inside the radius of -// the effect. -// -void DPusher::Tick () -{ - sector_t *sec; - AActor *thing; - msecnode_t *node; - int xspeed,yspeed; - int ht; - - if (!var_pushers) - return; - - sec = sectors + m_Affectee; - - // Be sure the special sector type is still turned on. If so, proceed. - // Else, bail out; the sector type has been changed on us. - - if (!(sec->Flags & SECF_PUSH)) - return; - - // For constant pushers (wind/current) there are 3 situations: - // - // 1) Affected Thing is above the floor. - // - // Apply the full force if wind, no force if current. - // - // 2) Affected Thing is on the ground. - // - // Apply half force if wind, full force if current. - // - // 3) Affected Thing is below the ground (underwater effect). - // - // Apply no force if wind, full force if current. - // - // Apply the effect to clipped players only for now. - // - // In Phase II, you can apply these effects to Things other than players. - // [RH] No Phase II, but it works with anything having MF2_WINDTHRUST now. - - if (m_Type == p_push) - { - // Seek out all pushable things within the force radius of this - // point pusher. Crosses sectors, so use blockmap. - - FBlockThingsIterator it(FBoundingBox(m_X, m_Y, m_Radius)); - AActor *thing; - - while ((thing = it.Next())) - { - // Normal ZDoom is based only on the WINDTHRUST flag, with the noclip cheat as an exemption. - bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP)); - - // MBF allows any sentient or shootable thing to be affected, but players with a fly cheat aren't. - if (compatflags & COMPATF_MBFMONSTERMOVE) - { - pusharound = ((pusharound || (thing->IsSentient()) || (thing->flags & MF_SHOOTABLE)) // Add categories here - && (!(thing->player && (thing->flags & (MF_NOGRAVITY))))); // Exclude flying players here - } - - if ((pusharound) ) - { - int sx = m_X; - int sy = m_Y; - int dist = thing->AproxDistance (sx, sy); - int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); - - // If speed <= 0, you're outside the effective radius. You also have - // to be able to see the push/pull source point. - - if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY))) - { - angle_t pushangle = thing->AngleTo(sx, sy); - if (m_Source->GetClass()->TypeName == NAME_PointPusher) - pushangle += ANG180; // away - pushangle >>= ANGLETOFINESHIFT; - thing->velx += FixedMul (speed, finecosine[pushangle]); - thing->vely += FixedMul (speed, finesine[pushangle]); - } - } - } - return; - } - - // constant pushers p_wind and p_current - - node = sec->touching_thinglist; // things touching this sector - for ( ; node ; node = node->m_snext) - { - thing = node->m_thing; - if (!(thing->flags2 & MF2_WINDTHRUST) || (thing->flags & MF_NOCLIP)) - continue; - - sector_t *hsec = sec->GetHeightSec(); - fixedvec3 pos = thing->PosRelative(sec); - if (m_Type == p_wind) - { - if (hsec == NULL) - { // NOT special water sector - if (thing->Z() > thing->floorz) // above ground - { - xspeed = m_Xmag; // full force - yspeed = m_Ymag; - } - else // on ground - { - xspeed = (m_Xmag)>>1; // half force - yspeed = (m_Ymag)>>1; - } - } - else // special water sector - { - ht = hsec->floorplane.ZatPoint(pos); - if (thing->Z() > ht) // above ground - { - xspeed = m_Xmag; // full force - yspeed = m_Ymag; - } - else if (thing->player->viewz < ht) // underwater - { - xspeed = yspeed = 0; // no force - } - else // wading in water - { - xspeed = (m_Xmag)>>1; // half force - yspeed = (m_Ymag)>>1; - } - } - } - else // p_current - { - const secplane_t *floor; - - if (hsec == NULL) - { // NOT special water sector - floor = &sec->floorplane; - } - else - { // special water sector - floor = &hsec->floorplane; - } - if (thing->Z() > floor->ZatPoint(pos)) - { // above ground - xspeed = yspeed = 0; // no force - } - else - { // on ground/underwater - xspeed = m_Xmag; // full force - yspeed = m_Ymag; - } - } - thing->velx += xspeed<<(FRACBITS-PUSH_FACTOR); - thing->vely += yspeed<<(FRACBITS-PUSH_FACTOR); - } -} - -///////////////////////////// -// -// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing, -// NULL otherwise. - -AActor *P_GetPushThing (int s) -{ - AActor* thing; - sector_t* sec; - - sec = sectors + s; - thing = sec->thinglist; - - while (thing && - thing->GetClass()->TypeName != NAME_PointPusher && - thing->GetClass()->TypeName != NAME_PointPuller) - { - thing = thing->snext; - } - return thing; -} - -///////////////////////////// -// -// Initialize the sectors where pushers are present -// - -static void P_SpawnPushers () -{ - int i; - line_t *l = lines; - int s; - - for (i = 0; i < numlines; i++, l++) - { - switch (l->special) - { - case Sector_SetWind: // wind - { - FSectorTagIterator itr(l->args[0]); - while ((s = itr.Next()) >= 0) - new DPusher(DPusher::p_wind, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s); - l->special = 0; - break; - } - - case Sector_SetCurrent: // current - { - FSectorTagIterator itr(l->args[0]); - while ((s = itr.Next()) >= 0) - new DPusher(DPusher::p_current, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s); - l->special = 0; - break; - } - - case PointPush_SetForce: // push/pull - if (l->args[0]) { // [RH] Find thing by sector - FSectorTagIterator itr(l->args[0]); - while ((s = itr.Next()) >= 0) - { - AActor *thing = P_GetPushThing (s); - if (thing) { // No MT_P* means no effect - // [RH] Allow narrowing it down by tid - if (!l->args[1] || l->args[1] == thing->tid) - new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], - 0, thing, s); - } - } - } else { // [RH] Find thing by tid - AActor *thing; - FActorIterator iterator (l->args[1]); - - while ( (thing = iterator.Next ()) ) - { - if (thing->GetClass()->TypeName == NAME_PointPusher || - thing->GetClass()->TypeName == NAME_PointPuller) - { - new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], - 0, thing, int(thing->Sector - sectors)); - } - } - } - l->special = 0; - break; - } - } -} - -// -// phares 3/20/98: End of Pusher effects -// -//////////////////////////////////////////////////////////////////////////// - -void sector_t::AdjustFloorClip () const -{ - msecnode_t *node; - - for (node = touching_thinglist; node; node = node->m_snext) - { - if (node->m_thing->flags2 & MF2_FLOORCLIP) - { - node->m_thing->AdjustFloorClip(); - } - } -} +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// +// $Log:$ +// +// DESCRIPTION: +// Implements special effects: +// Texture animation, height or lighting changes +// according to adjacent sectors, respective +// utility functions, etc. +// Line Tag handling. Line and Sector triggers. +// Implements donut linedef triggers +// Initializes and implements BOOM linedef triggers for +// Scrollers/Conveyors +// Friction +// Wind/Current +// +//----------------------------------------------------------------------------- + + +#include + +#include "templates.h" +#include "doomdef.h" +#include "doomstat.h" +#include "d_event.h" +#include "gstrings.h" + +#include "i_system.h" +#include "m_argv.h" +#include "m_random.h" +#include "m_bbox.h" +#include "w_wad.h" + +#include "p_local.h" +#include "p_spec.h" +#include "p_blockmap.h" +#include "p_lnspec.h" +#include "p_terrain.h" +#include "p_acs.h" +#include "p_3dmidtex.h" + +#include "g_game.h" + +#include "s_sound.h" +#include "sc_man.h" +#include "gi.h" +#include "statnums.h" +#include "g_level.h" +#include "v_font.h" +#include "a_sharedglobal.h" +#include "farchive.h" +#include "a_keys.h" +#include "c_dispatch.h" +#include "r_sky.h" +#include "d_player.h" +#include "p_maputl.h" +#include "p_blockmap.h" +#ifndef NO_EDATA +#include "edata.h" +#endif + +// State. +#include "r_state.h" + +#include "c_console.h" + +#include "r_data/r_interpolate.h" + +static FRandom pr_playerinspecialsector ("PlayerInSpecialSector"); + +EXTERN_CVAR(Bool, cl_predict_specials) + +IMPLEMENT_POINTY_CLASS (DScroller) + DECLARE_POINTER (m_Interpolations[0]) + DECLARE_POINTER (m_Interpolations[1]) + DECLARE_POINTER (m_Interpolations[2]) +END_POINTERS + +IMPLEMENT_POINTY_CLASS (DPusher) + DECLARE_POINTER (m_Source) +END_POINTERS + +inline FArchive &operator<< (FArchive &arc, DScroller::EScrollType &type) +{ + BYTE val = (BYTE)type; + arc << val; + type = (DScroller::EScrollType)val; + return arc; +} + +DScroller::DScroller () +{ +} + +void DScroller::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + arc << m_Type + << m_dx << m_dy + << m_Affectee + << m_Control + << m_LastHeight + << m_vdx << m_vdy + << m_Accel + << m_Parts + << m_Interpolations[0] + << m_Interpolations[1] + << m_Interpolations[2]; +} + +DPusher::DPusher () +{ +} + +inline FArchive &operator<< (FArchive &arc, DPusher::EPusher &type) +{ + BYTE val = (BYTE)type; + arc << val; + type = (DPusher::EPusher)val; + return arc; +} + +void DPusher::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + arc << m_Type + << m_Source + << m_Xmag + << m_Ymag + << m_Magnitude + << m_Radius + << m_X + << m_Y + << m_Affectee; +} + +// killough 3/7/98: Initialize generalized scrolling +static void P_SpawnScrollers(); +static void P_SpawnFriction (); // phares 3/16/98 +static void P_SpawnPushers (); // phares 3/20/98 + + +// [RH] Check dmflags for noexit and respond accordingly +bool CheckIfExitIsGood (AActor *self, level_info_t *info) +{ + cluster_info_t *cluster; + + // The world can always exit itself. + if (self == NULL) + return true; + + // We must kill all monsters to exit the level. + if ((dmflags2 & DF2_KILL_MONSTERS) && level.killed_monsters != level.total_monsters) + return false; + + // Is this a deathmatch game and we're not allowed to exit? + if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT)) + { + P_DamageMobj (self, self, self, TELEFRAG_DAMAGE, NAME_Exit); + return false; + } + // Is this a singleplayer game and the next map is part of the same hub and we're dead? + if (self->health <= 0 && + !multiplayer && + info != NULL && + info->cluster == level.cluster && + (cluster = FindClusterInfo(level.cluster)) != NULL && + cluster->flags & CLUSTER_HUB) + { + return false; + } + if (deathmatch && gameaction != ga_completed) + { + Printf ("%s exited the level.\n", self->player->userinfo.GetName()); + } + return true; +} + + +// +// UTILITIES +// + +//============================================================================ +// +// P_ActivateLine +// +//============================================================================ + +bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType, fixedvec3 *optpos) +{ + int lineActivation; + INTBOOL repeat; + INTBOOL buttonSuccess; + BYTE special; + + if (!P_TestActivateLine (line, mo, side, activationType, optpos)) + { + return false; + } + bool remote = (line->special != 7 && line->special != 8 && (line->special < 11 || line->special > 14)); + if (line->locknumber > 0 && !P_CheckKeys (mo, line->locknumber, remote)) return false; + lineActivation = line->activation; + repeat = line->flags & ML_REPEAT_SPECIAL; + buttonSuccess = false; + buttonSuccess = P_ExecuteSpecial(line->special, + line, mo, side == 1, line->args[0], + line->args[1], line->args[2], + line->args[3], line->args[4]); + + special = line->special; + if (!repeat && buttonSuccess) + { // clear the special on non-retriggerable lines + line->special = 0; + } + + if (buttonSuccess) + { + if (activationType == SPAC_Use || activationType == SPAC_Impact || activationType == SPAC_Push) + { + P_ChangeSwitchTexture (line->sidedef[0], repeat, special); + } + } + // some old WADs use this method to create walls that change the texture when shot. + else if (activationType == SPAC_Impact && // only for shootable triggers + (level.flags2 & LEVEL2_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack! + !repeat && // only non-repeatable triggers + (specialGeneric_Crusher) && // not for Boom's generalized linedefs + special && // not for lines without a special + tagManager.LineHasID(line, line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0] + line->args[0] && // only if there's a tag (which is stored in the first arg) + P_FindFirstSectorFromTag (line->args[0]) == -1) // only if no sector is tagged to this linedef + { + P_ChangeSwitchTexture (line->sidedef[0], repeat, special); + line->special = 0; + } +// end of changed code + if (developer && buttonSuccess) + { + Printf ("Line special %d activated on line %i\n", special, int(line - lines)); + } + return true; +} + +//============================================================================ +// +// P_TestActivateLine +// +//============================================================================ + +bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType, fixedvec3 *optpos) +{ + int lineActivation = line->activation; + + if (line->flags & ML_FIRSTSIDEONLY && side == 1) + { + return false; + } + + if (lineActivation & SPAC_UseThrough) + { + lineActivation |= SPAC_Use; + } + else if (line->special == Teleport && + (lineActivation & SPAC_Cross) && + activationType == SPAC_PCross && + mo != NULL && + mo->flags & MF_MISSILE) + { // Let missiles use regular player teleports + lineActivation |= SPAC_PCross; + } + // BOOM's generalized line types that allow monster use can actually be + // activated by anything except projectiles. + if (lineActivation & SPAC_AnyCross) + { + lineActivation |= SPAC_Cross|SPAC_MCross; + } + if (activationType == SPAC_Use || activationType == SPAC_UseBack) + { + if (!P_CheckSwitchRange(mo, line, side, optpos)) + { + return false; + } + } + + if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS) + { + return true; + } + if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL) + { + return true; + } + if ((lineActivation & activationType) == 0) + { + if (activationType != SPAC_MCross || lineActivation != SPAC_Cross) + { + return false; + } + } + if (activationType == SPAC_AnyCross && (lineActivation & activationType)) + { + return true; + } + if (mo && !mo->player && + !(mo->flags & MF_MISSILE) && + !(line->flags & ML_MONSTERSCANACTIVATE) && + (activationType != SPAC_MCross || (!(lineActivation & SPAC_MCross)))) + { + // [RH] monsters' ability to activate this line depends on its type + // In Hexen, only MCROSS lines could be activated by monsters. With + // lax activation checks, monsters can also activate certain lines + // even without them being marked as monster activate-able. This is + // the default for non-Hexen maps in Hexen format. + if (!(level.flags2 & LEVEL2_LAXMONSTERACTIVATION)) + { + return false; + } + if ((activationType == SPAC_Use || activationType == SPAC_Push) + && (line->flags & ML_SECRET)) + return false; // never open secret doors + + bool noway = true; + + switch (activationType) + { + case SPAC_Use: + case SPAC_Push: + switch (line->special) + { + case Door_Raise: + if (line->args[0] == 0 && line->args[1] < 64) + noway = false; + break; + case Teleport: + case Teleport_NoFog: + noway = false; + } + break; + + case SPAC_MCross: + if (!(lineActivation & SPAC_MCross)) + { + switch (line->special) + { + case Door_Raise: + if (line->args[1] >= 64) + { + break; + } + case Teleport: + case Teleport_NoFog: + case Teleport_Line: + case Plat_DownWaitUpStayLip: + case Plat_DownWaitUpStay: + noway = false; + } + } + else noway = false; + break; + + default: + noway = false; + } + return !noway; + } + if (activationType == SPAC_MCross && !(lineActivation & SPAC_MCross) && + !(line->flags & ML_MONSTERSCANACTIVATE)) + { + return false; + } + return true; +} + +//============================================================================ +// +// P_PredictLine +// +//============================================================================ + +bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType) +{ + int lineActivation; + INTBOOL buttonSuccess; + BYTE special; + + // Only predict a very specifc section of specials + if (line->special != Teleport_Line && + line->special != Teleport) + { + return false; + } + + if (!P_TestActivateLine(line, mo, side, activationType) || !cl_predict_specials) + { + return false; + } + + if (line->locknumber > 0) return false; + lineActivation = line->activation; + buttonSuccess = false; + buttonSuccess = P_ExecuteSpecial(line->special, + line, mo, side == 1, line->args[0], + line->args[1], line->args[2], + line->args[3], line->args[4]); + + special = line->special; + + // end of changed code + if (developer && buttonSuccess) + { + Printf("Line special %d predicted on line %i\n", special, int(line - lines)); + } + return true; +} + +// +// P_PlayerInSpecialSector +// Called every tic frame +// that the player origin is in a special sector +// +void P_PlayerInSpecialSector (player_t *player, sector_t * sector) +{ + if (sector == NULL) + { + // Falling, not all the way down yet? + sector = player->mo->Sector; + if (player->mo->Z() != sector->LowestFloorAt(player->mo) + && !player->mo->waterlevel) + { + return; + } + } + + // Has hit ground. + AInventory *ironfeet; + + // [RH] Apply any customizable damage + if (sector->damageamount > 0) + { + // Allow subclasses. Better would be to implement it as armor and let that reduce + // the damage as part of the normal damage procedure. Unfortunately, I don't have + // different damage types yet, so that's not happening for now. + for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) + { + if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) + break; + } + + if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE; + if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) + { + if (sector->Flags & SECF_HAZARD) + { + player->hazardcount += sector->damageamount; + player->hazardtype = sector->damagetype; + player->hazardinterval = sector->damageinterval; + } + else if (level.time % sector->damageinterval == 0) + { + if (!(player->cheats & (CF_GODMODE|CF_GODMODE2))) P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); + if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) + { + G_ExitLevel(0, false); + } + if (sector->Flags & SECF_DMGTERRAINFX) + { + P_HitWater(player->mo, player->mo->Sector, INT_MIN, INT_MIN, INT_MIN, false, true, true); + } + } + } + } + else if (sector->damageamount < 0) + { + if (level.time % sector->damageinterval == 0) + { + P_GiveBody(player->mo, -sector->damageamount, 100); + } + } + + if (sector->isSecret()) + { + sector->ClearSecret(); + P_GiveSecret(player->mo, true, true, int(sector - sectors)); + } +} + +//============================================================================ +// +// P_SectorDamage +// +//============================================================================ + +static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, PClassActor *protectClass, int flags) +{ + if (!(actor->flags & MF_SHOOTABLE)) + return; + + if (!(flags & DAMAGE_NONPLAYERS) && actor->player == NULL) + return; + + if (!(flags & DAMAGE_PLAYERS) && actor->player != NULL) + return; + + if (!(flags & DAMAGE_IN_AIR) && actor->Z() != sec->floorplane.ZatPoint(actor) && !actor->waterlevel) + return; + + if (protectClass != NULL) + { + if (actor->FindInventory(protectClass, !!(flags & DAMAGE_SUBCLASSES_PROTECT))) + return; + } + + P_DamageMobj (actor, NULL, NULL, amount, type); +} + +void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass, int flags) +{ + FSectorTagIterator itr(tag); + int secnum; + while ((secnum = itr.Next()) >= 0) + { + AActor *actor, *next; + sector_t *sec = §ors[secnum]; + + // Do for actors in this sector. + for (actor = sec->thinglist; actor != NULL; actor = next) + { + next = actor->snext; + DoSectorDamage(actor, sec, amount, type, protectClass, flags); + } + // If this is a 3D floor control sector, also do for anything in/on + // those 3D floors. + for (unsigned i = 0; i < sec->e->XFloor.attached.Size(); ++i) + { + sector_t *sec2 = sec->e->XFloor.attached[i]; + + for (actor = sec2->thinglist; actor != NULL; actor = next) + { + next = actor->snext; + // Only affect actors touching the 3D floor + fixed_t z1 = sec->floorplane.ZatPoint(actor); + fixed_t z2 = sec->ceilingplane.ZatPoint(actor); + if (z2 < z1) + { + // Account for Vavoom-style 3D floors + fixed_t zz = z1; + z1 = z2; + z2 = zz; + } + if (actor->Z() + actor->height > z1) + { + // If DAMAGE_IN_AIR is used, anything not beneath the 3D floor will be + // damaged (so, anything touching it or above it). Other 3D floors between + // the actor and this one will not stop this effect. + if ((flags & DAMAGE_IN_AIR) || actor->Z() <= z2) + { + // Here we pass the DAMAGE_IN_AIR flag to disable the floor check, since it + // only works with the real sector's floor. We did the appropriate height checks + // for 3D floors already. + DoSectorDamage(actor, NULL, amount, type, protectClass, flags | DAMAGE_IN_AIR); + } + } + } + } + } +} + +//============================================================================ +// +// P_GiveSecret +// +//============================================================================ + +CVAR(Bool, showsecretsector, false, 0) +CVAR(Bool, cl_showsecretmessage, true, CVAR_ARCHIVE) + +void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum) +{ + if (actor != NULL) + { + if (actor->player != NULL) + { + actor->player->secretcount++; + } + if (cl_showsecretmessage && actor->CheckLocalView(consoleplayer)) + { + if (printmessage) + { + if (!showsecretsector || sectornum < 0) C_MidPrint(SmallFont, GStrings["SECRETMESSAGE"]); + else + { + FString s = GStrings["SECRETMESSAGE"]; + s.AppendFormat(" (Sector %d)", sectornum); + C_MidPrint(SmallFont, s); + } + } + if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM); + } + } + level.found_secrets++; +} + +//============================================================================ +// +// P_PlayerOnSpecialFlat +// +//============================================================================ + +void P_PlayerOnSpecialFlat (player_t *player, int floorType) +{ + if (Terrains[floorType].DamageAmount && + !(level.time & Terrains[floorType].DamageTimeMask)) + { + AInventory *ironfeet = NULL; + + if (Terrains[floorType].AllowProtection) + { + for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) + { + if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) + break; + } + } + + int damage = 0; + if (ironfeet == NULL) + { + damage = P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount, + Terrains[floorType].DamageMOD); + } + if (damage > 0 && Terrains[floorType].Splash != -1) + { + S_Sound (player->mo, CHAN_AUTO, + Splashes[Terrains[floorType].Splash].NormalSplashSound, 1, + ATTN_IDLE); + } + } +} + + + +// +// P_UpdateSpecials +// Animate planes, scroll walls, etc. +// +EXTERN_CVAR (Float, timelimit) + +void P_UpdateSpecials () +{ + // LEVEL TIMER + if (deathmatch && timelimit) + { + if (level.maptime >= (int)(timelimit * TICRATE * 60)) + { + Printf ("%s\n", GStrings("TXT_TIMELIMIT")); + G_ExitLevel(0, false); + } + } +} + + + +// +// SPECIAL SPAWNING +// + +CUSTOM_CVAR (Bool, forcewater, false, CVAR_ARCHIVE|CVAR_SERVERINFO) +{ + if (gamestate == GS_LEVEL) + { + int i; + + for (i = 0; i < numsectors; i++) + { + sector_t *hsec = sectors[i].GetHeightSec(); + if (hsec && + !(sectors[i].heightsec->MoreFlags & SECF_UNDERWATER)) + { + if (self) + { + hsec->MoreFlags |= SECF_FORCEDUNDERWATER; + } + else + { + hsec->MoreFlags &= ~SECF_FORCEDUNDERWATER; + } + } + } + } +} + +class DLightTransfer : public DThinker +{ + DECLARE_CLASS (DLightTransfer, DThinker) + + DLightTransfer() {} +public: + DLightTransfer (sector_t *srcSec, int target, bool copyFloor); + void Serialize (FArchive &arc); + void Tick (); + +protected: + static void DoTransfer (int level, int target, bool floor); + + sector_t *Source; + int TargetTag; + bool CopyFloor; + short LastLight; +}; + +IMPLEMENT_CLASS (DLightTransfer) + +void DLightTransfer::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + if (SaveVersion < 3223) + { + BYTE bytelight; + arc << bytelight; + LastLight = bytelight; + } + else + { + arc << LastLight; + } + arc << Source << TargetTag << CopyFloor; +} + +DLightTransfer::DLightTransfer (sector_t *srcSec, int target, bool copyFloor) +{ + int secnum; + + Source = srcSec; + TargetTag = target; + CopyFloor = copyFloor; + DoTransfer (LastLight = srcSec->lightlevel, target, copyFloor); + + if (copyFloor) + { + FSectorTagIterator itr(target); + while ((secnum = itr.Next()) >= 0) + sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING); + } + else + { + FSectorTagIterator itr(target); + while ((secnum = itr.Next()) >= 0) + sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING); + } + ChangeStatNum (STAT_LIGHTTRANSFER); +} + +void DLightTransfer::Tick () +{ + int light = Source->lightlevel; + + if (light != LastLight) + { + LastLight = light; + DoTransfer (light, TargetTag, CopyFloor); + } +} + +void DLightTransfer::DoTransfer (int level, int target, bool floor) +{ + int secnum; + + if (floor) + { + FSectorTagIterator itr(target); + while ((secnum = itr.Next()) >= 0) + sectors[secnum].SetPlaneLight(sector_t::floor, level); + } + else + { + FSectorTagIterator itr(target); + while ((secnum = itr.Next()) >= 0) + sectors[secnum].SetPlaneLight(sector_t::ceiling, level); + } +} + + +class DWallLightTransfer : public DThinker +{ + enum + { + WLF_SIDE1=1, + WLF_SIDE2=2, + WLF_NOFAKECONTRAST=4 + }; + + DECLARE_CLASS (DWallLightTransfer, DThinker) + DWallLightTransfer() {} +public: + DWallLightTransfer (sector_t *srcSec, int target, BYTE flags); + void Serialize (FArchive &arc); + void Tick (); + +protected: + static void DoTransfer (short level, int target, BYTE flags); + + sector_t *Source; + int TargetID; + short LastLight; + BYTE Flags; +}; + +IMPLEMENT_CLASS (DWallLightTransfer) + +void DWallLightTransfer::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + if (SaveVersion < 3223) + { + BYTE bytelight; + arc << bytelight; + LastLight = bytelight; + } + else + { + arc << LastLight; + } + arc << Source << TargetID << Flags; +} + +DWallLightTransfer::DWallLightTransfer (sector_t *srcSec, int target, BYTE flags) +{ + int linenum; + int wallflags; + + Source = srcSec; + TargetID = target; + Flags = flags; + DoTransfer (LastLight = srcSec->GetLightLevel(), target, Flags); + + if (!(flags & WLF_NOFAKECONTRAST)) + { + wallflags = WALLF_ABSLIGHTING; + } + else + { + wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST; + } + + FLineIdIterator itr(target); + while ((linenum = itr.Next()) >= 0) + { + if (flags & WLF_SIDE1 && lines[linenum].sidedef[0] != NULL) + { + lines[linenum].sidedef[0]->Flags |= wallflags; + } + + if (flags & WLF_SIDE2 && lines[linenum].sidedef[1] != NULL) + { + lines[linenum].sidedef[1]->Flags |= wallflags; + } + } + ChangeStatNum(STAT_LIGHTTRANSFER); +} + +void DWallLightTransfer::Tick () +{ + short light = sector_t::ClampLight(Source->lightlevel); + + if (light != LastLight) + { + LastLight = light; + DoTransfer (light, TargetID, Flags); + } +} + +void DWallLightTransfer::DoTransfer (short lightlevel, int target, BYTE flags) +{ + int linenum; + + FLineIdIterator itr(target); + while ((linenum = itr.Next()) >= 0) + { + line_t *line = &lines[linenum]; + + if (flags & WLF_SIDE1 && line->sidedef[0] != NULL) + { + line->sidedef[0]->SetLight(lightlevel); + } + + if (flags & WLF_SIDE2 && line->sidedef[1] != NULL) + { + line->sidedef[1]->SetLight(lightlevel); + } + } +} + +//----------------------------------------------------------------------------- +// +// Portals +// +//----------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Upper stacks go in the top sector. Lower stacks go in the bottom sector. + +static void SetupFloorPortal (AStackPoint *point) +{ + NActorIterator it (NAME_LowerStackLookOnly, point->tid); + sector_t *Sector = point->Sector; + ASkyViewpoint *skyv = static_cast(it.Next()); + Sector->SkyBoxes[sector_t::floor] = skyv; + if (skyv != NULL && skyv->bAlways) + { + skyv->Mate = point; + if (Sector->GetAlpha(sector_t::floor) == OPAQUE) + Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255)); + } +} + +static void SetupCeilingPortal (AStackPoint *point) +{ + NActorIterator it (NAME_UpperStackLookOnly, point->tid); + sector_t *Sector = point->Sector; + ASkyViewpoint *skyv = static_cast(it.Next()); + Sector->SkyBoxes[sector_t::ceiling] = skyv; + if (skyv != NULL && skyv->bAlways) + { + skyv->Mate = point; + if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE) + Sector->SetAlpha(sector_t::ceiling, Scale(point->args[0], OPAQUE, 255)); + } +} + +void P_SetupPortals() +{ + TThinkerIterator it; + AStackPoint *pt; + TArray points; + + while ((pt = it.Next())) + { + FName nm = pt->GetClass()->TypeName; + if (nm == NAME_UpperStackLookOnly) + { + SetupFloorPortal(pt); + } + else if (nm == NAME_LowerStackLookOnly) + { + SetupCeilingPortal(pt); + } + pt->special1 = 0; + points.Push(pt); + } +} + +static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_t alpha) +{ + // plane: 0=floor, 1=ceiling, 2=both + if (plane > 0) + { + if (sector->SkyBoxes[sector_t::ceiling] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::ceiling])->bAlways) + { + sector->SkyBoxes[sector_t::ceiling] = portal; + if (sector->GetAlpha(sector_t::ceiling) == OPAQUE) + sector->SetAlpha(sector_t::ceiling, alpha); + + if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum); + } + } + if (plane == 2 || plane == 0) + { + if (sector->SkyBoxes[sector_t::floor] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::floor])->bAlways) + { + sector->SkyBoxes[sector_t::floor] = portal; + } + if (sector->GetAlpha(sector_t::floor) == OPAQUE) + sector->SetAlpha(sector_t::floor, alpha); + + if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum); + } +} + +static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t alpha, bool tolines) +{ + int s; + FSectorTagIterator itr(sectortag); + while ((s = itr.Next()) >= 0) + { + SetPortal(§ors[s], plane, origin, alpha); + } + + for (int j=0;j= 0) + { + SetPortal(§ors[s], plane, origin, alpha); + } + } + } + if (tolines && lines[j].special == Sector_SetPortal && + lines[j].args[1] == 5 && + lines[j].args[3] == sectortag) + { + if (lines[j].args[0] == 0) + { + lines[j].skybox = origin; + } + else + { + FLineIdIterator itr(lines[j].args[0]); + while ((s = itr.Next()) >= 0) + { + lines[s].skybox = origin; + } + } + } + } +} + +void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha, int linked) +{ + if (plane < 0 || plane > 2 || (linked && plane == 2)) return; + for (int i=0;iv1->x) + SQWORD(line->v2->x)) >> 1); + fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1); + fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1); + fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1); + fixed_t z = linked ? line->frontsector->planes[plane].TexZ : 0; // the map's sector height defines the portal plane for linked portals + + fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255); + + AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE); + AStackPoint *reference = Spawn(x2, y2, 0, NO_REPLACE); + reference->special1 = linked ? SKYBOX_LINKEDPORTAL : SKYBOX_PORTAL; + anchor->special1 = SKYBOX_ANCHOR; + // store the portal displacement in the unused scaleX/Y members of the portal reference actor. + anchor->scaleX = -(reference->scaleX = x2 - x1); + anchor->scaleY = -(reference->scaleY = y2 - y1); + anchor->threshold = reference->threshold = z; + + reference->Mate = anchor; + anchor->Mate = reference; + + // This is so that the renderer can distinguish these portals from + // the ones spawned with the '*StackLookOnly' things. + reference->flags |= MF_JUSTATTACKED; + anchor->flags |= MF_JUSTATTACKED; + + CopyPortal(sectortag, plane, reference, alpha, false); + return; + } + } +} + +// This searches the viewpoint's sector +// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors. +void P_SpawnSkybox(ASkyViewpoint *origin) +{ + sector_t *Sector = origin->Sector; + if (Sector == NULL) + { + Printf("Sector not initialized for SkyCamCompat\n"); + origin->Sector = Sector = P_PointInSector(origin->X(), origin->Y()); + } + if (Sector) + { + line_t * refline = NULL; + for (short i = 0; i < Sector->linecount; i++) + { + refline = Sector->lines[i]; + if (refline->special == Sector_SetPortal && refline->args[1] == 2) + { + // We found the setup linedef for this skybox, so let's use it for our init. + CopyPortal(refline->args[0], refline->args[2], origin, 0, true); + return; + } + } + } +} + + + +// +// P_SetSectorDamage +// +// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties +// + +static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags) +{ + // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials. + if (sector->damageamount == 0) + { + sector->damageamount = damage; + sector->damageinterval = MAX(1, interval); + sector->leakydamage = leakchance; + sector->damagetype = type; + sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS); + } +} + +// +// P_InitSectorSpecial +// +// Sets up everything derived from 'sector->special' for one sector +// ('fromload' is necessary to allow conversion upon savegame load.) +// + +void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) +{ + // [RH] All secret sectors are marked with a BOOM-ish bitfield + if (sector->special & SECRET_MASK) + { + sector->Flags |= SECF_SECRET | SECF_WASSECRET; + level.total_secrets++; + } + if (sector->special & FRICTION_MASK) + { + sector->Flags |= SECF_FRICTION; + } + if (sector->special & PUSH_MASK) + { + sector->Flags |= SECF_PUSH; + } + if ((sector->special & DAMAGE_MASK) == 0x100) + { + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x200) + { + P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x300) + { + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + } + sector->special &= 0xff; + + // [RH] Normal DOOM special or BOOM specialized? + bool keepspecial = false; + switch (sector->special) + { + case Light_Phased: + if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); + break; + + // [RH] Hexen-like phased lighting + case LightSequenceStart: + if (!nothinkers) new DPhased (sector); + break; + + case dLight_Flicker: + if (!nothinkers) new DLightFlash (sector); + break; + + case dLight_StrobeFast: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + break; + + case dLight_StrobeSlow: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); + break; + + case dLight_Strobe_Hurt: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + break; + + case dDamage_Hellslime: + P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + break; + + case dDamage_Nukage: + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); + break; + + case dLight_Glow: + if (!nothinkers) new DGlow (sector); + break; + + case dSector_DoorCloseIn30: + new DDoor(sector, DDoor::doorWaitClose, FRACUNIT * 2, 0, 0, 30 * TICRATE); + break; + + case dDamage_End: + P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL); + break; + + case dLight_StrobeSlowSync: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); + break; + + case dLight_StrobeFastSync: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); + break; + + case dSector_DoorRaiseIn5Mins: + new DDoor (sector, DDoor::doorWaitRaise, 2*FRACUNIT, TICRATE*30/7, 5*60*TICRATE, 0); + break; + + case dFriction_Low: + sector->friction = FRICTION_LOW; + sector->movefactor = 0x269; + sector->Flags |= SECF_FRICTION; + break; + + case dDamage_SuperHellslime: + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + break; + + case dLight_FireFlicker: + if (!nothinkers) new DFireFlicker (sector); + break; + + case dDamage_LavaWimpy: + P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + break; + + case dDamage_LavaHefty: + P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + break; + + case dScroll_EastLavaDamage: + P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + if (!nothinkers) + { + new DStrobe(sector, STROBEBRIGHT, FASTDARK, false); + new DScroller(DScroller::sc_floor, -((FRACUNIT / 2) << 3), + 0, -1, int(sector - sectors), 0); + } + keepspecial = true; + break; + + case hDamage_Sludge: + P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0); + break; + + case sLight_Strobe_Hurt: + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + break; + + case sDamage_Hellslime: + P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD); + break; + + case Damage_InstantDeath: + // Strife's instant death sector + P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0); + break; + + case sDamage_SuperHellslime: + P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD); + break; + + case Sector_Hidden: + sector->MoreFlags |= SECF_HIDDEN; + break; + + case Sector_Heal: + // CoD's healing sector + P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0); + break; + + case Sky2: + sector->sky = PL_SKYFLAT; + break; + + default: + if (sector->special >= Scroll_North_Slow && + sector->special <= Scroll_SouthWest_Fast) + { // Hexen scroll special + static const char hexenScrollies[24][2] = + { + { 0, 1 }, { 0, 2 }, { 0, 4 }, + { -1, 0 }, { -2, 0 }, { -4, 0 }, + { 0, -1 }, { 0, -2 }, { 0, -4 }, + { 1, 0 }, { 2, 0 }, { 4, 0 }, + { 1, 1 }, { 2, 2 }, { 4, 4 }, + { -1, 1 }, { -2, 2 }, { -4, 4 }, + { -1, -1 }, { -2, -2 }, { -4, -4 }, + { 1, -1 }, { 2, -2 }, { 4, -4 } + }; + + + int i = sector->special - Scroll_North_Slow; + fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); + fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); + if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); + } + else if (sector->special >= Carry_East5 && + sector->special <= Carry_East35) + { // Heretic scroll special + // Only east scrollers also scroll the texture + if (!nothinkers) new DScroller (DScroller::sc_floor, + (-FRACUNIT/2)<<(sector->special - Carry_East5), + 0, -1, int(sector-sectors), 0); + } + keepspecial = true; + break; + } + if (!keepspecial) sector->special = 0; +} + +// +// P_SpawnSpecials +// +// After the map has been loaded, scan for specials that spawn thinkers +// + +void P_SpawnSpecials (void) +{ + sector_t *sector; + int i; + + P_SetupPortals(); + + // Init special SECTORs. + sector = sectors; + + for (i = 0; i < numsectors; i++, sector++) + { + if (sector->special == 0) + continue; + + P_InitSectorSpecial(sector, sector->special, false); + } + +#ifndef NO_EDATA + ProcessEDSectors(); +#endif + + + // Init other misc stuff + + P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers + P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs + P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs + + TThinkerIterator it2; + ASkyCamCompat *pt2; + while ((pt2 = it2.Next())) + { + P_SpawnSkybox(pt2); + } + + for (i = 0; i < numlines; i++) + { + switch (lines[i].special) + { + int s; + sector_t *sec; + + // killough 3/7/98: + // support for drawn heights coming from different sector + case Transfer_Heights: + { + sec = lines[i].frontsector; + if (lines[i].args[1] & 2) + { + sec->MoreFlags |= SECF_FAKEFLOORONLY; + } + if (lines[i].args[1] & 4) + { + sec->MoreFlags |= SECF_CLIPFAKEPLANES; + } + if (lines[i].args[1] & 8) + { + sec->MoreFlags |= SECF_UNDERWATER; + } + else if (forcewater) + { + sec->MoreFlags |= SECF_FORCEDUNDERWATER; + } + if (lines[i].args[1] & 16) + { + sec->MoreFlags |= SECF_IGNOREHEIGHTSEC; + } + if (lines[i].args[1] & 32) + { + sec->MoreFlags |= SECF_NOFAKELIGHT; + } + FSectorTagIterator itr(lines[i].args[0]); + while ((s = itr.Next()) >= 0) + { + sectors[s].heightsec = sec; + sec->e->FakeFloor.Sectors.Push(§ors[s]); + sectors[s].AdjustFloorClip(); + } + break; + } + + // killough 3/16/98: Add support for setting + // floor lighting independently (e.g. lava) + case Transfer_FloorLight: + new DLightTransfer (lines[i].frontsector, lines[i].args[0], true); + break; + + // killough 4/11/98: Add support for setting + // ceiling lighting independently + case Transfer_CeilingLight: + new DLightTransfer (lines[i].frontsector, lines[i].args[0], false); + break; + + // [Graf Zahl] Add support for setting lighting + // per wall independently + case Transfer_WallLight: + new DWallLightTransfer (lines[i].frontsector, lines[i].args[0], lines[i].args[1]); + break; + + case Sector_Attach3dMidtex: + P_Attach3dMidtexLinesToSector(lines[i].frontsector, lines[i].args[0], lines[i].args[1], !!lines[i].args[2]); + break; + + case Sector_SetLink: + if (lines[i].args[0] == 0) + { + P_AddSectorLinks(lines[i].frontsector, lines[i].args[1], lines[i].args[2], lines[i].args[3]); + } + break; + + case Sector_SetPortal: + // arg 0 = sector tag + // arg 1 = type + // - 0: normal (handled here) + // - 1: copy (handled by the portal they copy) + // - 2: EE-style skybox (handled by the camera object) + // - 3: EE-style flat portal (GZDoom HW renderer only for now) + // - 4: EE-style horizon portal (GZDoom HW renderer only for now) + // - 5: copy portal to line (GZDoom HW renderer only for now) + // - 6: linked portal + // other values reserved for later use + // arg 2 = 0:floor, 1:ceiling, 2:both + // arg 3 = 0: anchor, 1: reference line + // arg 4 = for the anchor only: alpha + if ((lines[i].args[1] == 0 || lines[i].args[1] == 6) && lines[i].args[3] == 0) + { + P_SpawnPortal(&lines[i], lines[i].args[0], lines[i].args[2], lines[i].args[4], lines[i].args[1]); + } + else if (lines[i].args[1] == 3 || lines[i].args[1] == 4) + { + line_t *line = &lines[i]; + ASkyViewpoint *origin = Spawn(0, 0, 0, NO_REPLACE); + origin->Sector = line->frontsector; + origin->special1 = line->args[1] == 3? SKYBOX_PLANE:SKYBOX_HORIZON; + + CopyPortal(line->args[0], line->args[2], origin, 0, true); + } + break; + + case Line_SetPortal: + P_SpawnLinePortal(&lines[i]); + break; + + // [RH] ZDoom Static_Init settings + case Static_Init: + switch (lines[i].args[1]) + { + case Init_Gravity: + { + float grav = ((float)P_AproxDistance (lines[i].dx, lines[i].dy)) / (FRACUNIT * 100.0f); + FSectorTagIterator itr(lines[i].args[0]); + while ((s = itr.Next()) >= 0) + sectors[s].gravity = grav; + } + break; + + //case Init_Color: + // handled in P_LoadSideDefs2() + + case Init_Damage: + { + int damage = P_AproxDistance (lines[i].dx, lines[i].dy) >> FRACBITS; + FSectorTagIterator itr(lines[i].args[0]); + while ((s = itr.Next()) >= 0) + { + sector_t *sec = §ors[s]; + sec->damageamount = damage; + sec->damagetype = NAME_None; + if (sec->damageamount < 20) + { + sec->leakydamage = 0; + sec->damageinterval = 32; + } + else if (sec->damageamount < 50) + { + sec->leakydamage = 5; + sec->damageinterval = 32; + } + else + { + sec->leakydamage = 256; + sec->damageinterval = 1; + } + } + } + break; + + case Init_SectorLink: + if (lines[i].args[3] == 0) + P_AddSectorLinksByID(lines[i].frontsector, lines[i].args[0], lines[i].args[2]); + break; + + // killough 10/98: + // + // Support for sky textures being transferred from sidedefs. + // Allows scrolling and other effects (but if scrolling is + // used, then the same sector tag needs to be used for the + // sky sector, the sky-transfer linedef, and the scroll-effect + // linedef). Still requires user to use F_SKY1 for the floor + // or ceiling texture, to distinguish floor and ceiling sky. + + case Init_TransferSky: + { + FSectorTagIterator itr(lines[i].args[0]); + while ((s = itr.Next()) >= 0) + sectors[s].sky = (i + 1) | PL_SKYFLAT; + break; + } + } + break; + } + } + // [RH] Start running any open scripts on this map + FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); +} + +// killough 2/28/98: +// +// This function, with the help of r_plane.c and r_bsp.c, supports generalized +// scrolling floors and walls, with optional mobj-carrying properties, e.g. +// conveyor belts, rivers, etc. A linedef with a special type affects all +// tagged sectors the same way, by creating scrolling and/or object-carrying +// properties. Multiple linedefs may be used on the same sector and are +// cumulative, although the special case of scrolling a floor and carrying +// things on it, requires only one linedef. The linedef's direction determines +// the scrolling direction, and the linedef's length determines the scrolling +// speed. This was designed so that an edge around the sector could be used to +// control the direction of the sector's scrolling, which is usually what is +// desired. +// +// Process the active scrollers. +// +// This is the main scrolling code +// killough 3/7/98 + +// [RH] Compensate for rotated sector textures by rotating the scrolling +// in the opposite direction. +static void RotationComp(const sector_t *sec, int which, fixed_t dx, fixed_t dy, fixed_t &tdx, fixed_t &tdy) +{ + angle_t an = sec->GetAngle(which); + if (an == 0) + { + tdx = dx; + tdy = dy; + } + else + { + an = an >> ANGLETOFINESHIFT; + fixed_t ca = -finecosine[an]; + fixed_t sa = -finesine[an]; + tdx = DMulScale16(dx, ca, -dy, sa); + tdy = DMulScale16(dy, ca, dx, sa); + } +} + +void DScroller::Tick () +{ + fixed_t dx = m_dx, dy = m_dy, tdx, tdy; + + if (m_Control != -1) + { // compute scroll amounts based on a sector's height changes + fixed_t height = sectors[m_Control].CenterFloor () + + sectors[m_Control].CenterCeiling (); + fixed_t delta = height - m_LastHeight; + m_LastHeight = height; + dx = FixedMul(dx, delta); + dy = FixedMul(dy, delta); + } + + // killough 3/14/98: Add acceleration + if (m_Accel) + { + m_vdx = dx += m_vdx; + m_vdy = dy += m_vdy; + } + + if (!(dx | dy)) // no-op if both (x,y) offsets are 0 + return; + + switch (m_Type) + { + case sc_side: // killough 3/7/98: Scroll wall texture + if (m_Parts & scw_top) + { + sides[m_Affectee].AddTextureXOffset(side_t::top, dx); + sides[m_Affectee].AddTextureYOffset(side_t::top, dy); + } + if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL || + !(sides[m_Affectee].linedef->flags&ML_3DMIDTEX))) + { + sides[m_Affectee].AddTextureXOffset(side_t::mid, dx); + sides[m_Affectee].AddTextureYOffset(side_t::mid, dy); + } + if (m_Parts & scw_bottom) + { + sides[m_Affectee].AddTextureXOffset(side_t::bottom, dx); + sides[m_Affectee].AddTextureYOffset(side_t::bottom, dy); + } + break; + + case sc_floor: // killough 3/7/98: Scroll floor texture + RotationComp(§ors[m_Affectee], sector_t::floor, dx, dy, tdx, tdy); + sectors[m_Affectee].AddXOffset(sector_t::floor, tdx); + sectors[m_Affectee].AddYOffset(sector_t::floor, tdy); + break; + + case sc_ceiling: // killough 3/7/98: Scroll ceiling texture + RotationComp(§ors[m_Affectee], sector_t::ceiling, dx, dy, tdx, tdy); + sectors[m_Affectee].AddXOffset(sector_t::ceiling, tdx); + sectors[m_Affectee].AddYOffset(sector_t::ceiling, tdy); + break; + + // [RH] Don't actually carry anything here. That happens later. + case sc_carry: + level.Scrolls[m_Affectee].ScrollX += dx; + level.Scrolls[m_Affectee].ScrollY += dy; + break; + + case sc_carry_ceiling: // to be added later + break; + } +} + +// +// Add_Scroller() +// +// Add a generalized scroller to the thinker list. +// +// type: the enumerated type of scrolling: floor, ceiling, floor carrier, +// wall, floor carrier & scroller +// +// (dx,dy): the direction and speed of the scrolling or its acceleration +// +// control: the sector whose heights control this scroller's effect +// remotely, or -1 if no control sector +// +// affectee: the index of the affected object (sector or sidedef) +// +// accel: non-zero if this is an accelerative effect +// + +DScroller::DScroller (EScrollType type, fixed_t dx, fixed_t dy, + int control, int affectee, int accel, int scrollpos) + : DThinker (STAT_SCROLLER) +{ + m_Type = type; + m_dx = dx; + m_dy = dy; + m_Accel = accel; + m_Parts = scrollpos; + m_vdx = m_vdy = 0; + if ((m_Control = control) != -1) + m_LastHeight = + sectors[control].CenterFloor () + sectors[control].CenterCeiling (); + m_Affectee = affectee; + m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL; + + switch (type) + { + case sc_carry: + level.AddScroller (this, affectee); + break; + + case sc_side: + sides[affectee].Flags |= WALLF_NOAUTODECALS; + if (m_Parts & scw_top) + { + m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top); + } + if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL || + !(sides[m_Affectee].linedef->flags&ML_3DMIDTEX))) + { + m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid); + } + if (m_Parts & scw_bottom) + { + m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom); + } + break; + + case sc_floor: + m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::FloorScroll, false); + break; + + case sc_ceiling: + m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::CeilingScroll, false); + break; + + default: + break; + } +} + +void DScroller::Destroy () +{ + for(int i=0;i<3;i++) + { + if (m_Interpolations[i] != NULL) + { + m_Interpolations[i]->DelRef(); + m_Interpolations[i] = NULL; + } + } + Super::Destroy(); +} + +// Adds wall scroller. Scroll amount is rotated with respect to wall's +// linedef first, so that scrolling towards the wall in a perpendicular +// direction is translated into vertical motion, while scrolling along +// the wall in a parallel direction is translated into horizontal motion. +// +// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff + +DScroller::DScroller (fixed_t dx, fixed_t dy, const line_t *l, + int control, int accel, int scrollpos) + : DThinker (STAT_SCROLLER) +{ + fixed_t x = abs(l->dx), y = abs(l->dy), d; + if (y > x) + d = x, x = y, y = d; + d = FixedDiv (x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90) + >> ANGLETOFINESHIFT]); + x = -FixedDiv (FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d); + y = -FixedDiv (FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d); + + m_Type = sc_side; + m_dx = x; + m_dy = y; + m_vdx = m_vdy = 0; + m_Accel = accel; + m_Parts = scrollpos; + if ((m_Control = control) != -1) + m_LastHeight = sectors[control].CenterFloor() + sectors[control].CenterCeiling(); + m_Affectee = int(l->sidedef[0] - sides); + sides[m_Affectee].Flags |= WALLF_NOAUTODECALS; + m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL; + + if (m_Parts & scw_top) + { + m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top); + } + if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL || + !(sides[m_Affectee].linedef->flags&ML_3DMIDTEX))) + { + m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid); + } + if (m_Parts & scw_bottom) + { + m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom); + } +} + +// Amount (dx,dy) vector linedef is shifted right to get scroll amount +#define SCROLL_SHIFT 5 +#define SCROLLTYPE(i) (((i) <= 0) || ((i) & ~7) ? 7 : (i)) + +// Initialize the scrollers +static void P_SpawnScrollers(void) +{ + int i; + line_t *l = lines; + TArray copyscrollers; + + for (i = 0; i < numlines; i++) + { + if (lines[i].special == Sector_CopyScroller) + { + // don't allow copying the scroller if the sector has the same tag as it would just duplicate it. + if (!tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0])) + { + copyscrollers.Push(i); + } + lines[i].special = 0; + } + } + + for (i = 0; i < numlines; i++, l++) + { + fixed_t dx; // direction and speed of scrolling + fixed_t dy; + int control = -1, accel = 0; // no control sector or acceleration + int special = l->special; + + // Check for undefined parameters that are non-zero and output messages for them. + // We don't report for specials we don't understand. + FLineSpecial *spec = P_GetLineSpecialInfo(special); + if (spec != NULL) + { + int max = spec->map_args; + for (unsigned arg = max; arg < countof(l->args); ++arg) + { + if (l->args[arg] != 0) + { + Printf("Line %d (type %d:%s), arg %u is %d (should be 0)\n", + i, special, spec->name, arg+1, l->args[arg]); + } + } + } + + // killough 3/7/98: Types 245-249 are same as 250-254 except that the + // first side's sector's heights cause scrolling when they change, and + // this linedef controls the direction and speed of the scrolling. The + // most complicated linedef since donuts, but powerful :) + // + // killough 3/15/98: Add acceleration. Types 214-218 are the same but + // are accelerative. + + // [RH] Assume that it's a scroller and zero the line's special. + l->special = 0; + + dx = dy = 0; // Shut up, GCC + + if (special == Scroll_Ceiling || + special == Scroll_Floor || + special == Scroll_Texture_Model) + { + if (l->args[1] & 3) + { + // if 1, then displacement + // if 2, then accelerative (also if 3) + control = int(l->sidedef[0]->sector - sectors); + if (l->args[1] & 2) + accel = 1; + } + if (special == Scroll_Texture_Model || + l->args[1] & 4) + { + // The line housing the special controls the + // direction and speed of scrolling. + dx = l->dx >> SCROLL_SHIFT; + dy = l->dy >> SCROLL_SHIFT; + } + else + { + // The speed and direction are parameters to the special. + dx = (l->args[3] - 128) * (FRACUNIT / 32); + dy = (l->args[4] - 128) * (FRACUNIT / 32); + } + } + + switch (special) + { + int s; + + case Scroll_Ceiling: + { + FSectorTagIterator itr(l->args[0]); + while ((s = itr.Next()) >= 0) + { + new DScroller(DScroller::sc_ceiling, -dx, dy, control, s, accel); + } + for (unsigned j = 0; j < copyscrollers.Size(); j++) + { + line_t *line = &lines[copyscrollers[j]]; + + if (line->args[0] == l->args[0] && (line->args[1] & 1)) + { + new DScroller(DScroller::sc_ceiling, -dx, dy, control, int(line->frontsector - sectors), accel); + } + } + break; + } + + case Scroll_Floor: + if (l->args[2] != 1) + { // scroll the floor texture + FSectorTagIterator itr(l->args[0]); + while ((s = itr.Next()) >= 0) + { + new DScroller (DScroller::sc_floor, -dx, dy, control, s, accel); + } + for(unsigned j = 0;j < copyscrollers.Size(); j++) + { + line_t *line = &lines[copyscrollers[j]]; + + if (line->args[0] == l->args[0] && (line->args[1] & 2)) + { + new DScroller (DScroller::sc_floor, -dx, dy, control, int(line->frontsector-sectors), accel); + } + } + } + + if (l->args[2] > 0) + { // carry objects on the floor + FSectorTagIterator itr(l->args[0]); + while ((s = itr.Next()) >= 0) + { + new DScroller (DScroller::sc_carry, dx, dy, control, s, accel); + } + for(unsigned j = 0;j < copyscrollers.Size(); j++) + { + line_t *line = &lines[copyscrollers[j]]; + + if (line->args[0] == l->args[0] && (line->args[1] & 4)) + { + new DScroller (DScroller::sc_carry, dx, dy, control, int(line->frontsector-sectors), accel); + } + } + } + break; + + // killough 3/1/98: scroll wall according to linedef + // (same direction and speed as scrolling floors) + case Scroll_Texture_Model: + { + FLineIdIterator itr(l->args[0]); + while ((s = itr.Next()) >= 0) + { + if (s != i) + new DScroller(dx, dy, lines + s, control, accel); + } + break; + } + + case Scroll_Texture_Offsets: + // killough 3/2/98: scroll according to sidedef offsets + s = int(lines[i].sidedef[0] - sides); + new DScroller (DScroller::sc_side, -sides[s].GetTextureXOffset(side_t::mid), + sides[s].GetTextureYOffset(side_t::mid), -1, s, accel, SCROLLTYPE(l->args[0])); + break; + + case Scroll_Texture_Left: + l->special = special; // Restore the special, for compat_useblocking's benefit. + s = int(lines[i].sidedef[0] - sides); + new DScroller (DScroller::sc_side, l->args[0] * (FRACUNIT/64), 0, + -1, s, accel, SCROLLTYPE(l->args[1])); + break; + + case Scroll_Texture_Right: + l->special = special; + s = int(lines[i].sidedef[0] - sides); + new DScroller (DScroller::sc_side, l->args[0] * (-FRACUNIT/64), 0, + -1, s, accel, SCROLLTYPE(l->args[1])); + break; + + case Scroll_Texture_Up: + l->special = special; + s = int(lines[i].sidedef[0] - sides); + new DScroller (DScroller::sc_side, 0, l->args[0] * (FRACUNIT/64), + -1, s, accel, SCROLLTYPE(l->args[1])); + break; + + case Scroll_Texture_Down: + l->special = special; + s = int(lines[i].sidedef[0] - sides); + new DScroller (DScroller::sc_side, 0, l->args[0] * (-FRACUNIT/64), + -1, s, accel, SCROLLTYPE(l->args[1])); + break; + + case Scroll_Texture_Both: + s = int(lines[i].sidedef[0] - sides); + if (l->args[0] == 0) { + dx = (l->args[1] - l->args[2]) * (FRACUNIT/64); + dy = (l->args[4] - l->args[3]) * (FRACUNIT/64); + new DScroller (DScroller::sc_side, dx, dy, -1, s, accel); + } + break; + + default: + // [RH] It wasn't a scroller after all, so restore the special. + l->special = special; + break; + } + } +} + +// killough 3/7/98 -- end generalized scroll effects + +//////////////////////////////////////////////////////////////////////////// +// +// FRICTION EFFECTS +// +// phares 3/12/98: Start of friction effects + +// As the player moves, friction is applied by decreasing the x and y +// velocity values on each tic. By varying the percentage of decrease, +// we can simulate muddy or icy conditions. In mud, the player slows +// down faster. In ice, the player slows down more slowly. +// +// The amount of friction change is controlled by the length of a linedef +// with type 223. A length < 100 gives you mud. A length > 100 gives you ice. +// +// Also, each sector where these effects are to take place is given a +// new special type _______. Changing the type value at runtime allows +// these effects to be turned on or off. +// +// Sector boundaries present problems. The player should experience these +// friction changes only when his feet are touching the sector floor. At +// sector boundaries where floor height changes, the player can find +// himself still 'in' one sector, but with his feet at the floor level +// of the next sector (steps up or down). To handle this, Thinkers are used +// in icy/muddy sectors. These thinkers examine each object that is touching +// their sectors, looking for players whose feet are at the same level as +// their floors. Players satisfying this condition are given new friction +// values that are applied by the player movement code later. + +// +// killough 8/28/98: +// +// Completely redid code, which did not need thinkers, and which put a heavy +// drag on CPU. Friction is now a property of sectors, NOT objects inside +// them. All objects, not just players, are affected by it, if they touch +// the sector's floor. Code simpler and faster, only calling on friction +// calculations when an object needs friction considered, instead of doing +// friction calculations on every sector during every tic. +// +// Although this -might- ruin Boom demo sync involving friction, it's the only +// way, short of code explosion, to fix the original design bug. Fixing the +// design bug in Boom's original friction code, while maintaining demo sync +// under every conceivable circumstance, would double or triple code size, and +// would require maintenance of buggy legacy code which is only useful for old +// demos. Doom demos, which are more important IMO, are not affected by this +// change. +// +// [RH] On the other hand, since I've given up on trying to maintain demo +// sync between versions, these considerations aren't a big deal to me. +// +///////////////////////////// +// +// Initialize the sectors where friction is increased or decreased + +static void P_SpawnFriction(void) +{ + int i; + line_t *l = lines; + + for (i = 0 ; i < numlines ; i++,l++) + { + if (l->special == Sector_SetFriction) + { + int length; + + if (l->args[1]) + { // [RH] Allow setting friction amount from parameter + length = l->args[1] <= 200 ? l->args[1] : 200; + } + else + { + length = P_AproxDistance(l->dx,l->dy)>>FRACBITS; + } + + P_SetSectorFriction (l->args[0], length, false); + l->special = 0; + } + } +} + +void P_SetSectorFriction (int tag, int amount, bool alterFlag) +{ + int s; + fixed_t friction, movefactor; + + // An amount of 100 should result in a friction of + // ORIG_FRICTION (0xE800) + friction = (0x1EB8*amount)/0x80 + 0xD001; + + // killough 8/28/98: prevent odd situations + friction = clamp(friction, 0, FRACUNIT); + + // The following check might seem odd. At the time of movement, + // the move distance is multiplied by 'friction/0x10000', so a + // higher friction value actually means 'less friction'. + movefactor = FrictionToMoveFactor(friction); + + FSectorTagIterator itr(tag); + while ((s = itr.Next()) >= 0) + { + // killough 8/28/98: + // + // Instead of spawning thinkers, which are slow and expensive, + // modify the sector's own friction values. Friction should be + // a property of sectors, not objects which reside inside them. + // Original code scanned every object in every friction sector + // on every tic, adjusting its friction, putting unnecessary + // drag on CPU. New code adjusts friction of sector only once + // at level startup, and then uses this friction value. + + sectors[s].friction = friction; + sectors[s].movefactor = movefactor; + if (alterFlag) + { + // When used inside a script, the sectors' friction flags + // can be enabled and disabled at will. + if (friction == ORIG_FRICTION) + { + sectors[s].Flags &= ~SECF_FRICTION; + } + else + { + sectors[s].Flags |= SECF_FRICTION; + } + } + } +} + +// +// phares 3/12/98: End of friction effects +// +//////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// +// +// PUSH/PULL EFFECT +// +// phares 3/20/98: Start of push/pull effects +// +// This is where push/pull effects are applied to objects in the sectors. +// +// There are four kinds of push effects +// +// 1) Pushing Away +// +// Pushes you away from a point source defined by the location of an +// MT_PUSH Thing. The force decreases linearly with distance from the +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PUSH. The force is felt only if the point +// MT_PUSH can see the target object. +// +// 2) Pulling toward +// +// Same as Pushing Away except you're pulled toward an MT_PULL point +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PULL. The force is felt only if the point +// MT_PULL can see the target object. +// +// 3) Wind +// +// Pushes you in a constant direction. Full force above ground, half +// force on the ground, nothing if you're below it (water). +// +// 4) Current +// +// Pushes you in a constant direction. No force above ground, full +// force if on the ground or below it (water). +// +// The magnitude of the force is controlled by the length of a controlling +// linedef. The force vector for types 3 & 4 is determined by the angle +// of the linedef, and is constant. +// +// For each sector where these effects occur, the sector special type has +// to have the PUSH_MASK bit set. If this bit is turned off by a switch +// at run-time, the effect will not occur. The controlling sector for +// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing. + + +#define PUSH_FACTOR 7 + +///////////////////////////// +// +// Add a push thinker to the thinker list + +DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle, + AActor *source, int affectee) +{ + m_Source = source; + m_Type = type; + if (l) + { + m_Xmag = l->dx>>FRACBITS; + m_Ymag = l->dy>>FRACBITS; + m_Magnitude = P_AproxDistance (m_Xmag, m_Ymag); + } + else + { // [RH] Allow setting magnitude and angle with parameters + ChangeValues (magnitude, angle); + } + if (source) // point source exist? + { + m_Radius = (m_Magnitude) << (FRACBITS+1); // where force goes to zero + m_X = m_Source->X(); + m_Y = m_Source->Y(); + } + m_Affectee = affectee; +} + +int DPusher::CheckForSectorMatch (EPusher type, int tag) +{ + if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag)) + return m_Affectee; + else + return -1; +} + + +///////////////////////////// +// +// T_Pusher looks for all objects that are inside the radius of +// the effect. +// +void DPusher::Tick () +{ + sector_t *sec; + AActor *thing; + msecnode_t *node; + int xspeed,yspeed; + int ht; + + if (!var_pushers) + return; + + sec = sectors + m_Affectee; + + // Be sure the special sector type is still turned on. If so, proceed. + // Else, bail out; the sector type has been changed on us. + + if (!(sec->Flags & SECF_PUSH)) + return; + + // For constant pushers (wind/current) there are 3 situations: + // + // 1) Affected Thing is above the floor. + // + // Apply the full force if wind, no force if current. + // + // 2) Affected Thing is on the ground. + // + // Apply half force if wind, full force if current. + // + // 3) Affected Thing is below the ground (underwater effect). + // + // Apply no force if wind, full force if current. + // + // Apply the effect to clipped players only for now. + // + // In Phase II, you can apply these effects to Things other than players. + // [RH] No Phase II, but it works with anything having MF2_WINDTHRUST now. + + if (m_Type == p_push) + { + // Seek out all pushable things within the force radius of this + // point pusher. Crosses sectors, so use blockmap. + + FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals); // no sector portals because this thing is utterly z-unaware. + FMultiBlockThingsIterator it(check, m_X, m_Y, 0, 0, m_Radius); + FMultiBlockThingsIterator::CheckResult cres; + + + while (it.Next(&cres)) + { + AActor *thing = cres.thing; + // Normal ZDoom is based only on the WINDTHRUST flag, with the noclip cheat as an exemption. + bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP)); + + // MBF allows any sentient or shootable thing to be affected, but players with a fly cheat aren't. + if (compatflags & COMPATF_MBFMONSTERMOVE) + { + pusharound = ((pusharound || (thing->IsSentient()) || (thing->flags & MF_SHOOTABLE)) // Add categories here + && (!(thing->player && (thing->flags & (MF_NOGRAVITY))))); // Exclude flying players here + } + + if ((pusharound) ) + { + int sx = m_X; + int sy = m_Y; + int dist = thing->AproxDistance (sx, sy); + int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); + + // If speed <= 0, you're outside the effective radius. You also have + // to be able to see the push/pull source point. + + if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY))) + { + angle_t pushangle = thing->AngleTo(sx, sy); + if (m_Source->GetClass()->TypeName == NAME_PointPusher) + pushangle += ANG180; // away + pushangle >>= ANGLETOFINESHIFT; + thing->velx += FixedMul (speed, finecosine[pushangle]); + thing->vely += FixedMul (speed, finesine[pushangle]); + } + } + } + return; + } + + // constant pushers p_wind and p_current + + node = sec->touching_thinglist; // things touching this sector + for ( ; node ; node = node->m_snext) + { + thing = node->m_thing; + if (!(thing->flags2 & MF2_WINDTHRUST) || (thing->flags & MF_NOCLIP)) + continue; + + sector_t *hsec = sec->GetHeightSec(); + fixedvec3 pos = thing->PosRelative(sec); + if (m_Type == p_wind) + { + if (hsec == NULL) + { // NOT special water sector + if (thing->Z() > thing->floorz) // above ground + { + xspeed = m_Xmag; // full force + yspeed = m_Ymag; + } + else // on ground + { + xspeed = (m_Xmag)>>1; // half force + yspeed = (m_Ymag)>>1; + } + } + else // special water sector + { + ht = hsec->floorplane.ZatPoint(pos); + if (thing->Z() > ht) // above ground + { + xspeed = m_Xmag; // full force + yspeed = m_Ymag; + } + else if (thing->player->viewz < ht) // underwater + { + xspeed = yspeed = 0; // no force + } + else // wading in water + { + xspeed = (m_Xmag)>>1; // half force + yspeed = (m_Ymag)>>1; + } + } + } + else // p_current + { + const secplane_t *floor; + + if (hsec == NULL) + { // NOT special water sector + floor = &sec->floorplane; + } + else + { // special water sector + floor = &hsec->floorplane; + } + if (thing->Z() > floor->ZatPoint(pos)) + { // above ground + xspeed = yspeed = 0; // no force + } + else + { // on ground/underwater + xspeed = m_Xmag; // full force + yspeed = m_Ymag; + } + } + thing->velx += xspeed<<(FRACBITS-PUSH_FACTOR); + thing->vely += yspeed<<(FRACBITS-PUSH_FACTOR); + } +} + +///////////////////////////// +// +// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing, +// NULL otherwise. + +AActor *P_GetPushThing (int s) +{ + AActor* thing; + sector_t* sec; + + sec = sectors + s; + thing = sec->thinglist; + + while (thing && + thing->GetClass()->TypeName != NAME_PointPusher && + thing->GetClass()->TypeName != NAME_PointPuller) + { + thing = thing->snext; + } + return thing; +} + +///////////////////////////// +// +// Initialize the sectors where pushers are present +// + +static void P_SpawnPushers () +{ + int i; + line_t *l = lines; + int s; + + for (i = 0; i < numlines; i++, l++) + { + switch (l->special) + { + case Sector_SetWind: // wind + { + FSectorTagIterator itr(l->args[0]); + while ((s = itr.Next()) >= 0) + new DPusher(DPusher::p_wind, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s); + l->special = 0; + break; + } + + case Sector_SetCurrent: // current + { + FSectorTagIterator itr(l->args[0]); + while ((s = itr.Next()) >= 0) + new DPusher(DPusher::p_current, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s); + l->special = 0; + break; + } + + case PointPush_SetForce: // push/pull + if (l->args[0]) { // [RH] Find thing by sector + FSectorTagIterator itr(l->args[0]); + while ((s = itr.Next()) >= 0) + { + AActor *thing = P_GetPushThing (s); + if (thing) { // No MT_P* means no effect + // [RH] Allow narrowing it down by tid + if (!l->args[1] || l->args[1] == thing->tid) + new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], + 0, thing, s); + } + } + } else { // [RH] Find thing by tid + AActor *thing; + FActorIterator iterator (l->args[1]); + + while ( (thing = iterator.Next ()) ) + { + if (thing->GetClass()->TypeName == NAME_PointPusher || + thing->GetClass()->TypeName == NAME_PointPuller) + { + new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], + 0, thing, int(thing->Sector - sectors)); + } + } + } + l->special = 0; + break; + } + } +} + +// +// phares 3/20/98: End of Pusher effects +// +//////////////////////////////////////////////////////////////////////////// + +void sector_t::AdjustFloorClip () const +{ + msecnode_t *node; + + for (node = touching_thinglist; node; node = node->m_snext) + { + if (node->m_thing->flags2 & MF2_FLOORCLIP) + { + node->m_thing->AdjustFloorClip(); + } + } +} diff --git a/src/p_spec.h b/src/p_spec.h index 0548a6b51..560ec9acd 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -165,8 +165,8 @@ void P_SpawnSpecials (void); void P_UpdateSpecials (void); // when needed -bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType); -bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType); +bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType, fixedvec3 *optpos = NULL); +bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType, fixedvec3 *optpos = NULL); bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType); void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL); @@ -404,7 +404,7 @@ void EV_StartLightFading (int tag, int value, int tics); #define BUTTONTIME TICRATE // 1 second, in ticks. bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *quest=NULL); -bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno); +bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, fixedvec3 *optpos = NULL); // // P_PLATS diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 0c9d37ccc..98630705c 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -112,7 +112,7 @@ static bool P_StartButton (side_t *side, int Where, FSwitchDef *Switch, fixed_t // //========================================================================== -bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) +bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, fixedvec3 *optpos) { // Activated from an empty side -> always succeed side_t *side = line->sidedef[sideno]; @@ -140,7 +140,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) P_MakeDivline (line, &dll); - fixedvec3 pos = user->PosRelative(line); + fixedvec3 pos = optpos? *optpos : user->PosRelative(line); dlu.x = pos.x; dlu.y = pos.y; dlu.dx = finecosine[user->angle >> ANGLETOFINESHIFT]; diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index b7f9c4fd5..594ad7cc2 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -106,7 +106,6 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, fixedvec3 old; fixed_t aboveFloor; player_t *player; - angle_t an; sector_t *destsect; bool resetpitch = false; fixed_t floorheight, ceilingheight; @@ -193,8 +192,9 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, if (!predicting) { fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; - an = angle >> ANGLETOFINESHIFT; - P_SpawnTeleportFog(thing, x + 20 * finecosine[an], y + 20 * finesine[an], thing->Z() + fogDelta, false, true); + fixedvec2 vector = Vec2Angle(20 * FRACUNIT, angle); + fixedvec2 fogpos = P_GetOffsetPosition(x, y, vector.x, vector.y); + P_SpawnTeleportFog(thing, fogpos.x, fogpos.y, thing->Z() + fogDelta, false, true); } if (thing->player) diff --git a/src/portal.cpp b/src/portal.cpp index cd501513a..6f7192a52 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -277,7 +277,7 @@ void P_SpawnLinePortal(line_t* line) for (int i = 0; i < numlines; i++) { - if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1) + if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1 && lines[i].special == Line_SetPortal) { line->portalindex = linePortals.Reserve(1); FLinePortal *port = &linePortals.Last(); @@ -323,12 +323,6 @@ void P_UpdatePortal(FLinePortal *port) // Portal has no destination: switch it off port->mFlags = 0; } - else if ((port->mOrigin->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ)) || - (port->mDestination->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ))) - { - // disable teleporting capability if a portal is or links to a one-sided wall (unless part of a polyobject.) - port->mFlags = PORTF_VISIBLE; - } else if (port->mDestination->getPortalDestination() != port->mOrigin) { //portal doesn't link back. This will be a simple teleporter portal. @@ -562,24 +556,17 @@ void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y) // Get the angle between the two linedefs, for rotating // orientation and velocity. Rotate 180 degrees, and flip // the position across the exit linedef, if reversed. - angle_t angle = - R_PointToAngle2(0, 0, dst->dx, dst->dy) - - R_PointToAngle2(0, 0, src->dx, src->dy); - angle += ANGLE_180; - - // Sine, cosine of angle adjustment - fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; - fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; - - fixed_t tx, ty; + double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI; + fixed_t s = FLOAT2FIXED(sin(angle)); + fixed_t c = FLOAT2FIXED(cos(angle)); nposx = x - src->v1->x; nposy = y - src->v1->y; // Rotate position along normal to match exit linedef - tx = FixedMul(nposx, c) - FixedMul(nposy, s); - ty = FixedMul(nposy, c) + FixedMul(nposx, s); + fixed_t tx = FixedMul(nposx, c) - FixedMul(nposy, s); + fixed_t ty = FixedMul(nposy, c) + FixedMul(nposx, s); tx += dst->v2->x; ty += dst->v2->y; @@ -596,15 +583,9 @@ void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y) void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy) { - angle_t angle = - R_PointToAngle2(0, 0, dst->dx, dst->dy) - - R_PointToAngle2(0, 0, src->dx, src->dy); - - angle += ANGLE_180; - - // Sine, cosine of angle adjustment - fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; - fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; + double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI; + fixed_t s = FLOAT2FIXED(sin(angle)); + fixed_t c = FLOAT2FIXED(cos(angle)); fixed_t orig_velx = vx; fixed_t orig_vely = vy; @@ -626,12 +607,7 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle) // Get the angle between the two linedefs, for rotating // orientation and velocity. Rotate 180 degrees, and flip // the position across the exit linedef, if reversed. - angle_t xangle = - R_PointToAngle2(0, 0, dst->dx, dst->dy) - - R_PointToAngle2(0, 0, src->dx, src->dy); - - xangle += ANGLE_180; - angle += xangle; + angle += RAD2ANGLE(atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx)) + ANGLE_180; } //============================================================================ @@ -701,17 +677,17 @@ void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy) // //============================================================================ -fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy) +fixedvec2 P_GetOffsetPosition(fixed_t x, fixed_t y, fixed_t dx, fixed_t dy) { - fixedvec2 dest = { actor->X() + dx, actor->Y() + dy }; + fixedvec2 dest = { x + dx, y + dy }; if (PortalBlockmap.containsLines) { - fixed_t actx = actor->X(), acty = actor->Y(); + fixed_t actx = x, acty = y; // Try some easily discoverable early-out first. If we know that the trace cannot possibly find a portal, this saves us from calling the traverser completely for vast parts of the map. if (dx < 128 * FRACUNIT && dy < 128 * FRACUNIT) { fixed_t blockx = GetSafeBlockX(actx - bmaporgx); - fixed_t blocky = GetSafeBlockX(acty - bmaporgy); + fixed_t blocky = GetSafeBlockY(acty - bmaporgy); if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest; } @@ -1117,87 +1093,157 @@ void P_CreateLinkedPortals() // //============================================================================ + +static bool ProcessLayer() +{ +} + bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out) { // Keep this temporary work stuff static. This function can never be called recursively // and this would have to be reallocated for each call otherwise. static FPortalBits processMask; static TArray foundPortals; + static TArray groupsToCheck; bool retval = false; out.inited = true; - if (linkedPortals.Size() == 0) + if (linkedPortals.Size() != 0) { - // If there are no portals, all sectors are in group 0. - return false; - } - processMask.setSize(linkedPortals.Size()); - processMask.clear(); - foundPortals.Clear(); + processMask.setSize(linkedPortals.Size()); + processMask.clear(); + foundPortals.Clear(); - int thisgroup = startgroup; - processMask.setBit(thisgroup); - //out.Add(thisgroup); + int thisgroup = startgroup; + processMask.setBit(thisgroup); + //out.Add(thisgroup); - for (unsigned i = 0; i < linkedPortals.Size(); i++) - { - line_t *ld = linkedPortals[i]->mOrigin; - int othergroup = ld->frontsector->PortalGroup; - FDisplacement &disp = Displacements(thisgroup, othergroup); - if (!disp.isSet) continue; // no connection. - - FBoundingBox box(position.x + disp.pos.x, position.y + disp.pos.y, checkradius); - - if (box.Right() <= ld->bbox[BOXLEFT] - || box.Left() >= ld->bbox[BOXRIGHT] - || box.Top() <= ld->bbox[BOXBOTTOM] - || box.Bottom() >= ld->bbox[BOXTOP]) - continue; // not touched - - if (box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched - foundPortals.Push(linkedPortals[i]); - } - bool foundone = true; - while (foundone) - { - foundone = false; - for (int i = foundPortals.Size() - 1; i >= 0; i--) + for (unsigned i = 0; i < linkedPortals.Size(); i++) { - if (processMask.getBit(foundPortals[i]->mOrigin->frontsector->PortalGroup) && - !processMask.getBit(foundPortals[i]->mDestination->frontsector->PortalGroup)) + line_t *ld = linkedPortals[i]->mOrigin; + int othergroup = ld->frontsector->PortalGroup; + FDisplacement &disp = Displacements(thisgroup, othergroup); + if (!disp.isSet) continue; // no connection. + + FBoundingBox box(position.x + disp.pos.x, position.y + disp.pos.y, checkradius); + + if (box.Right() <= ld->bbox[BOXLEFT] + || box.Left() >= ld->bbox[BOXRIGHT] + || box.Top() <= ld->bbox[BOXBOTTOM] + || box.Bottom() >= ld->bbox[BOXTOP]) + continue; // not touched + + if (box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched + foundPortals.Push(linkedPortals[i]); + } + bool foundone = true; + while (foundone) + { + foundone = false; + for (int i = foundPortals.Size() - 1; i >= 0; i--) { - processMask.setBit(foundPortals[i]->mDestination->frontsector->PortalGroup); - out.Add(foundPortals[i]->mDestination->frontsector->PortalGroup); - foundone = true; - retval = true; - foundPortals.Delete(i); + if (processMask.getBit(foundPortals[i]->mOrigin->frontsector->PortalGroup) && + !processMask.getBit(foundPortals[i]->mDestination->frontsector->PortalGroup)) + { + processMask.setBit(foundPortals[i]->mDestination->frontsector->PortalGroup); + out.Add(foundPortals[i]->mDestination->frontsector->PortalGroup); + foundone = true; + retval = true; + foundPortals.Delete(i); + } } } } - sector_t *sec = P_PointInSector(position.x, position.y); - sector_t *wsec = sec; - while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold) + if (out.method != FPortalGroupArray::PGA_NoSectorPortals) { - sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; - fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); - fixed_t dx = position.x + pos.x; - fixed_t dy = position.y + pos.y; - processMask.setBit(othersec->PortalGroup); - out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER); - wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat - retval = true; - } - wsec = sec; - while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold) - { - sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector; - fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); - fixed_t dx = position.x + pos.x; - fixed_t dy = position.y + pos.y; - processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER); - out.Add(othersec->PortalGroup); - wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat - retval = true; + sector_t *sec = P_PointInSector(position.x, position.y); + sector_t *wsec = sec; + while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold) + { + sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; + fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + pos.x; + fixed_t dy = position.y + pos.y; + processMask.setBit(othersec->PortalGroup); + out.Add(othersec->PortalGroup | FPortalGroupArray::UPPER); + wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat + retval = true; + } + wsec = sec; + while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold) + { + sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector; + fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + pos.x; + fixed_t dy = position.y + pos.y; + processMask.setBit(othersec->PortalGroup | FPortalGroupArray::LOWER); + out.Add(othersec->PortalGroup); + wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat + retval = true; + } + if (out.method == FPortalGroupArray::PGA_Full3d) + { + groupsToCheck.Clear(); + groupsToCheck.Push(startgroup); + int thisgroup = startgroup; + for (unsigned i = 0; i < groupsToCheck.Size();i++) + { + fixedvec2 disp = Displacements.getOffset(startgroup, thisgroup & ~FPortalGroupArray::FLAT); + FBoundingBox box(position.x + disp.x, position.y + disp.y, checkradius); + FBlockLinesIterator it(box); + line_t *ld; + while ((ld = it.Next())) + { + if (box.Right() <= ld->bbox[BOXLEFT] + || box.Left() >= ld->bbox[BOXRIGHT] + || box.Top() <= ld->bbox[BOXBOTTOM] + || box.Bottom() >= ld->bbox[BOXTOP]) + continue; + + if (box.BoxOnLineSide(ld) != -1) + continue; + + if (!(thisgroup & FPortalGroupArray::LOWER)) + { + for (int s = 0; s < 2; s++) + { + sector_t *sec = s ? ld->backsector : ld->frontsector; + if (sec && !(sec->PortalBlocksMovement(sector_t::ceiling))) + { + if (sec->SkyBoxes[sector_t::ceiling]->threshold < upperz) + { + int grp = sec->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup; + if (!(processMask.getBit(grp))) + { + processMask.setBit(grp); + groupsToCheck.Push(grp | FPortalGroupArray::UPPER); + } + } + } + } + } + if (!(thisgroup & FPortalGroupArray::UPPER)) + { + for (int s = 0; s < 2; s++) + { + sector_t *sec = s ? ld->backsector : ld->frontsector; + if (sec && !(sec->PortalBlocksMovement(sector_t::floor))) + { + if (sec->SkyBoxes[sector_t::floor]->threshold > position.z) + { + int grp = sec->SkyBoxes[sector_t::floor]->Sector->PortalGroup; + if (!(processMask.getBit(grp))) + { + processMask.setBit(grp); + groupsToCheck.Push(grp | FPortalGroupArray::LOWER); + } + } + } + } + } + } + } + } } return retval; } diff --git a/src/portal.h b/src/portal.h index ef8cec98a..127a9ec3b 100644 --- a/src/portal.h +++ b/src/portal.h @@ -198,6 +198,6 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle); void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z); void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy); fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y); -fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy); +fixedvec2 P_GetOffsetPosition(fixed_t x, fixed_t y, fixed_t dx, fixed_t dy); #endif \ No newline at end of file diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index c0986b90a..beff4a33d 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -145,6 +145,10 @@ enum static const NSOpenGLPixelFormatAttribute NSOpenGLPFAAllowOfflineRenderers = NSOpenGLPixelFormatAttribute(96); +@interface NSWindow(SetCollectionBehavior) +- (void)setCollectionBehavior:(NSUInteger)collectionBehavior; +@end + #endif // prior to 10.5 @@ -182,6 +186,8 @@ typedef NSInteger NSApplicationActivationPolicy; - (NSRect)convertRectToBacking:(NSRect)aRect; @end +static const NSWindowCollectionBehavior NSWindowCollectionBehaviorFullScreenAuxiliary = NSWindowCollectionBehavior(1 << 8); + #endif // prior to 10.7 #endif // COCOA_I_COMMON_INCLUDED diff --git a/src/posix/cocoa/st_console.h b/src/posix/cocoa/st_console.h index 6b6f01820..b2af7bade 100644 --- a/src/posix/cocoa/st_console.h +++ b/src/posix/cocoa/st_console.h @@ -89,6 +89,8 @@ private: void ExpandTextView(float height); void AddText(const PalEntry& color, const char* message); + + void ScrollTextToBottom(); }; #endif // COCOA_ST_CONSOLE_INCLUDED diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index b990b9b33..b59502398 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -94,7 +94,7 @@ FConsoleWindow::FConsoleWindow() [textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)]; [textContainer setWidthTracksTextView:YES]; - [m_scrollView initWithFrame:NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight)]; + [m_scrollView initWithFrame:initialRect]; [m_scrollView setBorderType:NSNoBorder]; [m_scrollView setHasVerticalScroller:YES]; [m_scrollView setHasHorizontalScroller:NO]; @@ -113,6 +113,12 @@ FConsoleWindow::FConsoleWindow() [m_window center]; [m_window exitAppOnClose]; + if (NSAppKitVersionNumber >= AppKit10_7) + { + // Do not allow fullscreen mode for this window + [m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + } + [[m_window contentView] addSubview:m_scrollView]; [m_window makeKeyAndOrderFront:nil]; @@ -182,10 +188,45 @@ void FConsoleWindow::ShowFatalError(const char* const message) AddText(PalEntry(255, 255, 170), message); AddText("\n"); + ScrollTextToBottom(); + [NSApp runModalForWindow:m_window]; } +static const unsigned int THIRTY_FPS = 33; // milliseconds per update + + +template +struct TimedUpdater +{ + explicit TimedUpdater(const Function& function) + { + const unsigned int currentTime = I_MSTime(); + + if (currentTime - m_previousTime > interval) + { + m_previousTime = currentTime; + + function(); + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + } + } + + static unsigned int m_previousTime; +}; + +template +unsigned int TimedUpdater::m_previousTime; + +template +static void UpdateTimed(const Function& function) +{ + TimedUpdater dummy(function); +} + + void FConsoleWindow::AddText(const char* message) { PalEntry color(223, 223, 223); @@ -274,15 +315,17 @@ void FConsoleWindow::AddText(const char* message) if ([m_window isVisible]) { - [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)]; - - [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + UpdateTimed([&]() + { + [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)]; + }); } } void FConsoleWindow::AddText(const PalEntry& color, const char* const message) { - NSString* const text = [NSString stringWithUTF8String:message]; + NSString* const text = [NSString stringWithCString:message + encoding:NSISOLatin1StringEncoding]; NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSFont systemFontOfSize:14.0f], NSFontAttributeName, @@ -298,6 +341,14 @@ void FConsoleWindow::AddText(const PalEntry& color, const char* const message) } +void FConsoleWindow::ScrollTextToBottom() +{ + [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)]; + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; +} + + void FConsoleWindow::SetTitleText() { static const CGFloat TITLE_TEXT_HEIGHT = 32.0f; @@ -337,7 +388,12 @@ void FConsoleWindow::SetProgressBar(const bool visible) { ExpandTextView(-PROGRESS_BAR_HEIGHT); - m_progressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(2.0f, 0.0f, 508.0f, 16.0f)]; + static const CGFloat PROGRESS_BAR_X = 2.0f; + const NSRect PROGRESS_BAR_RECT = NSMakeRect( + PROGRESS_BAR_X, 0.0f, + [m_window frame].size.width - PROGRESS_BAR_X * 2, 16.0f); + + m_progressBar = [[NSProgressIndicator alloc] initWithFrame:PROGRESS_BAR_RECT]; [m_progressBar setIndeterminate:NO]; [m_progressBar setAutoresizingMask:NSViewWidthSizable]; @@ -370,18 +426,11 @@ void FConsoleWindow::Progress(const int current, const int maximum) return; } - static unsigned int previousTime = I_MSTime(); - unsigned int currentTime = I_MSTime(); - - if (currentTime - previousTime > 33) // approx. 30 FPS + UpdateTimed([&]() { - previousTime = currentTime; - [m_progressBar setMaxValue:maximum]; [m_progressBar setDoubleValue:current]; - - [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; - } + }); } @@ -447,6 +496,8 @@ void FConsoleWindow::NetInit(const char* const message, const int playerCount) [m_window setFrame:windowRect display:YES]; [[m_window contentView] addSubview:m_netView]; + + ScrollTextToBottom(); } [m_netMessageText setStringValue:[NSString stringWithUTF8String:message]]; diff --git a/src/r_defs.h b/src/r_defs.h index 088d253d1..9300ce71f 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1,1409 +1,1409 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Refresh/rendering module, shared data struct definitions. -// -//----------------------------------------------------------------------------- - - -#ifndef __R_DEFS_H__ -#define __R_DEFS_H__ - -#include "doomdef.h" -#include "templates.h" -#include "memarena.h" - -// Some more or less basic data types -// we depend on. -#include "m_fixed.h" - -// We rely on the thinker data struct -// to handle sound origins in sectors. -// SECTORS do store MObjs anyway. -#include "actor.h" -struct FLightNode; -struct FGLSection; -struct seg_t; - -#include "dthinker.h" - -#define MAXWIDTH 5760 -#define MAXHEIGHT 3600 - -const WORD NO_INDEX = 0xffffu; -const DWORD NO_SIDE = 0xffffffffu; - -// Silhouette, needed for clipping Segs (mainly) -// and sprites representing things. -enum -{ - SIL_NONE, - SIL_BOTTOM, - SIL_TOP, - SIL_BOTH -}; - -extern size_t MaxDrawSegs; -struct FDisplacement; - - -enum -{ - SKYBOX_ANCHOR = -1, - SKYBOX_SKYVIEWPOINT = 0, // a regular skybox - SKYBOX_STACKEDSECTORTHING, // stacked sectors with the thing method - SKYBOX_PORTAL, // stacked sectors with Sector_SetPortal - SKYBOX_LINKEDPORTAL, // linked portal (interactive) - SKYBOX_PLANE, // EE-style plane portal (not implemented in SW renderer) - SKYBOX_HORIZON, // EE-style horizon portal (not implemented in SW renderer) -}; - - -// -// INTERNAL MAP TYPES -// used by play and refresh -// - -// -// Your plain vanilla vertex. -// Note: transformed values not buffered locally, -// like some DOOM-alikes ("wt", "WebView") did. -// -enum -{ - VERTEXFLAG_ZCeilingEnabled = 0x01, - VERTEXFLAG_ZFloorEnabled = 0x02 -}; -struct vertexdata_t -{ - fixed_t zCeiling, zFloor; - DWORD flags; -}; -struct vertex_t -{ - fixed_t x, y; - - float fx, fy; // Floating point coordinates of this vertex (excluding polyoblect translation!) - angle_t viewangle; // precalculated angle for clipping - int angletime; // recalculation time for view angle - bool dirty; // something has changed and needs to be recalculated - int numheights; - int numsectors; - sector_t ** sectors; - float * heightlist; - - vertex_t() - { - x = y = 0; - fx = fy = 0; - angletime = 0; - viewangle = 0; - dirty = true; - numheights = numsectors = 0; - sectors = NULL; - heightlist = NULL; - } - - bool operator== (const vertex_t &other) - { - return x == other.x && y == other.y; - } - - bool operator!= (const vertex_t &other) - { - return x != other.x || y != other.y; - } - - void clear() - { - x = y = 0; - } - - angle_t GetClipAngle(); -}; - -// Forward of LineDefs, for Sectors. -struct line_t; - -class player_t; -class FScanner; -class FBitmap; -struct FCopyInfo; -class DInterpolation; -class FArchive; - -enum -{ - UDMF_Line, - UDMF_Side, - UDMF_Sector, - UDMF_Thing -}; - - -struct FUDMFKey -{ - enum - { - UDMF_Int, - UDMF_Float, - UDMF_String - }; - - FName Key; - int Type; - int IntVal; - double FloatVal; - FString StringVal; - - FUDMFKey() - { - } - - FUDMFKey& operator =(int val) - { - Type = UDMF_Int; - IntVal = val; - FloatVal = val; - StringVal = ""; - return *this; - } - - FUDMFKey& operator =(double val) - { - Type = UDMF_Float; - IntVal = int(val); - FloatVal = val; - StringVal = ""; - return *this; - } - - FUDMFKey& operator =(const FString &val) - { - Type = UDMF_String; - IntVal = strtol(val.GetChars(), NULL, 0); - FloatVal = strtod(val.GetChars(), NULL); - StringVal = val; - return *this; - } - -}; - -class FUDMFKeys : public TArray -{ -public: - void Sort(); - FUDMFKey *Find(FName key); -}; - -// -// The SECTORS record, at runtime. -// Stores things/mobjs. -// -class DSectorEffect; -struct sector_t; -struct line_t; -struct FRemapTable; - -enum -{ - SECSPAC_Enter = 1, // Trigger when player enters - SECSPAC_Exit = 2, // Trigger when player exits - SECSPAC_HitFloor = 4, // Trigger when player hits floor - SECSPAC_HitCeiling = 8, // Trigger when player hits ceiling - SECSPAC_Use = 16, // Trigger when player uses - SECSPAC_UseWall = 32, // Trigger when player uses a wall - SECSPAC_EyesDive = 64, // Trigger when player eyes go below fake floor - SECSPAC_EyesSurface = 128, // Trigger when player eyes go above fake floor - SECSPAC_EyesBelowC = 256, // Trigger when player eyes go below fake ceiling - SECSPAC_EyesAboveC = 512, // Trigger when player eyes go above fake ceiling - SECSPAC_HitFakeFloor= 1024, // Trigger when player hits fake floor -}; - -class ASectorAction : public AActor -{ - DECLARE_CLASS (ASectorAction, AActor) -public: - ASectorAction (bool activatedByUse = false); - void Destroy (); - void BeginPlay (); - void Activate (AActor *source); - void Deactivate (AActor *source); - bool TriggerAction(AActor *triggerer, int activationType); - bool CanTrigger (AActor *triggerer) const; - bool IsActivatedByUse() const; -protected: - virtual bool DoTriggerAction(AActor *triggerer, int activationType); - bool CheckTrigger(AActor *triggerer) const; -private: - bool ActivatedByUse; -}; - -class ASkyViewpoint; - -struct secplane_t -{ - // the plane is defined as a*x + b*y + c*z + d = 0 - // ic is 1/c, for faster Z calculations - - fixed_t a, b, c, d, ic; - - // Returns < 0 : behind; == 0 : on; > 0 : in front - int PointOnSide (fixed_t x, fixed_t y, fixed_t z) const - { - return TMulScale16(a,x, b,y, c,z) + d; - } - - // Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes - fixed_t Zat0 () const - { - return ic < 0 ? d : -d; - } - - fixed_t ZatPoint(const fixedvec2 &spot) const - { - return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); - } - - fixed_t ZatPoint(const fixedvec3 &spot) const - { - return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); - } - - // Returns the value of z at (x,y) - fixed_t ZatPoint (fixed_t x, fixed_t y) const - { - return FixedMul (ic, -d - DMulScale16 (a, x, b, y)); - } - - // Returns the value of z at (x,y) as a double - double ZatPoint (double x, double y) const - { - return (d + a*x + b*y) * ic / (-65536.0 * 65536.0); - } - - // Returns the value of z at vertex v - fixed_t ZatPoint (const vertex_t *v) const - { - return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y)); - } - - fixed_t ZatPoint (const AActor *ac) const - { - return FixedMul (ic, -d - DMulScale16 (a, ac->X(), b, ac->Y())); - } - - // Returns the value of z at (x,y) if d is equal to dist - fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const - { - return FixedMul (ic, -dist - DMulScale16 (a, x, b, y)); - } - - // Returns the value of z at vertex v if d is equal to dist - fixed_t ZatPointDist (const vertex_t *v, fixed_t dist) - { - return FixedMul (ic, -dist - DMulScale16 (a, v->x, b, v->y)); - } - - // Flips the plane's vertical orientiation, so that if it pointed up, - // it will point down, and vice versa. - void FlipVert () - { - a = -a; - b = -b; - c = -c; - d = -d; - ic = -ic; - } - - // Returns true if 2 planes are the same - bool operator== (const secplane_t &other) const - { - return a == other.a && b == other.b && c == other.c && d == other.d; - } - - // Returns true if 2 planes are different - bool operator!= (const secplane_t &other) const - { - return a != other.a || b != other.b || c != other.c || d != other.d; - } - - // Moves a plane up/down by hdiff units - void ChangeHeight (fixed_t hdiff) - { - d = d - FixedMul (hdiff, c); - } - - // Moves a plane up/down by hdiff units - fixed_t GetChangedHeight (fixed_t hdiff) - { - return d - FixedMul (hdiff, c); - } - - // Returns how much this plane's height would change if d were set to oldd - fixed_t HeightDiff (fixed_t oldd) const - { - return FixedMul (oldd - d, ic); - } - - // Returns how much this plane's height would change if d were set to oldd - fixed_t HeightDiff (fixed_t oldd, fixed_t newd) const - { - return FixedMul (oldd - newd, ic); - } - - fixed_t PointToDist (fixed_t x, fixed_t y, fixed_t z) const - { - return -TMulScale16 (a, x, y, b, z, c); - } - - fixed_t PointToDist(fixedvec2 xy, fixed_t z) const - { - return -TMulScale16(a, xy.x, xy.y, b, z, c); - } - - fixed_t PointToDist (const vertex_t *v, fixed_t z) const - { - return -TMulScale16 (a, v->x, b, v->y, z, c); - } - - void SetAtHeight(fixed_t height, int ceiling) - { - a = b = 0; - if (ceiling) - { - c = ic = -FRACUNIT; - d = height; - } - else - { - c = ic = FRACUNIT; - d = -height; - } - } - - bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const; - -}; - -FArchive &operator<< (FArchive &arc, secplane_t &plane); - - -#include "p_3dfloors.h" -struct subsector_t; -struct sector_t; -struct side_t; -extern bool gl_plane_reflection_i; -struct FPortal; - -// Ceiling/floor flags -enum -{ - PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative - PLANEF_BLOCKED = 2, // can not be moved anymore. - PLANEF_ADDITIVE = 4, // rendered additive - - // linked portal stuff - PLANEF_NORENDER = 8, - PLANEF_NOPASS = 16, - PLANEF_BLOCKSOUND = 32, - PLANEF_DISABLED = 64, - PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling. -}; - -// Internal sector flags -enum -{ - SECF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor - SECF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes - SECF_NOFAKELIGHT = 8, // heightsec does not change lighting - SECF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions - SECF_UNDERWATER = 32, // sector is underwater - SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater - SECF_UNDERWATERMASK = 32+64, - SECF_DRAWN = 128, // sector has been drawn at least once - SECF_HIDDEN = 256, // Do not draw on textured automap - SECF_NOFLOORSKYBOX = 512, // force use of regular sky - SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!) -}; - -enum -{ - SECF_SILENT = 1, // actors in sector make no noise - SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector - SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. - SECF_NORESPAWN = 8, // players can not respawn in this sector - SECF_FRICTION = 16, // sector has friction enabled - SECF_PUSH = 32, // pushers enabled - SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) - SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage - 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_WASSECRET = 1 << 30, // a secret that was discovered - SECF_SECRET = 1 << 31, // a secret sector - - SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, - SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags - SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers -}; - -enum -{ - PL_SKYFLAT = 0x40000000 -}; - -struct FDynamicColormap; - - -struct FLinkedSector -{ - sector_t *Sector; - int Type; -}; - - -// this substructure contains a few sector properties that are stored in dynamic arrays -// These must not be copied by R_FakeFlat etc. or bad things will happen. -struct extsector_t -{ - // Boom sector transfer information - struct fakefloor - { - TArray Sectors; - } FakeFloor; - - // 3DMIDTEX information - struct midtex - { - struct plane - { - TArray AttachedSectors; // all sectors containing 3dMidtex lines attached to this sector - TArray AttachedLines; // all 3dMidtex lines attached to this sector - } Floor, Ceiling; - } Midtex; - - // Linked sector information - struct linked - { - struct plane - { - TArray Sectors; - } Floor, Ceiling; - } Linked; - - // 3D floors - struct xfloor - { - TDeletingArray ffloors; // 3D floors in this sector - TArray lightlist; // 3D light list - TArray attached; // 3D floors attached to this sector - } XFloor; - - TArray vertices; - - void Serialize(FArchive &arc); -}; - -struct FTransform -{ - // killough 3/7/98: floor and ceiling texture offsets - fixed_t xoffs, yoffs; - - // [RH] floor and ceiling texture scales - fixed_t xscale, yscale; - - // [RH] floor and ceiling texture rotation - angle_t angle; - - // base values - fixed_t base_angle, base_yoffs; -}; - -struct secspecial_t -{ - FNameNoInit damagetype; // [RH] Means-of-death for applied damage - int damageamount; // [RH] Damage to do while standing on floor - short special; - short damageinterval; // Interval for damage application - short leakydamage; // chance of leaking through radiation suit - int Flags; - - secspecial_t() - { - Clear(); - } - - void Clear() - { - memset(this, 0, sizeof(*this)); - } -}; - -FArchive &operator<< (FArchive &arc, secspecial_t &p); - -struct sector_t -{ - // Member functions - bool IsLinked(sector_t *other, bool ceiling) const; - fixed_t FindLowestFloorSurrounding (vertex_t **v) const; - fixed_t FindHighestFloorSurrounding (vertex_t **v) const; - fixed_t FindNextHighestFloor (vertex_t **v) const; - fixed_t FindNextLowestFloor (vertex_t **v) const; - fixed_t FindLowestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98 - fixed_t FindHighestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98 - fixed_t FindNextLowestCeiling (vertex_t **v) const; // jff 2/04/98 - fixed_t FindNextHighestCeiling (vertex_t **v) const; // jff 2/04/98 - fixed_t FindShortestTextureAround () const; // jff 2/04/98 - fixed_t FindShortestUpperAround () const; // jff 2/04/98 - sector_t *FindModelFloorSector (fixed_t floordestheight) const; // jff 2/04/98 - sector_t *FindModelCeilingSector (fixed_t floordestheight) const; // jff 2/04/98 - int FindMinSurroundingLight (int max) const; - sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH] - fixed_t FindLowestCeilingPoint (vertex_t **v) const; - fixed_t FindHighestFloorPoint (vertex_t **v) const; - void AdjustFloorClip () const; - void SetColor(int r, int g, int b, int desat); - void SetFade(int r, int g, int b); - void ClosestPoint(fixed_t x, fixed_t y, fixed_t &ox, fixed_t &oy) const; - int GetFloorLight () const; - int GetCeilingLight () const; - sector_t *GetHeightSec() const; - - DInterpolation *SetInterpolation(int position, bool attach); - - ASkyViewpoint *GetSkyBox(int which); - void CheckPortalPlane(int plane); - - enum - { - floor, - ceiling - }; - - struct splane - { - FTransform xform; - int Flags; - int Light; - fixed_t alpha; - FTextureID Texture; - fixed_t TexZ; - }; - - - splane planes[2]; - - void SetXOffset(int pos, fixed_t o) - { - planes[pos].xform.xoffs = o; - } - - void AddXOffset(int pos, fixed_t o) - { - planes[pos].xform.xoffs += o; - } - - fixed_t GetXOffset(int pos) const - { - return planes[pos].xform.xoffs; - } - - void SetYOffset(int pos, fixed_t o) - { - planes[pos].xform.yoffs = o; - } - - void AddYOffset(int pos, fixed_t o) - { - planes[pos].xform.yoffs += o; - } - - fixed_t GetYOffset(int pos, bool addbase = true) const - { - if (!addbase) - { - return planes[pos].xform.yoffs; - } - else - { - return planes[pos].xform.yoffs + planes[pos].xform.base_yoffs; - } - } - - void SetXScale(int pos, fixed_t o) - { - planes[pos].xform.xscale = o; - } - - fixed_t GetXScale(int pos) const - { - return planes[pos].xform.xscale; - } - - void SetYScale(int pos, fixed_t o) - { - planes[pos].xform.yscale = o; - } - - fixed_t GetYScale(int pos) const - { - return planes[pos].xform.yscale; - } - - void SetAngle(int pos, angle_t o) - { - planes[pos].xform.angle = o; - } - - angle_t GetAngle(int pos, bool addbase = true) const - { - if (!addbase) - { - return planes[pos].xform.angle; - } - else - { - return planes[pos].xform.angle + planes[pos].xform.base_angle; - } - } - - void SetBase(int pos, fixed_t y, angle_t o) - { - planes[pos].xform.base_yoffs = y; - planes[pos].xform.base_angle = o; - } - - void SetAlpha(int pos, fixed_t o) - { - planes[pos].alpha = o; - } - - fixed_t GetAlpha(int pos) const - { - return planes[pos].alpha; - } - - int GetFlags(int pos) const - { - return planes[pos].Flags; - } - - void ChangeFlags(int pos, int And, int Or) - { - planes[pos].Flags &= ~And; - planes[pos].Flags |= Or; - } - - int GetPlaneLight(int pos) const - { - return planes[pos].Light; - } - - void SetPlaneLight(int pos, int level) - { - planes[pos].Light = level; - } - - FTextureID GetTexture(int pos) const - { - return planes[pos].Texture; - } - - void SetTexture(int pos, FTextureID tex, bool floorclip = true) - { - FTextureID old = planes[pos].Texture; - planes[pos].Texture = tex; - if (floorclip && pos == floor && tex != old) AdjustFloorClip(); - } - - fixed_t GetPlaneTexZ(int pos) const - { - return planes[pos].TexZ; - } - - void SetVerticesDirty() - { - for (unsigned i = 0; i < e->vertices.Size(); i++) e->vertices[i]->dirty = true; - } - - void SetAllVerticesDirty() - { - SetVerticesDirty(); - for (unsigned i = 0; i < e->FakeFloor.Sectors.Size(); i++) e->FakeFloor.Sectors[i]->SetVerticesDirty(); - for (unsigned i = 0; i < e->XFloor.attached.Size(); i++) e->XFloor.attached[i]->SetVerticesDirty(); - } - - void SetPlaneTexZ(int pos, fixed_t val, bool dirtify = false) // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code. - { - planes[pos].TexZ = val; - if (dirtify) SetAllVerticesDirty(); - } - - void ChangePlaneTexZ(int pos, fixed_t val) - { - planes[pos].TexZ += val; - SetAllVerticesDirty(); - } - - static inline short ClampLight(int level) - { - return (short)clamp(level, SHRT_MIN, SHRT_MAX); - } - - void ChangeLightLevel(int newval) - { - lightlevel = ClampLight(lightlevel + newval); - } - - void SetLightLevel(int newval) - { - lightlevel = ClampLight(newval); - } - - int GetLightLevel() const - { - return lightlevel; - } - - secplane_t &GetSecPlane(int pos) - { - return pos == floor? floorplane:ceilingplane; - } - - bool isSecret() const - { - return !!(Flags & SECF_SECRET); - } - - bool wasSecret() const - { - return !!(Flags & SECF_WASSECRET); - } - - void ClearSecret() - { - Flags &= ~SECF_SECRET; - } - - void ClearSpecial() - { - // clears all variables that originate from 'special'. Used for sector type transferring thinkers - special = 0; - damageamount = 0; - damageinterval = 0; - damagetype = NAME_None; - leakydamage = 0; - Flags &= ~SECF_SPECIALFLAGS; - } - - bool PortalBlocksView(int plane) - { - if (SkyBoxes[plane] == NULL) return true; - if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false; - return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); - } - - bool PortalBlocksSight(int plane) - { - if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); - } - - bool PortalBlocksMovement(int plane) - { - if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); - } - - bool PortalBlocksSound(int plane) - { - if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); - } - - // These may only be called if the portal has been validated - fixedvec2 FloorDisplacement() - { - return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); - } - - fixedvec2 CeilingDisplacement() - { - return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); - } - - int GetTerrain(int pos) const; - - void TransferSpecial(sector_t *model); - void GetSpecial(secspecial_t *spec); - void SetSpecial(const secspecial_t *spec); - bool PlaneMoving(int pos); - - // Portal-aware height calculation - fixed_t HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL); - fixed_t LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL); - - fixed_t HighestCeilingAt(AActor *a, sector_t **resultsec = NULL) - { - return HighestCeilingAt(a->X(), a->Y(), resultsec); - } - - fixed_t LowestFloorAt(AActor *a, sector_t **resultsec = NULL) - { - return LowestFloorAt(a->X(), a->Y(), resultsec); - } - - fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); - fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, fixed_t steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); - - fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) - { - return NextHighestCeilingAt(a->X(), a->Y(), z, flags, resultsec, resultffloor); - } - - fixed_t NextLowestFloorAt(AActor *a, fixed_t z, int flags, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) - { - return NextLowestFloorAt(a->X(), a->Y(), z, flags, a->MaxStepHeight, resultsec, resultffloor); - } - - // Member variables - fixed_t CenterFloor () const { return floorplane.ZatPoint (centerspot); } - fixed_t CenterCeiling () const { return ceilingplane.ZatPoint (centerspot); } - - // [RH] store floor and ceiling planes instead of heights - secplane_t floorplane, ceilingplane; - - // [RH] give floor and ceiling even more properties - FDynamicColormap *ColorMap; // [RH] Per-sector colormap - - - TObjPtr SoundTarget; - - short special; - short lightlevel; - short seqType; // this sector's sound sequence - - int sky; - FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this. - - fixedvec2 centerspot; // origin for any sounds played by the sector - int validcount; // if == validcount, already checked - AActor* thinglist; // list of mobjs in sector - - // killough 8/28/98: friction is a sector property, not an mobj property. - // these fields used to be in AActor, but presented performance problems - // when processed as mobj properties. Fix is to make them sector properties. - fixed_t friction, movefactor; - - int terrainnum[2]; - - // thinker_t for reversable actions - TObjPtr floordata; // jff 2/22/98 make thinkers on - TObjPtr ceilingdata; // floors, ceilings, lighting, - TObjPtr lightingdata; // independent of one another - - enum - { - CeilingMove, - FloorMove, - CeilingScroll, - FloorScroll - }; - TObjPtr interpolations[4]; - - BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1 - // jff 2/26/98 lockout machinery for stairbuilding - SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally - SWORD prevsec; // -1 or number of sector for previous step - SWORD nextsec; // -1 or number of next step sector - - short linecount; - struct line_t **lines; // [linecount] size - - // killough 3/7/98: support flat heights drawn at another sector's heights - sector_t *heightsec; // other sector, or NULL if no other sector - - DWORD bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps - // [RH] these can also be blend values if - // the alpha mask is non-zero - - // list of mobjs that are at least partially in the sector - // thinglist is a subset of touching_thinglist - struct msecnode_t *touching_thinglist; // phares 3/14/98 - - float gravity; // [RH] Sector gravity (1.0 is normal) - FNameNoInit damagetype; // [RH] Means-of-death for applied damage - int damageamount; // [RH] Damage to do while standing on floor - short damageinterval; // Interval for damage application - short leakydamage; // chance of leaking through radiation suit - - WORD ZoneNumber; // [RH] Zone this sector belongs to - WORD MoreFlags; // [RH] Internal sector flags - DWORD Flags; // Sector flags - - // [RH] Action specials for sectors. Like Skull Tag, but more - // flexible in a Bloody way. SecActTarget forms a list of actors - // joined by their tracer fields. When a potential sector action - // occurs, SecActTarget's TriggerAction method is called. - TObjPtr SecActTarget; - - // [RH] The sky box to render for this sector. NULL means use a - // regular sky. - TObjPtr SkyBoxes[2]; - int PortalGroup; - - int sectornum; // for comparing sector copies - - extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. - - // GL only stuff starts here - float reflect[2]; - - bool transdoor; // For transparent door hacks - fixed_t transdoorheight; // for transparent door hacks - int subsectorcount; // list of subsectors - subsector_t ** subsectors; - FPortal * portals[2]; // floor and ceiling portals - FLightNode * lighthead; - - enum - { - vbo_fakefloor = floor+2, - vbo_fakeceiling = ceiling+2, - }; - - int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering - fixed_t vboheight[2]; // Last calculated height for the 2 planes of this actual sector - int vbocount[2]; // Total count of vertices belonging to this sector's planes - - float GetReflect(int pos) { return gl_plane_reflection_i? reflect[pos] : 0; } - bool VBOHeightcheck(int pos) const { return vboheight[pos] == GetPlaneTexZ(pos); } - - enum - { - INVALIDATE_PLANES = 1, - INVALIDATE_OTHER = 2 - }; - -}; - -FArchive &operator<< (FArchive &arc, sector_t::splane &p); - - -struct ReverbContainer; -struct zone_t -{ - ReverbContainer *Environment; -}; - - -// -// The SideDef. -// - -class DBaseDecal; - -enum -{ - WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative - WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall - WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel - WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles. - WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. - WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. - WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. - WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. -}; - -struct side_t -{ - enum ETexpart - { - top=0, - mid=1, - bottom=2 - }; - struct part - { - fixed_t xoffset; - fixed_t yoffset; - fixed_t xscale; - fixed_t yscale; - FTextureID texture; - TObjPtr interpolation; - //int Light; - }; - - sector_t* sector; // Sector the SideDef is facing. - DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall - part textures[3]; - line_t *linedef; - //DWORD linenum; - DWORD LeftSide, RightSide; // [RH] Group walls into loops - WORD TexelLength; - SWORD Light; - BYTE Flags; - int Index; // needed to access custom UDMF fields which are stored in loading order. - - int GetLightLevel (bool foggy, int baselight, bool noabsolute=false, int *pfakecontrast_usedbygzdoom=NULL) const; - - void SetLight(SWORD l) - { - Light = l; - } - - FTextureID GetTexture(int which) const - { - return textures[which].texture; - } - void SetTexture(int which, FTextureID tex) - { - textures[which].texture = tex; - } - - void SetTextureXOffset(int which, fixed_t offset) - { - textures[which].xoffset = offset; - } - void SetTextureXOffset(fixed_t offset) - { - textures[top].xoffset = - textures[mid].xoffset = - textures[bottom].xoffset = offset; - } - fixed_t GetTextureXOffset(int which) const - { - return textures[which].xoffset; - } - void AddTextureXOffset(int which, fixed_t delta) - { - textures[which].xoffset += delta; - } - - void SetTextureYOffset(int which, fixed_t offset) - { - textures[which].yoffset = offset; - } - void SetTextureYOffset(fixed_t offset) - { - textures[top].yoffset = - textures[mid].yoffset = - textures[bottom].yoffset = offset; - } - fixed_t GetTextureYOffset(int which) const - { - return textures[which].yoffset; - } - void AddTextureYOffset(int which, fixed_t delta) - { - textures[which].yoffset += delta; - } - - void SetTextureXScale(int which, fixed_t scale) - { - textures[which].xscale = scale == 0 ? FRACUNIT : scale; - } - void SetTextureXScale(fixed_t scale) - { - textures[top].xscale = textures[mid].xscale = textures[bottom].xscale = scale == 0 ? FRACUNIT : scale; - } - fixed_t GetTextureXScale(int which) const - { - return textures[which].xscale; - } - void MultiplyTextureXScale(int which, fixed_t delta) - { - textures[which].xscale = FixedMul(textures[which].xscale, delta); - } - - - void SetTextureYScale(int which, fixed_t scale) - { - textures[which].yscale = scale == 0 ? FRACUNIT : scale; - } - void SetTextureYScale(fixed_t scale) - { - textures[top].yscale = textures[mid].yscale = textures[bottom].yscale = scale == 0 ? FRACUNIT : scale; - } - fixed_t GetTextureYScale(int which) const - { - return textures[which].yscale; - } - void MultiplyTextureYScale(int which, fixed_t delta) - { - textures[which].yscale = FixedMul(textures[which].yscale, delta); - } - - DInterpolation *SetInterpolation(int position); - void StopInterpolation(int position); - - vertex_t *V1() const; - vertex_t *V2() const; - - //For GL - FLightNode * lighthead; // all blended lights that may affect this wall - - seg_t **segs; // all segs belonging to this sidedef in ascending order. Used for precise rendering - int numsegs; - -}; - -FArchive &operator<< (FArchive &arc, side_t::part &p); - -struct line_t -{ - vertex_t *v1, *v2; // vertices, from v1 to v2 - fixed_t dx, dy; // precalculated v2 - v1 for side checking - DWORD flags; - DWORD activation; // activation type - int special; - fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) - int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) - side_t *sidedef[2]; - fixed_t bbox[4]; // bounding box, for the extent of the LineDef. - sector_t *frontsector, *backsector; - int validcount; // if == validcount, already checked - int locknumber; // [Dusk] lock number for special - unsigned portalindex; - TObjPtr skybox; - - FLinePortal *getPortal() const - { - return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex]; - } - - // returns true if the portal is crossable by actors - bool isLinePortal() const - { - return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE); - } - - // returns true if the portal needs to be handled by the renderer - bool isVisualPortal() const - { - return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE); - } - - line_t *getPortalDestination() const - { - return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination; - } - - int getPortalAlignment() const - { - return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign; - } -}; - -// phares 3/14/98 -// -// Sector list node showing all sectors an object appears in. -// -// There are two threads that flow through these nodes. The first thread -// starts at touching_thinglist in a sector_t and flows through the m_snext -// links to find all mobjs that are entirely or partially in the sector. -// The second thread starts at touching_sectorlist in a AActor and flows -// through the m_tnext links to find all sectors a thing touches. This is -// useful when applying friction or push effects to sectors. These effects -// can be done as thinkers that act upon all objects touching their sectors. -// As an mobj moves through the world, these nodes are created and -// destroyed, with the links changed appropriately. -// -// For the links, NULL means top or end of list. - -struct msecnode_t -{ - sector_t *m_sector; // a sector containing this object - AActor *m_thing; // this object - struct msecnode_t *m_tprev; // prev msecnode_t for this thing - struct msecnode_t *m_tnext; // next msecnode_t for this thing - struct msecnode_t *m_sprev; // prev msecnode_t for this sector - struct msecnode_t *m_snext; // next msecnode_t for this sector - bool visited; // killough 4/4/98, 4/7/98: used in search algorithms -}; - -struct FPolyNode; -struct FMiniBSP; - -// -// The LineSeg. -// -struct seg_t -{ - vertex_t* v1; - vertex_t* v2; - - side_t* sidedef; - line_t* linedef; - - // Sector references. Could be retrieved from linedef, too. - sector_t* frontsector; - sector_t* backsector; // NULL for one-sided lines - - seg_t* PartnerSeg; - subsector_t* Subsector; - - float sidefrac; // relative position of seg's ending vertex on owning sidedef -}; - -struct glsegextra_t -{ - DWORD PartnerSeg; - subsector_t *Subsector; -}; - -extern seg_t *segs; - - -// -// A SubSector. -// References a Sector. -// Basically, this is a list of LineSegs indicating the visible walls that -// define (all or some) sides of a convex BSP leaf. -// - -enum -{ - SSECF_DEGENERATE = 1, - SSECF_DRAWN = 2, - SSECF_POLYORG = 4, -}; - -struct FPortalCoverage -{ - DWORD * subsectors; - int sscount; -}; - -struct subsector_t -{ - sector_t *sector; - FPolyNode *polys; - FMiniBSP *BSP; - seg_t *firstline; - sector_t *render_sector; - DWORD numlines; - int flags; - - void BuildPolyBSP(); - // subsector related GL data - FLightNode * lighthead; // Light nodes (blended and additive) - int validcount; - short mapsection; - char hacked; // 1: is part of a render hack - // 2: has one-sided walls - FPortalCoverage portalcoverage[2]; -}; - - - - -// -// BSP node. -// -struct node_t -{ - // Partition line. - fixed_t x; - fixed_t y; - fixed_t dx; - fixed_t dy; - fixed_t bbox[2][4]; // Bounding box for each child. - float len; - union - { - void *children[2]; // If bit 0 is set, it's a subsector. - int intchildren[2]; // Used by nodebuilder. - }; -}; - - -// An entire BSP tree. - -struct FMiniBSP -{ - bool bDirty; - - TArray Nodes; - TArray Segs; - TArray Subsectors; - TArray Verts; -}; - - - -// -// OTHER TYPES -// - -typedef BYTE lighttable_t; // This could be wider for >8 bit display. - -// This encapsulates the fields of vissprite_t that can be altered by AlterWeaponSprite -struct visstyle_t -{ - lighttable_t *colormap; - fixed_t alpha; - FRenderStyle RenderStyle; -}; - - -//---------------------------------------------------------------------------------- -// -// The playsim can use different nodes than the renderer so this is -// not the same as R_PointInSubsector -// -//---------------------------------------------------------------------------------- -subsector_t *P_PointInSubsector(fixed_t x, fixed_t y); -inline sector_t *P_PointInSector(fixed_t x, fixed_t y) -{ - return P_PointInSubsector(x, y)->sector; -} - -inline fixedvec3 AActor::PosRelative(const AActor *other) const -{ - return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup); -} - -inline fixedvec3 AActor::PosRelative(sector_t *sec) const -{ - return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup); -} - -inline fixedvec3 AActor::PosRelative(line_t *line) const -{ - return __pos + Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup); -} - -inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL) -{ - return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup); -} - -inline void AActor::ClearInterpolation() -{ - PrevX = X(); - PrevY = Y(); - PrevZ = Z(); - PrevAngle = angle; - if (Sector) PrevPortalGroup = Sector->PortalGroup; - else PrevPortalGroup = 0; -} - - -#endif +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// +// DESCRIPTION: +// Refresh/rendering module, shared data struct definitions. +// +//----------------------------------------------------------------------------- + + +#ifndef __R_DEFS_H__ +#define __R_DEFS_H__ + +#include "doomdef.h" +#include "templates.h" +#include "memarena.h" + +// Some more or less basic data types +// we depend on. +#include "m_fixed.h" + +// We rely on the thinker data struct +// to handle sound origins in sectors. +// SECTORS do store MObjs anyway. +#include "actor.h" +struct FLightNode; +struct FGLSection; +struct seg_t; + +#include "dthinker.h" + +#define MAXWIDTH 5760 +#define MAXHEIGHT 3600 + +const WORD NO_INDEX = 0xffffu; +const DWORD NO_SIDE = 0xffffffffu; + +// Silhouette, needed for clipping Segs (mainly) +// and sprites representing things. +enum +{ + SIL_NONE, + SIL_BOTTOM, + SIL_TOP, + SIL_BOTH +}; + +extern size_t MaxDrawSegs; +struct FDisplacement; + + +enum +{ + SKYBOX_ANCHOR = -1, + SKYBOX_SKYVIEWPOINT = 0, // a regular skybox + SKYBOX_STACKEDSECTORTHING, // stacked sectors with the thing method + SKYBOX_PORTAL, // stacked sectors with Sector_SetPortal + SKYBOX_LINKEDPORTAL, // linked portal (interactive) + SKYBOX_PLANE, // EE-style plane portal (not implemented in SW renderer) + SKYBOX_HORIZON, // EE-style horizon portal (not implemented in SW renderer) +}; + + +// +// INTERNAL MAP TYPES +// used by play and refresh +// + +// +// Your plain vanilla vertex. +// Note: transformed values not buffered locally, +// like some DOOM-alikes ("wt", "WebView") did. +// +enum +{ + VERTEXFLAG_ZCeilingEnabled = 0x01, + VERTEXFLAG_ZFloorEnabled = 0x02 +}; +struct vertexdata_t +{ + fixed_t zCeiling, zFloor; + DWORD flags; +}; +struct vertex_t +{ + fixed_t x, y; + + float fx, fy; // Floating point coordinates of this vertex (excluding polyoblect translation!) + angle_t viewangle; // precalculated angle for clipping + int angletime; // recalculation time for view angle + bool dirty; // something has changed and needs to be recalculated + int numheights; + int numsectors; + sector_t ** sectors; + float * heightlist; + + vertex_t() + { + x = y = 0; + fx = fy = 0; + angletime = 0; + viewangle = 0; + dirty = true; + numheights = numsectors = 0; + sectors = NULL; + heightlist = NULL; + } + + bool operator== (const vertex_t &other) + { + return x == other.x && y == other.y; + } + + bool operator!= (const vertex_t &other) + { + return x != other.x || y != other.y; + } + + void clear() + { + x = y = 0; + } + + angle_t GetClipAngle(); +}; + +// Forward of LineDefs, for Sectors. +struct line_t; + +class player_t; +class FScanner; +class FBitmap; +struct FCopyInfo; +class DInterpolation; +class FArchive; + +enum +{ + UDMF_Line, + UDMF_Side, + UDMF_Sector, + UDMF_Thing +}; + + +struct FUDMFKey +{ + enum + { + UDMF_Int, + UDMF_Float, + UDMF_String + }; + + FName Key; + int Type; + int IntVal; + double FloatVal; + FString StringVal; + + FUDMFKey() + { + } + + FUDMFKey& operator =(int val) + { + Type = UDMF_Int; + IntVal = val; + FloatVal = val; + StringVal = ""; + return *this; + } + + FUDMFKey& operator =(double val) + { + Type = UDMF_Float; + IntVal = int(val); + FloatVal = val; + StringVal = ""; + return *this; + } + + FUDMFKey& operator =(const FString &val) + { + Type = UDMF_String; + IntVal = strtol(val.GetChars(), NULL, 0); + FloatVal = strtod(val.GetChars(), NULL); + StringVal = val; + return *this; + } + +}; + +class FUDMFKeys : public TArray +{ +public: + void Sort(); + FUDMFKey *Find(FName key); +}; + +// +// The SECTORS record, at runtime. +// Stores things/mobjs. +// +class DSectorEffect; +struct sector_t; +struct line_t; +struct FRemapTable; + +enum +{ + SECSPAC_Enter = 1, // Trigger when player enters + SECSPAC_Exit = 2, // Trigger when player exits + SECSPAC_HitFloor = 4, // Trigger when player hits floor + SECSPAC_HitCeiling = 8, // Trigger when player hits ceiling + SECSPAC_Use = 16, // Trigger when player uses + SECSPAC_UseWall = 32, // Trigger when player uses a wall + SECSPAC_EyesDive = 64, // Trigger when player eyes go below fake floor + SECSPAC_EyesSurface = 128, // Trigger when player eyes go above fake floor + SECSPAC_EyesBelowC = 256, // Trigger when player eyes go below fake ceiling + SECSPAC_EyesAboveC = 512, // Trigger when player eyes go above fake ceiling + SECSPAC_HitFakeFloor= 1024, // Trigger when player hits fake floor +}; + +class ASectorAction : public AActor +{ + DECLARE_CLASS (ASectorAction, AActor) +public: + ASectorAction (bool activatedByUse = false); + void Destroy (); + void BeginPlay (); + void Activate (AActor *source); + void Deactivate (AActor *source); + bool TriggerAction(AActor *triggerer, int activationType); + bool CanTrigger (AActor *triggerer) const; + bool IsActivatedByUse() const; +protected: + virtual bool DoTriggerAction(AActor *triggerer, int activationType); + bool CheckTrigger(AActor *triggerer) const; +private: + bool ActivatedByUse; +}; + +class ASkyViewpoint; + +struct secplane_t +{ + // the plane is defined as a*x + b*y + c*z + d = 0 + // ic is 1/c, for faster Z calculations + + fixed_t a, b, c, d, ic; + + // Returns < 0 : behind; == 0 : on; > 0 : in front + int PointOnSide (fixed_t x, fixed_t y, fixed_t z) const + { + return TMulScale16(a,x, b,y, c,z) + d; + } + + // Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes + fixed_t Zat0 () const + { + return ic < 0 ? d : -d; + } + + fixed_t ZatPoint(const fixedvec2 &spot) const + { + return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); + } + + fixed_t ZatPoint(const fixedvec3 &spot) const + { + return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); + } + + // Returns the value of z at (x,y) + fixed_t ZatPoint (fixed_t x, fixed_t y) const + { + return FixedMul (ic, -d - DMulScale16 (a, x, b, y)); + } + + // Returns the value of z at (x,y) as a double + double ZatPoint (double x, double y) const + { + return (d + a*x + b*y) * ic / (-65536.0 * 65536.0); + } + + // Returns the value of z at vertex v + fixed_t ZatPoint (const vertex_t *v) const + { + return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y)); + } + + fixed_t ZatPoint (const AActor *ac) const + { + return FixedMul (ic, -d - DMulScale16 (a, ac->X(), b, ac->Y())); + } + + // Returns the value of z at (x,y) if d is equal to dist + fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const + { + return FixedMul (ic, -dist - DMulScale16 (a, x, b, y)); + } + + // Returns the value of z at vertex v if d is equal to dist + fixed_t ZatPointDist (const vertex_t *v, fixed_t dist) + { + return FixedMul (ic, -dist - DMulScale16 (a, v->x, b, v->y)); + } + + // Flips the plane's vertical orientiation, so that if it pointed up, + // it will point down, and vice versa. + void FlipVert () + { + a = -a; + b = -b; + c = -c; + d = -d; + ic = -ic; + } + + // Returns true if 2 planes are the same + bool operator== (const secplane_t &other) const + { + return a == other.a && b == other.b && c == other.c && d == other.d; + } + + // Returns true if 2 planes are different + bool operator!= (const secplane_t &other) const + { + return a != other.a || b != other.b || c != other.c || d != other.d; + } + + // Moves a plane up/down by hdiff units + void ChangeHeight (fixed_t hdiff) + { + d = d - FixedMul (hdiff, c); + } + + // Moves a plane up/down by hdiff units + fixed_t GetChangedHeight (fixed_t hdiff) + { + return d - FixedMul (hdiff, c); + } + + // Returns how much this plane's height would change if d were set to oldd + fixed_t HeightDiff (fixed_t oldd) const + { + return FixedMul (oldd - d, ic); + } + + // Returns how much this plane's height would change if d were set to oldd + fixed_t HeightDiff (fixed_t oldd, fixed_t newd) const + { + return FixedMul (oldd - newd, ic); + } + + fixed_t PointToDist (fixed_t x, fixed_t y, fixed_t z) const + { + return -TMulScale16 (a, x, y, b, z, c); + } + + fixed_t PointToDist(fixedvec2 xy, fixed_t z) const + { + return -TMulScale16(a, xy.x, xy.y, b, z, c); + } + + fixed_t PointToDist (const vertex_t *v, fixed_t z) const + { + return -TMulScale16 (a, v->x, b, v->y, z, c); + } + + void SetAtHeight(fixed_t height, int ceiling) + { + a = b = 0; + if (ceiling) + { + c = ic = -FRACUNIT; + d = height; + } + else + { + c = ic = FRACUNIT; + d = -height; + } + } + + bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const; + +}; + +FArchive &operator<< (FArchive &arc, secplane_t &plane); + + +#include "p_3dfloors.h" +struct subsector_t; +struct sector_t; +struct side_t; +extern bool gl_plane_reflection_i; +struct FPortal; + +// Ceiling/floor flags +enum +{ + PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative + PLANEF_BLOCKED = 2, // can not be moved anymore. + PLANEF_ADDITIVE = 4, // rendered additive + + // linked portal stuff + PLANEF_NORENDER = 8, + PLANEF_NOPASS = 16, + PLANEF_BLOCKSOUND = 32, + PLANEF_DISABLED = 64, + PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling. +}; + +// Internal sector flags +enum +{ + SECF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor + SECF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes + SECF_NOFAKELIGHT = 8, // heightsec does not change lighting + SECF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions + SECF_UNDERWATER = 32, // sector is underwater + SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater + SECF_UNDERWATERMASK = 32+64, + SECF_DRAWN = 128, // sector has been drawn at least once + SECF_HIDDEN = 256, // Do not draw on textured automap + SECF_NOFLOORSKYBOX = 512, // force use of regular sky + SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!) +}; + +enum +{ + SECF_SILENT = 1, // actors in sector make no noise + SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector + SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. + SECF_NORESPAWN = 8, // players can not respawn in this sector + SECF_FRICTION = 16, // sector has friction enabled + SECF_PUSH = 32, // pushers enabled + SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) + SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage + 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_WASSECRET = 1 << 30, // a secret that was discovered + SECF_SECRET = 1 << 31, // a secret sector + + SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, + SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers +}; + +enum +{ + PL_SKYFLAT = 0x40000000 +}; + +struct FDynamicColormap; + + +struct FLinkedSector +{ + sector_t *Sector; + int Type; +}; + + +// this substructure contains a few sector properties that are stored in dynamic arrays +// These must not be copied by R_FakeFlat etc. or bad things will happen. +struct extsector_t +{ + // Boom sector transfer information + struct fakefloor + { + TArray Sectors; + } FakeFloor; + + // 3DMIDTEX information + struct midtex + { + struct plane + { + TArray AttachedSectors; // all sectors containing 3dMidtex lines attached to this sector + TArray AttachedLines; // all 3dMidtex lines attached to this sector + } Floor, Ceiling; + } Midtex; + + // Linked sector information + struct linked + { + struct plane + { + TArray Sectors; + } Floor, Ceiling; + } Linked; + + // 3D floors + struct xfloor + { + TDeletingArray ffloors; // 3D floors in this sector + TArray lightlist; // 3D light list + TArray attached; // 3D floors attached to this sector + } XFloor; + + TArray vertices; + + void Serialize(FArchive &arc); +}; + +struct FTransform +{ + // killough 3/7/98: floor and ceiling texture offsets + fixed_t xoffs, yoffs; + + // [RH] floor and ceiling texture scales + fixed_t xscale, yscale; + + // [RH] floor and ceiling texture rotation + angle_t angle; + + // base values + fixed_t base_angle, base_yoffs; +}; + +struct secspecial_t +{ + FNameNoInit damagetype; // [RH] Means-of-death for applied damage + int damageamount; // [RH] Damage to do while standing on floor + short special; + short damageinterval; // Interval for damage application + short leakydamage; // chance of leaking through radiation suit + int Flags; + + secspecial_t() + { + Clear(); + } + + void Clear() + { + memset(this, 0, sizeof(*this)); + } +}; + +FArchive &operator<< (FArchive &arc, secspecial_t &p); + +struct sector_t +{ + // Member functions + bool IsLinked(sector_t *other, bool ceiling) const; + fixed_t FindLowestFloorSurrounding (vertex_t **v) const; + fixed_t FindHighestFloorSurrounding (vertex_t **v) const; + fixed_t FindNextHighestFloor (vertex_t **v) const; + fixed_t FindNextLowestFloor (vertex_t **v) const; + fixed_t FindLowestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98 + fixed_t FindHighestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98 + fixed_t FindNextLowestCeiling (vertex_t **v) const; // jff 2/04/98 + fixed_t FindNextHighestCeiling (vertex_t **v) const; // jff 2/04/98 + fixed_t FindShortestTextureAround () const; // jff 2/04/98 + fixed_t FindShortestUpperAround () const; // jff 2/04/98 + sector_t *FindModelFloorSector (fixed_t floordestheight) const; // jff 2/04/98 + sector_t *FindModelCeilingSector (fixed_t floordestheight) const; // jff 2/04/98 + int FindMinSurroundingLight (int max) const; + sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH] + fixed_t FindLowestCeilingPoint (vertex_t **v) const; + fixed_t FindHighestFloorPoint (vertex_t **v) const; + void AdjustFloorClip () const; + void SetColor(int r, int g, int b, int desat); + void SetFade(int r, int g, int b); + void ClosestPoint(fixed_t x, fixed_t y, fixed_t &ox, fixed_t &oy) const; + int GetFloorLight () const; + int GetCeilingLight () const; + sector_t *GetHeightSec() const; + + DInterpolation *SetInterpolation(int position, bool attach); + + ASkyViewpoint *GetSkyBox(int which); + void CheckPortalPlane(int plane); + + enum + { + floor, + ceiling + }; + + struct splane + { + FTransform xform; + int Flags; + int Light; + fixed_t alpha; + FTextureID Texture; + fixed_t TexZ; + }; + + + splane planes[2]; + + void SetXOffset(int pos, fixed_t o) + { + planes[pos].xform.xoffs = o; + } + + void AddXOffset(int pos, fixed_t o) + { + planes[pos].xform.xoffs += o; + } + + fixed_t GetXOffset(int pos) const + { + return planes[pos].xform.xoffs; + } + + void SetYOffset(int pos, fixed_t o) + { + planes[pos].xform.yoffs = o; + } + + void AddYOffset(int pos, fixed_t o) + { + planes[pos].xform.yoffs += o; + } + + fixed_t GetYOffset(int pos, bool addbase = true) const + { + if (!addbase) + { + return planes[pos].xform.yoffs; + } + else + { + return planes[pos].xform.yoffs + planes[pos].xform.base_yoffs; + } + } + + void SetXScale(int pos, fixed_t o) + { + planes[pos].xform.xscale = o; + } + + fixed_t GetXScale(int pos) const + { + return planes[pos].xform.xscale; + } + + void SetYScale(int pos, fixed_t o) + { + planes[pos].xform.yscale = o; + } + + fixed_t GetYScale(int pos) const + { + return planes[pos].xform.yscale; + } + + void SetAngle(int pos, angle_t o) + { + planes[pos].xform.angle = o; + } + + angle_t GetAngle(int pos, bool addbase = true) const + { + if (!addbase) + { + return planes[pos].xform.angle; + } + else + { + return planes[pos].xform.angle + planes[pos].xform.base_angle; + } + } + + void SetBase(int pos, fixed_t y, angle_t o) + { + planes[pos].xform.base_yoffs = y; + planes[pos].xform.base_angle = o; + } + + void SetAlpha(int pos, fixed_t o) + { + planes[pos].alpha = o; + } + + fixed_t GetAlpha(int pos) const + { + return planes[pos].alpha; + } + + int GetFlags(int pos) const + { + return planes[pos].Flags; + } + + void ChangeFlags(int pos, int And, int Or) + { + planes[pos].Flags &= ~And; + planes[pos].Flags |= Or; + } + + int GetPlaneLight(int pos) const + { + return planes[pos].Light; + } + + void SetPlaneLight(int pos, int level) + { + planes[pos].Light = level; + } + + FTextureID GetTexture(int pos) const + { + return planes[pos].Texture; + } + + void SetTexture(int pos, FTextureID tex, bool floorclip = true) + { + FTextureID old = planes[pos].Texture; + planes[pos].Texture = tex; + if (floorclip && pos == floor && tex != old) AdjustFloorClip(); + } + + fixed_t GetPlaneTexZ(int pos) const + { + return planes[pos].TexZ; + } + + void SetVerticesDirty() + { + for (unsigned i = 0; i < e->vertices.Size(); i++) e->vertices[i]->dirty = true; + } + + void SetAllVerticesDirty() + { + SetVerticesDirty(); + for (unsigned i = 0; i < e->FakeFloor.Sectors.Size(); i++) e->FakeFloor.Sectors[i]->SetVerticesDirty(); + for (unsigned i = 0; i < e->XFloor.attached.Size(); i++) e->XFloor.attached[i]->SetVerticesDirty(); + } + + void SetPlaneTexZ(int pos, fixed_t val, bool dirtify = false) // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code. + { + planes[pos].TexZ = val; + if (dirtify) SetAllVerticesDirty(); + } + + void ChangePlaneTexZ(int pos, fixed_t val) + { + planes[pos].TexZ += val; + SetAllVerticesDirty(); + } + + static inline short ClampLight(int level) + { + return (short)clamp(level, SHRT_MIN, SHRT_MAX); + } + + void ChangeLightLevel(int newval) + { + lightlevel = ClampLight(lightlevel + newval); + } + + void SetLightLevel(int newval) + { + lightlevel = ClampLight(newval); + } + + int GetLightLevel() const + { + return lightlevel; + } + + secplane_t &GetSecPlane(int pos) + { + return pos == floor? floorplane:ceilingplane; + } + + bool isSecret() const + { + return !!(Flags & SECF_SECRET); + } + + bool wasSecret() const + { + return !!(Flags & SECF_WASSECRET); + } + + void ClearSecret() + { + Flags &= ~SECF_SECRET; + } + + void ClearSpecial() + { + // clears all variables that originate from 'special'. Used for sector type transferring thinkers + special = 0; + damageamount = 0; + damageinterval = 0; + damagetype = NAME_None; + leakydamage = 0; + Flags &= ~SECF_SPECIALFLAGS; + } + + bool PortalBlocksView(int plane) + { + if (SkyBoxes[plane] == NULL) return true; + if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false; + return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + bool PortalBlocksSight(int plane) + { + if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; + return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + bool PortalBlocksMovement(int plane) + { + if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; + return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + bool PortalBlocksSound(int plane) + { + if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; + return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + // These may only be called if the portal has been validated + fixedvec2 FloorDisplacement() + { + return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); + } + + fixedvec2 CeilingDisplacement() + { + return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); + } + + int GetTerrain(int pos) const; + + void TransferSpecial(sector_t *model); + void GetSpecial(secspecial_t *spec); + void SetSpecial(const secspecial_t *spec); + bool PlaneMoving(int pos); + + // Portal-aware height calculation + fixed_t HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL); + fixed_t LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL); + + fixed_t HighestCeilingAt(AActor *a, sector_t **resultsec = NULL) + { + return HighestCeilingAt(a->X(), a->Y(), resultsec); + } + + fixed_t LowestFloorAt(AActor *a, sector_t **resultsec = NULL) + { + return LowestFloorAt(a->X(), a->Y(), resultsec); + } + + fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); + fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, fixed_t steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); + + fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) + { + return NextHighestCeilingAt(a->X(), a->Y(), z, flags, resultsec, resultffloor); + } + + fixed_t NextLowestFloorAt(AActor *a, fixed_t z, int flags, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) + { + return NextLowestFloorAt(a->X(), a->Y(), z, flags, a->MaxStepHeight, resultsec, resultffloor); + } + + // Member variables + fixed_t CenterFloor () const { return floorplane.ZatPoint (centerspot); } + fixed_t CenterCeiling () const { return ceilingplane.ZatPoint (centerspot); } + + // [RH] store floor and ceiling planes instead of heights + secplane_t floorplane, ceilingplane; + + // [RH] give floor and ceiling even more properties + FDynamicColormap *ColorMap; // [RH] Per-sector colormap + + + TObjPtr SoundTarget; + + short special; + short lightlevel; + short seqType; // this sector's sound sequence + + int sky; + FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this. + + fixedvec2 centerspot; // origin for any sounds played by the sector + int validcount; // if == validcount, already checked + AActor* thinglist; // list of mobjs in sector + + // killough 8/28/98: friction is a sector property, not an mobj property. + // these fields used to be in AActor, but presented performance problems + // when processed as mobj properties. Fix is to make them sector properties. + fixed_t friction, movefactor; + + int terrainnum[2]; + + // thinker_t for reversable actions + TObjPtr floordata; // jff 2/22/98 make thinkers on + TObjPtr ceilingdata; // floors, ceilings, lighting, + TObjPtr lightingdata; // independent of one another + + enum + { + CeilingMove, + FloorMove, + CeilingScroll, + FloorScroll + }; + TObjPtr interpolations[4]; + + BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1 + // jff 2/26/98 lockout machinery for stairbuilding + SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally + SWORD prevsec; // -1 or number of sector for previous step + SWORD nextsec; // -1 or number of next step sector + + short linecount; + struct line_t **lines; // [linecount] size + + // killough 3/7/98: support flat heights drawn at another sector's heights + sector_t *heightsec; // other sector, or NULL if no other sector + + DWORD bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps + // [RH] these can also be blend values if + // the alpha mask is non-zero + + // list of mobjs that are at least partially in the sector + // thinglist is a subset of touching_thinglist + struct msecnode_t *touching_thinglist; // phares 3/14/98 + + float gravity; // [RH] Sector gravity (1.0 is normal) + FNameNoInit damagetype; // [RH] Means-of-death for applied damage + int damageamount; // [RH] Damage to do while standing on floor + short damageinterval; // Interval for damage application + short leakydamage; // chance of leaking through radiation suit + + WORD ZoneNumber; // [RH] Zone this sector belongs to + WORD MoreFlags; // [RH] Internal sector flags + DWORD Flags; // Sector flags + + // [RH] Action specials for sectors. Like Skull Tag, but more + // flexible in a Bloody way. SecActTarget forms a list of actors + // joined by their tracer fields. When a potential sector action + // occurs, SecActTarget's TriggerAction method is called. + TObjPtr SecActTarget; + + // [RH] The sky box to render for this sector. NULL means use a + // regular sky. + TObjPtr SkyBoxes[2]; + int PortalGroup; + + int sectornum; // for comparing sector copies + + extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. + + // GL only stuff starts here + float reflect[2]; + + bool transdoor; // For transparent door hacks + fixed_t transdoorheight; // for transparent door hacks + int subsectorcount; // list of subsectors + subsector_t ** subsectors; + FPortal * portals[2]; // floor and ceiling portals + FLightNode * lighthead; + + enum + { + vbo_fakefloor = floor+2, + vbo_fakeceiling = ceiling+2, + }; + + int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering + fixed_t vboheight[2]; // Last calculated height for the 2 planes of this actual sector + int vbocount[2]; // Total count of vertices belonging to this sector's planes + + float GetReflect(int pos) { return gl_plane_reflection_i? reflect[pos] : 0; } + bool VBOHeightcheck(int pos) const { return vboheight[pos] == GetPlaneTexZ(pos); } + + enum + { + INVALIDATE_PLANES = 1, + INVALIDATE_OTHER = 2 + }; + +}; + +FArchive &operator<< (FArchive &arc, sector_t::splane &p); + + +struct ReverbContainer; +struct zone_t +{ + ReverbContainer *Environment; +}; + + +// +// The SideDef. +// + +class DBaseDecal; + +enum +{ + WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative + WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall + WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel + WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles. + WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. + WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. + WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. + WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. +}; + +struct side_t +{ + enum ETexpart + { + top=0, + mid=1, + bottom=2 + }; + struct part + { + fixed_t xoffset; + fixed_t yoffset; + fixed_t xscale; + fixed_t yscale; + FTextureID texture; + TObjPtr interpolation; + //int Light; + }; + + sector_t* sector; // Sector the SideDef is facing. + DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall + part textures[3]; + line_t *linedef; + //DWORD linenum; + DWORD LeftSide, RightSide; // [RH] Group walls into loops + WORD TexelLength; + SWORD Light; + BYTE Flags; + int Index; // needed to access custom UDMF fields which are stored in loading order. + + int GetLightLevel (bool foggy, int baselight, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const; + + void SetLight(SWORD l) + { + Light = l; + } + + FTextureID GetTexture(int which) const + { + return textures[which].texture; + } + void SetTexture(int which, FTextureID tex) + { + textures[which].texture = tex; + } + + void SetTextureXOffset(int which, fixed_t offset) + { + textures[which].xoffset = offset; + } + void SetTextureXOffset(fixed_t offset) + { + textures[top].xoffset = + textures[mid].xoffset = + textures[bottom].xoffset = offset; + } + fixed_t GetTextureXOffset(int which) const + { + return textures[which].xoffset; + } + void AddTextureXOffset(int which, fixed_t delta) + { + textures[which].xoffset += delta; + } + + void SetTextureYOffset(int which, fixed_t offset) + { + textures[which].yoffset = offset; + } + void SetTextureYOffset(fixed_t offset) + { + textures[top].yoffset = + textures[mid].yoffset = + textures[bottom].yoffset = offset; + } + fixed_t GetTextureYOffset(int which) const + { + return textures[which].yoffset; + } + void AddTextureYOffset(int which, fixed_t delta) + { + textures[which].yoffset += delta; + } + + void SetTextureXScale(int which, fixed_t scale) + { + textures[which].xscale = scale == 0 ? FRACUNIT : scale; + } + void SetTextureXScale(fixed_t scale) + { + textures[top].xscale = textures[mid].xscale = textures[bottom].xscale = scale == 0 ? FRACUNIT : scale; + } + fixed_t GetTextureXScale(int which) const + { + return textures[which].xscale; + } + void MultiplyTextureXScale(int which, fixed_t delta) + { + textures[which].xscale = FixedMul(textures[which].xscale, delta); + } + + + void SetTextureYScale(int which, fixed_t scale) + { + textures[which].yscale = scale == 0 ? FRACUNIT : scale; + } + void SetTextureYScale(fixed_t scale) + { + textures[top].yscale = textures[mid].yscale = textures[bottom].yscale = scale == 0 ? FRACUNIT : scale; + } + fixed_t GetTextureYScale(int which) const + { + return textures[which].yscale; + } + void MultiplyTextureYScale(int which, fixed_t delta) + { + textures[which].yscale = FixedMul(textures[which].yscale, delta); + } + + DInterpolation *SetInterpolation(int position); + void StopInterpolation(int position); + + vertex_t *V1() const; + vertex_t *V2() const; + + //For GL + FLightNode * lighthead; // all blended lights that may affect this wall + + seg_t **segs; // all segs belonging to this sidedef in ascending order. Used for precise rendering + int numsegs; + +}; + +FArchive &operator<< (FArchive &arc, side_t::part &p); + +struct line_t +{ + vertex_t *v1, *v2; // vertices, from v1 to v2 + fixed_t dx, dy; // precalculated v2 - v1 for side checking + DWORD flags; + DWORD activation; // activation type + int special; + fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) + int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) + side_t *sidedef[2]; + fixed_t bbox[4]; // bounding box, for the extent of the LineDef. + sector_t *frontsector, *backsector; + int validcount; // if == validcount, already checked + int locknumber; // [Dusk] lock number for special + unsigned portalindex; + TObjPtr skybox; + + FLinePortal *getPortal() const + { + return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex]; + } + + // returns true if the portal is crossable by actors + bool isLinePortal() const + { + return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE); + } + + // returns true if the portal needs to be handled by the renderer + bool isVisualPortal() const + { + return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE); + } + + line_t *getPortalDestination() const + { + return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination; + } + + int getPortalAlignment() const + { + return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign; + } +}; + +// phares 3/14/98 +// +// Sector list node showing all sectors an object appears in. +// +// There are two threads that flow through these nodes. The first thread +// starts at touching_thinglist in a sector_t and flows through the m_snext +// links to find all mobjs that are entirely or partially in the sector. +// The second thread starts at touching_sectorlist in a AActor and flows +// through the m_tnext links to find all sectors a thing touches. This is +// useful when applying friction or push effects to sectors. These effects +// can be done as thinkers that act upon all objects touching their sectors. +// As an mobj moves through the world, these nodes are created and +// destroyed, with the links changed appropriately. +// +// For the links, NULL means top or end of list. + +struct msecnode_t +{ + sector_t *m_sector; // a sector containing this object + AActor *m_thing; // this object + struct msecnode_t *m_tprev; // prev msecnode_t for this thing + struct msecnode_t *m_tnext; // next msecnode_t for this thing + struct msecnode_t *m_sprev; // prev msecnode_t for this sector + struct msecnode_t *m_snext; // next msecnode_t for this sector + bool visited; // killough 4/4/98, 4/7/98: used in search algorithms +}; + +struct FPolyNode; +struct FMiniBSP; + +// +// The LineSeg. +// +struct seg_t +{ + vertex_t* v1; + vertex_t* v2; + + side_t* sidedef; + line_t* linedef; + + // Sector references. Could be retrieved from linedef, too. + sector_t* frontsector; + sector_t* backsector; // NULL for one-sided lines + + seg_t* PartnerSeg; + subsector_t* Subsector; + + float sidefrac; // relative position of seg's ending vertex on owning sidedef +}; + +struct glsegextra_t +{ + DWORD PartnerSeg; + subsector_t *Subsector; +}; + +extern seg_t *segs; + + +// +// A SubSector. +// References a Sector. +// Basically, this is a list of LineSegs indicating the visible walls that +// define (all or some) sides of a convex BSP leaf. +// + +enum +{ + SSECF_DEGENERATE = 1, + SSECF_DRAWN = 2, + SSECF_POLYORG = 4, +}; + +struct FPortalCoverage +{ + DWORD * subsectors; + int sscount; +}; + +struct subsector_t +{ + sector_t *sector; + FPolyNode *polys; + FMiniBSP *BSP; + seg_t *firstline; + sector_t *render_sector; + DWORD numlines; + int flags; + + void BuildPolyBSP(); + // subsector related GL data + FLightNode * lighthead; // Light nodes (blended and additive) + int validcount; + short mapsection; + char hacked; // 1: is part of a render hack + // 2: has one-sided walls + FPortalCoverage portalcoverage[2]; +}; + + + + +// +// BSP node. +// +struct node_t +{ + // Partition line. + fixed_t x; + fixed_t y; + fixed_t dx; + fixed_t dy; + fixed_t bbox[2][4]; // Bounding box for each child. + float len; + union + { + void *children[2]; // If bit 0 is set, it's a subsector. + int intchildren[2]; // Used by nodebuilder. + }; +}; + + +// An entire BSP tree. + +struct FMiniBSP +{ + bool bDirty; + + TArray Nodes; + TArray Segs; + TArray Subsectors; + TArray Verts; +}; + + + +// +// OTHER TYPES +// + +typedef BYTE lighttable_t; // This could be wider for >8 bit display. + +// This encapsulates the fields of vissprite_t that can be altered by AlterWeaponSprite +struct visstyle_t +{ + lighttable_t *colormap; + fixed_t alpha; + FRenderStyle RenderStyle; +}; + + +//---------------------------------------------------------------------------------- +// +// The playsim can use different nodes than the renderer so this is +// not the same as R_PointInSubsector +// +//---------------------------------------------------------------------------------- +subsector_t *P_PointInSubsector(fixed_t x, fixed_t y); +inline sector_t *P_PointInSector(fixed_t x, fixed_t y) +{ + return P_PointInSubsector(x, y)->sector; +} + +inline fixedvec3 AActor::PosRelative(const AActor *other) const +{ + return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup); +} + +inline fixedvec3 AActor::PosRelative(sector_t *sec) const +{ + return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup); +} + +inline fixedvec3 AActor::PosRelative(line_t *line) const +{ + return __pos + Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup); +} + +inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL) +{ + return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup); +} + +inline void AActor::ClearInterpolation() +{ + PrevX = X(); + PrevY = Y(); + PrevZ = Z(); + PrevAngle = angle; + if (Sector) PrevPortalGroup = Sector->PortalGroup; + else PrevPortalGroup = 0; +} + + +#endif diff --git a/src/r_segs.cpp b/src/r_segs.cpp index ae38b3978..0448cf6aa 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -272,17 +272,17 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) if (fixedlightlev < 0) { + if (!(fake3D & FAKE3D_CLIPTOP)) + { + sclipTop = sec->ceilingplane.ZatPoint(viewx, viewy); + } for (i = frontsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--) { - if (!(fake3D & FAKE3D_CLIPTOP)) - { - sclipTop = sec->ceilingplane.ZatPoint(viewx, viewy); - } - if (sclipTop <= frontsector->e->XFloor.lightlist[i].plane.ZatPoint(viewx, viewy)) + if (sclipTop <= frontsector->e->XFloor.lightlist[i].plane.Zat0()) { lightlist_t *lit = &frontsector->e->XFloor.lightlist[i]; basecolormap = lit->extra_colormap; - wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource == NULL) + r_actualextralight); + wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight); break; } } diff --git a/src/r_things.cpp b/src/r_things.cpp index 1fb4c845b..21fd1605b 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -324,18 +324,19 @@ nextpost: // [ZZ] // R_ClipSpriteColumnWithPortals // -static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprite_t* spr) -{ - // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox. - if (CurrentPortalInSkybox) - return false; +static TArray portaldrawsegs; + +static inline void R_CollectPortals() +{ + // This function collects all drawsegs that may be of interest to R_ClipSpriteColumnWithPortals + // Having that function over the entire list of drawsegs can break down performance quite drastically. + // This is doing the costly stuff only once so that R_ClipSpriteColumnWithPortals can + // a) exit early if no relevant info is found and + // b) skip most of the collected drawsegs which have no portal attached. + portaldrawsegs.Clear(); for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below { - // ignore segs from other portals - if (seg->CurrentPortalUniq != CurrentPortalUniq) - continue; - // I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...) // crashes at the first frame of the first map of Action2.wad if (!seg->curline) continue; @@ -352,8 +353,28 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit if (seg->curline->sidedef != line->sidedef[0]) continue; + portaldrawsegs.Push(seg); + } +} + +static inline bool R_ClipSpriteColumnWithPortals(fixed_t x, fixed_t y, vissprite_t* spr) +{ + // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox. + if (CurrentPortalInSkybox) + return false; + + for(drawseg_t *seg : portaldrawsegs) + { + // ignore segs from other portals + if (seg->CurrentPortalUniq != CurrentPortalUniq) + continue; + + // (all checks that are already done in R_CollectPortals have been removed for performance reasons.) + + line_t* line = seg->curline->linedef; + // don't clip if the sprite is in front of the portal - if (!P_PointOnLineSide(x, y, line)) + if (!P_PointOnLineSidePrecise(x, y, line)) continue; // now if current column is covered by this drawseg, we clip it away @@ -364,6 +385,7 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit return false; } + // // R_DrawVisSprite // mfloorclip and mceilingclip should also be set. @@ -2332,6 +2354,7 @@ void R_DrawHeightPlanes(fixed_t height); // kg3D - fake planes void R_DrawMasked (void) { + R_CollectPortals(); R_SortVisSprites (DrewAVoxel ? sv_compare2d : sv_compare, firstvissprite - vissprites); if (height_top == NULL) diff --git a/src/resourcefiles/file_directory.cpp b/src/resourcefiles/file_directory.cpp index 8b85425f1..068ea508a 100644 --- a/src/resourcefiles/file_directory.cpp +++ b/src/resourcefiles/file_directory.cpp @@ -302,8 +302,13 @@ void FDirectory::AddEntry(const char *fullpath, int size) // Store the full path here so that we can access the file later, even if it is from a filter directory. lump_p->mFullPath = fullpath; + + // [mxd] Convert name to lowercase + FString name = fullpath + strlen(Filename); + name.ToLower(); + // The lump's name is only the part relative to the main directory - lump_p->LumpNameSetup(fullpath + strlen(Filename)); + lump_p->LumpNameSetup(name); lump_p->LumpSize = size; lump_p->Owner = this; lump_p->Flags = 0; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index ec876da15..c1724c2c5 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -960,7 +960,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) else { // Does the player aim at something that can be shot? - P_BulletSlope(self, &target); + FTranslatedLineTarget t; + P_BulletSlope(self, &t, ALF_PORTALRESTRICT); + target = t.linetarget; } return DoJumpIfCloser(target, VM_ARGS_NAMES); } @@ -1637,7 +1639,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) player_t *player = self->player; AWeapon *weapon = player->ReadyWeapon; - AActor *linetarget; + FTranslatedLineTarget t; // Only use ammo if called from a weapon if (useammo && ACTION_CALL_FROM_WEAPON() && weapon) @@ -1659,7 +1661,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) // Temporarily adjusts the pitch fixed_t saved_player_pitch = self->pitch; self->pitch -= pitch; - AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget, NULL, false, (flags & FPF_NOAUTOAIM) != 0); + AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &t, NULL, false, (flags & FPF_NOAUTOAIM) != 0); self->pitch = saved_player_pitch; // automatic handling of seeker missiles @@ -1667,8 +1669,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) { if (flags & FPF_TRANSFERTRANSLATION) misl->Translation = self->Translation; - if (linetarget && (misl->flags2 & MF2_SEEKERMISSILE)) - misl->tracer = linetarget; + if (t.linetarget && !t.unlinked && (misl->flags2 & MF2_SEEKERMISSILE)) + misl->tracer = t.linetarget; if (!(flags & FPF_AIMATANGLE)) { // This original implementation is to aim straight ahead and then offset @@ -1727,7 +1729,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) angle_t angle; int pitch; - AActor * linetarget; + FTranslatedLineTarget t; int actualdamage; if (!norandom) @@ -1736,10 +1738,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) angle = self->angle + (pr_cwpunch.Random2() << 18); if (range == 0) range = MELEERANGE; - pitch = P_AimLineAttack (self, angle, range, &linetarget); + pitch = P_AimLineAttack (self, angle, range, &t); // only use ammo when actually hitting something! - if ((flags & CPF_USEAMMO) && linetarget && weapon && ACTION_CALL_FROM_WEAPON()) + if ((flags & CPF_USEAMMO) && t.linetarget && weapon && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return 0; // out of ammo @@ -1749,15 +1751,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) pufftype = PClass::FindActor(NAME_BulletPuff); int puffFlags = LAF_ISMELEEATTACK | ((flags & CPF_NORANDOMPUFFZ) ? LAF_NORANDOMPUFFZ : 0); - P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, puffFlags, &linetarget, &actualdamage); + P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, puffFlags, &t, &actualdamage); - if (!linetarget) + if (!t.linetarget) { if (MissSound) S_Sound(self, CHAN_WEAPON, MissSound, 1, ATTN_NORM); } else { - if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN)) + if (lifesteal && !(t.linetarget->flags5 & MF5_DONTDRAIN)) { if (flags & CPF_STEALARMOR) { @@ -1794,11 +1796,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (!(flags & CPF_NOTURN)) { // turn to face target - self->angle = self->AngleTo(linetarget); + self->angle = t.SourceAngleToTarget(); } if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; - if (flags & CPF_DAGGER) P_DaggerAlert (self, linetarget); + if (flags & CPF_DAGGER) P_DaggerAlert (self, t.linetarget); } return 0; } @@ -1900,7 +1902,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (range == 0) range = 8192*FRACUNIT; if (sparsity == 0) sparsity = 1; - AActor *linetarget; + FTranslatedLineTarget t; fixedvec3 savedpos = self->Pos(); angle_t saved_angle = self->angle; @@ -1923,8 +1925,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { self->angle = self->AngleTo(self->target); } - self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, aim ? self->target : NULL); - if (linetarget == NULL && aim) + self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &t, ANGLE_1*60, 0, aim ? self->target : NULL); + if (t.linetarget == NULL && aim) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. fixedvec2 pos = self->Vec2To(self->target); @@ -3929,6 +3931,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) angle_t an; AActor *target, *viewport; + FTranslatedLineTarget t; bool doCheckSight; @@ -3964,12 +3967,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { // Does the player aim at something that can be shot? - P_AimLineAttack(self, self->angle, MISSILERANGE, &target, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0); + P_AimLineAttack(self, self->angle, MISSILERANGE, &t, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0, ALF_PORTALRESTRICT); - if (!target) + if (!t.linetarget) { ACTION_RETURN_STATE(NULL); } + target = t.linetarget; switch (flags & (JLOSF_TARGETLOS|JLOSF_FLIPFOV)) { @@ -5570,10 +5574,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) } else { - FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance)); - while ((thing = it.Next())) + FPortalGroupArray check(FPortalGroupArray::PGA_Full3d); + fixed_t mid = self->Z() + self->height / 2; + FMultiBlockThingsIterator it(check, self->X(), self->Y(), mid-distance, mid+distance, distance); + FMultiBlockThingsIterator::CheckResult cres; + + while ((it.Next(&cres))) { - given += DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist); + given += DoRadiusGive(self, cres.thing, item, amount, distance, flags, filter, species, mindist); } } ACTION_RETURN_INT(given); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index daa824264..3ae20a83d 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -84,7 +84,7 @@ struct FCompileContext struct ExpVal { - ExpValType Type; + PType *Type; union { int Int; @@ -94,13 +94,13 @@ struct ExpVal ExpVal() { - Type = VAL_Int; + Type = TypeSInt32; Int = 0; } ~ExpVal() { - if (Type == VAL_String) + if (Type == TypeString) { ((FString *)&pointer)->~FString(); } @@ -108,14 +108,14 @@ struct ExpVal ExpVal(const FString &str) { - Type = VAL_String; + Type = TypeString; ::new(&pointer) FString(str); } ExpVal(const ExpVal &o) { Type = o.Type; - if (o.Type == VAL_String) + if (o.Type == TypeString) { ::new(&pointer) FString(*(FString *)&o.pointer); } @@ -127,12 +127,12 @@ struct ExpVal ExpVal &operator=(const ExpVal &o) { - if (Type == VAL_String) + if (Type == TypeString) { ((FString *)&pointer)->~FString(); } Type = o.Type; - if (o.Type == VAL_String) + if (o.Type == TypeString) { ::new(&pointer) FString(*(FString *)&o.pointer); } @@ -145,27 +145,30 @@ struct ExpVal int GetInt() const { - return Type == VAL_Int? Int : Type == VAL_Float? int(Float) : 0; + int regtype = Type->GetRegType(); + return regtype == REGT_INT ? Int : regtype == REGT_FLOAT ? int(Float) : 0; } double GetFloat() const { - return Type == VAL_Int? double(Int) : Type == VAL_Float? Float : 0; + int regtype = Type->GetRegType(); + return regtype == REGT_INT ? double(Int) : regtype == REGT_FLOAT ? Float : 0; } const FString GetString() const { - return Type == VAL_String ? *(FString *)&pointer : Type == VAL_Name ? FString(FName(ENamedName(Int)).GetChars()) : ""; + return Type == TypeString ? *(FString *)&pointer : Type == TypeName ? FString(FName(ENamedName(Int)).GetChars()) : ""; } bool GetBool() const { - return (Type == VAL_Int || Type == VAL_Sound) ? !!Int : Type == VAL_Float? Float!=0. : false; + int regtype = Type->GetRegType(); + return regtype == REGT_INT ? !!Int : regtype == REGT_FLOAT ? Float!=0. : false; } FName GetName() const { - return Type == VAL_Name? ENamedName(Int) : NAME_None; + return Type == TypeName ? ENamedName(Int) : NAME_None; } }; @@ -195,7 +198,7 @@ protected: { isresolved = false; ScriptPosition = pos; - ValueType = VAL_Unresolved; + ValueType = NULL; } public: virtual ~FxExpression() {} @@ -205,26 +208,17 @@ public: virtual bool isConstant() const; virtual void RequestAddress(); virtual VMFunction *GetDirectFunction(); + bool IsNumeric() const { return ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT; } + bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } virtual ExpEmit Emit(VMFunctionBuilder *build); FScriptPosition ScriptPosition; - FExpressionType ValueType; + PType *ValueType; bool isresolved; }; -class FxParameter : public FxExpression -{ - FxExpression *Operand; - -public: - FxParameter(FxExpression*); - ~FxParameter(); - FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); -}; - //========================================================================== // // FxIdentifier @@ -288,35 +282,35 @@ class FxConstant : public FxExpression public: FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos) { - ValueType = value.Type = VAL_Int; + ValueType = value.Type = TypeSInt32; value.Int = val; isresolved = true; } FxConstant(double val, const FScriptPosition &pos) : FxExpression(pos) { - ValueType = value.Type = VAL_Float; + ValueType = value.Type = TypeFloat64; value.Float = val; isresolved = true; } FxConstant(FSoundID val, const FScriptPosition &pos) : FxExpression(pos) { - ValueType = value.Type = VAL_Sound; + ValueType = value.Type = TypeSound; value.Int = val; isresolved = true; } FxConstant(FName val, const FScriptPosition &pos) : FxExpression(pos) { - ValueType = value.Type = VAL_Name; + ValueType = value.Type = TypeName; value.Int = val; isresolved = true; } FxConstant(const FString &str, const FScriptPosition &pos) : FxExpression(pos) { - ValueType = VAL_String; + ValueType = TypeString; value = ExpVal(str); isresolved = true; } @@ -327,19 +321,19 @@ public: ValueType = cv.Type; isresolved = true; } - - FxConstant(const PClass *val, const FScriptPosition &pos) : FxExpression(pos) + + FxConstant(PClass *val, const FScriptPosition &pos) : FxExpression(pos) { value.pointer = (void*)val; ValueType = val; - value.Type = VAL_Class; + value.Type = NewClassPointer(RUNTIME_CLASS(AActor)); isresolved = true; } FxConstant(FState *state, const FScriptPosition &pos) : FxExpression(pos) { value.pointer = state; - ValueType = value.Type = VAL_State; + ValueType = value.Type = TypeState; isresolved = true; } @@ -864,6 +858,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); + bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®); unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); } VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; } bool IsDirectFunction(); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index b5b35a770..5eb77aa80 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -189,25 +189,20 @@ FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx) FxExpression *x = Resolve(ctx); if (x != NULL) { - switch (x->ValueType.Type) + if (x->ValueType->GetRegType() == REGT_INT) + { + x->ValueType = TypeSInt32; + } + else if (x->ValueType == TypeState) { - case VAL_Int: - case VAL_Sound: - case VAL_Color: - case VAL_Name: - x->ValueType = VAL_Int; - break; - - case VAL_State: x = new FxCastStateToBool(x); x = x->Resolve(ctx); - break; - - default: + } + else + { ScriptPosition.Message(MSG_ERROR, "Not an integral type"); delete this; return NULL; - break; } } return x; @@ -230,85 +225,25 @@ void FxExpression::RequestAddress() // //========================================================================== -FxParameter::FxParameter(FxExpression *operand) -: FxExpression(operand->ScriptPosition) +static void EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos) { - Operand = operand; - ValueType = operand->ValueType; -} + ExpEmit where = operand->Emit(build); -//========================================================================== -// -// -// -//========================================================================== - -FxParameter::~FxParameter() -{ - SAFE_DELETE(Operand); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxParameter::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Operand, ctx); - ValueType = Operand->ValueType; - return this; -} - -ExpEmit FxParameter::Emit(VMFunctionBuilder *build) -{ - if (Operand->isConstant()) + if (where.RegType == REGT_NIL) { - ExpVal val = static_cast(Operand)->GetValue(); - if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) - { - build->EmitParamInt(val.Int); - } - else if (val.Type == VAL_Float) - { - build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Float)); - } - else if (val.Type == VAL_Class || val.Type == VAL_Object) - { - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_OBJECT)); - } - else if (val.Type == VAL_State) - { - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_STATE)); - } - else if (val.Type == VAL_String) - { - build->Emit(OP_PARAM, 0, REGT_STRING | REGT_KONST, build->GetConstantString(val.GetString())); - } - else - { - build->Emit(OP_PARAM, 0, REGT_NIL, 0); - ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); - } + pos.Message(MSG_ERROR, "Attempted to pass a non-value"); + build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); } else { - ExpEmit where = Operand->Emit(build); - - if (where.RegType == REGT_NIL) + int regtype = where.RegType; + if (where.Konst) { - ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value"); - build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); - } - else - { - build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); - where.Free(build); + regtype |= REGT_KONST; } + build->Emit(OP_PARAM, 0, regtype, where.RegNum); + where.Free(build); } - return ExpEmit(); } //========================================================================== @@ -350,35 +285,36 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) ExpEmit out; out.Konst = true; - if (value.Type == VAL_Int || value.Type == VAL_Sound || value.Type == VAL_Name || value.Type == VAL_Color) + int regtype = value.Type->GetRegType(); + out.RegType = regtype; + if (regtype == REGT_INT) { - out.RegType = REGT_INT; out.RegNum = build->GetConstantInt(value.Int); } - else if (value.Type == VAL_Float) + else if (regtype == REGT_FLOAT) { - out.RegType = REGT_FLOAT; out.RegNum = build->GetConstantFloat(value.Float); } - else if (value.Type == VAL_Class || value.Type == VAL_Object) + else if (regtype == REGT_POINTER) { - out.RegType = REGT_POINTER; - out.RegNum = build->GetConstantAddress(value.pointer, ATAG_OBJECT); + VM_ATAG tag = ATAG_GENERIC; + if (value.Type == TypeState) + { + tag = ATAG_STATE; + } + else if (value.Type->GetLoadOp() == OP_LO) + { + tag = ATAG_OBJECT; + } + out.RegNum = build->GetConstantAddress(value.pointer, tag); } - else if (value.Type == VAL_State) + else if (regtype == REGT_STRING) { - out.RegType = REGT_POINTER; - out.RegNum = build->GetConstantAddress(value.pointer, ATAG_STATE); - } - else if (value.Type == VAL_String) - { - out.RegType = REGT_STRING; out.RegNum = build->GetConstantString(value.GetString()); } else { ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); - out.RegType = REGT_NIL; out.RegNum = 0; } return out; @@ -394,7 +330,7 @@ FxIntCast::FxIntCast(FxExpression *x) : FxExpression(x->ScriptPosition) { basex=x; - ValueType = VAL_Int; + ValueType = TypeSInt32; } //========================================================================== @@ -419,14 +355,14 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); - if (basex->ValueType == VAL_Int) + if (basex->ValueType->GetRegType() == REGT_INT) { FxExpression *x = basex; basex = NULL; delete this; return x; } - else if (basex->ValueType == VAL_Float) + else if (basex->ValueType->GetRegType() == REGT_FLOAT) { if (basex->isConstant()) { @@ -455,7 +391,7 @@ ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) { ExpEmit from = basex->Emit(build); assert(!from.Konst); - assert(basex->ValueType == VAL_Float); + assert(basex->ValueType->GetRegType() == REGT_FLOAT); from.Free(build); ExpEmit to(build, REGT_INT); build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I); @@ -472,7 +408,7 @@ FxFloatCast::FxFloatCast(FxExpression *x) : FxExpression(x->ScriptPosition) { basex=x; - ValueType = VAL_Float; + ValueType = TypeFloat64; } //========================================================================== @@ -497,14 +433,14 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); - if (basex->ValueType == VAL_Float) + if (basex->ValueType->GetRegType() == REGT_FLOAT) { FxExpression *x = basex; basex = NULL; delete this; return x; } - else if (basex->ValueType == VAL_Int) + else if (basex->ValueType->GetRegType() == REGT_INT) { if (basex->isConstant()) { @@ -533,7 +469,7 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) { ExpEmit from = basex->Emit(build); assert(!from.Konst); - assert(basex->ValueType == VAL_Int); + assert(basex->ValueType->GetRegType() == REGT_INT); from.Free(build); ExpEmit to(build, REGT_FLOAT); build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F); @@ -550,7 +486,7 @@ FxCastStateToBool::FxCastStateToBool(FxExpression *x) : FxExpression(x->ScriptPosition) { basex = x; - ValueType = VAL_Int; + ValueType = TypeSInt32; } //========================================================================== @@ -575,7 +511,7 @@ FxExpression *FxCastStateToBool::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); - assert(basex->ValueType == VAL_State); + assert(basex->ValueType == TypeState); assert(!basex->isConstant() && "We shouldn't be able to generate a constant state ref"); return this; } @@ -635,7 +571,7 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); - if (Operand->ValueType.isNumeric()) + if (Operand->IsNumeric()) { FxExpression *e = Operand; Operand = NULL; @@ -689,12 +625,12 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); - if (Operand->ValueType.isNumeric()) + if (Operand->IsNumeric()) { if (Operand->isConstant()) { ExpVal val = static_cast(Operand)->GetValue(); - FxExpression *e = val.Type == VAL_Int? + FxExpression *e = val.Type->GetRegType() == REGT_INT ? new FxConstant(-val.Int, ScriptPosition) : new FxConstant(-val.Float, ScriptPosition); delete this; @@ -719,17 +655,17 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) { - assert(ValueType.Type == Operand->ValueType.Type); + assert(ValueType == Operand->ValueType); ExpEmit from = Operand->Emit(build); assert(from.Konst == 0); // Do it in-place. - if (ValueType == VAL_Int) + if (ValueType->GetRegType() == REGT_INT) { build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); } else { - assert(ValueType == VAL_Float); + assert(ValueType->GetRegType() == REGT_FLOAT); build->Emit(OP_FLOP, from.RegNum, from.RegNum, FLOP_NEG); } return from; @@ -769,7 +705,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); - if (Operand->ValueType == VAL_Float /* lax */) + if (Operand->ValueType->GetRegType() == REGT_FLOAT /* lax */) { // DECORATE allows floats here so cast them to int. Operand = new FxIntCast(Operand); @@ -781,7 +717,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) } } - if (Operand->ValueType != VAL_Int) + if (Operand->ValueType->GetRegType() != REGT_INT) { ScriptPosition.Message(MSG_ERROR, "Integer type expected"); delete this; @@ -795,7 +731,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) delete this; return e; } - ValueType = VAL_Int; + ValueType = TypeSInt32; return this; } @@ -807,8 +743,8 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) { - assert(ValueType.Type == Operand->ValueType.Type); - assert(ValueType == VAL_Int); + assert(ValueType == Operand->ValueType); + assert(ValueType == TypeSInt32); ExpEmit from = Operand->Emit(build); assert(from.Konst == 0); // Do it in-place. @@ -858,7 +794,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) return NULL; } - if (Operand->ValueType.isNumeric() || Operand->ValueType.isPointer()) + if (Operand->IsNumeric() || Operand->IsPointer()) { if (Operand->isConstant()) { @@ -874,7 +810,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) delete this; return NULL; } - ValueType = VAL_Int; + ValueType = TypeSInt32; return this; } @@ -956,25 +892,21 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) return false; } - if (left->ValueType == VAL_Int && right->ValueType == VAL_Int) + if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT) { - ValueType = VAL_Int; + ValueType = TypeSInt32; } - else if (left->ValueType.isNumeric() && right->ValueType.isNumeric()) + else if (left->IsNumeric() && right->IsNumeric()) { - ValueType = VAL_Float; + ValueType = TypeFloat64; } - else if (left->ValueType == VAL_Object && right->ValueType == VAL_Object) + else if (left->ValueType->GetRegType() == REGT_POINTER && left->ValueType == right->ValueType) { - ValueType = VAL_Object; - } - else if (left->ValueType == VAL_Class && right->ValueType == VAL_Class) - { - ValueType = VAL_Class; + ValueType = left->ValueType; } else { - ValueType = VAL_Unknown; + ValueType = TypeVoid; } if (castnumeric) @@ -986,11 +918,11 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) void FxBinary::Promote(FCompileContext &ctx) { - if (left->ValueType == VAL_Float && right->ValueType == VAL_Int) + if (left->ValueType->GetRegType() == REGT_FLOAT && right->ValueType->GetRegType() == REGT_INT) { right = (new FxFloatCast(right))->Resolve(ctx); } - else if (left->ValueType == VAL_Int && right->ValueType == VAL_Float) + else if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_FLOAT) { left = (new FxFloatCast(left))->Resolve(ctx); } @@ -1018,7 +950,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) CHECKRESOLVED(); if (!ResolveLR(ctx, true)) return NULL; - if (!ValueType.isNumeric()) + if (!IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; @@ -1026,7 +958,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) } else if (left->isConstant() && right->isConstant()) { - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { double v; double v1 = static_cast(left)->GetValue().GetFloat(); @@ -1079,7 +1011,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) assert(!op1.Konst); op1.Free(build); op2.Free(build); - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); ExpEmit to(build, REGT_FLOAT); @@ -1088,7 +1020,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) } else { - assert(ValueType == VAL_Int); + assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); ExpEmit to(build, REGT_INT); build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum); @@ -1101,7 +1033,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) assert(!op1.Konst || !op2.Konst); op1.Free(build); op2.Free(build); - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); ExpEmit to(build, REGT_FLOAT); @@ -1111,7 +1043,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) } else { - assert(ValueType == VAL_Int); + assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); ExpEmit to(build, REGT_INT); build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR, @@ -1144,7 +1076,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) if (!ResolveLR(ctx, true)) return NULL; - if (!ValueType.isNumeric()) + if (!IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; @@ -1152,7 +1084,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) } else if (left->isConstant() && right->isConstant()) { - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { double v; double v1 = static_cast(left)->GetValue().GetFloat(); @@ -1222,7 +1154,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) assert(!op1.Konst); op1.Free(build); op2.Free(build); - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); ExpEmit to(build, REGT_FLOAT); @@ -1231,7 +1163,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) } else { - assert(ValueType == VAL_Int); + assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); ExpEmit to(build, REGT_INT); build->Emit(op2.Konst ? OP_MUL_RK : OP_MUL_RR, to.RegNum, op1.RegNum, op2.RegNum); @@ -1245,7 +1177,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) assert(Operator == '%' || Operator == '/'); op1.Free(build); op2.Free(build); - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); ExpEmit to(build, REGT_FLOAT); @@ -1256,7 +1188,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) } else { - assert(ValueType == VAL_Int); + assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); ExpEmit to(build, REGT_INT); build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR) @@ -1289,7 +1221,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) CHECKRESOLVED(); if (!ResolveLR(ctx, true)) return NULL; - if (!ValueType.isNumeric()) + if (!IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; @@ -1299,7 +1231,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) { int v; - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { double v1 = static_cast(left)->GetValue().GetFloat(); double v2 = static_cast(right)->GetValue().GetFloat(); @@ -1322,7 +1254,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) return e; } Promote(ctx); - ValueType = VAL_Int; + ValueType = TypeSInt32; return this; } @@ -1410,28 +1342,18 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) return NULL; } - if (!ValueType.isNumeric() && !ValueType.isPointer()) + if (!IsNumeric() && !IsPointer()) { - if (left->ValueType.Type == right->ValueType.Type) - { - // compare other types? - if (left->ValueType == VAL_Sound || left->ValueType == VAL_Color || left->ValueType == VAL_Name) - { - left->ValueType = right->ValueType = VAL_Int; - goto cont; - } - } - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } -cont: + if (left->isConstant() && right->isConstant()) { int v; - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { double v1 = static_cast(left)->GetValue().GetFloat(); double v2 = static_cast(right)->GetValue().GetFloat(); @@ -1448,7 +1370,7 @@ cont: return e; } Promote(ctx); - ValueType = VAL_Int; + ValueType = TypeSInt32; return this; } @@ -1505,7 +1427,7 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r) : FxBinary(o, l, r) { - ValueType = VAL_Int; + ValueType = TypeSInt32; } //========================================================================== @@ -1519,15 +1441,15 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) CHECKRESOLVED(); if (!ResolveLR(ctx, false)) return NULL; - if (ValueType == VAL_Float /* lax */) + if (ValueType->GetRegType() == REGT_FLOAT /* lax */) { // For DECORATE which allows floats here. - if (left->ValueType != VAL_Int) + if (left->ValueType->GetRegType() != REGT_INT) { left = new FxIntCast(left); left = left->Resolve(ctx); } - if (right->ValueType != VAL_Int) + if (right->ValueType->GetRegType() != REGT_INT) { right = new FxIntCast(right); right = right->Resolve(ctx); @@ -1537,10 +1459,10 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) delete this; return NULL; } - ValueType = VAL_Int; + ValueType = TypeSInt32; } - if (ValueType != VAL_Int) + if (ValueType->GetRegType() != REGT_INT) { ScriptPosition.Message(MSG_ERROR, "Integer type expected"); delete this; @@ -1573,8 +1495,8 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) { - assert(left->ValueType == VAL_Int); - assert(right->ValueType == VAL_Int); + assert(left->ValueType->GetRegType() == REGT_INT); + assert(right->ValueType->GetRegType() == REGT_INT); static const VM_UBYTE InstrMap[][4] = { { OP_SLL_RR, OP_SLL_KR, OP_SLL_RI }, // TK_LShift @@ -1656,7 +1578,7 @@ FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r) Operator=o; left=l; right=r; - ValueType = VAL_Int; + ValueType = TypeSInt32; } //========================================================================== @@ -1753,11 +1675,11 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) return x; } } - if (left->ValueType != VAL_Int && left->ValueType != VAL_Sound) + if (left->ValueType->GetRegType() != REGT_INT) { left = new FxIntCast(left); } - if (right->ValueType != VAL_Int && right->ValueType != VAL_Sound) + if (right->ValueType->GetRegType() != REGT_INT) { right = new FxIntCast(right); } @@ -1775,7 +1697,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) // This is not the "right" way to do these, but it works for now. // (Problem: No information sharing is done between nodes to reduce the // code size if you have something like a1 && a2 && a3 && ... && an.) - assert(left->ValueType == VAL_Int && right->ValueType == VAL_Int); + assert(left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT); ExpEmit op1 = left->Emit(build); assert(!op1.Konst); int zero = build->GetConstantInt(0); @@ -1865,10 +1787,10 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) RESOLVE(falsex, ctx); ABORT(condition && truex && falsex); - if (truex->ValueType == VAL_Int && falsex->ValueType == VAL_Int) - ValueType = VAL_Int; - else if (truex->ValueType.isNumeric() && falsex->ValueType.isNumeric()) - ValueType = VAL_Float; + if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT) + ValueType = TypeSInt32; + else if (truex->IsNumeric() && falsex->IsNumeric()) + ValueType = TypeFloat64; //else if (truex->ValueType != falsex->ValueType) if (condition->isConstant()) @@ -1883,14 +1805,14 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) return e; } - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { - if (truex->ValueType != VAL_Float) + if (truex->ValueType->GetRegType() != REGT_FLOAT) { truex = new FxFloatCast(truex); RESOLVE(truex, ctx); } - if (falsex->ValueType != VAL_Float) + if (falsex->ValueType->GetRegType() != REGT_FLOAT) { falsex = new FxFloatCast(falsex); RESOLVE(falsex, ctx); @@ -1921,7 +1843,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) size_t patchspot = build->Emit(OP_JMP, 0); // Evaluate true expression. - if (truex->isConstant() && truex->ValueType == VAL_Int) + if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT) { out = ExpEmit(build, REGT_INT); build->EmitLoadInt(out.RegNum, static_cast(truex)->GetValue().GetInt()); @@ -1945,7 +1867,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) // Evaluate false expression. build->BackpatchToHere(patchspot); - if (falsex->isConstant() && falsex->ValueType == VAL_Int) + if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT) { build->EmitLoadInt(out.RegNum, static_cast(falsex)->GetValue().GetInt()); } @@ -2013,7 +1935,7 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) SAFE_RESOLVE(val, ctx); - if (!val->ValueType.isNumeric()) + if (!val->IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; @@ -2022,13 +1944,13 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) else if (val->isConstant()) { ExpVal value = static_cast(val)->GetValue(); - switch (value.Type) + switch (value.Type->GetRegType()) { - case VAL_Int: + case REGT_INT: value.Int = abs(value.Int); break; - case VAL_Float: + case REGT_FLOAT: value.Float = fabs(value.Float); break; @@ -2079,7 +2001,6 @@ FxMinMax::FxMinMax(TArray &expr, FName type, const FScriptPositio assert(expr.Size() > 0); assert(type == NAME_Min || type == NAME_Max); - ValueType = VAL_Unknown; choices.Resize(expr.Size()); for (unsigned i = 0; i < expr.Size(); ++i) { @@ -2106,11 +2027,11 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) RESOLVE(choices[i], ctx); ABORT(choices[i]); - if (choices[i]->ValueType == VAL_Float) + if (choices[i]->ValueType->GetRegType() == REGT_FLOAT) { floatcount++; } - else if (choices[i]->ValueType == VAL_Int) + else if (choices[i]->ValueType->GetRegType() == REGT_INT) { intcount++; } @@ -2123,12 +2044,12 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) } if (floatcount != 0) { - ValueType = VAL_Float; + ValueType = TypeFloat64; if (intcount != 0) { // There are some ints that need to be cast to floats for (i = 0; i < choices.Size(); ++i) { - if (choices[i]->ValueType == VAL_Int) + if (choices[i]->ValueType->GetRegType() == REGT_INT) { choices[i] = new FxFloatCast(choices[i]); RESOLVE(choices[i], ctx); @@ -2139,7 +2060,7 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) } else { - ValueType = VAL_Int; + ValueType = TypeSInt32; } // If at least two arguments are constants, they can be solved now. @@ -2161,10 +2082,10 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) else { ExpVal value = static_cast(choices[j])->GetValue(); - assert(value.Type == ValueType.Type); + assert(value.Type == ValueType); if (Type == NAME_Min) { - if (value.Type == VAL_Float) + if (value.Type->GetRegType() == REGT_FLOAT) { if (value.Float < best.Float) { @@ -2181,7 +2102,7 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) } else { - if (value.Type == VAL_Float) + if (value.Type->GetRegType() == REGT_FLOAT) { if (value.Float > best.Float) { @@ -2245,12 +2166,12 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) if (Type == NAME_Min) { - opcode = ValueType.Type == VAL_Float ? OP_LEF_RR : OP_LE_RR; + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LEF_RR : OP_LE_RR; opA = 1; } else { - opcode = ValueType.Type == VAL_Float ? OP_LTF_RR : OP_LT_RR; + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LTF_RR : OP_LT_RR; opA = 0; } @@ -2259,7 +2180,7 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) // Get first value into a register. This will also be the result register. if (choices[0]->isConstant()) { - bestreg = ExpEmit(build, ValueType.Type == VAL_Float ? REGT_FLOAT : REGT_INT); + bestreg = ExpEmit(build, ValueType->GetRegType()); EmitLoad(build, bestreg, static_cast(choices[0])->GetValue()); } else @@ -2297,12 +2218,12 @@ FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip { if (mi != NULL && ma != NULL) { - min = new FxParameter(new FxIntCast(mi)); - max = new FxParameter(new FxIntCast(ma)); + min = new FxIntCast(mi); + max = new FxIntCast(ma); } else min = max = NULL; rng = r; - ValueType = VAL_Int; + ValueType = TypeSInt32; } //========================================================================== @@ -2331,8 +2252,8 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) RESOLVE(min, ctx); RESOLVE(max, ctx); ABORT(min && max); - assert(min->ValueType == ValueType.Type); - assert(max->ValueType == ValueType.Type); + assert(min->ValueType == ValueType); + assert(max->ValueType == ValueType); } return this; }; @@ -2382,8 +2303,8 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { - min->Emit(build); - max->Emit(build); + EmitParameter(build, min, ScriptPosition); + EmitParameter(build, max, ScriptPosition); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else @@ -2418,7 +2339,14 @@ FxRandomPick::FxRandomPick(FRandom *r, TArray &expr, bool floaty, } rng = r; - ValueType = floaty ? VAL_Float : VAL_Int; + if (floaty) + { + ValueType = TypeFloat64; + } + else + { + ValueType = TypeSInt32; + } } //========================================================================== @@ -2444,7 +2372,7 @@ FxExpression *FxRandomPick::Resolve(FCompileContext &ctx) { RESOLVE(choices[index], ctx); ABORT(choices[index]); - assert(choices[index]->ValueType == ValueType.Type); + assert(choices[index]->ValueType == ValueType); } return this; }; @@ -2498,7 +2426,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) // For floating point results, we need to get a new register, since we can't // reuse the integer one used to store the random result. - if (ValueType == VAL_Float) + if (ValueType->GetRegType() == REGT_FLOAT) { resultreg = ExpEmit(build, REGT_FLOAT); resultreg.Free(build); @@ -2528,7 +2456,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) // was expected. Copy it to the one we wanted. resultreg.Reuse(build); // This is really just for the assert in Reuse() - build->Emit(ValueType == VAL_Int ? OP_MOVE : OP_MOVEF, resultreg.RegNum, casereg.RegNum, 0); + build->Emit(ValueType->GetRegType() == REGT_INT ? OP_MOVE : OP_MOVEF, resultreg.RegNum, casereg.RegNum, 0); resultreg.Free(build); } // Free this register so the remaining cases can use it. @@ -2562,10 +2490,10 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri { if (mi != NULL && ma != NULL) { - min = new FxParameter(new FxFloatCast(mi)); - max = new FxParameter(new FxFloatCast(ma)); + min = new FxFloatCast(mi); + max = new FxFloatCast(ma); } - ValueType = VAL_Float; + ValueType = TypeFloat64; } //========================================================================== @@ -2611,8 +2539,8 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { - min->Emit(build); - max->Emit(build); + EmitParameter(build, min, ScriptPosition); + EmitParameter(build, max, ScriptPosition); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else @@ -2636,8 +2564,7 @@ FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) rng = r; if (m) mask = new FxIntCast(m); else mask = new FxConstant(-1, pos); - mask = new FxParameter(mask); - ValueType = VAL_Int; + ValueType = TypeSInt32; } //========================================================================== @@ -2681,7 +2608,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) callfunc = ((PSymbolVMFunction *)sym)->Function; build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - mask->Emit(build); + EmitParameter(build, mask, ScriptPosition); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); @@ -2814,7 +2741,7 @@ FxExpression *FxSelf::Resolve(FCompileContext& ctx) return NULL; } ValueType = ctx.cls; - ValueType.Type = VAL_Object; + ValueType = NewPointer(RUNTIME_CLASS(DObject)); return this; } @@ -2853,7 +2780,7 @@ FxDamage::FxDamage(const FScriptPosition &pos) FxExpression *FxDamage::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - ValueType = VAL_Int; + ValueType = TypeSInt32; return this; } @@ -2940,41 +2867,14 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(classx, ctx); - if (classx->ValueType != VAL_Object && classx->ValueType != VAL_Class) + PPointer *ptrtype = dyn_cast(classx->ValueType); + if (ptrtype == NULL || !ptrtype->IsKindOf(RUNTIME_CLASS(DObject))) { ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object"); delete this; return NULL; } - PType *type = membervar->Type; - PArray *arraytype = dyn_cast(type); - - if (arraytype != NULL) - { - type = arraytype->ElementType; - } - if (type->IsKindOf(RUNTIME_CLASS(PPointer))) - { - ValueType = VAL_Object; - } - else if (type->IsKindOf(RUNTIME_CLASS(PInt))) - { - ValueType = VAL_Int; - } - else if (type->IsKindOf(RUNTIME_CLASS(PFloat))) - { - ValueType = VAL_Float; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Invalid type for member variable %s", membervar->SymbolName.GetChars()); - delete this; - return NULL; - } - if (arraytype != NULL) - { - ValueType.MakeArray(arraytype->ElementCount); - } + ValueType = membervar->Type; return this; } @@ -3067,7 +2967,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Array,ctx); SAFE_RESOLVE(index,ctx); - if (index->ValueType == VAL_Float /* lax */) + if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */) { // DECORATE allows floats here so cast them to int. index = new FxIntCast(index); @@ -3078,22 +2978,23 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return NULL; } } - if (index->ValueType != VAL_Int) + if (index->ValueType->GetRegType() != REGT_INT) { ScriptPosition.Message(MSG_ERROR, "Array index must be integer"); delete this; return NULL; } - if (Array->ValueType != VAL_Array) + PArray *arraytype = dyn_cast(Array->ValueType); + if (arraytype == NULL) { ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); delete this; return NULL; } - ValueType = Array->ValueType.GetBaseType(); - if (ValueType != VAL_Int) + ValueType = arraytype->ElementType; + if (ValueType->GetRegType() != REGT_INT) { // int arrays only for now ScriptPosition.Message(MSG_ERROR, "Only integer arrays are supported."); @@ -3122,8 +3023,8 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) } if (index->isConstant()) { - int indexval = static_cast(index)->GetValue().GetInt(); - if (indexval < 0 || indexval >= Array->ValueType.size) + unsigned indexval = static_cast(index)->GetValue().GetInt(); + if (indexval >= static_cast(Array->ValueType)->ElementCount) { I_Error("Array index out of bounds"); } @@ -3134,7 +3035,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit indexv(index->Emit(build)); build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2); - build->Emit(OP_BOUND, indexv.RegNum, Array->ValueType.size); + build->Emit(OP_BOUND, indexv.RegNum, static_cast(Array->ValueType)->ElementCount); build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum); indexv.Free(build); } @@ -3275,21 +3176,21 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) if (ArgList != NULL) { - for(unsigned i = 0; i < ArgList->Size(); i++) + for (unsigned i = 0; i < ArgList->Size(); i++) { (*ArgList)[i] = (*ArgList)[i]->Resolve(ctx); if ((*ArgList)[i] == NULL) failed = true; if (Special < 0 && i == 0) { - if ((*ArgList)[i]->ValueType != VAL_Name) + if ((*ArgList)[i]->ValueType != TypeName) { ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i); failed = true; } } - else if ((*ArgList)[i]->ValueType != VAL_Int) + else if ((*ArgList)[i]->ValueType->GetRegType() != REGT_INT) { - if ((*ArgList)[i]->ValueType == VAL_Float /* lax */) + if ((*ArgList)[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */) { (*ArgList)[i] = new FxIntCast((*ArgList)[i]); } @@ -3306,7 +3207,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) return NULL; } } - ValueType = VAL_Int; + ValueType = TypeSInt32; return this; } @@ -3347,13 +3248,13 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) FxExpression *argex = (*ArgList)[i]; if (Special < 0 && i == 0) { - assert(argex->ValueType == VAL_Name); + assert(argex->ValueType == TypeName); assert(argex->isConstant()); build->EmitParamInt(-static_cast(argex)->GetValue().GetName()); } else { - assert(argex->ValueType == VAL_Int); + assert(argex->ValueType->GetRegType() == REGT_INT); if (argex->isConstant()) { build->EmitParamInt(static_cast(argex)->GetValue().GetInt()); @@ -3432,17 +3333,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) TArray &rets = Function->Variants[0].Implementation->Proto->ReturnTypes; if (rets.Size() > 0) { - // If more types are added to ParseNativeFunction(), add them here too. - if (rets[0] == TypeSInt32) ValueType = VAL_Int; - else if (rets[0] == TypeFloat64) ValueType = VAL_Float; - else if (rets[0] == TypeAngle) ValueType = VAL_Angle; - else if (rets[0] == TypeFixed) ValueType = VAL_Fixed; - else if (rets[0] == TypeState) ValueType = VAL_State; - else - { - ValueType = VAL_Int; - assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve"); - } + ValueType = rets[0]; } return this; } @@ -3465,6 +3356,14 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); int count = GetArgCount(); + if (count == 1) + { + ExpEmit reg; + if (CheckEmitCast(build, tailcall, reg)) + { + return reg; + } + } // Emit code to pass implied parameters if (Function->Flags & VARF_Method) { @@ -3482,7 +3381,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) { for (unsigned i = 0; i < ArgList->Size(); ++i) { - (*ArgList)[i]->Emit(build); + EmitParameter(build, (*ArgList)[i], ScriptPosition); } } // Get a constant register for this function @@ -3508,6 +3407,47 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) } } +//========================================================================== +// +// If calling one of the casting kludge functions, don't bother calling the +// function; just use the parameter directly. Returns true if this was a +// kludge function, false otherwise. +// +//========================================================================== + +bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®) +{ + FName funcname = Function->SymbolName; + if (funcname == NAME___decorate_internal_int__ || + funcname == NAME___decorate_internal_bool__ || + funcname == NAME___decorate_internal_state__) + { + FxExpression *arg = (*ArgList)[0]; + if (returnit) + { + if (arg->isConstant() && + (funcname == NAME___decorate_internal_int__ || + funcname == NAME___decorate_internal_bool__)) + { // Use immediate version for integers in range + build->EmitRetInt(0, true, static_cast(arg)->GetValue().Int); + } + else + { + ExpEmit where = arg->Emit(build); + build->Emit(OP_RET, RET_FINAL, where.RegType | (where.Konst ? REGT_KONST : 0), where.RegNum); + where.Free(build); + } + reg = ExpEmit(); + } + else + { + reg = arg->Emit(build); + } + return true; + } + return false; +} + //========================================================================== // // @@ -3518,7 +3458,7 @@ FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList *args, const : FxExpression(pos) { assert(index < countof(FxFlops) && "FLOP index out of range"); - Index = index; + Index = (int)index; ArgList = args; } @@ -3551,7 +3491,7 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) return NULL; } - if (!(*ArgList)[0]->ValueType.isNumeric()) + if (!(*ArgList)[0]->IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); delete this; @@ -3565,11 +3505,11 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) delete this; return x; } - if ((*ArgList)[0]->ValueType == VAL_Int) + if ((*ArgList)[0]->ValueType->GetRegType() == REGT_INT) { (*ArgList)[0] = new FxFloatCast((*ArgList)[0]); } - ValueType = VAL_Float; + ValueType = TypeFloat64; return this; } @@ -3682,7 +3622,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) WhenFalse = WhenFalse->Resolve(ctx); ABORT(WhenFalse); } - ValueType = VAL_Unknown; + ValueType = TypeVoid; if (Condition->isConstant()) { @@ -3834,7 +3774,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); - if (basex->ValueType != VAL_Name) + if (basex->ValueType != TypeName) { ScriptPosition.Message(MSG_ERROR, "Cannot convert to class type"); delete this; @@ -3904,7 +3844,7 @@ int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) { - if (basex->ValueType != VAL_Name) + if (basex->ValueType != TypeName) { return ExpEmit(build->GetConstantAddress(NULL, ATAG_OBJECT), REGT_POINTER, true); } @@ -4035,7 +3975,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) } names.Delete(0); names.ShrinkToFit(); - ValueType = VAL_State; + ValueType = TypeState; return this; } @@ -4133,7 +4073,7 @@ FxDamageValue::FxDamageValue(FxExpression *v, bool calc) : FxExpression(v->ScriptPosition) { val = v; - ValueType = VAL_Unknown; + ValueType = TypeVoid; Calculated = calc; MyFunction = NULL; @@ -4154,7 +4094,7 @@ FxExpression *FxDamageValue::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(val, ctx) - if (!val->ValueType.isNumeric()) + if (!val->IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index daff4a99b..105bf237f 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -127,7 +127,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c v = MAKEARGB(1, RPART(c), GPART(c), BPART(c)); } ExpVal val; - val.Type = VAL_Color; + val.Type = TypeColor; val.Int = v; x = new FxConstant(val, sc); } diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 50b03eb27..702758eb7 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -77,7 +77,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) if (special > 0 && min_args >= 0) { FArgumentList *args = new FArgumentList; - args->Push(new FxParameter(new FxConstant(special, sc))); + args->Push(new FxConstant(special, sc)); i = 0; // Make this consistent with all other parameter parsing @@ -85,7 +85,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { while (i < 5) { - args->Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info)))); + args->Push(new FxIntCast(ParseExpression(sc, bag.Info))); i++; if (!sc.CheckToken (',')) break; } @@ -441,6 +441,45 @@ static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner // //========================================================================== +static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, + PPrototype *&retproto, bool &lastwasret) +{ + FxExpression *add, *cond; + FxExpression *true_part, *false_part = NULL; + PPrototype *true_proto, *false_proto = NULL; + bool true_ret, false_ret = false; + sc.MustGetStringName("("); + cond = ParseExpression(sc, bag.Info); + sc.MustGetStringName(")"); + sc.MustGetStringName("{"); // braces are mandatory + true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret); + sc.MustGetString(); + if (sc.Compare("else")) + { + if (sc.CheckString("if")) + { + false_part = ParseIf(sc, state, statestring, bag, false_proto, false_ret); + } + else + { + sc.MustGetStringName("{"); // braces are still mandatory + false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret); + sc.MustGetString(); + } + } + add = new FxIfStatement(cond, true_part, false_part, sc); + retproto = ReturnCheck(retproto, true_proto, sc); + retproto = ReturnCheck(retproto, false_proto, sc); + // If one side does not end with a return, we don't consider the if statement + // to end with a return. If the else case is missing, it can never be considered + // as ending with a return. + if (true_ret && false_ret) + { + lastwasret = true; + } + return add; +} + FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&retproto, bool &endswithret) { @@ -467,32 +506,7 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg lastwasret = false; if (sc.Compare("if")) { // Hangle an if statement - FxExpression *cond; - FxExpression *true_part, *false_part = NULL; - PPrototype *true_proto, *false_proto = NULL; - bool true_ret, false_ret = false; - sc.MustGetStringName("("); - cond = ParseExpression(sc, bag.Info); - sc.MustGetStringName(")"); - sc.MustGetStringName("{"); // braces are mandatory - true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret); - sc.MustGetString(); - if (sc.Compare("else")) - { - sc.MustGetStringName("{"); // braces are still mandatory - false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret); - sc.MustGetString(); - } - add = new FxIfStatement(cond, true_part, false_part, sc); - proto = ReturnCheck(proto, true_proto, sc); - proto = ReturnCheck(proto, false_proto, sc); - // If one side does not end with a return, we don't consider the if statement - // to end with a return. If the else case is missing, it can never be considered - // as ending with a return. - if (true_ret && false_ret) - { - lastwasret = true; - } + add = ParseIf(sc, state, statestring, bag, proto, lastwasret); } else if (sc.Compare("return")) { // Handle a return statement @@ -569,7 +583,7 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B } return call; } - sc.ScriptError("Invalid state parameter %s\n", sc.String); + sc.ScriptError("Invalid parameter '%s'\n", sc.String); return NULL; } @@ -647,7 +661,7 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray 0) diff --git a/src/thingdef/thingdef_type.h b/src/thingdef/thingdef_type.h deleted file mode 100644 index 1707a8939..000000000 --- a/src/thingdef/thingdef_type.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef THINGDEF_TYPE_H -#define THINGDEF_TYPE_H -//========================================================================== -// -// -// -//========================================================================== - -enum ExpValType -{ - VAL_Unresolved, // type not yet known - VAL_Int, // integer number - VAL_Float, // floating point number - VAL_Unknown, // nothing - VAL_Array, // Array (very limited right now) - VAL_Object, // Object reference - VAL_Class, // Class reference - VAL_Sound, // Sound identifier. Internally it's an int. - VAL_Name, // A Name - VAL_String, // A string - VAL_Color, // A color - VAL_State, // A State pointer - - // only used for accessing external variables to ensure proper conversion - VAL_Fixed, - VAL_Angle, - VAL_Bool, -}; - -struct FExpressionType -{ - BYTE Type; - BYTE BaseType; - WORD size; // for arrays; - const PClass *ClassType; - - FExpressionType &operator=(int typeval) - { - Type = typeval; - BaseType = 0; - size = 0; - ClassType = NULL; - return *this; - } - - FExpressionType &operator=(const PClass *cls) - { - Type = VAL_Class; - BaseType = 0; - size = 0; - ClassType = cls; - return *this; - } - - bool operator==(int typeval) const - { - return Type == typeval; - } - - bool operator!=(int typeval) const - { - return Type != typeval; - } - - bool isNumeric() const - { - return Type == VAL_Float || Type == VAL_Int; - } - - bool isPointer() const - { - return Type == VAL_Object || Type == VAL_Class; - } - - FExpressionType GetBaseType() const - { - FExpressionType ret = *this; - ret.Type = BaseType; - ret.BaseType = 0; - ret.size = 0; - return ret; - } - - - // currently only used for args[]. - // Needs to be done differently for a generic implementation! - void MakeArray(int siz) - { - BaseType = Type; - Type = VAL_Array; - size = siz; - } - -}; - -#endif diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp index 0735e3553..70d10fa30 100644 --- a/src/win32/i_crash.cpp +++ b/src/win32/i_crash.cpp @@ -45,7 +45,13 @@ #include #endif #ifndef __GNUC__ +#if _MSC_VER +#pragma warning(disable:4091) // this silences a warning for a bogus definition in the Windows 8.1 SDK. +#endif #include +#if _MSC_VER +#pragma warning(default:4091) +#endif #endif #include #include diff --git a/src/win32/zdoom.RES b/src/win32/zdoom.RES deleted file mode 100644 index 55d9e7549..000000000 Binary files a/src/win32/zdoom.RES and /dev/null differ diff --git a/src/zscript/vm.h b/src/zscript/vm.h index f92906fd2..5b37aa47c 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -900,7 +900,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a; #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; #define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); // For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.: // PARAM_INT_OPT(0,myint) { myint = 55; } @@ -918,7 +918,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else #define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else #define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else -#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); } else +#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else // The above, but with an automatically increasing position index. #define PARAM_PROLOGUE int paramnum = -1; diff --git a/tools/fixrtext/fixrtext.vcproj b/tools/fixrtext/fixrtext.vcproj deleted file mode 100644 index 33bfde6f0..000000000 --- a/tools/fixrtext/fixrtext.vcproj +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/lemon/lemon.vcproj b/tools/lemon/lemon.vcproj deleted file mode 100644 index d3205b967..000000000 --- a/tools/lemon/lemon.vcproj +++ /dev/null @@ -1,431 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/re2c/re2c.vcproj b/tools/re2c/re2c.vcproj deleted file mode 100644 index 81d8c4941..000000000 --- a/tools/re2c/re2c.vcproj +++ /dev/null @@ -1,845 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/updaterevision/updaterevision.vcproj b/tools/updaterevision/updaterevision.vcproj deleted file mode 100644 index 17675b681..000000000 --- a/tools/updaterevision/updaterevision.vcproj +++ /dev/null @@ -1,376 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/zipdir/zipdir.vcproj b/tools/zipdir/zipdir.vcproj deleted file mode 100644 index e279e551c..000000000 --- a/tools/zipdir/zipdir.vcproj +++ /dev/null @@ -1,356 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index c3de91e30..19e4d4f6d 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -1,216 +1,217 @@ -#include "xlat/doom.txt" - -// xlat file for Eternity levels. -// Many specials are unsupported, especially portal stuff. -// Some unsupported linedefs wouldn't be hard to add to ZDoom, -// or are already there but implemented differently. Others are -// practically impossible, or aren't worth the effort. - -define Unsupported (0) - -enum -{ - Init_EDSector = 253, - Init_EDLine = 254 -} - -// The tag for such a line is actually a key to find, in an ExtraData lump -// indicated for the current level by the EMAPINFO lump, what line special -// to actually use. This is how parameterized linedefs are used by Eternity -// in the Doom format. - -270 = 0, Static_Init(tag, Init_EDLine) // "ExtraDataSpecial" - -// These two are standard MBF specials, no need to redefine them, they're in xlat/doom.txt -// 271 = 0, Static_Init (tag, Init_TransferSky, 0) -// 272 = 0, Static_Init (tag, Init_TransferSky, 1) - -// Small script starters. Small is considered deprecated now anyway. -273 = 0, Unsupported() // "WR_StartScript_1S" -274 = 0, Unsupported() // "W1_StartScript" -275 = 0, Unsupported() // "W1_StartScript_1S" -276 = 0, Unsupported() // "SR_StartScript" -277 = 0, Unsupported() // "S1_StartScript" -278 = 0, Unsupported() // "GR_StartScript" -279 = 0, Unsupported() // "G1_StartScript" -280 = 0, Unsupported() // "WR_StartScript" - -// 3D mid-textures -281 = 0, Sector_Attach3DMidtex(tag, 0, 0) // "3DMidTex_MoveWithFloor" -282 = 0, Sector_Attach3DMidtex(tag, 0, 1) // "3DMidTex_MoveWithCeiling" - -// Plane portals are not supported in ZDoom, though they probably wouldn't be too hard to implement. -283 = 0, Sector_SetPortal(tag,3, 1, 0, 0) // "Portal_PlaneCeiling" -284 = 0, Sector_SetPortal(tag,3, 0, 0, 0) // "Portal_PlaneFloor" -285 = 0, Sector_SetPortal(tag,3, 2, 0, 0) // "Portal_PlaneFloorCeiling" -286 = 0, Sector_SetPortal(tag,4, 1, 0, 0) // "Portal_HorizonCeiling" -287 = 0, Sector_SetPortal(tag,4, 0, 0, 0) // "Portal_HorizonFloor" -288 = 0, Sector_SetPortal(tag,4, 2, 0, 0) // "Portal_HorizonFloorCeiling" -289 = 0, Sector_SetPortal(0, 5, 0, tag) // "Portal_LineTransfer" - -// Skybox portals -290 = 0, Sector_SetPortal(tag, 2, 1, 1, 0) // "Portal_SkyboxCeiling" -291 = 0, Sector_SetPortal(tag, 2, 0, 1, 0) // "Portal_SkyboxFloor" -292 = 0, Sector_SetPortal(tag, 2, 2, 1, 0) // "Portal_SkyboxFloorCeiling" - -// Sector specials -293 = 0, Sector_SetWind(tag, 0, 0, 1) // "TransferHereticWind" -294 = 0, Sector_SetCurrent(tag, 0, 0, 1) // "TransferHereticCurrent" - -// Anchored portals -- Sector_SetPortal needs to allow to set both floor and ceiling, though. -295 = 0, Sector_SetPortal(tag, 0, 1, 1, 0) // "Portal_AnchoredCeiling" -296 = 0, Sector_SetPortal(tag, 0, 0, 1, 0) // "Portal_AnchoredFloor" -297 = 0, Sector_SetPortal(tag, 0, 2, 1, 0) // "Portal_AnchoredFloorCeiling" -298 = 0, Sector_SetPortal(tag, 0, 1, 0, 0) // "Portal_AnchorLine" -299 = 0, Sector_SetPortal(tag, 0, 0, 0, 0) // "Portal_AnchorLineFloor" - -// Parameterized linedefs -// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270. -// Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF. -// The translation here is for the odd Extradata that specifies them as numbers. -300 = 0, Door_Raise(0) -301 = 0, Door_Open(0) -302 = 0, Door_Close(0) -303 = 0, Door_CloseWaitOpen(0) -304 = 0, Door_WaitRaise(0) -305 = 0, Door_WaitClose(0) -306 = 0, Floor_RaiseToHighest(0) -307 = 0, Floor_LowerToHighestEE(0) -308 = 0, Floor_RaiseToLowest(0) -309 = 0, Floor_LowerToLowest(0) -310 = 0, Floor_RaiseToNearest(0) -311 = 0, Floor_LowerToNearest(0) -312 = 0, Floor_RaiseToLowestCeiling(0) -313 = 0, Floor_LowerToLowestCeiling(0) -314 = 0, Floor_RaiseToCeiling(0) -315 = 0, Floor_RaiseByTexture(0) -316 = 0, Floor_LowerByTexture(0) -317 = 0, Floor_RaiseByValue(0) -318 = 0, Floor_LowerByValue(0) -319 = 0, Floor_MoveToValue(0) -320 = 0, Floor_RaiseInstant(0) -321 = 0, Floor_LowerInstant(0) -322 = 0, Floor_ToCeilingInstant(0) -323 = 0, Ceiling_RaiseToHighest(0) -324 = 0, Ceiling_ToHighestInstant(0) -325 = 0, Ceiling_RaiseToNearest(0) -326 = 0, Ceiling_LowerToNearest(0) -327 = 0, Ceiling_RaiseToLowest(0) -328 = 0, Ceiling_LowerToLowest(0) -329 = 0, Ceiling_RaiseToHighestFloor(0) -330 = 0, Ceiling_LowerToHighestFloor(0) -331 = 0, Ceiling_ToFloorInstant(0) -332 = 0, Ceiling_LowerToFloor(0) -333 = 0, Ceiling_RaiseByTexture(0) -334 = 0, Ceiling_LowerByTexture(0) -335 = 0, Ceiling_RaiseByValue(0) -336 = 0, Ceiling_LowerByValue(0) -337 = 0, Ceiling_MoveToValue(0) -338 = 0, Ceiling_RaiseInstant(0) -339 = 0, Ceiling_LowerInstant(0) -340 = 0, Stairs_BuildUpDoom(0) -341 = 0, Stairs_BuildDownDoom(0) -342 = 0, Stairs_BuildUpDoomSync(0) -343 = 0, Stairs_BuildDownDoomSync(0) - -// Two-way portals are not supported yet either -344 = 0, Unsupported() // "Portal_TwowayCeiling" -345 = 0, Unsupported() // "Portal_TwowayFloor" -346 = 0, Unsupported() // "Portal_TwowayAnchorLine" -347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor" - -// More parameterized linedefs -348 = 0, Polyobj_StartLine(0) -349 = 0, Polyobj_ExplicitLine(0) -350 = 0, Polyobj_DoorSlide(0) -351 = 0, Polyobj_DoorSwing(0) -352 = 0, Polyobj_Move(0) -353 = 0, Polyobj_OR_Move(0) -354 = 0, Polyobj_RotateRight(0) -355 = 0, Polyobj_OR_RotateRight(0) -356 = 0, Polyobj_RotateLeft(0) -357 = 0, Polyobj_OR_RotateLeft(0) - -// Eternity's linked portals, vertical link version (floor-to-ceiling) -358 = 0, Sector_SetPortal(tag, 6, 1, 1, 0) // "Portal_AnchoredCeiling" -359 = 0, Sector_SetPortal(tag, 6, 0, 1, 0) // "Portal_AnchoredFloor" -360 = 0, Sector_SetPortal(tag, 6, 1, 0, 0) // "Portal_AnchorLine" -361 = 0, Sector_SetPortal(tag, 6, 0, 0, 0) // "Portal_AnchorLineFloor" - -// Even more parameterized linedefs -362 = 0, Pillar_Build(0) -363 = 0, Pillar_BuildAndCrush(0) -364 = 0, Pillar_Open(0) -365 = 0, ACS_Execute(0) -366 = 0, ACS_Suspend(0) -367 = 0, ACS_Terminate(0) -368 = 0, Light_RaiseByValue(0) -369 = 0, Light_LowerByValue(0) -370 = 0, Light_ChangeToValue(0) -371 = 0, Light_Fade(0) -372 = 0, Light_Glow(0) -373 = 0, Light_Flicker(0) -374 = 0, Light_Strobe(0) -375 = 0, Radius_Quake(0) - -// Eternity's linked portals, horizontal link version (wall-to-wall) -376 = 0, Line_SetPortal(0, tag, 4) // "Portal_LinkedLineToLine" -377 = 0, Line_SetPortal(1, tag, 4) // "Portal_LinkedLineToLineAnchor" - -// The famous Hexen linedef -378 = 0, Line_SetIdentification(0) - -// Attached sectors == linked sectors; However, the implementation in Eternity -// is based on front sectors of tagged lines, not on sector tags. So instead -// of Sector_SetLink, we pass through Static_Init to translate those. -379 = 0, Static_Init(tag, 3, 1) // "Attach_SetCeilingControl" -380 = 0, Static_Init(tag, 3, 0) // "Attach_SetFloorControl" -381 = 0, Static_Init(0, 3, 0, 1) // "Attach_FloorToControl" -382 = 0, Static_Init(0, 3, 1, 2) // "Attach_CeilingToControl" -383 = 0, Static_Init(0, 3, 0, 5) // "Attach_MirrorFloorToControl" -384 = 0, Static_Init(0, 3, 0, 10) // "Attach_MirrorCeilingToControl" - -// Attach tagged portal to front sector -385 = 0, Sector_SetPortal(0, 1, 3, tag) // "Apply_PortalToFrontsector" - -// Slopes! -386 = 0, Plane_Align (1, 0) // "Slope_FrontsectorFloor" -387 = 0, Plane_Align (0, 1) // "Slope_FrontsectorCeiling" -388 = 0, Plane_Align (1, 1) // "Slope_FrontsectorFloorAndCeiling" -389 = 0, Plane_Align (2, 0) // "Slope_BacksectorFloor" -390 = 0, Plane_Align (0, 2) // "Slope_BacksectorCeiling" -391 = 0, Plane_Align (2, 2) // "Slope_BacksectorFloorAndCeiling" -392 = 0, Plane_Align (2, 1) // "Slope_BackFloorAndFrontCeiling" -393 = 0, Plane_Align (1, 2) // "Slope_BackCeilingAndFrontFloor" -394 = 0, Plane_Copy (tag, 0) // "Slope_FrontFloorToTaggedSlope" -395 = 0, Plane_Copy (0, tag) // "Slope_FrontCeilingToTaggedSlope" -396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope" - -// Last parameterized linedefs -397 = 0, Floor_Waggle(0) -398 = 0, Thing_Spawn(0) -399 = 0, Thing_SpawnNoFog(0) -400 = 0, Teleport_EndGame(0) - -401 = 0, Static_Init(tag, Init_EDSector) - -402 = 0, Thing_Projectile(0) -403 = 0, Thing_ProjectileGravity(0) -404 = 0, Thing_Activate(0) -405 = 0, Thing_Deactivate(0) -410 = 0, Plat_PerpetualRaise(0) -411 = 0, Plat_Stop(0) -412 = 0, Plat_DownWaitUpStay(0) -413 = 0, Plat_DownByValue(0) -414 = 0, Plat_UpWaitDownStay(0) -415 = 0, Plat_UpByValue(0) -416 = 0, Floor_LowerToHighest(0) -420 = 0, ACS_ExecuteWithResult(0) -421 = 0, Thing_ChangeTID(0) -422 = 0, Thing_Raise(0) -423 = 0, Thing_Stop(0) -424 = 0, ThrustThing(0) -425 = 0, ThrustThingZ(0) -426 = 0, DamageThing(0) -427 = 0, Thing_Damage(0) -428 = 0, Thing_Destroy(0) +#include "xlat/doom.txt" + +// xlat file for Eternity levels. +// Many specials are unsupported, especially portal stuff. +// Some unsupported linedefs wouldn't be hard to add to ZDoom, +// or are already there but implemented differently. Others are +// practically impossible, or aren't worth the effort. + +define Unsupported (0) + +enum +{ + Init_EDSector = 253, + Init_EDLine = 254 +} + +// The tag for such a line is actually a key to find, in an ExtraData lump +// indicated for the current level by the EMAPINFO lump, what line special +// to actually use. This is how parameterized linedefs are used by Eternity +// in the Doom format. + +270 = 0, Static_Init(tag, Init_EDLine) // "ExtraDataSpecial" + +// These two are standard MBF specials, no need to redefine them, they're in xlat/doom.txt +// 271 = 0, Static_Init (tag, Init_TransferSky, 0) +// 272 = 0, Static_Init (tag, Init_TransferSky, 1) + +273 = WALK|REP|FIRSTSIDE, ACS_Execute(tag) +274 = WALK, ACS_Execute(tag) +275 = WALK|FIRSTSIDE, ACS_Execute(tag) +276 = USE|REP, ACS_Execute(tag) +277 = USE, ACS_Execute(tag) +278 = SHOOT|REP, ACS_Execute(tag) +279 = SHOOT, ACS_Execute(tag) +280 = WALK|REP, ACS_Execute(tag) + +// 3D mid-textures +281 = 0, Sector_Attach3DMidtex(tag, 0, 0) // "3DMidTex_MoveWithFloor" +282 = 0, Sector_Attach3DMidtex(tag, 0, 1) // "3DMidTex_MoveWithCeiling" + +// Plane portals are not supported in ZDoom, though they probably wouldn't be too hard to implement. +283 = 0, Sector_SetPortal(tag,3, 1, 0, 0) // "Portal_PlaneCeiling" +284 = 0, Sector_SetPortal(tag,3, 0, 0, 0) // "Portal_PlaneFloor" +285 = 0, Sector_SetPortal(tag,3, 2, 0, 0) // "Portal_PlaneFloorCeiling" +286 = 0, Sector_SetPortal(tag,4, 1, 0, 0) // "Portal_HorizonCeiling" +287 = 0, Sector_SetPortal(tag,4, 0, 0, 0) // "Portal_HorizonFloor" +288 = 0, Sector_SetPortal(tag,4, 2, 0, 0) // "Portal_HorizonFloorCeiling" +289 = 0, Sector_SetPortal(0, 5, 0, tag) // "Portal_LineTransfer" + +// Skybox portals +290 = 0, Sector_SetPortal(tag, 2, 1, 1, 0) // "Portal_SkyboxCeiling" +291 = 0, Sector_SetPortal(tag, 2, 0, 1, 0) // "Portal_SkyboxFloor" +292 = 0, Sector_SetPortal(tag, 2, 2, 1, 0) // "Portal_SkyboxFloorCeiling" + +// Sector specials +293 = 0, Sector_SetWind(tag, 0, 0, 1) // "TransferHereticWind" +294 = 0, Sector_SetCurrent(tag, 0, 0, 1) // "TransferHereticCurrent" + +// Anchored portals -- Sector_SetPortal needs to allow to set both floor and ceiling, though. +295 = 0, Sector_SetPortal(tag, 0, 1, 1, 0) // "Portal_AnchoredCeiling" +296 = 0, Sector_SetPortal(tag, 0, 0, 1, 0) // "Portal_AnchoredFloor" +297 = 0, Sector_SetPortal(tag, 0, 2, 1, 0) // "Portal_AnchoredFloorCeiling" +298 = 0, Sector_SetPortal(tag, 0, 1, 0, 0) // "Portal_AnchorLine" +299 = 0, Sector_SetPortal(tag, 0, 0, 0, 0) // "Portal_AnchorLineFloor" + +// Parameterized linedefs +// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270. +// Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF. +// The translation here is for the odd Extradata that specifies them as numbers. +300 = 0, Door_Raise(0) +301 = 0, Door_Open(0) +302 = 0, Door_Close(0) +303 = 0, Door_CloseWaitOpen(0) +304 = 0, Door_WaitRaise(0) +305 = 0, Door_WaitClose(0) +306 = 0, Floor_RaiseToHighest(0) +307 = 0, Floor_LowerToHighestEE(0) +308 = 0, Floor_RaiseToLowest(0) +309 = 0, Floor_LowerToLowest(0) +310 = 0, Floor_RaiseToNearest(0) +311 = 0, Floor_LowerToNearest(0) +312 = 0, Floor_RaiseToLowestCeiling(0) +313 = 0, Floor_LowerToLowestCeiling(0) +314 = 0, Floor_RaiseToCeiling(0) +315 = 0, Floor_RaiseByTexture(0) +316 = 0, Floor_LowerByTexture(0) +317 = 0, Floor_RaiseByValue(0) +318 = 0, Floor_LowerByValue(0) +319 = 0, Floor_MoveToValue(0) +320 = 0, Floor_RaiseInstant(0) +321 = 0, Floor_LowerInstant(0) +322 = 0, Floor_ToCeilingInstant(0) +323 = 0, Ceiling_RaiseToHighest(0) +324 = 0, Ceiling_ToHighestInstant(0) +325 = 0, Ceiling_RaiseToNearest(0) +326 = 0, Ceiling_LowerToNearest(0) +327 = 0, Ceiling_RaiseToLowest(0) +328 = 0, Ceiling_LowerToLowest(0) +329 = 0, Ceiling_RaiseToHighestFloor(0) +330 = 0, Ceiling_LowerToHighestFloor(0) +331 = 0, Ceiling_ToFloorInstant(0) +332 = 0, Ceiling_LowerToFloor(0) +333 = 0, Ceiling_RaiseByTexture(0) +334 = 0, Ceiling_LowerByTexture(0) +335 = 0, Ceiling_RaiseByValue(0) +336 = 0, Ceiling_LowerByValue(0) +337 = 0, Ceiling_MoveToValue(0) +338 = 0, Ceiling_RaiseInstant(0) +339 = 0, Ceiling_LowerInstant(0) +340 = 0, Stairs_BuildUpDoom(0) +341 = 0, Stairs_BuildDownDoom(0) +342 = 0, Stairs_BuildUpDoomSync(0) +343 = 0, Stairs_BuildDownDoomSync(0) + +// Two-way portals are not supported yet either +344 = 0, Unsupported() // "Portal_TwowayCeiling" +345 = 0, Unsupported() // "Portal_TwowayFloor" +346 = 0, Unsupported() // "Portal_TwowayAnchorLine" +347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor" + +// More parameterized linedefs +348 = 0, Polyobj_StartLine(0) +349 = 0, Polyobj_ExplicitLine(0) +350 = 0, Polyobj_DoorSlide(0) +351 = 0, Polyobj_DoorSwing(0) +352 = 0, Polyobj_Move(0) +353 = 0, Polyobj_OR_Move(0) +354 = 0, Polyobj_RotateRight(0) +355 = 0, Polyobj_OR_RotateRight(0) +356 = 0, Polyobj_RotateLeft(0) +357 = 0, Polyobj_OR_RotateLeft(0) + +// Eternity's linked portals, vertical link version (floor-to-ceiling) +358 = 0, Sector_SetPortal(tag, 6, 1, 1, 0) // "Portal_AnchoredCeiling" +359 = 0, Sector_SetPortal(tag, 6, 0, 1, 0) // "Portal_AnchoredFloor" +360 = 0, Sector_SetPortal(tag, 6, 1, 0, 0) // "Portal_AnchorLine" +361 = 0, Sector_SetPortal(tag, 6, 0, 0, 0) // "Portal_AnchorLineFloor" + +// Even more parameterized linedefs +362 = 0, Pillar_Build(0) +363 = 0, Pillar_BuildAndCrush(0) +364 = 0, Pillar_Open(0) +365 = 0, ACS_Execute(0) +366 = 0, ACS_Suspend(0) +367 = 0, ACS_Terminate(0) +368 = 0, Light_RaiseByValue(0) +369 = 0, Light_LowerByValue(0) +370 = 0, Light_ChangeToValue(0) +371 = 0, Light_Fade(0) +372 = 0, Light_Glow(0) +373 = 0, Light_Flicker(0) +374 = 0, Light_Strobe(0) +375 = 0, Radius_Quake(0) + +// Eternity's linked portals, horizontal link version (wall-to-wall) +376 = 0, Line_SetPortal(0, tag, 4) // "Portal_LinkedLineToLine" +377 = 0, Line_SetPortal(1, tag, 4) // "Portal_LinkedLineToLineAnchor" + +// The famous Hexen linedef +378 = 0, Line_SetIdentification(0) + +// Attached sectors == linked sectors; However, the implementation in Eternity +// is based on front sectors of tagged lines, not on sector tags. So instead +// of Sector_SetLink, we pass through Static_Init to translate those. +379 = 0, Static_Init(tag, 3, 1) // "Attach_SetCeilingControl" +380 = 0, Static_Init(tag, 3, 0) // "Attach_SetFloorControl" +381 = 0, Static_Init(0, 3, 0, 1) // "Attach_FloorToControl" +382 = 0, Static_Init(0, 3, 1, 2) // "Attach_CeilingToControl" +383 = 0, Static_Init(0, 3, 0, 5) // "Attach_MirrorFloorToControl" +384 = 0, Static_Init(0, 3, 0, 10) // "Attach_MirrorCeilingToControl" + +// Attach tagged portal to front sector +385 = 0, Sector_SetPortal(0, 1, 3, tag) // "Apply_PortalToFrontsector" + +// Slopes! +386 = 0, Plane_Align (1, 0) // "Slope_FrontsectorFloor" +387 = 0, Plane_Align (0, 1) // "Slope_FrontsectorCeiling" +388 = 0, Plane_Align (1, 1) // "Slope_FrontsectorFloorAndCeiling" +389 = 0, Plane_Align (2, 0) // "Slope_BacksectorFloor" +390 = 0, Plane_Align (0, 2) // "Slope_BacksectorCeiling" +391 = 0, Plane_Align (2, 2) // "Slope_BacksectorFloorAndCeiling" +392 = 0, Plane_Align (2, 1) // "Slope_BackFloorAndFrontCeiling" +393 = 0, Plane_Align (1, 2) // "Slope_BackCeilingAndFrontFloor" +394 = 0, Plane_Copy (tag, 0) // "Slope_FrontFloorToTaggedSlope" +395 = 0, Plane_Copy (0, tag) // "Slope_FrontCeilingToTaggedSlope" +396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope" + +// Last parameterized linedefs +397 = 0, Floor_Waggle(0) +398 = 0, Thing_Spawn(0) +399 = 0, Thing_SpawnNoFog(0) +400 = 0, Teleport_EndGame(0) + +401 = 0, Static_Init(tag, Init_EDSector) + +402 = 0, Thing_Projectile(0) +403 = 0, Thing_ProjectileGravity(0) +404 = 0, Thing_Activate(0) +405 = 0, Thing_Deactivate(0) +410 = 0, Plat_PerpetualRaise(0) +411 = 0, Plat_Stop(0) +412 = 0, Plat_DownWaitUpStay(0) +413 = 0, Plat_DownByValue(0) +414 = 0, Plat_UpWaitDownStay(0) +415 = 0, Plat_UpByValue(0) +416 = 0, Floor_LowerToHighest(0) +420 = 0, ACS_ExecuteWithResult(0) +421 = 0, Thing_ChangeTID(0) +422 = 0, Thing_Raise(0) +423 = 0, Thing_Stop(0) +424 = 0, ThrustThing(0) +425 = 0, ThrustThingZ(0) +426 = 0, DamageThing(0) +427 = 0, Thing_Damage(0) +428 = 0, Thing_Destroy(0) +429 = 0, Door_LockedRaise(0) +430 = 0, ACS_LockedExecute(0) diff --git a/wadsrc/wadsrc.vcproj b/wadsrc/wadsrc.vcproj deleted file mode 100644 index f5d63706b..000000000 --- a/wadsrc/wadsrc.vcproj +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/zdoom.sln b/zdoom.sln deleted file mode 100644 index 11dc1b075..000000000 --- a/zdoom.sln +++ /dev/null @@ -1,177 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zdoom", "zdoom.vcproj", "{8049475B-5C87-46F9-9358-635218A4EF18}" - ProjectSection(ProjectDependencies) = postProject - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96} = {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96} - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} = {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} - {6077B7D6-349F-4077-B552-3BC302EF5859} = {6077B7D6-349F-4077-B552-3BC302EF5859} - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} = {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} - {0F80ACBF-460E-44F0-B28E-B3272D1774A7} = {0F80ACBF-460E-44F0-B28E-B3272D1774A7} - {DA47396F-60C1-4BDE-A977-7F7DE461CF77} = {DA47396F-60C1-4BDE-A977-7F7DE461CF77} - {1D179D4B-F008-431B-8C72-111F8372584F} = {1D179D4B-F008-431B-8C72-111F8372584F} - {B68E0ABF-B627-48A3-A92F-D8F827A75054} = {B68E0ABF-B627-48A3-A92F-D8F827A75054} - {8997289F-10BF-4678-8BAA-3BB509C84953} = {8997289F-10BF-4678-8BAA-3BB509C84953} - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466} = {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466} - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4} = {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4} - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F} = {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcproj", "{F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lemon", "tools\lemon\lemon.vcproj", "{0F80ACBF-460E-44F0-B28E-B3272D1774A7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "re2c", "tools\re2c\re2c.vcproj", "{667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wadsrc", "wadsrc\wadsrc.vcproj", "{1D179D4B-F008-431B-8C72-111F8372584F}" - ProjectSection(ProjectDependencies) = postProject - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3} = {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "updaterevision", "tools\updaterevision\updaterevision.vcproj", "{6077B7D6-349F-4077-B552-3BC302EF5859}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg-6b", "jpeg-6b\jpeg-6b.vcproj", "{AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fixrtext", "tools\fixrtext\fixrtext.vcproj", "{DA47396F-60C1-4BDE-A977-7F7DE461CF77}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dumb_static", "dumb\vc6\dumb_static\dumb_static.vcproj", "{8997289F-10BF-4678-8BAA-3BB509C84953}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gdtoa", "gdtoa\gdtoa.vcproj", "{B68E0ABF-B627-48A3-A92F-D8F827A75054}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zipdir", "tools\zipdir\zipdir.vcproj", "{24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}" - ProjectSection(ProjectDependencies) = postProject - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4} = {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4} - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} = {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F} = {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lzmalib", "lzma\lzmalib.vcproj", "{6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "bzip2\bzip2.vcproj", "{A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "game-music-emu", "game-music-emu\game-music-emu.vcproj", "{9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|Win32.ActiveCfg = Debug|Win32 - {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|Win32.Build.0 = Debug|Win32 - {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|x64.ActiveCfg = Debug|x64 - {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|x64.Build.0 = Debug|x64 - {8049475B-5C87-46F9-9358-635218A4EF18}.Release|Win32.ActiveCfg = Release|Win32 - {8049475B-5C87-46F9-9358-635218A4EF18}.Release|Win32.Build.0 = Release|Win32 - {8049475B-5C87-46F9-9358-635218A4EF18}.Release|x64.ActiveCfg = Release|x64 - {8049475B-5C87-46F9-9358-635218A4EF18}.Release|x64.Build.0 = Release|x64 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|Win32.ActiveCfg = Debug|Win32 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|Win32.Build.0 = Debug|Win32 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|x64.ActiveCfg = Debug|x64 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|x64.Build.0 = Debug|x64 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|Win32.ActiveCfg = Release|Win32 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|Win32.Build.0 = Release|Win32 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|x64.ActiveCfg = Release|x64 - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|x64.Build.0 = Release|x64 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|Win32.ActiveCfg = Debug|Win32 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|Win32.Build.0 = Debug|Win32 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|x64.ActiveCfg = Release|Win32 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|x64.Build.0 = Release|Win32 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|Win32.ActiveCfg = Release|Win32 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|Win32.Build.0 = Release|Win32 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|x64.ActiveCfg = Release|Win32 - {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|x64.Build.0 = Release|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|Win32.ActiveCfg = Debug|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|Win32.Build.0 = Debug|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|x64.ActiveCfg = Release|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|x64.Build.0 = Release|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|Win32.ActiveCfg = Release|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|Win32.Build.0 = Release|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|x64.ActiveCfg = Release|Win32 - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|x64.Build.0 = Release|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|Win32.ActiveCfg = Debug|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|Win32.Build.0 = Debug|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|x64.ActiveCfg = Release|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|x64.Build.0 = Release|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Release|Win32.ActiveCfg = Release|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Release|Win32.Build.0 = Release|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Release|x64.ActiveCfg = Release|Win32 - {1D179D4B-F008-431B-8C72-111F8372584F}.Release|x64.Build.0 = Release|Win32 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|Win32.ActiveCfg = Debug|Win32 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|Win32.Build.0 = Debug|Win32 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|x64.ActiveCfg = Debug|x64 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|x64.Build.0 = Debug|x64 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|Win32.ActiveCfg = Release|Win32 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|Win32.Build.0 = Release|Win32 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|x64.ActiveCfg = Release|x64 - {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|x64.Build.0 = Release|x64 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|Win32.ActiveCfg = Debug|Win32 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|Win32.Build.0 = Debug|Win32 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|x64.ActiveCfg = Debug|x64 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|x64.Build.0 = Debug|x64 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|Win32.ActiveCfg = Release|Win32 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|Win32.Build.0 = Release|Win32 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|x64.ActiveCfg = Release|x64 - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|x64.Build.0 = Release|x64 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|Win32.Build.0 = Debug|Win32 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|x64.ActiveCfg = Debug|Win32 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|x64.Build.0 = Debug|Win32 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|Win32.ActiveCfg = Release|Win32 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|Win32.Build.0 = Release|Win32 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|x64.ActiveCfg = Release|Win32 - {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|x64.Build.0 = Release|Win32 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|Win32.ActiveCfg = Debug|Win32 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|Win32.Build.0 = Debug|Win32 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|x64.ActiveCfg = Debug|x64 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|x64.Build.0 = Debug|x64 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|Win32.ActiveCfg = Release|Win32 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|Win32.Build.0 = Release|Win32 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|x64.ActiveCfg = Release|x64 - {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|x64.Build.0 = Release|x64 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|Win32.ActiveCfg = Debug|Win32 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|Win32.Build.0 = Debug|Win32 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|x64.ActiveCfg = Debug|x64 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|x64.Build.0 = Debug|x64 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|Win32.ActiveCfg = Release|Win32 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|Win32.Build.0 = Release|Win32 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|x64.ActiveCfg = Release|x64 - {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|x64.Build.0 = Release|x64 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|Win32.ActiveCfg = Debug|Win32 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|Win32.Build.0 = Debug|Win32 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|x64.ActiveCfg = Debug|x64 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|x64.Build.0 = Debug|x64 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|Win32.ActiveCfg = Release|Win32 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|Win32.Build.0 = Release|Win32 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|x64.ActiveCfg = Release|x64 - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|x64.Build.0 = Release|x64 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|Win32.ActiveCfg = Debug|Win32 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|Win32.Build.0 = Debug|Win32 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|x64.ActiveCfg = Debug|x64 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|x64.Build.0 = Debug|x64 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|Win32.ActiveCfg = Release|Win32 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|Win32.Build.0 = Release|Win32 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|x64.ActiveCfg = Release|x64 - {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|x64.Build.0 = Release|x64 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|Win32.ActiveCfg = Debug|Win32 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|Win32.Build.0 = Debug|Win32 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|x64.ActiveCfg = Debug|x64 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|x64.Build.0 = Debug|x64 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|Win32.ActiveCfg = Release|Win32 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|Win32.Build.0 = Release|Win32 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|x64.ActiveCfg = Release|x64 - {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|x64.Build.0 = Release|x64 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|Win32.ActiveCfg = Debug|Win32 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|Win32.Build.0 = Debug|Win32 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|x64.ActiveCfg = Release|x64 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|x64.Build.0 = Release|x64 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|Win32.ActiveCfg = Release|Win32 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|Win32.Build.0 = Release|Win32 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|x64.ActiveCfg = Release|x64 - {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/zdoom.vcproj b/zdoom.vcproj deleted file mode 100644 index 3b98c29b1..000000000 --- a/zdoom.vcproj +++ /dev/null @@ -1,6970 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/zlib/zlib.vcproj b/zlib/zlib.vcproj deleted file mode 100644 index 06d9ed48c..000000000 --- a/zlib/zlib.vcproj +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -