* Updated to ZDoom r3532:

- Added Thomas's patch to add a Pufftype parameter to A_Explode.
- Expanded 'info' CCMD to also print the TID.
- Added Xaser's weapon patch to check +reload and +zoom in A_WeaponReady.
- Added Xaser's modified version of kgsws's railgun enhancements patch.
- Added DavidPH's A_FaceTarget with pitch submission.
- Added NOTAUTOAIMED patch but did not set it for Heretic's pod.
- Added FDARI's submission for A_CustomMissile options.
- Added patch to have D'Sparil transfer his translations to his second state and the teleport effect.
- Fixed TArray compilation issue with GCC 4.7.
- Added FDARI's Default/global damagetype properties submission.
- Fixed ammo usage issues with Dehacked modified weapons that switch attack code pointers. Unless Dehacked specifies an 'ammo use' value for a weapon any Dehacked modified weapon determines ammo use by attack function, like Doom did originally, and not by the weapon's AmmoUse property. This also addresses that the Cells/BFG shot value always modified the BFG itself.
- Fixed: A_Saw depleted ammo after the attack so it still went through with it, even though it was out of ammo.
- Fixed: The bounce on actors check handled infinite bouncers (bouncecount == 0) incorrectly.


git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@1348 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
gez 2012-04-07 19:55:17 +00:00
parent 0d15a59cc2
commit f79b8147d9
34 changed files with 675 additions and 122 deletions

View file

@ -331,6 +331,7 @@ enum
MF6_POISONALWAYS = 0x04000000, // Always apply poison, even when target can't take the damage.
MF6_DOHARMSPECIES = 0x08000000, // Do hurt one's own species with projectiles.
MF6_INTRYMOVE = 0x10000000, // Executing P_TryMove
MF6_NOTAUTOAIMED = 0x20000000, // Do not subject actor to player autoaim.
// --- mobj.renderflags ---

View file

@ -162,6 +162,41 @@ struct CodePointerAlias
};
static TArray<CodePointerAlias> MBFCodePointers;
struct AmmoPerAttack
{
actionf_p func;
int ammocount;
};
DECLARE_ACTION(A_Punch)
DECLARE_ACTION(A_FirePistol)
DECLARE_ACTION(A_FireShotgun)
DECLARE_ACTION(A_FireShotgun2)
DECLARE_ACTION(A_FireCGun)
DECLARE_ACTION(A_FireMissile)
DECLARE_ACTION_PARAMS(A_Saw)
DECLARE_ACTION(A_FirePlasma)
DECLARE_ACTION(A_FireBFG)
DECLARE_ACTION(A_FireOldBFG)
DECLARE_ACTION(A_FireRailgun)
// Default ammo use of the various weapon attacks
static AmmoPerAttack AmmoPerAttacks[] = {
{ AF_A_Punch, 0},
{ AF_A_FirePistol, 1},
{ AF_A_FireShotgun, 1},
{ AF_A_FireShotgun2, 2},
{ AF_A_FireCGun, 1},
{ AF_A_FireMissile, 1},
{ AFP_A_Saw, 0},
{ AF_A_FirePlasma, 1},
{ AF_A_FireBFG, -1}, // uses deh.BFGCells
{ AF_A_FireOldBFG, 1},
{ AF_A_FireRailgun, 1},
{ NULL, 0}
};
// Miscellaneous info that used to be constant
DehInfo deh =
{
@ -183,6 +218,7 @@ DehInfo deh =
255, // Rocket explosion style, 255=use cvar
FRACUNIT*2/3, // Rocket explosion alpha
false, // .NoAutofreeze
40, // BFG cells per shot
};
// Doom identified pickup items by their sprites. ZDoom prefers to use their
@ -1589,6 +1625,7 @@ static int PatchWeapon (int weapNum)
else if (stricmp (Line1, "Ammo use") == 0 || stricmp (Line1, "Ammo per shot") == 0)
{
info->AmmoUse1 = val;
info->flags6 |= MF6_INTRYMOVE; // flag the weapon for postprocessing (reuse a flag that can't be set by external means)
}
else if (stricmp (Line1, "Min ammo") == 0)
{
@ -1742,7 +1779,7 @@ static int PatchMisc (int dummy)
{
if (stricmp (Line1, "BFG Cells/Shot") == 0)
{
((AWeapon*)GetDefaultByName ("BFG9000"))->AmmoUse1 = atoi (Line2);
deh.BFGCells = atoi (Line2);
}
else if (stricmp (Line1, "Rocket Explosion Style") == 0)
{
@ -2500,8 +2537,6 @@ static void UnloadDehSupp ()
BitNames.ShrinkToFit();
StyleNames.Clear();
StyleNames.ShrinkToFit();
WeaponNames.Clear();
WeaponNames.ShrinkToFit();
AmmoNames.Clear();
AmmoNames.ShrinkToFit();
@ -2794,6 +2829,7 @@ static bool LoadDehSupp ()
}
else if (sc.Compare("WeaponNames"))
{
WeaponNames.Clear(); // This won't be cleared by UnloadDEHSupp so we need to do it here explicitly
sc.MustGetStringName("{");
while (!sc.CheckString("}"))
{
@ -2900,6 +2936,55 @@ void FinishDehPatch ()
StateMap.ShrinkToFit();
TouchedActors.Clear();
TouchedActors.ShrinkToFit();
// Now it gets nasty: We have to fiddle around with the weapons' ammo use info to make Doom's original
// ammo consumption work as intended.
for(unsigned i = 0; i < WeaponNames.Size(); i++)
{
AWeapon *weap = (AWeapon*)GetDefaultByType(WeaponNames[i]);
bool found = false;
if (weap->flags6 & MF6_INTRYMOVE)
{
// Weapon sets an explicit amount of ammo to use so we won't need any special processing here
weap->flags6 &= ~MF6_INTRYMOVE;
}
else
{
weap->WeaponFlags |= WIF_DEHAMMO;
weap->AmmoUse1 = 0;
// to allow proper checks in CheckAmmo we have to find the first attack pointer in the Fire sequence
// and set its default ammo use as the weapon's AmmoUse1.
TMap<FState*, bool> StateVisited;
FState *state = WeaponNames[i]->ActorInfo->FindState(NAME_Fire);
while (state != NULL)
{
bool *check = StateVisited.CheckKey(state);
if (check != NULL && *check)
{
break; // State has already been checked so we reached a loop
}
StateVisited[state] = true;
for(unsigned j = 0; AmmoPerAttacks[j].func != NULL; j++)
{
if (state->ActionFunc == AmmoPerAttacks[j].func)
{
found = true;
int use = AmmoPerAttacks[j].ammocount;
if (use < 0) use = deh.BFGCells;
weap->AmmoUse1 = use;
break;
}
}
if (found) break;
state = state->GetNextState();
}
}
}
WeaponNames.Clear();
WeaponNames.ShrinkToFit();
}
void ModifyDropAmount(AInventory *inv, int dropamount);

View file

@ -90,8 +90,8 @@ typedef enum
BT_CROUCH = 1<<3,
BT_TURN180 = 1<<4,
BT_ALTATTACK = 1<<5, // Press your other "Fire".
BT_RELOAD = 1<<6, // Not connected to anything at the moment.
BT_ZOOM = 1<<7, // Neither is this.
BT_RELOAD = 1<<6, // [XA] Reload key. Causes state jump in A_WeaponReady.
BT_ZOOM = 1<<7, // [XA] Zoom key. Ditto.
// The rest are all ignored by the play simulation and are for scripts.
BT_SPEED = 1<<8,

View file

@ -205,6 +205,8 @@ typedef enum
CF_WEAPONREADYALT = 1 << 25, // Weapon can fire its secondary attack
CF_WEAPONSWITCHOK = 1 << 26, // It is okay to switch away from this weapon
CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die
CF_WEAPONRELOADOK = 1 << 28, // [XA] Okay to reload this weapon.
CF_WEAPONZOOMOK = 1 << 29, // [XA] Okay to use weapon zoom function.
} cheat_t;
#define WPIECE1 1

View file

@ -230,6 +230,7 @@ struct DehInfo
BYTE ExplosionStyle;
fixed_t ExplosionAlpha;
int NoAutofreeze;
int BFGCells;
};
extern DehInfo deh;
EXTERN_CVAR (Int, infighting)

View file

@ -36,7 +36,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch)
if (self->player != NULL)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
if (weapon != NULL && !(weapon->WeaponFlags & WIF_DEHAMMO))
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return;
@ -78,7 +78,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash));
@ -144,17 +144,15 @@ 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));
P_LineAttack (self, angle, Range,
slope, damage,
NAME_None, pufftype);
AWeapon *weapon = self->player->ReadyWeapon;
if ((weapon != NULL) && !(Flags & SF_NOUSEAMMO) && !(!linetarget && (Flags & SF_NOUSEAMMOMISS)))
if ((weapon != NULL) && !(Flags & SF_NOUSEAMMO) && !(!linetarget && (Flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO))
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return;
}
P_LineAttack (self, angle, Range, slope, damage, NAME_None, pufftype);
if (!linetarget)
{
if ((Flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64))
@ -224,7 +222,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
}
@ -255,7 +253,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2))
return;
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
}
@ -360,7 +358,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun)
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM);
@ -401,7 +399,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
}
P_SpawnPlayerMissile (self, PClass::FindClass("Rocket"));
@ -449,7 +447,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
FState *flash = weapon->FindState(NAME_Flash);
@ -478,7 +476,7 @@ static void FireRailgun(AActor *self, int RailOffset)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
FState *flash = weapon->FindState(NAME_Flash);
@ -530,7 +528,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, deh.BFGCells))
return;
}
@ -623,7 +621,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG)
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
}
self->player->extralight = 2;

View file

@ -117,6 +117,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise)
self->flags &= ~MF_SOLID;
mo = Spawn("Sorcerer2", self->x, self->y, self->z, ALLOW_REPLACE);
mo->Translation = self->Translation;
mo->SetState (mo->FindState("Rise"));
mo->angle = self->angle;
mo->CopyFriendliness (self, true);
@ -148,6 +149,7 @@ void P_DSparilTeleport (AActor *actor)
if (P_TeleportMove (actor, spot->x, spot->y, spot->z, false))
{
mo = Spawn("Sorcerer2Telefade", prevX, prevY, prevZ, ALLOW_REPLACE);
if (mo) mo->Translation = actor->Translation;
S_Sound (mo, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);
actor->SetState (actor->FindState("Teleport"));
S_Sound (actor, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);

View file

@ -115,7 +115,7 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
int saved;
if (damageType != NAME_Drowning)
if (!DamageTypeDefinition::IgnoreArmor(damageType))
{
int full = MAX(0, MaxFullAbsorb - AbsorbCount);
if (damage < full)
@ -490,7 +490,7 @@ bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount)
void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (damageType != NAME_Drowning)
if (!DamageTypeDefinition::IgnoreArmor(damageType))
{
fixed_t savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];

View file

@ -289,6 +289,8 @@ public:
virtual FState *GetReadyState ();
virtual FState *GetAtkState (bool hold);
virtual FState *GetAltAtkState (bool hold);
virtual FState *GetRelState ();
virtual FState *GetZoomState ();
virtual void PostMorphWeapon ();
virtual void EndPowerup ();
@ -299,8 +301,8 @@ public:
AltFire,
EitherFire
};
bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false);
bool DepleteAmmo (bool altFire, bool checkEnough=true);
bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false, int ammocount = -1);
bool DepleteAmmo (bool altFire, bool checkEnough=true, int ammouse = -1);
protected:
AAmmo *AddAmmo (AActor *other, const PClass *ammotype, int amount);
@ -326,6 +328,8 @@ enum
WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback
WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles)
WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI.
WIF_DEHAMMO = 0x00010000, // Uses Doom's original amount of ammo for the respective attack functions so that old DEHACKED patches work as intended.
// AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works
WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil)

View file

@ -430,11 +430,12 @@ bool AWeapon::ShouldStay ()
//
//===========================================================================
bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo)
bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int ammocount)
{
int altFire;
int count1, count2;
int enough, enoughmask;
int lAmmoUse1;
if ((dmflags & DF_INFINITE_AMMO) || (Owner->player->cheats & CF_INFINITEAMMO))
{
@ -457,7 +458,16 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo)
count1 = (Ammo1 != NULL) ? Ammo1->Amount : 0;
count2 = (Ammo2 != NULL) ? Ammo2->Amount : 0;
enough = (count1 >= AmmoUse1) | ((count2 >= AmmoUse2) << 1);
if (ammocount >= 0 && (WeaponFlags & WIF_DEHAMMO))
{
lAmmoUse1 = ammocount;
}
else
{
lAmmoUse1 = AmmoUse1;
}
enough = (count1 >= lAmmoUse1) | ((count2 >= AmmoUse2) << 1);
if (WeaponFlags & (WIF_PRIMARY_USES_BOTH << altFire))
{
enoughmask = 3;
@ -492,11 +502,11 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo)
//
//===========================================================================
bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough)
bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse)
{
if (!((dmflags & DF_INFINITE_AMMO) || (Owner->player->cheats & CF_INFINITEAMMO)))
{
if (checkEnough && !CheckAmmo (altFire ? AltFire : PrimaryFire, false))
if (checkEnough && !CheckAmmo (altFire ? AltFire : PrimaryFire, false, false, ammouse))
{
return false;
}
@ -504,7 +514,14 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough)
{
if (Ammo1 != NULL)
{
Ammo1->Amount -= AmmoUse1;
if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO))
{
Ammo1->Amount -= ammouse;
}
else
{
Ammo1->Amount -= AmmoUse1;
}
}
if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != NULL)
{
@ -636,6 +653,28 @@ FState *AWeapon::GetAltAtkState (bool hold)
return state;
}
//===========================================================================
//
// AWeapon :: GetRelState
//
//===========================================================================
FState *AWeapon::GetRelState ()
{
return FindState(NAME_Reload);
}
//===========================================================================
//
// AWeapon :: GetZoomState
//
//===========================================================================
FState *AWeapon::GetZoomState ()
{
return FindState(NAME_Zoom);
}
/* Weapon giver ***********************************************************/
class AWeaponGiver : public AWeapon

View file

@ -55,7 +55,6 @@ extern void LoadActors ();
extern void InitBotStuff();
extern void ClearStrifeTypes();
//==========================================================================
//
//
@ -545,3 +544,84 @@ CCMD (summonfoe)
{
SummonActor (DEM_SUMMONFOE, DEM_SUMMONFOE2, argv);
}
// Damage type defaults / global settings
TMap<FName, DamageTypeDefinition> GlobalDamageDefinitions;
void DamageTypeDefinition::Apply(FName const type)
{
GlobalDamageDefinitions[type] = *this;
}
DamageTypeDefinition *DamageTypeDefinition::Get(FName const type)
{
return GlobalDamageDefinitions.CheckKey(type);
}
bool DamageTypeDefinition::IgnoreArmor(FName const type)
{
if (type == NAME_Drowning) return true;
DamageTypeDefinition *dtd = Get(type);
if (dtd) return dtd->NoArmor;
return false;
}
//==========================================================================
//
// DamageTypeDefinition :: ApplyMobjDamageFactor
//
// Calculates mobj damage based on original damage, defined damage factors
// and damage type.
//
// If the specific damage type is not defined, the damage factor for
// type 'None' will be used (with 1.0 as a default value).
//
// Globally declared damage types may override or multiply the damage
// factor when 'None' is used as a fallback in this function.
//
//==========================================================================
int DamageTypeDefinition::ApplyMobjDamageFactor(int damage, FName const type, DmgFactors const * const factors)
{
if (factors)
{
// If the actor has named damage factors, look for a specific factor
fixed_t const *pdf = factors->CheckKey(type);
if (pdf) return FixedMul(damage, *pdf); // type specific damage type
// If this was nonspecific damage, don't fall back to nonspecific search
if (type == NAME_None) return damage;
}
// If this was nonspecific damage, don't fall back to nonspecific search
else if (type == NAME_None)
{
return damage;
}
else
{
// Normal is unsupplied / 1.0, so there's no difference between modifying and overriding
DamageTypeDefinition *dtd = Get(type);
return dtd ? FixedMul(damage, dtd->DefaultFactor) : damage;
}
{
fixed_t const *pdf = factors->CheckKey(NAME_None);
// Here we are looking for modifications to untyped damage
// If the calling actor defines untyped damage factor, that is contained in "pdf".
if (pdf) // normal damage available
{
DamageTypeDefinition *dtd = Get(type);
if (dtd)
{
if (dtd->ReplaceFactor) return FixedMul(damage, dtd->DefaultFactor); // use default instead of untyped factor
return FixedMul(damage, FixedMul(*pdf, dtd->DefaultFactor)); // use default as modification of untyped factor
}
return FixedMul(damage, *pdf); // there was no default, so actor default is used
}
}
return damage;
}

View file

@ -44,6 +44,8 @@
#include "dobject.h"
#include "doomdef.h"
#include "m_fixed.h"
struct Baggage;
class FScanner;
struct FActorInfo;
@ -185,6 +187,31 @@ typedef TMap<FName, int> PainChanceList;
typedef TMap<FName, PalEntry> PainFlashList;
typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap;
struct DamageTypeDefinition
{
public:
DamageTypeDefinition() { Clear(); }
fixed_t DefaultFactor;
bool ReplaceFactor;
bool NoArmor;
void Apply(FName const type);
void Clear()
{
DefaultFactor = (fixed_t)1;
ReplaceFactor = false;
NoArmor = false;
}
static DamageTypeDefinition *Get(FName const type);
static bool IgnoreArmor(FName const type);
static int ApplyMobjDamageFactor(int damage, FName const type, DmgFactors const * const factors);
};
struct FActorInfo
{
static void StaticInit ();

View file

@ -198,6 +198,8 @@ xx(AltFire)
xx(AltHold)
xx(Flash)
xx(AltFlash)
xx(Reload)
xx(Zoom)
// State names used by ASwitchableDecoration
xx(Active)

View file

@ -310,11 +310,16 @@ void P_RunEffects ()
}
//
// AddParticle
// JitterParticle
//
// Creates a particle with "jitter"
//
particle_t *JitterParticle (int ttl)
{
return JitterParticle (ttl, 1.0);
}
// [XA] Added "drift speed" multiplier setting for enhanced railgun stuffs.
particle_t *JitterParticle (int ttl, float drift)
{
particle_t *particle = NewParticle ();
@ -324,10 +329,10 @@ particle_t *JitterParticle (int ttl)
// Set initial velocities
for (i = 3; i; i--, val++)
*val = (FRACUNIT/4096) * (M_Random () - 128);
*val = (int)((FRACUNIT/4096) * (M_Random () - 128) * drift);
// Set initial accelerations
for (i = 3; i; i--, val++)
*val = (FRACUNIT/16384) * (M_Random () - 128);
*val = (int)((FRACUNIT/16384) * (M_Random () - 128) * drift);
particle->trans = 255; // fully opaque
particle->ttl = ttl;
@ -580,7 +585,7 @@ void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, i
}
}
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff, bool silent)
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff, bool silent, const PClass *spawnclass, angle_t angle, bool fullbright, int duration, float sparsity, float drift)
{
double length, lengthsquared;
int steps, i;
@ -663,10 +668,10 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end
step = dir * 3;
// Create the outer spiral.
if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0)
if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0 && (spawnclass == NULL))
{
FVector3 spiral_step = step * r_rail_spiralsparsity;
int spiral_steps = steps * r_rail_spiralsparsity;
FVector3 spiral_step = step * r_rail_spiralsparsity * sparsity;
int spiral_steps = (int)(steps * r_rail_spiralsparsity / sparsity);
color1 = color1 == 0 ? -1 : ParticleColor(color1);
pos = start;
@ -680,14 +685,16 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end
return;
p->trans = 255;
p->ttl = 35;
p->fade = FADEFROMTTL(35);
p->ttl = duration;
p->fade = FADEFROMTTL(duration);
p->size = 3;
if(fullbright)
p->bright = true;
tempvec = FMatrix3x3(dir, deg) * extend;
p->velx = FLOAT2FIXED(tempvec.X)>>4;
p->vely = FLOAT2FIXED(tempvec.Y)>>4;
p->velz = FLOAT2FIXED(tempvec.Z)>>4;
p->velx = FLOAT2FIXED(tempvec.X * drift)>>4;
p->vely = FLOAT2FIXED(tempvec.Y * drift)>>4;
p->velz = FLOAT2FIXED(tempvec.Z * drift)>>4;
tempvec += pos;
p->x = FLOAT2FIXED(tempvec.X);
p->y = FLOAT2FIXED(tempvec.Y);
@ -770,6 +777,21 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end
}
}
}
// create actors
if(spawnclass != NULL) {
if(sparsity < 1) sparsity = 32;
FVector3 trail_step = (step / 3) * sparsity;
int trail_steps = (int)((steps * 3) / sparsity);
pos = start;
for (i = trail_steps; i; i--)
{
AActor *thing = Spawn (spawnclass, FLOAT2FIXED(pos.X), FLOAT2FIXED(pos.Y), FLOAT2FIXED(pos.Z), ALLOW_REPLACE);
if(thing) thing->angle = angle;
pos += trail_step;
}
}
}
void P_DisconnectEffect (AActor *actor)

View file

@ -65,6 +65,7 @@ struct particle_t
WORD tnext;
WORD snext;
subsector_t * subsector;
bool bright;
};
extern particle_t *Particles;
@ -79,6 +80,7 @@ void P_FindParticleSubsectors ();
class AActor;
particle_t *JitterParticle (int ttl);
particle_t *JitterParticle (int ttl, float drift);
void P_ThinkParticles (void);
void P_InitEffects (void);
@ -86,7 +88,7 @@ void P_RunEffects (void);
void P_RunEffect (AActor *actor, int effects);
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff = 0, bool silent = false);
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff = 0, bool silent = false, const PClass *spawnclass = NULL, angle_t angle = 0, bool fullbright = false, int duration = 35, float sparsity = 1.0, float drift = 1.0);
void P_DrawSplash (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int kind);
void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int updown, int kind);
void P_DisconnectEffect (AActor *actor);

View file

@ -2726,7 +2726,7 @@ void A_Chase(AActor *self)
// A_FaceTracer
//
//=============================================================================
void A_Face (AActor *self, AActor *other, angle_t max_turn)
void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch)
{
if (!other)
return;
@ -2773,6 +2773,50 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn)
self->angle = other_angle;
}
// [DH] Now set pitch. In order to maintain compatibility, this can be
// disabled and is so by default.
if (max_pitch <= ANGLE_180)
{
// [DH] Don't need to do proper fixed->double conversion, since the
// result is only used in a ratio.
double dist_x = self->target->x - self->x;
double dist_y = self->target->y - self->y;
double dist_z = self->target->z - self->z;
double dist = sqrt(dist_x*dist_x + dist_y*dist_y + dist_z*dist_z);
angle_t other_pitch = rad2bam(asin(dist_z / dist));
if (max_pitch && (max_pitch < (angle_t)abs(self->pitch - other_pitch)))
{
if (self->pitch > other_pitch)
{
if (self->pitch - other_pitch < ANGLE_180)
{
self->pitch -= max_pitch;
}
else
{
self->pitch += max_pitch;
}
}
else
{
if (other_pitch - self->pitch < ANGLE_180)
{
self->pitch += max_pitch;
}
else
{
self->pitch -= max_pitch;
}
}
}
else
{
self->pitch = other_pitch;
}
}
// This will never work well if the turn angle is limited.
if (max_turn == 0 && (self->angle == other_angle) && other->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE) )
{
@ -2780,43 +2824,46 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn)
}
}
void A_FaceTarget (AActor *self, angle_t max_turn)
void A_FaceTarget (AActor *self, angle_t max_turn, angle_t max_pitch)
{
A_Face(self, self->target, max_turn);
A_Face(self, self->target, max_turn, max_pitch);
}
void A_FaceMaster (AActor *self, angle_t max_turn)
void A_FaceMaster (AActor *self, angle_t max_turn, angle_t max_pitch)
{
A_Face(self, self->master, max_turn);
A_Face(self, self->master, max_turn, max_pitch);
}
void A_FaceTracer (AActor *self, angle_t max_turn)
void A_FaceTracer (AActor *self, angle_t max_turn, angle_t max_pitch)
{
A_Face(self, self->tracer, max_turn);
A_Face(self, self->tracer, max_turn, max_pitch);
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTarget)
{
ACTION_PARAM_START(1);
ACTION_PARAM_START(2);
ACTION_PARAM_ANGLE(max_turn, 0);
ACTION_PARAM_ANGLE(max_pitch, 1);
A_FaceTarget(self, max_turn);
A_FaceTarget(self, max_turn, max_pitch);
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMaster)
{
ACTION_PARAM_START(1);
ACTION_PARAM_START(2);
ACTION_PARAM_ANGLE(max_turn, 0);
ACTION_PARAM_ANGLE(max_pitch, 1);
A_FaceMaster(self, max_turn);
A_FaceMaster(self, max_turn, max_pitch);
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTracer)
{
ACTION_PARAM_START(1);
ACTION_PARAM_START(2);
ACTION_PARAM_ANGLE(max_turn, 0);
ACTION_PARAM_ANGLE(max_pitch, 1);
A_FaceTracer(self, max_turn);
A_FaceTracer(self, max_turn, max_pitch);
}
//===========================================================================

View file

@ -72,7 +72,7 @@ DECLARE_ACTION(A_FreezeDeathChunks)
DECLARE_ACTION(A_BossDeath)
void A_Chase(AActor *self);
void A_FaceTarget (AActor *actor, angle_t max_turn = 0);
void A_FaceTarget (AActor *actor, angle_t max_turn = 0, angle_t max_pitch = ANGLE_270);
bool A_RaiseMobj (AActor *, fixed_t speed);
bool A_SinkMobj (AActor *, fixed_t speed);

View file

@ -997,20 +997,12 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
if (!(flags & DMG_NO_FACTOR))
{
DmgFactors *df = target->GetClass()->ActorInfo->DamageFactors;
if (df != NULL)
{
fixed_t *pdf = df->CheckFactor(mod);
if (pdf != NULL)
{
damage = FixedMul(damage, *pdf);
if (damage <= 0)
return;
}
}
damage = FixedMul(damage, target->DamageFactor);
if (damage < 0)
return;
damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, mod, target->GetClass()->ActorInfo->DamageFactors);
if (damage <= 0)
return;
}
damage = target->TakeSpecialDamage (inflictor, source, damage, mod);

View file

@ -453,10 +453,11 @@ void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target,
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, AActor *target); // random direction version
void P_RailAttack (AActor *source, int damage, int offset, int color1 = 0, int color2 = 0, float maxdiff = 0, bool silent = false, const PClass *puff = NULL, bool pierce = true, angle_t angleoffset = 0, angle_t pitchoffset = 0); // [RH] Shoot a railgun
void P_RailAttack (AActor *source, int damage, int offset, int color1 = 0, int color2 = 0, float maxdiff = 0, bool silent = false, const PClass *puff = NULL, bool pierce = true, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 0, bool fullbright = false, int duration = 35, float sparsity = 1.0, float drift = 1.0, const PClass *spawnclass = NULL); // [RH] Shoot a railgun
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);
void P_CheckSplash(AActor *self, fixed_t distance);
bool P_CheckMissileSpawn (AActor *missile);
void P_PlaySpawnSound(AActor *missile, AActor *spawner);

View file

@ -60,6 +60,7 @@
CVAR (Bool, cl_bloodsplats, true, CVAR_ARCHIVE)
CVAR (Int, sv_smartaim, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
CVAR (Bool, cl_doautoaim, false, CVAR_ARCHIVE)
static void CheckForPushSpecial (line_t *line, int side, AActor *mobj, bool windowcheck);
static void SpawnShootDecal (AActor *t1, const FTraceResults &trace);
@ -2845,20 +2846,19 @@ bool P_BounceActor (AActor *mo, AActor * BlockingMobj)
|| ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER)))
))
{
if (mo->bouncecount > 0 && --mo->bouncecount == 0) return false;
fixed_t speed;
if (mo->bouncecount > 0 && --mo->bouncecount > 0)
{
angle_t angle = R_PointToAngle2 (BlockingMobj->x,
BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce()%16)-8);
speed = P_AproxDistance (mo->velx, mo->vely);
speed = FixedMul (speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent
mo->angle = angle;
angle >>= ANGLETOFINESHIFT;
mo->velx = FixedMul (speed, finecosine[angle]);
mo->vely = FixedMul (speed, finesine[angle]);
mo->PlayBounceSound(true);
return true;
}
angle_t angle = R_PointToAngle2 (BlockingMobj->x,
BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce()%16)-8);
speed = P_AproxDistance (mo->velx, mo->vely);
speed = FixedMul (speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent
mo->angle = angle;
angle >>= ANGLETOFINESHIFT;
mo->velx = FixedMul (speed, finecosine[angle]);
mo->vely = FixedMul (speed, finesine[angle]);
mo->PlayBounceSound(true);
return true;
}
return false;
}
@ -3089,6 +3089,12 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
}
dist = FixedMul (attackrange, in->frac);
// Don't autoaim certain special actors
if (!cl_doautoaim && th->flags6 & MF6_NOTAUTOAIMED)
{
continue;
}
#ifdef _3DFLOORS
// we must do one last check whether the trace has crossed a 3D floor
if (lastsector==th->Sector && th->Sector->e->XFloor.ffloors.Size())
@ -3838,8 +3844,7 @@ static bool ProcessNoPierceRailHit (FTraceResults &res)
//
//
//==========================================================================
void P_RailAttack (AActor *source, int damage, int offset, int color1, int color2, float maxdiff, bool silent, const PClass *puffclass, bool pierce, angle_t angleoffset, angle_t pitchoffset)
void P_RailAttack (AActor *source, int damage, int offset, int color1, int color2, float maxdiff, bool silent, const PClass *puffclass, bool pierce, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, bool fullbright, int duration, float sparsity, float drift, const PClass *spawnclass)
{
fixed_t vx, vy, vz;
angle_t angle, pitch;
@ -3882,8 +3887,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
int flags;
AActor *puffDefaults = puffclass == NULL?
NULL : GetDefaultByType (puffclass->GetReplacement());
AActor *puffDefaults = puffclass == NULL ? NULL : GetDefaultByType (puffclass->GetReplacement());
if (puffDefaults != NULL && puffDefaults->flags6 & MF6_NOTRIGGER) flags = 0;
else flags = TRACE_PCross|TRACE_Impact;
@ -3891,13 +3895,13 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
if (pierce)
{
Trace (x1, y1, shootz, source->Sector, vx, vy, vz,
8192*FRACUNIT, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace,
distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace,
flags, ProcessRailHit);
}
else
{
Trace (x1, y1, shootz, source->Sector, vx, vy, vz,
8192*FRACUNIT, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace,
distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace,
flags, ProcessNoPierceRailHit);
}
@ -3922,7 +3926,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
if ((RailHits[i].HitActor->flags & MF_NOBLOOD) ||
(RailHits[i].HitActor->flags2 & (MF2_DORMANT|MF2_INVULNERABLE)))
{
spawnpuff = puffclass != NULL;
spawnpuff = (puffclass != NULL);
}
else
{
@ -3971,7 +3975,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
end.X = FIXED2FLOAT(trace.X);
end.Y = FIXED2FLOAT(trace.Y);
end.Z = FIXED2FLOAT(trace.Z);
P_DrawRailTrail (source, start, end, color1, color2, maxdiff, silent);
P_DrawRailTrail (source, start, end, color1, color2, maxdiff, silent, spawnclass, source->angle + angleoffset, fullbright, duration, sparsity, drift);
}
//==========================================================================

View file

@ -5873,6 +5873,7 @@ void PrintMiscActorInfo(AActor * query)
(query->special ? LineSpecialsInfo[query->special]->name : "None"),
query->args[0], query->args[1], query->args[2], query->args[3],
query->args[4], query->special1, query->special2);
Printf("\nTID is %d", query->tid);
Printf("\nIts coordinates are x: %f, y: %f, z:%f, floor:%f, ceiling:%f.",
FIXED2FLOAT(query->x), FIXED2FLOAT(query->y), FIXED2FLOAT(query->z),
FIXED2FLOAT(query->floorz), FIXED2FLOAT(query->ceilingz));

View file

@ -95,7 +95,7 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio
if (position == ps_weapon && !nofunction)
{ // A_WeaponReady will re-set these as needed
player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONSWITCHOK);
player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONSWITCHOK | CF_WEAPONRELOADOK | CF_WEAPONZOOMOK);
}
psp = &player->psprites[position];
@ -282,6 +282,66 @@ void P_FireWeaponAlt (player_t *player, FState *state)
}
}
//---------------------------------------------------------------------------
//
// PROC P_ReloadWeapon
//
//---------------------------------------------------------------------------
void P_ReloadWeapon (player_t *player, FState *state)
{
AWeapon *weapon;
if (!player->isbot && bot_observer)
{
return;
}
weapon = player->ReadyWeapon;
if (weapon == NULL)
{
return;
}
if (state == NULL)
{
state = weapon->GetRelState();
}
// [XA] don't change state if still null, so if the modder sets
// WRF_RELOAD to true but forgets to define the Reload state, the weapon
// won't disappear. ;)
if (state != NULL)
P_SetPsprite (player, ps_weapon, state);
}
//---------------------------------------------------------------------------
//
// PROC P_ZoomWeapon
//
//---------------------------------------------------------------------------
void P_ZoomWeapon (player_t *player, FState *state)
{
AWeapon *weapon;
if (!player->isbot && bot_observer)
{
return;
}
weapon = player->ReadyWeapon;
if (weapon == NULL)
{
return;
}
if (state == NULL)
{
state = weapon->GetZoomState();
}
// [XA] don't change state if still null. Same reasons as above.
if (state != NULL)
P_SetPsprite (player, ps_weapon, state);
}
//---------------------------------------------------------------------------
//
// PROC P_DropWeapon
@ -368,6 +428,7 @@ void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y)
//
// Readies a weapon for firing or bobbing with its three ancillary functions,
// DoReadyWeaponToSwitch(), DoReadyWeaponToFire() and DoReadyWeaponToBob().
// [XA] Added DoReadyWeaponToReload() and DoReadyWeaponToZoom()
//
//============================================================================
@ -421,12 +482,32 @@ void DoReadyWeaponToBob (AActor * self)
}
}
void DoReadyWeaponToReload (AActor * self)
{
// Prepare for reload action.
player_t *player;
if (self && (player = self->player))
player->cheats |= CF_WEAPONRELOADOK;
return;
}
void DoReadyWeaponToZoom (AActor * self)
{
// Prepare for reload action.
player_t *player;
if (self && (player = self->player))
player->cheats |= CF_WEAPONZOOMOK;
return;
}
// This function replaces calls to A_WeaponReady in other codepointers.
void DoReadyWeapon(AActor * self)
{
DoReadyWeaponToBob(self);
DoReadyWeaponToFire(self);
DoReadyWeaponToSwitch(self);
DoReadyWeaponToReload(self);
DoReadyWeaponToZoom(self);
}
enum EWRF_Options
@ -436,6 +517,8 @@ enum EWRF_Options
WRF_NoSwitch = 2,
WRF_NoPrimary = 4,
WRF_NoSecondary = 8,
WRF_AllowReload = 16,
WRF_AllowZoom = 32,
};
DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady)
@ -447,6 +530,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady)
if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self,
(!(paramflags & WRF_NoPrimary)), (!(paramflags & WRF_NoSecondary)));
if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self);
if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self);
if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self);
}
//---------------------------------------------------------------------------
@ -520,6 +605,50 @@ void P_CheckWeaponSwitch (player_t *player)
}
}
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponReload
//
// The player can reload the weapon.
//
//---------------------------------------------------------------------------
void P_CheckWeaponReload (player_t *player)
{
AWeapon *weapon = player->ReadyWeapon;
if (weapon == NULL)
return;
// Check for reload.
if ((player->cheats & CF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD))
{
P_ReloadWeapon (player, NULL);
}
}
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponZoom
//
// The player can use the weapon's zoom function.
//
//---------------------------------------------------------------------------
void P_CheckWeaponZoom (player_t *player)
{
AWeapon *weapon = player->ReadyWeapon;
if (weapon == NULL)
return;
// Check for zoom.
if ((player->cheats & CF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM))
{
P_ZoomWeapon (player, NULL);
}
}
//---------------------------------------------------------------------------
//
// PROC A_ReFire
@ -892,6 +1021,14 @@ void P_MovePsprites (player_t *player)
{
P_CheckWeaponFire (player);
}
if (player->cheats & CF_WEAPONRELOADOK)
{
P_CheckWeaponReload (player);
}
if (player->cheats & CF_WEAPONZOOMOK)
{
P_CheckWeaponZoom (player);
}
}
}

View file

@ -2138,6 +2138,9 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
{
vis->Style.colormap = fixedcolormap;
}
else if(particle->bright) {
vis->Style.colormap = map;
}
else
{
// Using MulScale15 instead of 16 makes particles slightly more visible

View file

@ -3,5 +3,5 @@
// This file was automatically generated by the
// updaterevision tool. Do not edit by hand.
#define ZD_SVN_REVISION_STRING "3520"
#define ZD_SVN_REVISION_NUMBER 3520
#define ZD_SVN_REVISION_STRING "3532"
#define ZD_SVN_REVISION_NUMBER 3532

View file

@ -109,5 +109,9 @@ inline double bam2rad(angle_t ang)
{
return double(ang >> 1) * (PI / ANGLE_90);
}
inline angle_t rad2bam(double ang)
{
return angle_t(ang * (double(1<<30) / PI)) << 1;
}
#endif // __TABLES_H__

View file

@ -37,6 +37,7 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <new>
#if !defined(_WIN32)

View file

@ -368,6 +368,7 @@ struct StateCallData
// Macros to handle action functions. These are here so that I don't have to
// change every single use in case the parameters change.
#define DECLARE_ACTION(name) void AF_##name(AActor *self, AActor *stateowner, FState *, int, StateCallData *);
#define DECLARE_ACTION_PARAMS(name) void AFP_##name(AActor *self, AActor *stateowner, FState *, int, StateCallData *);
// This distinction is here so that CALL_ACTION produces errors when trying to
// access a function that requires parameters.

View file

@ -729,7 +729,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType)
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
{
ACTION_PARAM_START(7);
ACTION_PARAM_START(8);
ACTION_PARAM_INT(damage, 0);
ACTION_PARAM_INT(distance, 1);
ACTION_PARAM_BOOL(hurtSource, 2);
@ -737,6 +737,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
ACTION_PARAM_INT(fulldmgdistance, 4);
ACTION_PARAM_INT(nails, 5);
ACTION_PARAM_INT(naildamage, 6);
ACTION_PARAM_CLASS(pufftype, 7);
if (damage < 0) // get parameters from metadata
{
@ -761,7 +762,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
// Comparing the results of a test wad with Eternity, it seems A_NailBomb does not aim
P_LineAttack (self, ang, MISSILERANGE, 0,
//P_AimLineAttack (self, ang, MISSILERANGE),
naildamage, NAME_None, NAME_BulletPuff);
naildamage, NAME_None, pufftype);
}
}
@ -840,6 +841,12 @@ enum CM_Flags
CMF_AIMMODE = 3,
CMF_TRACKOWNER = 4,
CMF_CHECKTARGETDEAD = 8,
CMF_ABSOLUTEPITCH = 16,
CMF_OFFSETPITCH = 32,
CMF_SAVEPITCH = 64,
CMF_ABSOLUTEANGLE = 128
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile)
@ -888,22 +895,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile)
self->x+=x;
self->y+=y;
missile = P_SpawnMissileAngleZSpeed(self, self->z+SpawnHeight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false);
self->x-=x;
self->x-=x;
self->y-=y;
// It is not necessary to use the correct angle here.
// The only important thing is that the horizontal velocity is correct.
// Therefore use 0 as the missile's angle and simplify the calculations accordingly.
// The actual velocity vector is set below.
if (missile)
{
fixed_t vx = finecosine[pitch>>ANGLETOFINESHIFT];
fixed_t vz = finesine[pitch>>ANGLETOFINESHIFT];
missile->velx = FixedMul (vx, missile->Speed);
missile->vely = 0;
missile->velz = FixedMul (vz, missile->Speed);
}
flags |= CMF_ABSOLUTEPITCH;
break;
}
@ -913,11 +908,36 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile)
// Use the actual velocity instead of the missile's Speed property
// so that this can handle missiles with a high vertical velocity
// component properly.
FVector3 velocity (missile->velx, missile->vely, 0);
fixed_t missilespeed = (fixed_t)velocity.Length();
fixed_t missilespeed;
if ( (CMF_ABSOLUTEPITCH|CMF_OFFSETPITCH) & flags)
{
if (CMF_OFFSETPITCH & flags)
{
FVector2 velocity (missile->velx, missile->vely);
pitch += R_PointToAngle2(0,0, (fixed_t)velocity.Length(), missile->velz);
}
ang = pitch >> ANGLETOFINESHIFT;
missilespeed = FixedMul(finecosine[ang], missile->Speed);
missile->velz = FixedMul(finesine[ang], missile->Speed);
}
else
{
FVector2 velocity (missile->velx, missile->vely);
missilespeed = (fixed_t)velocity.Length();
}
if (CMF_SAVEPITCH & flags)
{
missile->pitch = pitch;
// In aimmode 0 and 1 without absolutepitch or offsetpitch, the pitch parameter
// contains the unapplied parameter. In that case, it is set as pitch without
// otherwise affecting the spawned actor.
}
missile->angle = (CMF_ABSOLUTEANGLE & flags) ? Angle : missile->angle + Angle ;
missile->angle += Angle;
ang = missile->angle >> ANGLETOFINESHIFT;
missile->velx = FixedMul (missilespeed, finecosine[ang]);
missile->vely = FixedMul (missilespeed, finesine[ang]);
@ -1353,6 +1373,7 @@ enum
RAF_SILENT = 1,
RAF_NOPIERCE = 2,
RAF_EXPLICITANGLE = 4,
RAF_FULLBRIGHT = 8
};
//==========================================================================
@ -1362,7 +1383,7 @@ enum
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
{
ACTION_PARAM_START(10);
ACTION_PARAM_START(15);
ACTION_PARAM_INT(Damage, 0);
ACTION_PARAM_INT(Spawnofs_XY, 1);
ACTION_PARAM_BOOL(UseAmmo, 2);
@ -1373,6 +1394,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
ACTION_PARAM_CLASS(PuffType, 7);
ACTION_PARAM_ANGLE(Spread_XY, 8);
ACTION_PARAM_ANGLE(Spread_Z, 9);
ACTION_PARAM_FIXED(Range, 10);
ACTION_PARAM_INT(Duration, 11);
ACTION_PARAM_FLOAT(Sparsity, 12);
ACTION_PARAM_FLOAT(DriftSpeed, 13);
ACTION_PARAM_CLASS(SpawnClass, 14);
if(Range==0) Range=8192*FRACUNIT;
if(Duration==0) Duration=35;
if(Sparsity==0) Sparsity=1.0;
if (!self->player) return;
@ -1398,7 +1428,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
slope = pr_crailgun.Random2() * (Spread_Z / 255);
}
P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE)), angle, slope);
P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE)), angle, slope, Range, (Flags & RAF_FULLBRIGHT), Duration, Sparsity, DriftSpeed, SpawnClass);
}
//==========================================================================
@ -1416,7 +1446,7 @@ enum
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
{
ACTION_PARAM_START(10);
ACTION_PARAM_START(15);
ACTION_PARAM_INT(Damage, 0);
ACTION_PARAM_INT(Spawnofs_XY, 1);
ACTION_PARAM_COLOR(Color1, 2);
@ -1427,6 +1457,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
ACTION_PARAM_CLASS(PuffType, 7);
ACTION_PARAM_ANGLE(Spread_XY, 8);
ACTION_PARAM_ANGLE(Spread_Z, 9);
ACTION_PARAM_FIXED(Range, 10);
ACTION_PARAM_INT(Duration, 11);
ACTION_PARAM_FLOAT(Sparsity, 12);
ACTION_PARAM_FLOAT(DriftSpeed, 13);
ACTION_PARAM_CLASS(SpawnClass, 14);
if(Range==0) Range=8192*FRACUNIT;
if(Duration==0) Duration=35;
if(Sparsity==0) Sparsity=1.0;
AActor *linetarget;
@ -1507,7 +1546,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
slopeoffset = pr_crailgun.Random2() * (Spread_Z / 255);
}
P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE)), angleoffset, slopeoffset);
P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE)), angleoffset, slopeoffset, Range, (Flags & RAF_FULLBRIGHT), Duration, Sparsity, DriftSpeed, SpawnClass);
self->x = saved_x;
self->y = saved_y;

View file

@ -233,6 +233,7 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF6, DONTCORPSE, AActor, flags6),
DEFINE_FLAG(MF6, DOHARMSPECIES, AActor, flags6),
DEFINE_FLAG(MF6, POISONALWAYS, AActor, flags6),
DEFINE_FLAG(MF6, NOTAUTOAIMED, AActor, flags6),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),

View file

@ -1179,7 +1179,50 @@ static void ParseActor(FScanner &sc)
sc.SetCMode (false);
}
//==========================================================================
//
// Reads a damage definition
//
//==========================================================================
static void ParseDamageDefinition(FScanner &sc)
{
sc.SetCMode (true); // This may be 100% irrelevant for such a simple syntax, but I don't know
// Get DamageType
sc.MustGetString();
FName damageType = sc.String;
DamageTypeDefinition dtd;
sc.MustGetToken('{');
while (sc.MustGetAnyToken(), sc.TokenType != '}')
{
if (sc.Compare("FACTOR"))
{
sc.MustGetFloat();
dtd.DefaultFactor = (fixed_t)sc.Float;
if (!dtd.DefaultFactor) dtd.ReplaceFactor = true; // Multiply by 0 yields 0: FixedMul(damage, FixedMul(factor, 0)) is more wasteful than FixedMul(factor, 0)
}
else if (sc.Compare("REPLACEFACTOR"))
{
dtd.ReplaceFactor = true;
}
else if (sc.Compare("NOARMOR"))
{
dtd.NoArmor = true;
}
else
{
sc.ScriptError("Unexpected data (%s) in damagetype definition.", sc.String);
}
}
dtd.Apply(damageType);
sc.SetCMode (false); // (set to true earlier in function)
}
//==========================================================================
//
@ -1263,6 +1306,11 @@ void ParseDecorate (FScanner &sc)
ParseOldDecoration (sc, DEF_Projectile);
break;
}
else if (sc.Compare("DAMAGETYPE"))
{
ParseDamageDefinition(sc);
break;
}
default:
sc.RestorePos(pos);
ParseOldDecoration(sc, DEF_Decoration);

View file

@ -69,9 +69,9 @@ ACTOR Actor native //: Thinker
action native A_XScream();
action native A_Look();
action native A_Chase(state melee = "*", state missile = "none", int flags = 0);
action native A_FaceTarget(float max_turn = 0);
action native A_FaceTracer(float max_turn = 0);
action native A_FaceMaster(float max_turn = 0);
action native A_FaceTarget(float max_turn = 0, float max_pitch = 270);
action native A_FaceTracer(float max_turn = 0, float max_pitch = 270);
action native A_FaceMaster(float max_turn = 0, float max_pitch = 270);
action native A_PosAttack();
action native A_Scream();
action native A_SPosAttack();
@ -196,7 +196,7 @@ ACTOR Actor native //: Thinker
action native A_Jump(int chance = 256, state label, ...);
action native A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0);
action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0);
action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0);
action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none");
action native A_JumpIfHealthLower(int health, state label);
action native A_JumpIfCloser(float distance, state label);
action native A_JumpIfTracerCloser(float distance, state label);
@ -254,7 +254,7 @@ ACTOR Actor native //: Thinker
action native A_Burst(class<Actor> chunktype);
action native A_Blast(int flags = 0, int strength = 255, int radius = 255, float speed = 20, class<Actor> blasteffect = "BlastEffect", sound blastsound = "BlastRadius");
action native A_RadiusThrust(int force = 128, int distance = -1, bool affectsource = true, int fullthrustdistance = 0);
action native A_Explode(int damage = -1, int distance = -1, bool hurtsource = true, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10);
action native A_Explode(int damage = -1, int distance = -1, bool hurtsource = true, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff");
action native A_Stop();
action native A_Respawn(int flags = 1);
action native A_BarrelDestroy();

View file

@ -17,6 +17,10 @@ const int CMF_AIMOFFSET = 1;
const int CMF_AIMDIRECTION = 2;
const int CMF_TRACKOWNER = 4;
const int CMF_CHECKTARGETDEAD = 8;
const int CMF_ABSOLUTEPITCH = 16;
const int CMF_OFFSETPITCH = 32;
const int CMF_SAVEPITCH = 64;
const int CMF_ABSOLUTEANGLE = 128;
// Flags for A_CustomBulletAttack
const int CBAF_AIMFACING = 1;
@ -91,6 +95,8 @@ const int WRF_NOFIRE = 12;
const int WRF_NOSWITCH = 2;
const int WRF_NOPRIMARY = 4;
const int WRF_NOSECONDARY = 8;
const int WRF_ALLOWRELOAD = 16;
const int WRF_ALLOWZOOM = 32;
// Morph constants
const int MRF_ADDSTAMINA = 1;
@ -110,6 +116,7 @@ const int MRF_UNDOBYDEATHSAVES = 2048;
const int RGF_SILENT = 1;
const int RGF_NOPIERCING = 2;
const int RGF_EXPLICITANGLE = 4;
const int RGF_FULLBRIGHT = 8;
// Flags for A_Mushroom
const int MSF_Standard = 0;

View file

@ -11,7 +11,7 @@ ACTOR Inventory native
action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class<Actor> pufftype = "BulletPuff", float range = 0, float lifesteal = 0);
action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0);
action native A_FireCustomMissile(class<Actor> missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0);
action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0);
action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none");
action native A_Light(int extralight);
action native A_Light0();
action native A_Light1();

View file

@ -436,6 +436,8 @@ OptionMenu "CustomizeControls"
StaticText "Controls", 1
Control "Fire", "+attack"
Control "Secondary Fire", "+altattack"
Control "Weapon Reload", "+reload"
Control "Weapon Zoom", "+zoom"
Control "Use / Open", "+use"
Control "Move forward", "+forward"
Control "Move backward", "+back"