From 1e2ce9a6220f6cfcb6d137bb0d7faa68644f268c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 17:52:41 +0100 Subject: [PATCH 1/7] - some refactoring of P_AproxDistance calls into newly defined AActor method AproxDistance. The main reason here is to reduce the number of instances where AActor::x and AActor::y are being referenced. --- src/actor.h | 2414 +++++++++++++++-------------- src/b_func.cpp | 16 +- src/b_move.cpp | 2 +- src/b_think.cpp | 12 +- src/g_doom/a_lostsoul.cpp | 2 +- src/g_doom/a_revenant.cpp | 5 +- src/g_game.cpp | 3 +- src/g_heretic/a_ironlich.cpp | 3 +- src/g_hexen/a_blastradius.cpp | 2 +- src/g_hexen/a_clericholy.cpp | 7 +- src/g_hexen/a_dragon.cpp | 8 +- src/g_hexen/a_firedemon.cpp | 2 +- src/g_hexen/a_healingradius.cpp | 2 +- src/g_hexen/a_heresiarch.cpp | 3 +- src/g_hexen/a_korax.cpp | 6 +- src/g_raven/a_minotaur.cpp | 6 +- src/g_shared/a_quake.cpp | 5 +- src/g_shared/a_specialspot.cpp | 2 +- src/g_strife/a_crusader.cpp | 4 +- src/g_strife/a_inquisitor.cpp | 4 +- src/p_enemy.cpp | 34 +- src/p_map.cpp | 6 +- src/p_mobj.cpp | 11 +- src/p_spec.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 18 +- 25 files changed, 1293 insertions(+), 1286 deletions(-) diff --git a/src/actor.h b/src/actor.h index cb0524587..0cd87ec52 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1,1189 +1,1225 @@ -// 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: -// Map Objects, MObj, definition and handling. -// -//----------------------------------------------------------------------------- - - -#ifndef __P_MOBJ_H__ -#define __P_MOBJ_H__ - -// Basics. -#include "tables.h" - -// We need the thinker_t stuff. -#include "dthinker.h" - - -// States are tied to finite states are tied to animation frames. -#include "info.h" - -#include "doomdef.h" -#include "textures/textures.h" -#include "r_data/renderstyle.h" -#include "s_sound.h" -#include "memarena.h" -#include "g_level.h" -#include "tflags.h" - -struct subsector_t; -// -// NOTES: AActor -// -// Actors are used to tell the refresh where to draw an image, -// tell the world simulation when objects are contacted, -// and tell the sound driver how to position a sound. -// -// The refresh uses the next and prev links to follow -// lists of things in sectors as they are being drawn. -// The sprite, frame, and angle elements determine which patch_t -// is used to draw the sprite if it is visible. -// The sprite and frame values are almost always set -// from state_t structures. -// The statescr.exe utility generates the states.h and states.c -// files that contain the sprite/frame numbers from the -// statescr.txt source file. -// The xyz origin point represents a point at the bottom middle -// of the sprite (between the feet of a biped). -// This is the default origin position for patch_ts grabbed -// with lumpy.exe. -// A walking creature will have its z equal to the floor -// it is standing on. -// -// The sound code uses the x,y, and sometimes z fields -// to do stereo positioning of any sound emitted by the actor. -// -// The play simulation uses the blocklinks, x,y,z, radius, height -// to determine when AActors are touching each other, -// touching lines in the map, or hit by trace lines (gunshots, -// lines of sight, etc). -// The AActor->flags element has various bit flags -// used by the simulation. -// -// Every actor is linked into a single sector -// based on its origin coordinates. -// The subsector_t is found with R_PointInSubsector(x,y), -// and the sector_t can be found with subsector->sector. -// The sector links are only used by the rendering code, -// the play simulation does not care about them at all. -// -// Any actor that needs to be acted upon by something else -// in the play world (block movement, be shot, etc) will also -// need to be linked into the blockmap. -// If the thing has the MF_NOBLOCK flag set, it will not use -// the block links. It can still interact with other things, -// but only as the instigator (missiles will run into other -// things, but nothing can run into a missile). -// Each block in the grid is 128*128 units, and knows about -// every line_t that it contains a piece of, and every -// interactable actor that has its origin contained. -// -// A valid actor is an actor that has the proper subsector_t -// filled in for its xy coordinates and is linked into the -// sector from which the subsector was made, or has the -// MF_NOSECTOR flag set (the subsector_t needs to be valid -// even if MF_NOSECTOR is set), and is linked into a blockmap -// block or has the MF_NOBLOCKMAP flag set. -// Links should only be modified by the P_[Un]SetThingPosition() -// functions. -// Do not change the MF_NO* flags while a thing is valid. -// -// Any questions? -// - -// --- mobj.flags --- -enum ActorFlag -{ - MF_SPECIAL = 0x00000001, // call P_SpecialThing when touched - MF_SOLID = 0x00000002, - MF_SHOOTABLE = 0x00000004, - MF_NOSECTOR = 0x00000008, // don't use the sector links - // (invisible but touchable) - MF_NOBLOCKMAP = 0x00000010, // don't use the blocklinks - // (inert but displayable) - MF_AMBUSH = 0x00000020, // not activated by sound; deaf monster - MF_JUSTHIT = 0x00000040, // try to attack right back - MF_JUSTATTACKED = 0x00000080, // take at least one step before attacking - MF_SPAWNCEILING = 0x00000100, // hang from ceiling instead of floor - MF_NOGRAVITY = 0x00000200, // don't apply gravity every tic - -// movement flags - MF_DROPOFF = 0x00000400, // allow jumps from high places - MF_PICKUP = 0x00000800, // for players to pick up items - MF_NOCLIP = 0x00001000, // player cheat - MF_INCHASE = 0x00002000, // [RH] used by A_Chase and A_Look to avoid recursion - MF_FLOAT = 0x00004000, // allow moves to any height, no gravity - MF_TELEPORT = 0x00008000, // don't cross lines or look at heights - MF_MISSILE = 0x00010000, // don't hit same species, explode on block - - MF_DROPPED = 0x00020000, // dropped by a demon, not level spawned - MF_SHADOW = 0x00040000, // actor is hard for monsters to see - MF_NOBLOOD = 0x00080000, // don't bleed when shot (use puff) - MF_CORPSE = 0x00100000, // don't stop moving halfway off a step - MF_INFLOAT = 0x00200000, // floating to a height for a move, don't - // auto float to target's height - MF_INBOUNCE = 0x00200000, // used by Heretic bouncing missiles - - MF_COUNTKILL = 0x00400000, // count towards intermission kill total - MF_COUNTITEM = 0x00800000, // count towards intermission item total - - MF_SKULLFLY = 0x01000000, // skull in flight - MF_NOTDMATCH = 0x02000000, // don't spawn in death match (key cards) - - MF_SPAWNSOUNDSOURCE = 0x04000000, // Plays missile's see sound at spawning object. - MF_FRIENDLY = 0x08000000, // [RH] Friendly monsters for Strife (and MBF) - MF_UNMORPHED = 0x10000000, // [RH] Actor is the unmorphed version of something else - MF_NOLIFTDROP = 0x20000000, // [RH] Used with MF_NOGRAVITY to avoid dropping with lifts - MF_STEALTH = 0x40000000, // [RH] Andy Baker's stealth monsters - MF_ICECORPSE = 0x80000000, // a frozen corpse (for blasting) [RH] was 0x800000 - - // --- dummies for unknown/unimplemented Strife flags --- - MF_STRIFEx8000000 = 0, // seems related to MF_SHADOW -}; - -// --- mobj.flags2 --- -enum ActorFlag2 -{ - MF2_DONTREFLECT = 0x00000001, // this projectile cannot be reflected - MF2_WINDTHRUST = 0x00000002, // gets pushed around by the wind specials - MF2_DONTSEEKINVISIBLE=0x00000004, // For seeker missiles: Don't home in on invisible/shadow targets - MF2_BLASTED = 0x00000008, // actor will temporarily take damage from impact - MF2_FLY = 0x00000010, // fly mode is active - MF2_FLOORCLIP = 0x00000020, // if feet are allowed to be clipped - MF2_SPAWNFLOAT = 0x00000040, // spawn random float z - MF2_NOTELEPORT = 0x00000080, // does not teleport - MF2_RIP = 0x00000100, // missile rips through solid targets - MF2_PUSHABLE = 0x00000200, // can be pushed by other moving actors - MF2_SLIDE = 0x00000400, // slides against walls - MF2_ONMOBJ = 0x00000800, // actor is resting on top of another actor - MF2_PASSMOBJ = 0x00001000, // Enable z block checking. If on, - // this flag will allow the actor to - // pass over/under other actors. - MF2_CANNOTPUSH = 0x00002000, // cannot push other pushable mobjs - MF2_THRUGHOST = 0x00004000, // missile will pass through ghosts [RH] was 8 - MF2_BOSS = 0x00008000, // mobj is a major boss - - MF2_DONTTRANSLATE = 0x00010000, // Don't apply palette translations - MF2_NODMGTHRUST = 0x00020000, // does not thrust target when damaging - MF2_TELESTOMP = 0x00040000, // mobj can stomp another - MF2_FLOATBOB = 0x00080000, // use float bobbing z movement - MF2_THRUACTORS = 0x00100000, // performs no actor<->actor collision checks - MF2_IMPACT = 0x00200000, // an MF_MISSILE mobj can activate SPAC_IMPACT - MF2_PUSHWALL = 0x00400000, // mobj can push walls - MF2_MCROSS = 0x00800000, // can activate monster cross lines - MF2_PCROSS = 0x01000000, // can activate projectile cross lines - MF2_CANTLEAVEFLOORPIC=0x02000000, // stay within a certain floor type - MF2_NONSHOOTABLE = 0x04000000, // mobj is totally non-shootable, - // but still considered solid - MF2_INVULNERABLE = 0x08000000, // mobj is invulnerable - MF2_DORMANT = 0x10000000, // thing is dormant - MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the - // args should not be taken from the mapthing definition - MF2_SEEKERMISSILE = 0x40000000, // is a seeker (for reflection) - MF2_REFLECTIVE = 0x80000000, // reflects missiles -}; - -// --- mobj.flags3 --- -enum ActorFlag3 -{ - MF3_FLOORHUGGER = 0x00000001, // Missile stays on floor - MF3_CEILINGHUGGER = 0x00000002, // Missile stays on ceiling - MF3_NORADIUSDMG = 0x00000004, // Actor does not take radius damage - MF3_GHOST = 0x00000008, // Actor is a ghost - MF3_ALWAYSPUFF = 0x00000010, // Puff always appears, even when hit nothing - MF3_SPECIALFLOORCLIP= 0x00000020, // Actor uses floorclip for special effect (e.g. Wraith) - MF3_DONTSPLASH = 0x00000040, // Thing doesn't make a splash - MF3_NOSIGHTCHECK = 0x00000080, // Go after first acceptable target without checking sight - MF3_DONTOVERLAP = 0x00000100, // Don't pass over/under other things with this bit set - MF3_DONTMORPH = 0x00000200, // Immune to arti_egg - MF3_DONTSQUASH = 0x00000400, // Death ball can't squash this actor - MF3_EXPLOCOUNT = 0x00000800, // Don't explode until special2 counts to special1 - MF3_FULLVOLACTIVE = 0x00001000, // Active sound is played at full volume - MF3_ISMONSTER = 0x00002000, // Actor is a monster - MF3_SKYEXPLODE = 0x00004000, // Explode missile when hitting sky - MF3_STAYMORPHED = 0x00008000, // Monster cannot unmorph - MF3_DONTBLAST = 0x00010000, // Actor cannot be pushed by blasting - MF3_CANBLAST = 0x00020000, // Actor is not a monster but can be blasted - MF3_NOTARGET = 0x00040000, // This actor not targetted when it hurts something else - MF3_DONTGIB = 0x00080000, // Don't gib this corpse - MF3_NOBLOCKMONST = 0x00100000, // Can cross ML_BLOCKMONSTERS lines - MF3_CRASHED = 0x00200000, // Actor entered its crash state - MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles) - MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set) - MF3_SCREENSEEKER = 0x01000000, // Fails the IsOkayToAttack test if potential target is outside player FOV - MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things - MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact - MF3_BLOODLESSIMPACT = 0x08000000, // Projectile does not leave blood - MF3_NOEXPLODEFLOOR = 0x10000000, // Missile stops at floor instead of exploding - MF3_WARNBOT = 0x20000000, // Missile warns bot - MF3_PUFFONACTORS = 0x40000000, // Puff appears even when hit bleeding actors - MF3_HUNTPLAYERS = 0x80000000, // Used with TIDtoHate, means to hate players too -}; - -// --- mobj.flags4 --- -enum ActorFlag4 -{ - MF4_NOHATEPLAYERS = 0x00000001, // Ignore player attacks - MF4_QUICKTORETALIATE= 0x00000002, // Always switch targets when hurt - MF4_NOICEDEATH = 0x00000004, // Actor never enters an ice death, not even the generic one - MF4_BOSSDEATH = 0x00000008, // A_FreezeDeathChunks calls A_BossDeath - MF4_RANDOMIZE = 0x00000010, // Missile has random initial tic count - MF4_NOSKIN = 0x00000020, // Player cannot use skins - MF4_FIXMAPTHINGPOS = 0x00000040, // Fix this actor's position when spawned as a map thing - MF4_ACTLIKEBRIDGE = 0x00000080, // Pickups can "stand" on this actor / cannot be moved by any sector action. - MF4_STRIFEDAMAGE = 0x00000100, // Strife projectiles only do up to 4x damage, not 8x - - MF4_CANUSEWALLS = 0x00000200, // Can activate 'use' specials - MF4_MISSILEMORE = 0x00000400, // increases the chance of a missile attack - MF4_MISSILEEVENMORE = 0x00000800, // significantly increases the chance of a missile attack - MF4_FORCERADIUSDMG = 0x00001000, // if put on an object it will override MF3_NORADIUSDMG - MF4_DONTFALL = 0x00002000, // Doesn't have NOGRAVITY disabled when dying. - MF4_SEESDAGGERS = 0x00004000, // This actor can see you striking with a dagger - MF4_INCOMBAT = 0x00008000, // Don't alert others when attacked by a dagger - MF4_LOOKALLAROUND = 0x00010000, // Monster has eyes in the back of its head - MF4_STANDSTILL = 0x00020000, // Monster should not chase targets unless attacked? - MF4_SPECTRAL = 0x00040000, - MF4_SCROLLMOVE = 0x00080000, // velocity has been applied by a scroller - MF4_NOSPLASHALERT = 0x00100000, // Splashes don't alert this monster - MF4_SYNCHRONIZED = 0x00200000, // For actors spawned at load-time only: Do not randomize tics - MF4_NOTARGETSWITCH = 0x00400000, // monster never switches target until current one is dead - MF4_VFRICTION = 0x00800000, // Internal flag used by A_PainAttack to push a monster down - MF4_DONTHARMCLASS = 0x01000000, // Don't hurt one's own kind with explosions (hitscans, too?) - MF4_SHIELDREFLECT = 0x02000000, - MF4_DEFLECT = 0x04000000, // different projectile reflection styles - MF4_ALLOWPARTICLES = 0x08000000, // this puff type can be replaced by particles - MF4_NOEXTREMEDEATH = 0x10000000, // this projectile or weapon never gibs its victim - MF4_EXTREMEDEATH = 0x20000000, // this projectile or weapon always gibs its victim - MF4_FRIGHTENED = 0x40000000, // Monster runs away from player - MF4_BOSSSPAWNED = 0x80000000, // Spawned by a boss spawn cube -}; - -// --- mobj.flags5 --- - -enum ActorFlag5 -{ - MF5_DONTDRAIN = 0x00000001, // cannot be drained health from. - /* = 0x00000002, reserved for use by scripting branch */ - MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. - MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this - MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret - MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away from dropoffs - MF5_NODAMAGE = 0x00000040, // Actor can be shot and reacts to being shot but takes no damage - MF5_CHASEGOAL = 0x00000080, // Walks to goal instead of target if a valid goal is set. - MF5_BLOODSPLATTER = 0x00000100, // Blood splatter like in Raven's games. - MF5_OLDRADIUSDMG = 0x00000200, // Use old radius damage code (for barrels and boss brain) - MF5_DEHEXPLOSION = 0x00000400, // Use the DEHACKED explosion options when this projectile explodes - MF5_PIERCEARMOR = 0x00000800, // Armor doesn't protect against damage from this actor - MF5_NOBLOODDECALS = 0x00001000, // Actor bleeds but doesn't spawn blood decals - MF5_USESPECIAL = 0x00002000, // Actor executes its special when being 'used'. - MF5_NOPAIN = 0x00004000, // If set the pain state won't be entered - MF5_ALWAYSFAST = 0x00008000, // always uses 'fast' attacking logic - MF5_NEVERFAST = 0x00010000, // never uses 'fast' attacking logic - MF5_ALWAYSRESPAWN = 0x00020000, // always respawns, regardless of skill setting - MF5_NEVERRESPAWN = 0x00040000, // never respawns, regardless of skill setting - MF5_DONTRIP = 0x00080000, // Ripping projectiles explode when hitting this actor - MF5_NOINFIGHTING = 0x00100000, // This actor doesn't switch target when it's hurt - MF5_NOINTERACTION = 0x00200000, // Thing is completely excluded from any gameplay related checks - MF5_NOTIMEFREEZE = 0x00400000, // Actor is not affected by time freezer - MF5_PUFFGETSOWNER = 0x00800000, // [BB] Sets the owner of the puff to the player who fired it - MF5_SPECIALFIREDAMAGE=0x01000000, // Special treatment of PhoenixFX1 turned into a flag to remove - // dependence of main engine code of specific actor types. - MF5_SUMMONEDMONSTER = 0x02000000, // To mark the friendly Minotaur. Hopefully to be generalized later. - MF5_NOVERTICALMELEERANGE=0x04000000,// Does not check vertical distance for melee range - MF5_BRIGHT = 0x08000000, // Actor is always rendered fullbright - MF5_CANTSEEK = 0x10000000, // seeker missiles cannot home in on this actor - MF5_INCONVERSATION = 0x20000000, // Actor is having a conversation - MF5_PAINLESS = 0x40000000, // Actor always inflicts painless damage. - MF5_MOVEWITHSECTOR = 0x80000000, // P_ChangeSector() will still process this actor if it has MF_NOBLOCKMAP -}; - -// --- mobj.flags6 --- -enum ActorFlag6 -{ - MF6_NOBOSSRIP = 0x00000001, // For rippermissiles: Don't rip through bosses. - MF6_THRUSPECIES = 0x00000002, // Actors passes through other of the same species. - MF6_MTHRUSPECIES = 0x00000004, // Missile passes through actors of its shooter's species. - MF6_FORCEPAIN = 0x00000008, // forces target into painstate (unless it has the NOPAIN flag) - MF6_NOFEAR = 0x00000010, // Not scared of frightening players - MF6_BUMPSPECIAL = 0x00000020, // Actor executes its special when being collided (as the ST flag) - MF6_DONTHARMSPECIES = 0x00000040, // Don't hurt one's own species with explosions (hitscans, too?) - MF6_STEPMISSILE = 0x00000080, // Missile can "walk" up steps - MF6_NOTELEFRAG = 0x00000100, // [HW] Actor can't be telefragged - MF6_TOUCHY = 0x00000200, // From MBF: killough 11/98: dies when solids touch it - MF6_CANJUMP = 0x00000400, // From MBF: a dedicated flag instead of the BOUNCES+FLOAT+sentient combo - MF6_JUMPDOWN = 0x00000800, // From MBF: generalization of dog behavior wrt. dropoffs. - MF6_VULNERABLE = 0x00001000, // Actor can be damaged (even if not shootable). - MF6_ARMED = 0x00002000, // From MBF: Object is armed (for MF6_TOUCHY objects) - MF6_FALLING = 0x00004000, // From MBF: Object is falling (for pseudotorque simulation) - MF6_LINEDONE = 0x00008000, // From MBF: Object has already run a line effect - MF6_NOTRIGGER = 0x00010000, // actor cannot trigger any line actions - MF6_SHATTERING = 0x00020000, // marks an ice corpse for forced shattering - MF6_KILLED = 0x00040000, // Something that was killed (but not necessarily a corpse) - MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself - MF6_ADDITIVEPOISONDAMAGE = 0x00100000, - MF6_ADDITIVEPOISONDURATION = 0x00200000, - MF6_NOMENU = 0x00400000, // Player class should not appear in the class selection menu. - MF6_BOSSCUBE = 0x00800000, // Actor spawned by A_BrainSpit, flagged for timefreeze reasons. - MF6_SEEINVISIBLE = 0x01000000, // Monsters can see invisible player. - MF6_DONTCORPSE = 0x02000000, // [RC] Don't autoset MF_CORPSE upon death and don't force Crash state change. - 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. - MF6_NOTONAUTOMAP = 0x40000000, // will not be shown on automap with the 'scanner' powerup. - MF6_RELATIVETOFLOOR = 0x80000000, // [RC] Make flying actors be affected by lifts. -}; - -// --- mobj.flags7 --- -enum ActorFlag7 -{ - MF7_NEVERTARGET = 0x00000001, // can not be targetted at all, even if monster friendliness is considered. - MF7_NOTELESTOMP = 0x00000002, // cannot telefrag under any circumstances (even when set by MAPINFO) - MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings. - MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag - MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag - MF7_HARMFRIENDS = 0x00000020, // is allowed to harm friendly monsters. - MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat. - MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode. - MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. - MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't. - MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN. - MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles. - MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected. - MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile. - MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway. - MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target. - MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer. - MF7_FLYCHEAT = 0x00020000, // must be part of the actor so that it can be tracked properly - MF7_NODECAL = 0x00040000, // [ZK] Forces puff to have no impact decal - MF7_FORCEDECAL = 0x00080000, // [ZK] Forces puff's decal to override the weapon's. - MF7_LAXTELEFRAGDMG = 0x00100000, // [MC] Telefrag damage can be reduced. - MF7_ICESHATTER = 0x00200000, // [MC] Shatters ice corpses regardless of damagetype. -}; - -// --- mobj.renderflags --- -enum ActorRenderFlag -{ - RF_XFLIP = 0x0001, // Flip sprite horizontally - RF_YFLIP = 0x0002, // Flip sprite vertically - RF_ONESIDED = 0x0004, // Wall/floor sprite is visible from front only - RF_FULLBRIGHT = 0x0010, // Sprite is drawn at full brightness - - RF_RELMASK = 0x0300, // ---Relative z-coord for bound actors (these obey texture pegging) - RF_RELABSOLUTE = 0x0000, // Actor z is absolute - RF_RELUPPER = 0x0100, // Actor z is relative to upper part of wall - RF_RELLOWER = 0x0200, // Actor z is relative to lower part of wall - RF_RELMID = 0x0300, // Actor z is relative to middle part of wall - - RF_CLIPMASK = 0x0c00, // ---Clipping for bound actors - RF_CLIPFULL = 0x0000, // Clip sprite to full height of wall - RF_CLIPUPPER = 0x0400, // Clip sprite to upper part of wall - RF_CLIPMID = 0x0800, // Clip sprite to mid part of wall - RF_CLIPLOWER = 0x0c00, // Clip sprite to lower part of wall - - RF_DECALMASK = RF_RELMASK|RF_CLIPMASK, - - RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types, not all implemented - RF_FACESPRITE = 0x0000, // Face sprite - RF_WALLSPRITE = 0x1000, // Wall sprite - RF_FLOORSPRITE = 0x2000, // Floor sprite - RF_VOXELSPRITE = 0x3000, // Voxel object - RF_INVISIBLE = 0x8000, // Don't bother drawing this actor - - RF_FORCEYBILLBOARD = 0x10000, // [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting) - RF_FORCEXYBILLBOARD = 0x20000, // [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting) -}; - -#define TRANSLUC25 (FRACUNIT/4) -#define TRANSLUC33 (FRACUNIT/3) -#define TRANSLUC50 (FRACUNIT/2) -#define TRANSLUC66 ((FRACUNIT*2)/3) -#define TRANSLUC75 ((FRACUNIT*3)/4) - -// also #defines OPAQUE -#ifndef OPAQUE -#define OPAQUE (FRACUNIT) -#endif - -// This translucency value produces the closest match to Heretic's TINTTAB. -// ~40% of the value of the overlaid image shows through. -#define HR_SHADOW (0x6800) - -// Hexen's TINTTAB is the same as Heretic's, just reversed. -#define HX_SHADOW (0x9800) -#define HX_ALTSHADOW (0x6800) - -// This could easily be a bool but then it'd be much harder to find later. ;) -enum replace_t -{ - NO_REPLACE = 0, - ALLOW_REPLACE = 1 -}; - -enum ActorBounceFlag -{ - BOUNCE_Walls = 1<<0, // bounces off of walls - BOUNCE_Floors = 1<<1, // bounces off of floors - BOUNCE_Ceilings = 1<<2, // bounces off of ceilings - BOUNCE_Actors = 1<<3, // bounces off of some actors - BOUNCE_AllActors = 1<<4, // bounces off of all actors (requires BOUNCE_Actors to be set, too) - BOUNCE_AutoOff = 1<<5, // when bouncing off a sector plane, if the new Z velocity is below 3.0, disable further bouncing - BOUNCE_HereticType = 1<<6, // goes into Death state when bouncing on floors or ceilings - - BOUNCE_UseSeeSound = 1<<7, // compatibility fallback. This will only be set by - // the compatibility handlers for the old bounce flags. - BOUNCE_NoWallSound = 1<<8, // don't make noise when bouncing off a wall - BOUNCE_Quiet = 1<<9, // Strife's grenades don't make a bouncing sound - BOUNCE_ExplodeOnWater = 1<<10, // explodes when hitting a water surface - BOUNCE_CanBounceWater = 1<<11, // can bounce on water - // MBF bouncing is a bit different from other modes as Killough coded many special behavioral cases - // for them that are not present in ZDoom, so it is necessary to identify it properly. - BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag. - BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors - BOUNCE_UseBounceState = 1<<14, // Use Bounce[.*] states - - BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, - - // The three "standard" types of bounciness are: - // HERETIC - Missile will only bounce off the floor once and then enter - // its death state. It does not bounce off walls at all. - // HEXEN - Missile bounces off of walls and floors indefinitely. - // DOOM - Like Hexen, but the bounce turns off if its vertical velocity - // is too low. - BOUNCE_None = 0, - BOUNCE_Heretic = BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_HereticType, - BOUNCE_Doom = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff, - BOUNCE_Hexen = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors, - BOUNCE_Grenade = BOUNCE_MBF | BOUNCE_Doom, // Bounces on walls and flats like ZDoom bounce. - BOUNCE_Classic = BOUNCE_MBF | BOUNCE_Floors | BOUNCE_Ceilings, // Bounces on flats only, but - // does not die when bouncing. - - // combined types - BOUNCE_DoomCompat = BOUNCE_Doom | BOUNCE_UseSeeSound, - BOUNCE_HereticCompat = BOUNCE_Heretic | BOUNCE_UseSeeSound, - BOUNCE_HexenCompat = BOUNCE_Hexen | BOUNCE_UseSeeSound - - // The distinction between BOUNCE_Actors and BOUNCE_AllActors: A missile with - // BOUNCE_Actors set will bounce off of reflective and "non-sentient" actors. - // A missile that also has BOUNCE_AllActors set will bounce off of any actor. - // For compatibility reasons when BOUNCE_Actors was implied by the bounce type - // being "Doom" or "Hexen" and BOUNCE_AllActors was the separate - // MF5_BOUNCEONACTORS, you must set BOUNCE_Actors for BOUNCE_AllActors to have - // an effect. - - -}; - -// [TP] Flagset definitions -typedef TFlags ActorFlags; -typedef TFlags ActorFlags2; -typedef TFlags ActorFlags3; -typedef TFlags ActorFlags4; -typedef TFlags ActorFlags5; -typedef TFlags ActorFlags6; -typedef TFlags ActorFlags7; -typedef TFlags ActorRenderFlags; -typedef TFlags ActorBounceFlags; -DEFINE_TFLAGS_OPERATORS (ActorFlags) -DEFINE_TFLAGS_OPERATORS (ActorFlags2) -DEFINE_TFLAGS_OPERATORS (ActorFlags3) -DEFINE_TFLAGS_OPERATORS (ActorFlags4) -DEFINE_TFLAGS_OPERATORS (ActorFlags5) -DEFINE_TFLAGS_OPERATORS (ActorFlags6) -DEFINE_TFLAGS_OPERATORS (ActorFlags7) -DEFINE_TFLAGS_OPERATORS (ActorRenderFlags) -DEFINE_TFLAGS_OPERATORS (ActorBounceFlags) - -// Used to affect the logic for thing activation through death, USESPECIAL and BUMPSPECIAL -// "thing" refers to what has the flag and the special, "trigger" refers to what used or bumped it -enum EThingSpecialActivationType -{ - THINGSPEC_Default = 0, // Normal behavior: a player must be the trigger, and is the activator - THINGSPEC_ThingActs = 1, // The thing itself is the activator of the special - THINGSPEC_ThingTargets = 1<<1, // The thing changes its target to the trigger - THINGSPEC_TriggerTargets = 1<<2, // The trigger changes its target to the thing - THINGSPEC_MonsterTrigger = 1<<3, // The thing can be triggered by a monster - THINGSPEC_MissileTrigger = 1<<4, // The thing can be triggered by a projectile - THINGSPEC_ClearSpecial = 1<<5, // Clears special after successful activation - THINGSPEC_NoDeathSpecial = 1<<6, // Don't activate special on death - THINGSPEC_TriggerActs = 1<<7, // The trigger is the activator of the special - // (overrides LEVEL_ACTOWNSPECIAL Hexen hack) - THINGSPEC_Activate = 1<<8, // The thing is activated when triggered - THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered - THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered -}; - -// [RH] Like msecnode_t, but for the blockmap -struct FBlockNode -{ - AActor *Me; // actor this node references - int BlockIndex; // index into blocklinks for the block this node is in - FBlockNode **PrevActor; // previous actor in this block - FBlockNode *NextActor; // next actor in this block - FBlockNode **PrevBlock; // previous block this actor is in - FBlockNode *NextBlock; // next block this actor is in - - static FBlockNode *Create (AActor *who, int x, int y); - void Release (); - - static FBlockNode *FreeBlocks; -}; - -class FDecalBase; -class AInventory; - -inline AActor *GetDefaultByName (const char *name) -{ - return (AActor *)(PClass::FindClass(name)->Defaults); -} - -inline AActor *GetDefaultByType (const PClass *type) -{ - return (AActor *)(type->Defaults); -} - -template -inline T *GetDefault () -{ - return (T *)(RUNTIME_CLASS(T)->Defaults); -} - -struct line_t; -struct secplane_t; -struct FStrifeDialogueNode; - -enum -{ - AMETA_BASE = 0x12000, - - AMETA_Obituary, // string (player was killed by this actor) - AMETA_HitObituary, // string (player was killed by this actor in melee) - AMETA_DeathHeight, // fixed (height on normal death) - AMETA_BurnHeight, // fixed (height on burning death) - AMETA_StrifeName, // string (for named Strife objects) - AMETA_BloodColor, // colorized blood - AMETA_GibHealth, // negative health below which this monster dies an extreme death - AMETA_WoundHealth, // health needed to enter wound state - AMETA_FastSpeed, // Speed in fast mode - AMETA_RDFactor, // Radius damage factor - AMETA_CameraHeight, // Height of camera when used as such - AMETA_HowlSound, // Sound being played when electrocuted or poisoned - AMETA_BloodType, // Blood replacement type - AMETA_BloodType2, // Bloodsplatter replacement type - AMETA_BloodType3, // AxeBlood replacement type -}; - -struct FDropItem -{ - FName Name; - int probability; - int amount; - FDropItem * Next; -}; - -class FDropItemPtrArray : public TArray -{ -public: - ~FDropItemPtrArray() - { - Clear(); - } - - void Clear(); -}; - -extern FDropItemPtrArray DropItemList; - -void FreeDropItemChain(FDropItem *chain); -int StoreDropItemChain(FDropItem *chain); - - - -// Map Object definition. -class AActor : public DThinker -{ - DECLARE_CLASS (AActor, DThinker) - HAS_OBJECT_POINTERS -public: - AActor () throw(); - AActor (const AActor &other) throw(); - AActor &operator= (const AActor &other); - void Destroy (); - ~AActor (); - - void Serialize (FArchive &arc); - - static AActor *StaticSpawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); - - inline AActor *GetDefault () const - { - return (AActor *)(RUNTIME_TYPE(this)->Defaults); - } - - FDropItem *GetDropItems(); - - // Return true if the monster should use a missile attack, false for melee - bool SuggestMissileAttack (fixed_t dist); - - // Adjusts the angle for deflection/reflection of incoming missiles - // Returns true if the missile should be allowed to explode anyway - bool AdjustReflectionAngle (AActor *thing, angle_t &angle); - - // Returns true if this actor is within melee range of its target - bool CheckMeleeRange(); - - virtual void BeginPlay(); // Called immediately after the actor is created - virtual void PostBeginPlay(); // Called immediately before the actor's first tick - virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world - virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. - - virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching. - - virtual void Activate (AActor *activator); - virtual void Deactivate (AActor *activator); - - virtual void Tick (); - - // Called when actor dies - virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0); - - // Perform some special damage action. Returns the amount of damage to do. - // Returning -1 signals the damage routine to exit immediately - virtual int DoSpecialDamage (AActor *target, int damage, FName damagetype); - - // Like DoSpecialDamage, but called on the actor receiving the damage. - virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); - - // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed - // Made a metadata property so no longer virtual - void Howl (); - - // Actor just hit the floor - virtual void HitFloor (); - - // plays bouncing sound - void PlayBounceSound(bool onfloor); - - // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor - virtual bool FloorBounceMissile (secplane_t &plane); - - // Called when an actor is to be reflected by a disc of repulsion. - // Returns true to continue normal blast processing. - virtual bool SpecialBlastHandling (AActor *source, fixed_t strength); - - // Called by RoughBlockCheck - bool IsOkayToAttack (AActor *target); - - // Plays the actor's ActiveSound if its voice isn't already making noise. - void PlayActiveSound (); - - // Actor had MF_SKULLFLY set and rammed into something - // Returns false to stop moving and true to keep moving - virtual bool Slam (AActor *victim); - - // Called by PIT_CheckThing() and needed for some Hexen things. - // Returns -1 for normal behavior, 0 to return false, and 1 to return true. - // I'm not sure I like it this way, but it will do for now. - virtual int SpecialMissileHit (AActor *victim); - - // Returns true if it's okay to switch target to "other" after being attacked by it. - virtual bool OkayToSwitchTarget (AActor *other); - - // Something just touched this actor. - virtual void Touch (AActor *toucher); - - // Adds the item to this actor's inventory and sets its Owner. - virtual void AddInventory (AInventory *item); - - // Removes the item from the inventory list. - virtual void RemoveInventory (AInventory *item); - - // Take the amount value of an item from the inventory list. - // If nothing is left, the item may be destroyed. - // Returns true if the initial item count is positive. - virtual bool TakeInventory (const PClass *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); - - // Uses an item and removes it from the inventory. - virtual bool UseInventory (AInventory *item); - - // Tosses an item out of the inventory. - virtual AInventory *DropInventory (AInventory *item); - - // Removes all items from the inventory. - void ClearInventory(); - - // Returns true if this view is considered "local" for the player. - bool CheckLocalView (int playernum) const; - - // Finds the first item of a particular type. - AInventory *FindInventory (const PClass *type, bool subclass = false); - AInventory *FindInventory (FName type); - template T *FindInventory () - { - return static_cast (FindInventory (RUNTIME_CLASS(T))); - } - - // Adds one item of a particular type. Returns NULL if it could not be added. - AInventory *GiveInventoryType (const PClass *type); - - // Returns the first item held with IF_INVBAR set. - AInventory *FirstInv (); - - // Tries to give the actor some ammo. - bool GiveAmmo (const PClass *type, int amount); - - // Destroys all the inventory the actor is holding. - void DestroyAllInventory (); - - // Set the alphacolor field properly - void SetShade (DWORD rgb); - void SetShade (int r, int g, int b); - - // Plays a conversation animation - void ConversationAnimation (int animnum); - - // Make this actor hate the same things as another actor - void CopyFriendliness (AActor *other, bool changeTarget, bool resetHealth=true); - - // Moves the other actor's inventory to this one - void ObtainInventory (AActor *other); - - // Die. Now. - virtual bool Massacre (); - - // Transforms the actor into a finely-ground paste - virtual bool Grind(bool items); - - // Get this actor's team - int GetTeam(); - - // Is the other actor on my team? - bool IsTeammate (AActor *other); - - // Is the other actor my friend? - bool IsFriend (AActor *other); - - // Do I hate the other actor? - bool IsHostile (AActor *other); - - inline bool IsNoClip2() const; - - // What species am I? - virtual FName GetSpecies(); - - fixed_t GetBobOffset(fixed_t ticfrac=0) const - { - if (!(flags2 & MF2_FLOATBOB)) - { - return 0; - } - return finesine[MulScale22(((FloatBobPhase + level.maptime) << FRACBITS) + ticfrac, FINEANGLES) & FINEMASK] * 8; - } - - // Enter the crash state - void Crash(); - - // Return starting health adjusted by skill level - int SpawnHealth(); - int GibHealth(); - - inline bool isMissile(bool precise=true) - { - return (flags&MF_MISSILE) || (precise && GetDefault()->flags&MF_MISSILE); - } - - // Check for monsters that count as kill but excludes all friendlies. - bool CountsAsKill() const - { - return (flags & MF_COUNTKILL) && !(flags & MF_FRIENDLY); - } - - bool intersects(AActor *other) const - { - fixed_t blockdist = radius + other->radius; - return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); - } - - PalEntry GetBloodColor() const - { - return (PalEntry)GetClass()->Meta.GetMetaInt(AMETA_BloodColor); - } - - // These also set CF_INTERPVIEW for players. - void SetPitch(int p, bool interpolate, bool forceclamp = false); - void SetAngle(angle_t ang, bool interpolate); - void SetRoll(angle_t roll, bool interpolate); - - const PClass *GetBloodType(int type = 0) const - { - const PClass *bloodcls; - if (type == 0) - { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); - } - else if (type == 1) - { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); - } - else if (type == 2) - { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); - } - else return NULL; - - if (bloodcls != NULL) - { - bloodcls = bloodcls->GetReplacement(); - } - return bloodcls; - } - - inline void SetFriendPlayer(player_t *player); - - bool IsVisibleToPlayer() const; - - // Calculate amount of missile damage - virtual int GetMissileDamage(int mask, int add); - - bool CanSeek(AActor *target) const; - - fixed_t GetGravity() const; - bool IsSentient() const; - const char *GetTag(const char *def = NULL) const; - void SetTag(const char *def); - - // Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector - void CheckSectorTransition(sector_t *oldsec); - -// info for drawing -// NOTE: The first member variable *must* be x. - fixed_t x,y,z; - AActor *snext, **sprev; // links in sector (if needed) - angle_t angle; - WORD sprite; // used to find patch_t and flip value - BYTE frame; // sprite frame to draw - fixed_t scaleX, scaleY; // Scaling values; FRACUNIT is normal size - FRenderStyle RenderStyle; // Style to draw this actor with - ActorRenderFlags renderflags; // Different rendering flags - FTextureID picnum; // Draw this instead of sprite if valid - DWORD effects; // [RH] see p_effect.h - fixed_t alpha; - DWORD fillcolor; // Color to draw when STYLE_Shaded - -// interaction info - fixed_t pitch; - angle_t roll; // This was fixed_t before, which is probably wrong - FBlockNode *BlockNode; // links in blocks (if needed) - struct sector_t *Sector; - subsector_t * subsector; - fixed_t floorz, ceilingz; // closest together of contacted secs - fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors. - - struct sector_t *floorsector; - FTextureID floorpic; // contacted sec floorpic - int floorterrain; - struct sector_t *ceilingsector; - FTextureID ceilingpic; // contacted sec ceilingpic - fixed_t radius, height; // for movement checking - fixed_t projectilepassheight; // height for clipping projectile movement against this actor - fixed_t velx, vely, velz; // velocity - SDWORD tics; // state tic counter - FState *state; - SDWORD Damage; // For missiles and monster railgun - int projectileKickback; - ActorFlags flags; - ActorFlags2 flags2; // Heretic flags - ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable - ActorFlags4 flags4; // [RH] Even more flags! - ActorFlags5 flags5; // OMG! We need another one. - ActorFlags6 flags6; // Shit! Where did all the flags go? - ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? - - // [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it. - DWORD VisibleToTeam; - - int special1; // Special info - int special2; // Special info - int weaponspecial; // Special info for weapons. - int health; - BYTE movedir; // 0-7 - SBYTE visdir; - SWORD movecount; // when 0, select a new dir - SWORD strafecount; // for MF3_AVOIDMELEE - TObjPtr target; // thing being chased/attacked (or NULL) - // also the originator for missiles - TObjPtr lastenemy; // Last known enemy -- killough 2/15/98 - TObjPtr LastHeard; // [RH] Last actor this one heard - SDWORD reactiontime; // if non 0, don't attack yet; used by - // player to freeze a bit after teleporting - SDWORD threshold; // if > 0, the target will be chased - // no matter what (even if shot) - player_t *player; // only valid if type of APlayerPawn - TObjPtr LastLookActor; // Actor last looked for (if TIDtoHate != 0) - fixed_t SpawnPoint[3]; // For nightmare respawn - WORD SpawnAngle; - int StartHealth; - BYTE WeaveIndexXY; // Separated from special2 because it's used by globally accessible functions. - BYTE WeaveIndexZ; - int skillrespawncount; - int TIDtoHate; // TID of things to hate (0 if none) - FNameNoInit Species; // For monster families - TObjPtr tracer; // Thing being chased/attacked for tracers - TObjPtr master; // Thing which spawned this one (prevents mutual attacks) - fixed_t floorclip; // value to use for floor clipping - int tid; // thing identifier - int special; // special - int args[5]; // special arguments - - int accuracy, stamina; // [RH] Strife stats -- [XA] moved here for DECORATE/ACS access. - - AActor *inext, **iprev;// Links to other mobjs in same bucket - TObjPtr goal; // Monster's goal if not chasing anything - int waterlevel; // 0=none, 1=feet, 2=waist, 3=eyes - BYTE boomwaterlevel; // splash information for non-swimmable water sectors - BYTE MinMissileChance;// [RH] If a random # is > than this, then missile attack. - SBYTE LastLookPlayerNumber;// Player number last looked for (if TIDtoHate == 0) - ActorBounceFlags BounceFlags; // which bouncing type? - DWORD SpawnFlags; // Increased to DWORD because of Doom 64 - fixed_t meleerange; // specifies how far a melee attack reaches. - fixed_t meleethreshold; // Distance below which a monster doesn't try to shoot missiles anynore - // but instead tries to come closer for a melee attack. - // This is not the same as meleerange - fixed_t maxtargetrange; // any target farther away cannot be attacked - fixed_t bouncefactor; // Strife's grenades use 50%, Hexen's Flechettes 70. - fixed_t wallbouncefactor; // The bounce factor for walls can be different. - int bouncecount; // Strife's grenades only bounce twice before exploding - fixed_t gravity; // [GRB] Gravity factor - fixed_t Friction; - int FastChaseStrafeCount; - fixed_t pushfactor; - int lastpush; - int activationtype; // How the thing behaves when activated with USESPECIAL or BUMPSPECIAL - int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL - int Score; // manipulated by score items, ACS or DECORATE. The engine doesn't use this itself for anything. - FString * Tag; // Strife's tag name. - int DesignatedTeam; // Allow for friendly fire cacluations to be done on non-players. - - AActor *BlockingMobj; // Actor that blocked the last move - line_t *BlockingLine; // Line that blocked the last move - - int PoisonDamage; // Damage received per tic from poison. - FNameNoInit PoisonDamageType; // Damage type dealt by poison. - int PoisonDuration; // Duration left for receiving poison damage. - int PoisonPeriod; // How often poison damage is applied. (Every X tics.) - - int PoisonDamageReceived; // Damage received per tic from poison. - FNameNoInit PoisonDamageTypeReceived; // Damage type received by poison. - int PoisonDurationReceived; // Duration left for receiving poison damage. - int PoisonPeriodReceived; // How often poison damage is applied. (Every X tics.) - TObjPtr Poisoner; // Last source of received poison damage. - - // a linked list of sectors where this object appears - struct msecnode_t *touching_sectorlist; // phares 3/14/98 - - TObjPtr Inventory; // [RH] This actor's inventory - DWORD InventoryID; // A unique ID to keep track of inventory items - - BYTE smokecounter; - BYTE FloatBobPhase; - BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) - DWORD Translation; - - // [RH] Stuff that used to be part of an Actor Info - FSoundIDNoInit SeeSound; - FSoundIDNoInit AttackSound; - FSoundIDNoInit PainSound; - FSoundIDNoInit DeathSound; - FSoundIDNoInit ActiveSound; - FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used. - FSoundIDNoInit BounceSound; - FSoundIDNoInit WallBounceSound; - FSoundIDNoInit CrushPainSound; - - fixed_t Speed; - fixed_t FloatSpeed; - fixed_t MaxDropOffHeight, MaxStepHeight; - SDWORD Mass; - SWORD PainChance; - int PainThreshold; - FNameNoInit DamageType; - FNameNoInit DamageTypeReceived; - fixed_t DamageFactor; - fixed_t DamageMultiply; - - FNameNoInit PainType; - FNameNoInit DeathType; - const PClass *TeleFogSourceType; - const PClass *TeleFogDestType; - int RipperLevel; - int RipLevelMin; - int RipLevelMax; - - FState *SpawnState; - FState *SeeState; - FState *MeleeState; - FState *MissileState; - - - int ConversationRoot; // THe root of the current dialogue - FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." - - // [RH] Decal(s) this weapon/projectile generates on impact. - FDecalBase *DecalGenerator; - - // [RH] Used to interpolate the view to get >35 FPS - fixed_t PrevX, PrevY, PrevZ; - angle_t PrevAngle; - - // ThingIDs - static void ClearTIDHashes (); - void AddToHash (); - void RemoveFromHash (); - -private: - static AActor *TIDHash[128]; - static inline int TIDHASH (int key) { return key & 127; } - static FSharedStringArena mStringPropertyData; - - friend class FActorIterator; - friend bool P_IsTIDUsed(int tid); - - sector_t *LinkToWorldForMapThing (); - -public: - void LinkToWorld (bool buggy=false); - void LinkToWorld (sector_t *sector); - void UnlinkFromWorld (); - void AdjustFloorClip (); - void SetOrigin (fixed_t x, fixed_t y, fixed_t z); - bool InStateSequence(FState * newstate, FState * basestate); - int GetTics(FState * newstate); - bool SetState (FState *newstate, bool nofunction=false); - virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); - bool isFast(); - bool isSlow(); - void SetIdle(bool nofunction=false); - void ClearCounters(); - FState *GetRaiseState(); - void Revive(); - - FState *FindState (FName label) const - { - return GetClass()->ActorInfo->FindState(1, &label); - } - - FState *FindState (FName label, FName sublabel, bool exact = false) const - { - FName names[] = { label, sublabel }; - return GetClass()->ActorInfo->FindState(2, names, exact); - } - - FState *FindState(int numnames, FName *names, bool exact = false) const - { - return GetClass()->ActorInfo->FindState(numnames, names, exact); - } - - bool HasSpecialDeathStates () const; -}; - -class FActorIterator -{ -public: - FActorIterator (int i) : base (NULL), id (i) - { - } - FActorIterator (int i, AActor *start) : base (start), id (i) - { - } - AActor *Next () - { - if (id == 0) - return NULL; - if (!base) - base = AActor::TIDHash[id & 127]; - else - base = base->inext; - - while (base && base->tid != id) - base = base->inext; - - return base; - } -private: - AActor *base; - int id; -}; - -template -class TActorIterator : public FActorIterator -{ -public: - TActorIterator (int id) : FActorIterator (id) {} - T *Next () - { - AActor *actor; - do - { - actor = FActorIterator::Next (); - } while (actor && !actor->IsKindOf (RUNTIME_CLASS(T))); - return static_cast(actor); - } -}; - -class NActorIterator : public FActorIterator -{ - const PClass *type; -public: - NActorIterator (const PClass *cls, int id) : FActorIterator (id) { type = cls; } - NActorIterator (FName cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } - NActorIterator (const char *cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } - AActor *Next () - { - AActor *actor; - if (type == NULL) return NULL; - do - { - actor = FActorIterator::Next (); - } while (actor && !actor->IsKindOf (type)); - return actor; - } -}; - -bool P_IsTIDUsed(int tid); -int P_FindUniqueTID(int start_tid, int limit); - -inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) -{ - return AActor::StaticSpawn (type, x, y, z, allowreplacement); -} - -AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); -AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); - -template -inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) -{ - return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); -} - - -void PrintMiscActorInfo(AActor * query); - -#define S_FREETARGMOBJ 1 - -#endif // __P_MOBJ_H__ +// 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: +// Map Objects, MObj, definition and handling. +// +//----------------------------------------------------------------------------- + + +#ifndef __P_MOBJ_H__ +#define __P_MOBJ_H__ + +// Basics. +#include "tables.h" + +// We need the thinker_t stuff. +#include "dthinker.h" + + +// States are tied to finite states are tied to animation frames. +#include "info.h" + +#include "doomdef.h" +#include "textures/textures.h" +#include "r_data/renderstyle.h" +#include "s_sound.h" +#include "memarena.h" +#include "g_level.h" +#include "tflags.h" + +struct subsector_t; +// +// NOTES: AActor +// +// Actors are used to tell the refresh where to draw an image, +// tell the world simulation when objects are contacted, +// and tell the sound driver how to position a sound. +// +// The refresh uses the next and prev links to follow +// lists of things in sectors as they are being drawn. +// The sprite, frame, and angle elements determine which patch_t +// is used to draw the sprite if it is visible. +// The sprite and frame values are almost always set +// from state_t structures. +// The statescr.exe utility generates the states.h and states.c +// files that contain the sprite/frame numbers from the +// statescr.txt source file. +// The xyz origin point represents a point at the bottom middle +// of the sprite (between the feet of a biped). +// This is the default origin position for patch_ts grabbed +// with lumpy.exe. +// A walking creature will have its z equal to the floor +// it is standing on. +// +// The sound code uses the x,y, and sometimes z fields +// to do stereo positioning of any sound emitted by the actor. +// +// The play simulation uses the blocklinks, x,y,z, radius, height +// to determine when AActors are touching each other, +// touching lines in the map, or hit by trace lines (gunshots, +// lines of sight, etc). +// The AActor->flags element has various bit flags +// used by the simulation. +// +// Every actor is linked into a single sector +// based on its origin coordinates. +// The subsector_t is found with R_PointInSubsector(x,y), +// and the sector_t can be found with subsector->sector. +// The sector links are only used by the rendering code, +// the play simulation does not care about them at all. +// +// Any actor that needs to be acted upon by something else +// in the play world (block movement, be shot, etc) will also +// need to be linked into the blockmap. +// If the thing has the MF_NOBLOCK flag set, it will not use +// the block links. It can still interact with other things, +// but only as the instigator (missiles will run into other +// things, but nothing can run into a missile). +// Each block in the grid is 128*128 units, and knows about +// every line_t that it contains a piece of, and every +// interactable actor that has its origin contained. +// +// A valid actor is an actor that has the proper subsector_t +// filled in for its xy coordinates and is linked into the +// sector from which the subsector was made, or has the +// MF_NOSECTOR flag set (the subsector_t needs to be valid +// even if MF_NOSECTOR is set), and is linked into a blockmap +// block or has the MF_NOBLOCKMAP flag set. +// Links should only be modified by the P_[Un]SetThingPosition() +// functions. +// Do not change the MF_NO* flags while a thing is valid. +// +// Any questions? +// + +// --- mobj.flags --- +enum ActorFlag +{ + MF_SPECIAL = 0x00000001, // call P_SpecialThing when touched + MF_SOLID = 0x00000002, + MF_SHOOTABLE = 0x00000004, + MF_NOSECTOR = 0x00000008, // don't use the sector links + // (invisible but touchable) + MF_NOBLOCKMAP = 0x00000010, // don't use the blocklinks + // (inert but displayable) + MF_AMBUSH = 0x00000020, // not activated by sound; deaf monster + MF_JUSTHIT = 0x00000040, // try to attack right back + MF_JUSTATTACKED = 0x00000080, // take at least one step before attacking + MF_SPAWNCEILING = 0x00000100, // hang from ceiling instead of floor + MF_NOGRAVITY = 0x00000200, // don't apply gravity every tic + +// movement flags + MF_DROPOFF = 0x00000400, // allow jumps from high places + MF_PICKUP = 0x00000800, // for players to pick up items + MF_NOCLIP = 0x00001000, // player cheat + MF_INCHASE = 0x00002000, // [RH] used by A_Chase and A_Look to avoid recursion + MF_FLOAT = 0x00004000, // allow moves to any height, no gravity + MF_TELEPORT = 0x00008000, // don't cross lines or look at heights + MF_MISSILE = 0x00010000, // don't hit same species, explode on block + + MF_DROPPED = 0x00020000, // dropped by a demon, not level spawned + MF_SHADOW = 0x00040000, // actor is hard for monsters to see + MF_NOBLOOD = 0x00080000, // don't bleed when shot (use puff) + MF_CORPSE = 0x00100000, // don't stop moving halfway off a step + MF_INFLOAT = 0x00200000, // floating to a height for a move, don't + // auto float to target's height + MF_INBOUNCE = 0x00200000, // used by Heretic bouncing missiles + + MF_COUNTKILL = 0x00400000, // count towards intermission kill total + MF_COUNTITEM = 0x00800000, // count towards intermission item total + + MF_SKULLFLY = 0x01000000, // skull in flight + MF_NOTDMATCH = 0x02000000, // don't spawn in death match (key cards) + + MF_SPAWNSOUNDSOURCE = 0x04000000, // Plays missile's see sound at spawning object. + MF_FRIENDLY = 0x08000000, // [RH] Friendly monsters for Strife (and MBF) + MF_UNMORPHED = 0x10000000, // [RH] Actor is the unmorphed version of something else + MF_NOLIFTDROP = 0x20000000, // [RH] Used with MF_NOGRAVITY to avoid dropping with lifts + MF_STEALTH = 0x40000000, // [RH] Andy Baker's stealth monsters + MF_ICECORPSE = 0x80000000, // a frozen corpse (for blasting) [RH] was 0x800000 + + // --- dummies for unknown/unimplemented Strife flags --- + MF_STRIFEx8000000 = 0, // seems related to MF_SHADOW +}; + +// --- mobj.flags2 --- +enum ActorFlag2 +{ + MF2_DONTREFLECT = 0x00000001, // this projectile cannot be reflected + MF2_WINDTHRUST = 0x00000002, // gets pushed around by the wind specials + MF2_DONTSEEKINVISIBLE=0x00000004, // For seeker missiles: Don't home in on invisible/shadow targets + MF2_BLASTED = 0x00000008, // actor will temporarily take damage from impact + MF2_FLY = 0x00000010, // fly mode is active + MF2_FLOORCLIP = 0x00000020, // if feet are allowed to be clipped + MF2_SPAWNFLOAT = 0x00000040, // spawn random float z + MF2_NOTELEPORT = 0x00000080, // does not teleport + MF2_RIP = 0x00000100, // missile rips through solid targets + MF2_PUSHABLE = 0x00000200, // can be pushed by other moving actors + MF2_SLIDE = 0x00000400, // slides against walls + MF2_ONMOBJ = 0x00000800, // actor is resting on top of another actor + MF2_PASSMOBJ = 0x00001000, // Enable z block checking. If on, + // this flag will allow the actor to + // pass over/under other actors. + MF2_CANNOTPUSH = 0x00002000, // cannot push other pushable mobjs + MF2_THRUGHOST = 0x00004000, // missile will pass through ghosts [RH] was 8 + MF2_BOSS = 0x00008000, // mobj is a major boss + + MF2_DONTTRANSLATE = 0x00010000, // Don't apply palette translations + MF2_NODMGTHRUST = 0x00020000, // does not thrust target when damaging + MF2_TELESTOMP = 0x00040000, // mobj can stomp another + MF2_FLOATBOB = 0x00080000, // use float bobbing z movement + MF2_THRUACTORS = 0x00100000, // performs no actor<->actor collision checks + MF2_IMPACT = 0x00200000, // an MF_MISSILE mobj can activate SPAC_IMPACT + MF2_PUSHWALL = 0x00400000, // mobj can push walls + MF2_MCROSS = 0x00800000, // can activate monster cross lines + MF2_PCROSS = 0x01000000, // can activate projectile cross lines + MF2_CANTLEAVEFLOORPIC=0x02000000, // stay within a certain floor type + MF2_NONSHOOTABLE = 0x04000000, // mobj is totally non-shootable, + // but still considered solid + MF2_INVULNERABLE = 0x08000000, // mobj is invulnerable + MF2_DORMANT = 0x10000000, // thing is dormant + MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the + // args should not be taken from the mapthing definition + MF2_SEEKERMISSILE = 0x40000000, // is a seeker (for reflection) + MF2_REFLECTIVE = 0x80000000, // reflects missiles +}; + +// --- mobj.flags3 --- +enum ActorFlag3 +{ + MF3_FLOORHUGGER = 0x00000001, // Missile stays on floor + MF3_CEILINGHUGGER = 0x00000002, // Missile stays on ceiling + MF3_NORADIUSDMG = 0x00000004, // Actor does not take radius damage + MF3_GHOST = 0x00000008, // Actor is a ghost + MF3_ALWAYSPUFF = 0x00000010, // Puff always appears, even when hit nothing + MF3_SPECIALFLOORCLIP= 0x00000020, // Actor uses floorclip for special effect (e.g. Wraith) + MF3_DONTSPLASH = 0x00000040, // Thing doesn't make a splash + MF3_NOSIGHTCHECK = 0x00000080, // Go after first acceptable target without checking sight + MF3_DONTOVERLAP = 0x00000100, // Don't pass over/under other things with this bit set + MF3_DONTMORPH = 0x00000200, // Immune to arti_egg + MF3_DONTSQUASH = 0x00000400, // Death ball can't squash this actor + MF3_EXPLOCOUNT = 0x00000800, // Don't explode until special2 counts to special1 + MF3_FULLVOLACTIVE = 0x00001000, // Active sound is played at full volume + MF3_ISMONSTER = 0x00002000, // Actor is a monster + MF3_SKYEXPLODE = 0x00004000, // Explode missile when hitting sky + MF3_STAYMORPHED = 0x00008000, // Monster cannot unmorph + MF3_DONTBLAST = 0x00010000, // Actor cannot be pushed by blasting + MF3_CANBLAST = 0x00020000, // Actor is not a monster but can be blasted + MF3_NOTARGET = 0x00040000, // This actor not targetted when it hurts something else + MF3_DONTGIB = 0x00080000, // Don't gib this corpse + MF3_NOBLOCKMONST = 0x00100000, // Can cross ML_BLOCKMONSTERS lines + MF3_CRASHED = 0x00200000, // Actor entered its crash state + MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles) + MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set) + MF3_SCREENSEEKER = 0x01000000, // Fails the IsOkayToAttack test if potential target is outside player FOV + MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things + MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact + MF3_BLOODLESSIMPACT = 0x08000000, // Projectile does not leave blood + MF3_NOEXPLODEFLOOR = 0x10000000, // Missile stops at floor instead of exploding + MF3_WARNBOT = 0x20000000, // Missile warns bot + MF3_PUFFONACTORS = 0x40000000, // Puff appears even when hit bleeding actors + MF3_HUNTPLAYERS = 0x80000000, // Used with TIDtoHate, means to hate players too +}; + +// --- mobj.flags4 --- +enum ActorFlag4 +{ + MF4_NOHATEPLAYERS = 0x00000001, // Ignore player attacks + MF4_QUICKTORETALIATE= 0x00000002, // Always switch targets when hurt + MF4_NOICEDEATH = 0x00000004, // Actor never enters an ice death, not even the generic one + MF4_BOSSDEATH = 0x00000008, // A_FreezeDeathChunks calls A_BossDeath + MF4_RANDOMIZE = 0x00000010, // Missile has random initial tic count + MF4_NOSKIN = 0x00000020, // Player cannot use skins + MF4_FIXMAPTHINGPOS = 0x00000040, // Fix this actor's position when spawned as a map thing + MF4_ACTLIKEBRIDGE = 0x00000080, // Pickups can "stand" on this actor / cannot be moved by any sector action. + MF4_STRIFEDAMAGE = 0x00000100, // Strife projectiles only do up to 4x damage, not 8x + + MF4_CANUSEWALLS = 0x00000200, // Can activate 'use' specials + MF4_MISSILEMORE = 0x00000400, // increases the chance of a missile attack + MF4_MISSILEEVENMORE = 0x00000800, // significantly increases the chance of a missile attack + MF4_FORCERADIUSDMG = 0x00001000, // if put on an object it will override MF3_NORADIUSDMG + MF4_DONTFALL = 0x00002000, // Doesn't have NOGRAVITY disabled when dying. + MF4_SEESDAGGERS = 0x00004000, // This actor can see you striking with a dagger + MF4_INCOMBAT = 0x00008000, // Don't alert others when attacked by a dagger + MF4_LOOKALLAROUND = 0x00010000, // Monster has eyes in the back of its head + MF4_STANDSTILL = 0x00020000, // Monster should not chase targets unless attacked? + MF4_SPECTRAL = 0x00040000, + MF4_SCROLLMOVE = 0x00080000, // velocity has been applied by a scroller + MF4_NOSPLASHALERT = 0x00100000, // Splashes don't alert this monster + MF4_SYNCHRONIZED = 0x00200000, // For actors spawned at load-time only: Do not randomize tics + MF4_NOTARGETSWITCH = 0x00400000, // monster never switches target until current one is dead + MF4_VFRICTION = 0x00800000, // Internal flag used by A_PainAttack to push a monster down + MF4_DONTHARMCLASS = 0x01000000, // Don't hurt one's own kind with explosions (hitscans, too?) + MF4_SHIELDREFLECT = 0x02000000, + MF4_DEFLECT = 0x04000000, // different projectile reflection styles + MF4_ALLOWPARTICLES = 0x08000000, // this puff type can be replaced by particles + MF4_NOEXTREMEDEATH = 0x10000000, // this projectile or weapon never gibs its victim + MF4_EXTREMEDEATH = 0x20000000, // this projectile or weapon always gibs its victim + MF4_FRIGHTENED = 0x40000000, // Monster runs away from player + MF4_BOSSSPAWNED = 0x80000000, // Spawned by a boss spawn cube +}; + +// --- mobj.flags5 --- + +enum ActorFlag5 +{ + MF5_DONTDRAIN = 0x00000001, // cannot be drained health from. + /* = 0x00000002, reserved for use by scripting branch */ + MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. + MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this + MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret + MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away from dropoffs + MF5_NODAMAGE = 0x00000040, // Actor can be shot and reacts to being shot but takes no damage + MF5_CHASEGOAL = 0x00000080, // Walks to goal instead of target if a valid goal is set. + MF5_BLOODSPLATTER = 0x00000100, // Blood splatter like in Raven's games. + MF5_OLDRADIUSDMG = 0x00000200, // Use old radius damage code (for barrels and boss brain) + MF5_DEHEXPLOSION = 0x00000400, // Use the DEHACKED explosion options when this projectile explodes + MF5_PIERCEARMOR = 0x00000800, // Armor doesn't protect against damage from this actor + MF5_NOBLOODDECALS = 0x00001000, // Actor bleeds but doesn't spawn blood decals + MF5_USESPECIAL = 0x00002000, // Actor executes its special when being 'used'. + MF5_NOPAIN = 0x00004000, // If set the pain state won't be entered + MF5_ALWAYSFAST = 0x00008000, // always uses 'fast' attacking logic + MF5_NEVERFAST = 0x00010000, // never uses 'fast' attacking logic + MF5_ALWAYSRESPAWN = 0x00020000, // always respawns, regardless of skill setting + MF5_NEVERRESPAWN = 0x00040000, // never respawns, regardless of skill setting + MF5_DONTRIP = 0x00080000, // Ripping projectiles explode when hitting this actor + MF5_NOINFIGHTING = 0x00100000, // This actor doesn't switch target when it's hurt + MF5_NOINTERACTION = 0x00200000, // Thing is completely excluded from any gameplay related checks + MF5_NOTIMEFREEZE = 0x00400000, // Actor is not affected by time freezer + MF5_PUFFGETSOWNER = 0x00800000, // [BB] Sets the owner of the puff to the player who fired it + MF5_SPECIALFIREDAMAGE=0x01000000, // Special treatment of PhoenixFX1 turned into a flag to remove + // dependence of main engine code of specific actor types. + MF5_SUMMONEDMONSTER = 0x02000000, // To mark the friendly Minotaur. Hopefully to be generalized later. + MF5_NOVERTICALMELEERANGE=0x04000000,// Does not check vertical distance for melee range + MF5_BRIGHT = 0x08000000, // Actor is always rendered fullbright + MF5_CANTSEEK = 0x10000000, // seeker missiles cannot home in on this actor + MF5_INCONVERSATION = 0x20000000, // Actor is having a conversation + MF5_PAINLESS = 0x40000000, // Actor always inflicts painless damage. + MF5_MOVEWITHSECTOR = 0x80000000, // P_ChangeSector() will still process this actor if it has MF_NOBLOCKMAP +}; + +// --- mobj.flags6 --- +enum ActorFlag6 +{ + MF6_NOBOSSRIP = 0x00000001, // For rippermissiles: Don't rip through bosses. + MF6_THRUSPECIES = 0x00000002, // Actors passes through other of the same species. + MF6_MTHRUSPECIES = 0x00000004, // Missile passes through actors of its shooter's species. + MF6_FORCEPAIN = 0x00000008, // forces target into painstate (unless it has the NOPAIN flag) + MF6_NOFEAR = 0x00000010, // Not scared of frightening players + MF6_BUMPSPECIAL = 0x00000020, // Actor executes its special when being collided (as the ST flag) + MF6_DONTHARMSPECIES = 0x00000040, // Don't hurt one's own species with explosions (hitscans, too?) + MF6_STEPMISSILE = 0x00000080, // Missile can "walk" up steps + MF6_NOTELEFRAG = 0x00000100, // [HW] Actor can't be telefragged + MF6_TOUCHY = 0x00000200, // From MBF: killough 11/98: dies when solids touch it + MF6_CANJUMP = 0x00000400, // From MBF: a dedicated flag instead of the BOUNCES+FLOAT+sentient combo + MF6_JUMPDOWN = 0x00000800, // From MBF: generalization of dog behavior wrt. dropoffs. + MF6_VULNERABLE = 0x00001000, // Actor can be damaged (even if not shootable). + MF6_ARMED = 0x00002000, // From MBF: Object is armed (for MF6_TOUCHY objects) + MF6_FALLING = 0x00004000, // From MBF: Object is falling (for pseudotorque simulation) + MF6_LINEDONE = 0x00008000, // From MBF: Object has already run a line effect + MF6_NOTRIGGER = 0x00010000, // actor cannot trigger any line actions + MF6_SHATTERING = 0x00020000, // marks an ice corpse for forced shattering + MF6_KILLED = 0x00040000, // Something that was killed (but not necessarily a corpse) + MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself + MF6_ADDITIVEPOISONDAMAGE = 0x00100000, + MF6_ADDITIVEPOISONDURATION = 0x00200000, + MF6_NOMENU = 0x00400000, // Player class should not appear in the class selection menu. + MF6_BOSSCUBE = 0x00800000, // Actor spawned by A_BrainSpit, flagged for timefreeze reasons. + MF6_SEEINVISIBLE = 0x01000000, // Monsters can see invisible player. + MF6_DONTCORPSE = 0x02000000, // [RC] Don't autoset MF_CORPSE upon death and don't force Crash state change. + 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. + MF6_NOTONAUTOMAP = 0x40000000, // will not be shown on automap with the 'scanner' powerup. + MF6_RELATIVETOFLOOR = 0x80000000, // [RC] Make flying actors be affected by lifts. +}; + +// --- mobj.flags7 --- +enum ActorFlag7 +{ + MF7_NEVERTARGET = 0x00000001, // can not be targetted at all, even if monster friendliness is considered. + MF7_NOTELESTOMP = 0x00000002, // cannot telefrag under any circumstances (even when set by MAPINFO) + MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings. + MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag + MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag + MF7_HARMFRIENDS = 0x00000020, // is allowed to harm friendly monsters. + MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat. + MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode. + MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. + MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't. + MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN. + MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles. + MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected. + MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile. + MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway. + MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target. + MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer. + MF7_FLYCHEAT = 0x00020000, // must be part of the actor so that it can be tracked properly + MF7_NODECAL = 0x00040000, // [ZK] Forces puff to have no impact decal + MF7_FORCEDECAL = 0x00080000, // [ZK] Forces puff's decal to override the weapon's. + MF7_LAXTELEFRAGDMG = 0x00100000, // [MC] Telefrag damage can be reduced. + MF7_ICESHATTER = 0x00200000, // [MC] Shatters ice corpses regardless of damagetype. +}; + +// --- mobj.renderflags --- +enum ActorRenderFlag +{ + RF_XFLIP = 0x0001, // Flip sprite horizontally + RF_YFLIP = 0x0002, // Flip sprite vertically + RF_ONESIDED = 0x0004, // Wall/floor sprite is visible from front only + RF_FULLBRIGHT = 0x0010, // Sprite is drawn at full brightness + + RF_RELMASK = 0x0300, // ---Relative z-coord for bound actors (these obey texture pegging) + RF_RELABSOLUTE = 0x0000, // Actor z is absolute + RF_RELUPPER = 0x0100, // Actor z is relative to upper part of wall + RF_RELLOWER = 0x0200, // Actor z is relative to lower part of wall + RF_RELMID = 0x0300, // Actor z is relative to middle part of wall + + RF_CLIPMASK = 0x0c00, // ---Clipping for bound actors + RF_CLIPFULL = 0x0000, // Clip sprite to full height of wall + RF_CLIPUPPER = 0x0400, // Clip sprite to upper part of wall + RF_CLIPMID = 0x0800, // Clip sprite to mid part of wall + RF_CLIPLOWER = 0x0c00, // Clip sprite to lower part of wall + + RF_DECALMASK = RF_RELMASK|RF_CLIPMASK, + + RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types, not all implemented + RF_FACESPRITE = 0x0000, // Face sprite + RF_WALLSPRITE = 0x1000, // Wall sprite + RF_FLOORSPRITE = 0x2000, // Floor sprite + RF_VOXELSPRITE = 0x3000, // Voxel object + RF_INVISIBLE = 0x8000, // Don't bother drawing this actor + + RF_FORCEYBILLBOARD = 0x10000, // [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting) + RF_FORCEXYBILLBOARD = 0x20000, // [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting) +}; + +#define TRANSLUC25 (FRACUNIT/4) +#define TRANSLUC33 (FRACUNIT/3) +#define TRANSLUC50 (FRACUNIT/2) +#define TRANSLUC66 ((FRACUNIT*2)/3) +#define TRANSLUC75 ((FRACUNIT*3)/4) + +// also #defines OPAQUE +#ifndef OPAQUE +#define OPAQUE (FRACUNIT) +#endif + +// This translucency value produces the closest match to Heretic's TINTTAB. +// ~40% of the value of the overlaid image shows through. +#define HR_SHADOW (0x6800) + +// Hexen's TINTTAB is the same as Heretic's, just reversed. +#define HX_SHADOW (0x9800) +#define HX_ALTSHADOW (0x6800) + +// This could easily be a bool but then it'd be much harder to find later. ;) +enum replace_t +{ + NO_REPLACE = 0, + ALLOW_REPLACE = 1 +}; + +enum ActorBounceFlag +{ + BOUNCE_Walls = 1<<0, // bounces off of walls + BOUNCE_Floors = 1<<1, // bounces off of floors + BOUNCE_Ceilings = 1<<2, // bounces off of ceilings + BOUNCE_Actors = 1<<3, // bounces off of some actors + BOUNCE_AllActors = 1<<4, // bounces off of all actors (requires BOUNCE_Actors to be set, too) + BOUNCE_AutoOff = 1<<5, // when bouncing off a sector plane, if the new Z velocity is below 3.0, disable further bouncing + BOUNCE_HereticType = 1<<6, // goes into Death state when bouncing on floors or ceilings + + BOUNCE_UseSeeSound = 1<<7, // compatibility fallback. This will only be set by + // the compatibility handlers for the old bounce flags. + BOUNCE_NoWallSound = 1<<8, // don't make noise when bouncing off a wall + BOUNCE_Quiet = 1<<9, // Strife's grenades don't make a bouncing sound + BOUNCE_ExplodeOnWater = 1<<10, // explodes when hitting a water surface + BOUNCE_CanBounceWater = 1<<11, // can bounce on water + // MBF bouncing is a bit different from other modes as Killough coded many special behavioral cases + // for them that are not present in ZDoom, so it is necessary to identify it properly. + BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag. + BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors + BOUNCE_UseBounceState = 1<<14, // Use Bounce[.*] states + + BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, + + // The three "standard" types of bounciness are: + // HERETIC - Missile will only bounce off the floor once and then enter + // its death state. It does not bounce off walls at all. + // HEXEN - Missile bounces off of walls and floors indefinitely. + // DOOM - Like Hexen, but the bounce turns off if its vertical velocity + // is too low. + BOUNCE_None = 0, + BOUNCE_Heretic = BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_HereticType, + BOUNCE_Doom = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff, + BOUNCE_Hexen = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors, + BOUNCE_Grenade = BOUNCE_MBF | BOUNCE_Doom, // Bounces on walls and flats like ZDoom bounce. + BOUNCE_Classic = BOUNCE_MBF | BOUNCE_Floors | BOUNCE_Ceilings, // Bounces on flats only, but + // does not die when bouncing. + + // combined types + BOUNCE_DoomCompat = BOUNCE_Doom | BOUNCE_UseSeeSound, + BOUNCE_HereticCompat = BOUNCE_Heretic | BOUNCE_UseSeeSound, + BOUNCE_HexenCompat = BOUNCE_Hexen | BOUNCE_UseSeeSound + + // The distinction between BOUNCE_Actors and BOUNCE_AllActors: A missile with + // BOUNCE_Actors set will bounce off of reflective and "non-sentient" actors. + // A missile that also has BOUNCE_AllActors set will bounce off of any actor. + // For compatibility reasons when BOUNCE_Actors was implied by the bounce type + // being "Doom" or "Hexen" and BOUNCE_AllActors was the separate + // MF5_BOUNCEONACTORS, you must set BOUNCE_Actors for BOUNCE_AllActors to have + // an effect. + + +}; + +// [TP] Flagset definitions +typedef TFlags ActorFlags; +typedef TFlags ActorFlags2; +typedef TFlags ActorFlags3; +typedef TFlags ActorFlags4; +typedef TFlags ActorFlags5; +typedef TFlags ActorFlags6; +typedef TFlags ActorFlags7; +typedef TFlags ActorRenderFlags; +typedef TFlags ActorBounceFlags; +DEFINE_TFLAGS_OPERATORS (ActorFlags) +DEFINE_TFLAGS_OPERATORS (ActorFlags2) +DEFINE_TFLAGS_OPERATORS (ActorFlags3) +DEFINE_TFLAGS_OPERATORS (ActorFlags4) +DEFINE_TFLAGS_OPERATORS (ActorFlags5) +DEFINE_TFLAGS_OPERATORS (ActorFlags6) +DEFINE_TFLAGS_OPERATORS (ActorFlags7) +DEFINE_TFLAGS_OPERATORS (ActorRenderFlags) +DEFINE_TFLAGS_OPERATORS (ActorBounceFlags) + +// Used to affect the logic for thing activation through death, USESPECIAL and BUMPSPECIAL +// "thing" refers to what has the flag and the special, "trigger" refers to what used or bumped it +enum EThingSpecialActivationType +{ + THINGSPEC_Default = 0, // Normal behavior: a player must be the trigger, and is the activator + THINGSPEC_ThingActs = 1, // The thing itself is the activator of the special + THINGSPEC_ThingTargets = 1<<1, // The thing changes its target to the trigger + THINGSPEC_TriggerTargets = 1<<2, // The trigger changes its target to the thing + THINGSPEC_MonsterTrigger = 1<<3, // The thing can be triggered by a monster + THINGSPEC_MissileTrigger = 1<<4, // The thing can be triggered by a projectile + THINGSPEC_ClearSpecial = 1<<5, // Clears special after successful activation + THINGSPEC_NoDeathSpecial = 1<<6, // Don't activate special on death + THINGSPEC_TriggerActs = 1<<7, // The trigger is the activator of the special + // (overrides LEVEL_ACTOWNSPECIAL Hexen hack) + THINGSPEC_Activate = 1<<8, // The thing is activated when triggered + THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered + THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered +}; + +// [RH] Like msecnode_t, but for the blockmap +struct FBlockNode +{ + AActor *Me; // actor this node references + int BlockIndex; // index into blocklinks for the block this node is in + FBlockNode **PrevActor; // previous actor in this block + FBlockNode *NextActor; // next actor in this block + FBlockNode **PrevBlock; // previous block this actor is in + FBlockNode *NextBlock; // next block this actor is in + + static FBlockNode *Create (AActor *who, int x, int y); + void Release (); + + static FBlockNode *FreeBlocks; +}; + +class FDecalBase; +class AInventory; + +inline AActor *GetDefaultByName (const char *name) +{ + return (AActor *)(PClass::FindClass(name)->Defaults); +} + +inline AActor *GetDefaultByType (const PClass *type) +{ + return (AActor *)(type->Defaults); +} + +template +inline T *GetDefault () +{ + return (T *)(RUNTIME_CLASS(T)->Defaults); +} + +struct line_t; +struct secplane_t; +struct FStrifeDialogueNode; + +enum +{ + AMETA_BASE = 0x12000, + + AMETA_Obituary, // string (player was killed by this actor) + AMETA_HitObituary, // string (player was killed by this actor in melee) + AMETA_DeathHeight, // fixed (height on normal death) + AMETA_BurnHeight, // fixed (height on burning death) + AMETA_StrifeName, // string (for named Strife objects) + AMETA_BloodColor, // colorized blood + AMETA_GibHealth, // negative health below which this monster dies an extreme death + AMETA_WoundHealth, // health needed to enter wound state + AMETA_FastSpeed, // Speed in fast mode + AMETA_RDFactor, // Radius damage factor + AMETA_CameraHeight, // Height of camera when used as such + AMETA_HowlSound, // Sound being played when electrocuted or poisoned + AMETA_BloodType, // Blood replacement type + AMETA_BloodType2, // Bloodsplatter replacement type + AMETA_BloodType3, // AxeBlood replacement type +}; + +struct FDropItem +{ + FName Name; + int probability; + int amount; + FDropItem * Next; +}; + +class FDropItemPtrArray : public TArray +{ +public: + ~FDropItemPtrArray() + { + Clear(); + } + + void Clear(); +}; + +extern FDropItemPtrArray DropItemList; + +void FreeDropItemChain(FDropItem *chain); +int StoreDropItemChain(FDropItem *chain); +fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_local here... + + + +// Map Object definition. +class AActor : public DThinker +{ + DECLARE_CLASS (AActor, DThinker) + HAS_OBJECT_POINTERS +public: + AActor () throw(); + AActor (const AActor &other) throw(); + AActor &operator= (const AActor &other); + void Destroy (); + ~AActor (); + + void Serialize (FArchive &arc); + + static AActor *StaticSpawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); + + inline AActor *GetDefault () const + { + return (AActor *)(RUNTIME_TYPE(this)->Defaults); + } + + FDropItem *GetDropItems(); + + // Return true if the monster should use a missile attack, false for melee + bool SuggestMissileAttack (fixed_t dist); + + // Adjusts the angle for deflection/reflection of incoming missiles + // Returns true if the missile should be allowed to explode anyway + bool AdjustReflectionAngle (AActor *thing, angle_t &angle); + + // Returns true if this actor is within melee range of its target + bool CheckMeleeRange(); + + virtual void BeginPlay(); // Called immediately after the actor is created + virtual void PostBeginPlay(); // Called immediately before the actor's first tick + virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world + virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. + + virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching. + + virtual void Activate (AActor *activator); + virtual void Deactivate (AActor *activator); + + virtual void Tick (); + + // Called when actor dies + virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0); + + // Perform some special damage action. Returns the amount of damage to do. + // Returning -1 signals the damage routine to exit immediately + virtual int DoSpecialDamage (AActor *target, int damage, FName damagetype); + + // Like DoSpecialDamage, but called on the actor receiving the damage. + virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); + + // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed + // Made a metadata property so no longer virtual + void Howl (); + + // Actor just hit the floor + virtual void HitFloor (); + + // plays bouncing sound + void PlayBounceSound(bool onfloor); + + // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor + virtual bool FloorBounceMissile (secplane_t &plane); + + // Called when an actor is to be reflected by a disc of repulsion. + // Returns true to continue normal blast processing. + virtual bool SpecialBlastHandling (AActor *source, fixed_t strength); + + // Called by RoughBlockCheck + bool IsOkayToAttack (AActor *target); + + // Plays the actor's ActiveSound if its voice isn't already making noise. + void PlayActiveSound (); + + // Actor had MF_SKULLFLY set and rammed into something + // Returns false to stop moving and true to keep moving + virtual bool Slam (AActor *victim); + + // Called by PIT_CheckThing() and needed for some Hexen things. + // Returns -1 for normal behavior, 0 to return false, and 1 to return true. + // I'm not sure I like it this way, but it will do for now. + virtual int SpecialMissileHit (AActor *victim); + + // Returns true if it's okay to switch target to "other" after being attacked by it. + virtual bool OkayToSwitchTarget (AActor *other); + + // Something just touched this actor. + virtual void Touch (AActor *toucher); + + // Adds the item to this actor's inventory and sets its Owner. + virtual void AddInventory (AInventory *item); + + // Removes the item from the inventory list. + virtual void RemoveInventory (AInventory *item); + + // Take the amount value of an item from the inventory list. + // If nothing is left, the item may be destroyed. + // Returns true if the initial item count is positive. + virtual bool TakeInventory (const PClass *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); + + // Uses an item and removes it from the inventory. + virtual bool UseInventory (AInventory *item); + + // Tosses an item out of the inventory. + virtual AInventory *DropInventory (AInventory *item); + + // Removes all items from the inventory. + void ClearInventory(); + + // Returns true if this view is considered "local" for the player. + bool CheckLocalView (int playernum) const; + + // Finds the first item of a particular type. + AInventory *FindInventory (const PClass *type, bool subclass = false); + AInventory *FindInventory (FName type); + template T *FindInventory () + { + return static_cast (FindInventory (RUNTIME_CLASS(T))); + } + + // Adds one item of a particular type. Returns NULL if it could not be added. + AInventory *GiveInventoryType (const PClass *type); + + // Returns the first item held with IF_INVBAR set. + AInventory *FirstInv (); + + // Tries to give the actor some ammo. + bool GiveAmmo (const PClass *type, int amount); + + // Destroys all the inventory the actor is holding. + void DestroyAllInventory (); + + // Set the alphacolor field properly + void SetShade (DWORD rgb); + void SetShade (int r, int g, int b); + + // Plays a conversation animation + void ConversationAnimation (int animnum); + + // Make this actor hate the same things as another actor + void CopyFriendliness (AActor *other, bool changeTarget, bool resetHealth=true); + + // Moves the other actor's inventory to this one + void ObtainInventory (AActor *other); + + // Die. Now. + virtual bool Massacre (); + + // Transforms the actor into a finely-ground paste + virtual bool Grind(bool items); + + // Get this actor's team + int GetTeam(); + + // Is the other actor on my team? + bool IsTeammate (AActor *other); + + // Is the other actor my friend? + bool IsFriend (AActor *other); + + // Do I hate the other actor? + bool IsHostile (AActor *other); + + inline bool IsNoClip2() const; + + // What species am I? + virtual FName GetSpecies(); + + fixed_t GetBobOffset(fixed_t ticfrac=0) const + { + if (!(flags2 & MF2_FLOATBOB)) + { + return 0; + } + return finesine[MulScale22(((FloatBobPhase + level.maptime) << FRACBITS) + ticfrac, FINEANGLES) & FINEMASK] * 8; + } + + // Enter the crash state + void Crash(); + + // Return starting health adjusted by skill level + int SpawnHealth(); + int GibHealth(); + + inline bool isMissile(bool precise=true) + { + return (flags&MF_MISSILE) || (precise && GetDefault()->flags&MF_MISSILE); + } + + // Check for monsters that count as kill but excludes all friendlies. + bool CountsAsKill() const + { + return (flags & MF_COUNTKILL) && !(flags & MF_FRIENDLY); + } + + bool intersects(AActor *other) const + { + fixed_t blockdist = radius + other->radius; + return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); + } + + PalEntry GetBloodColor() const + { + return (PalEntry)GetClass()->Meta.GetMetaInt(AMETA_BloodColor); + } + + // These also set CF_INTERPVIEW for players. + void SetPitch(int p, bool interpolate, bool forceclamp = false); + void SetAngle(angle_t ang, bool interpolate); + void SetRoll(angle_t roll, bool interpolate); + + const PClass *GetBloodType(int type = 0) const + { + const PClass *bloodcls; + if (type == 0) + { + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); + } + else if (type == 1) + { + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); + } + else if (type == 2) + { + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); + } + else return NULL; + + if (bloodcls != NULL) + { + bloodcls = bloodcls->GetReplacement(); + } + return bloodcls; + } + + // 'absolute' is reserved for a linked portal implementation which needs + // to distinguish between portal-aware and portal-unaware distance calculation. + fixed_t AproxDistance(AActor *other, bool absolute = false) + { + return P_AproxDistance(x - other->x, y - other->y); + } + + // same with 'ref' here. + fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL) + { + return P_AproxDistance(x - otherx, y - othery); + } + + fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false) + { + return P_AproxDistance(x - other->x + xadd, y - other->y + yadd); + } + + fixed_t AproxDistance3D(AActor *other, bool absolute = false) + { + return P_AproxDistance(AproxDistance(other), z - other->z); + } + + // more precise, but slower version, being used in a few places + fixed_t Distance2D(AActor *other, bool absolute = false) + { + return xs_RoundToInt(FVector2(x - other->x, y - other->y).Length()); + } + + // a full 3D version of the above + fixed_t Distance3D(AActor *other, bool absolute = false) + { + return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length()); + } + + inline void SetFriendPlayer(player_t *player); + + bool IsVisibleToPlayer() const; + + // Calculate amount of missile damage + virtual int GetMissileDamage(int mask, int add); + + bool CanSeek(AActor *target) const; + + fixed_t GetGravity() const; + bool IsSentient() const; + const char *GetTag(const char *def = NULL) const; + void SetTag(const char *def); + + // Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector + void CheckSectorTransition(sector_t *oldsec); + +// info for drawing +// NOTE: The first member variable *must* be x. + fixed_t x,y,z; + AActor *snext, **sprev; // links in sector (if needed) + angle_t angle; + WORD sprite; // used to find patch_t and flip value + BYTE frame; // sprite frame to draw + fixed_t scaleX, scaleY; // Scaling values; FRACUNIT is normal size + FRenderStyle RenderStyle; // Style to draw this actor with + ActorRenderFlags renderflags; // Different rendering flags + FTextureID picnum; // Draw this instead of sprite if valid + DWORD effects; // [RH] see p_effect.h + fixed_t alpha; + DWORD fillcolor; // Color to draw when STYLE_Shaded + +// interaction info + fixed_t pitch; + angle_t roll; // This was fixed_t before, which is probably wrong + FBlockNode *BlockNode; // links in blocks (if needed) + struct sector_t *Sector; + subsector_t * subsector; + fixed_t floorz, ceilingz; // closest together of contacted secs + fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors. + + struct sector_t *floorsector; + FTextureID floorpic; // contacted sec floorpic + int floorterrain; + struct sector_t *ceilingsector; + FTextureID ceilingpic; // contacted sec ceilingpic + fixed_t radius, height; // for movement checking + fixed_t projectilepassheight; // height for clipping projectile movement against this actor + fixed_t velx, vely, velz; // velocity + SDWORD tics; // state tic counter + FState *state; + SDWORD Damage; // For missiles and monster railgun + int projectileKickback; + ActorFlags flags; + ActorFlags2 flags2; // Heretic flags + ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable + ActorFlags4 flags4; // [RH] Even more flags! + ActorFlags5 flags5; // OMG! We need another one. + ActorFlags6 flags6; // Shit! Where did all the flags go? + ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? + + // [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it. + DWORD VisibleToTeam; + + int special1; // Special info + int special2; // Special info + int weaponspecial; // Special info for weapons. + int health; + BYTE movedir; // 0-7 + SBYTE visdir; + SWORD movecount; // when 0, select a new dir + SWORD strafecount; // for MF3_AVOIDMELEE + TObjPtr target; // thing being chased/attacked (or NULL) + // also the originator for missiles + TObjPtr lastenemy; // Last known enemy -- killough 2/15/98 + TObjPtr LastHeard; // [RH] Last actor this one heard + SDWORD reactiontime; // if non 0, don't attack yet; used by + // player to freeze a bit after teleporting + SDWORD threshold; // if > 0, the target will be chased + // no matter what (even if shot) + player_t *player; // only valid if type of APlayerPawn + TObjPtr LastLookActor; // Actor last looked for (if TIDtoHate != 0) + fixed_t SpawnPoint[3]; // For nightmare respawn + WORD SpawnAngle; + int StartHealth; + BYTE WeaveIndexXY; // Separated from special2 because it's used by globally accessible functions. + BYTE WeaveIndexZ; + int skillrespawncount; + int TIDtoHate; // TID of things to hate (0 if none) + FNameNoInit Species; // For monster families + TObjPtr tracer; // Thing being chased/attacked for tracers + TObjPtr master; // Thing which spawned this one (prevents mutual attacks) + fixed_t floorclip; // value to use for floor clipping + int tid; // thing identifier + int special; // special + int args[5]; // special arguments + + int accuracy, stamina; // [RH] Strife stats -- [XA] moved here for DECORATE/ACS access. + + AActor *inext, **iprev;// Links to other mobjs in same bucket + TObjPtr goal; // Monster's goal if not chasing anything + int waterlevel; // 0=none, 1=feet, 2=waist, 3=eyes + BYTE boomwaterlevel; // splash information for non-swimmable water sectors + BYTE MinMissileChance;// [RH] If a random # is > than this, then missile attack. + SBYTE LastLookPlayerNumber;// Player number last looked for (if TIDtoHate == 0) + ActorBounceFlags BounceFlags; // which bouncing type? + DWORD SpawnFlags; // Increased to DWORD because of Doom 64 + fixed_t meleerange; // specifies how far a melee attack reaches. + fixed_t meleethreshold; // Distance below which a monster doesn't try to shoot missiles anynore + // but instead tries to come closer for a melee attack. + // This is not the same as meleerange + fixed_t maxtargetrange; // any target farther away cannot be attacked + fixed_t bouncefactor; // Strife's grenades use 50%, Hexen's Flechettes 70. + fixed_t wallbouncefactor; // The bounce factor for walls can be different. + int bouncecount; // Strife's grenades only bounce twice before exploding + fixed_t gravity; // [GRB] Gravity factor + fixed_t Friction; + int FastChaseStrafeCount; + fixed_t pushfactor; + int lastpush; + int activationtype; // How the thing behaves when activated with USESPECIAL or BUMPSPECIAL + int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL + int Score; // manipulated by score items, ACS or DECORATE. The engine doesn't use this itself for anything. + FString * Tag; // Strife's tag name. + int DesignatedTeam; // Allow for friendly fire cacluations to be done on non-players. + + AActor *BlockingMobj; // Actor that blocked the last move + line_t *BlockingLine; // Line that blocked the last move + + int PoisonDamage; // Damage received per tic from poison. + FNameNoInit PoisonDamageType; // Damage type dealt by poison. + int PoisonDuration; // Duration left for receiving poison damage. + int PoisonPeriod; // How often poison damage is applied. (Every X tics.) + + int PoisonDamageReceived; // Damage received per tic from poison. + FNameNoInit PoisonDamageTypeReceived; // Damage type received by poison. + int PoisonDurationReceived; // Duration left for receiving poison damage. + int PoisonPeriodReceived; // How often poison damage is applied. (Every X tics.) + TObjPtr Poisoner; // Last source of received poison damage. + + // a linked list of sectors where this object appears + struct msecnode_t *touching_sectorlist; // phares 3/14/98 + + TObjPtr Inventory; // [RH] This actor's inventory + DWORD InventoryID; // A unique ID to keep track of inventory items + + BYTE smokecounter; + BYTE FloatBobPhase; + BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) + DWORD Translation; + + // [RH] Stuff that used to be part of an Actor Info + FSoundIDNoInit SeeSound; + FSoundIDNoInit AttackSound; + FSoundIDNoInit PainSound; + FSoundIDNoInit DeathSound; + FSoundIDNoInit ActiveSound; + FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used. + FSoundIDNoInit BounceSound; + FSoundIDNoInit WallBounceSound; + FSoundIDNoInit CrushPainSound; + + fixed_t Speed; + fixed_t FloatSpeed; + fixed_t MaxDropOffHeight, MaxStepHeight; + SDWORD Mass; + SWORD PainChance; + int PainThreshold; + FNameNoInit DamageType; + FNameNoInit DamageTypeReceived; + fixed_t DamageFactor; + fixed_t DamageMultiply; + + FNameNoInit PainType; + FNameNoInit DeathType; + const PClass *TeleFogSourceType; + const PClass *TeleFogDestType; + int RipperLevel; + int RipLevelMin; + int RipLevelMax; + + FState *SpawnState; + FState *SeeState; + FState *MeleeState; + FState *MissileState; + + + int ConversationRoot; // THe root of the current dialogue + FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." + + // [RH] Decal(s) this weapon/projectile generates on impact. + FDecalBase *DecalGenerator; + + // [RH] Used to interpolate the view to get >35 FPS + fixed_t PrevX, PrevY, PrevZ; + angle_t PrevAngle; + + // ThingIDs + static void ClearTIDHashes (); + void AddToHash (); + void RemoveFromHash (); + +private: + static AActor *TIDHash[128]; + static inline int TIDHASH (int key) { return key & 127; } + static FSharedStringArena mStringPropertyData; + + friend class FActorIterator; + friend bool P_IsTIDUsed(int tid); + + sector_t *LinkToWorldForMapThing (); + +public: + void LinkToWorld (bool buggy=false); + void LinkToWorld (sector_t *sector); + void UnlinkFromWorld (); + void AdjustFloorClip (); + void SetOrigin (fixed_t x, fixed_t y, fixed_t z); + bool InStateSequence(FState * newstate, FState * basestate); + int GetTics(FState * newstate); + bool SetState (FState *newstate, bool nofunction=false); + virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); + bool isFast(); + bool isSlow(); + void SetIdle(bool nofunction=false); + void ClearCounters(); + FState *GetRaiseState(); + void Revive(); + + FState *FindState (FName label) const + { + return GetClass()->ActorInfo->FindState(1, &label); + } + + FState *FindState (FName label, FName sublabel, bool exact = false) const + { + FName names[] = { label, sublabel }; + return GetClass()->ActorInfo->FindState(2, names, exact); + } + + FState *FindState(int numnames, FName *names, bool exact = false) const + { + return GetClass()->ActorInfo->FindState(numnames, names, exact); + } + + bool HasSpecialDeathStates () const; +}; + +class FActorIterator +{ +public: + FActorIterator (int i) : base (NULL), id (i) + { + } + FActorIterator (int i, AActor *start) : base (start), id (i) + { + } + AActor *Next () + { + if (id == 0) + return NULL; + if (!base) + base = AActor::TIDHash[id & 127]; + else + base = base->inext; + + while (base && base->tid != id) + base = base->inext; + + return base; + } +private: + AActor *base; + int id; +}; + +template +class TActorIterator : public FActorIterator +{ +public: + TActorIterator (int id) : FActorIterator (id) {} + T *Next () + { + AActor *actor; + do + { + actor = FActorIterator::Next (); + } while (actor && !actor->IsKindOf (RUNTIME_CLASS(T))); + return static_cast(actor); + } +}; + +class NActorIterator : public FActorIterator +{ + const PClass *type; +public: + NActorIterator (const PClass *cls, int id) : FActorIterator (id) { type = cls; } + NActorIterator (FName cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } + NActorIterator (const char *cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } + AActor *Next () + { + AActor *actor; + if (type == NULL) return NULL; + do + { + actor = FActorIterator::Next (); + } while (actor && !actor->IsKindOf (type)); + return actor; + } +}; + +bool P_IsTIDUsed(int tid); +int P_FindUniqueTID(int start_tid, int limit); + +inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) +{ + return AActor::StaticSpawn (type, x, y, z, allowreplacement); +} + +AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); +AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); + +template +inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) +{ + return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); +} + + +void PrintMiscActorInfo(AActor * query); + +#define S_FREETARGMOBJ 1 + +#endif // __P_MOBJ_H__ diff --git a/src/b_func.cpp b/src/b_func.cpp index f93625612..87b1e5416 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -37,7 +37,7 @@ bool DBot::Reachable (AActor *rtarget) sector_t *last_s = player->mo->Sector; fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y); - fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y); + fixed_t estimated_dist = player->mo->AproxDistance(rtarget); bool reachable = true; FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS); @@ -165,10 +165,8 @@ void DBot::Dofire (ticcmd_t *cmd) //MAKEME: Decrease the rocket suicides even more. no_fire = true; - //angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); //Distance to enemy. - dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx), - (player->mo->y + player->mo->vely) - (enemy->y + enemy->vely)); + dist = player->mo->AproxDistance(enemy, player->mo->velx - enemy->velx, player->mo->vely - enemy->vely); //FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go. if (player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON) @@ -219,7 +217,7 @@ void DBot::Dofire (ticcmd_t *cmd) } // prediction aiming shootmissile: - dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y); + dist = player->mo->AproxDistance (enemy); m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed; bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y); @@ -331,8 +329,7 @@ AActor *DBot::Choose_Mate () { if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY)) { - test = P_AproxDistance (client->mo->x - player->mo->x, - client->mo->y - player->mo->y); + test = client->mo->AproxDistance(player->mo); if (test < closest_dist) { @@ -402,8 +399,7 @@ AActor *DBot::Find_enemy () if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up. //if(P_CheckSight(player->mo, players[count].mo)) { - temp = P_AproxDistance (client->mo->x - player->mo->x, - client->mo->y - player->mo->y); + temp = client->mo->AproxDistance(player->mo); //Too dark? if (temp > DARK_DIST && @@ -505,7 +501,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) actor = bglobal.body2; - dist = P_AproxDistance (actor->x-enemy->x, actor->y-enemy->y); + dist = actor->AproxDistance (enemy); if (dist < SAFE_SELF_MISDIST) return 0; //Predict. diff --git a/src/b_move.cpp b/src/b_move.cpp index 4759f22d9..c608c5d03 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -347,7 +347,7 @@ void DBot::Pitch (AActor *target) double diff; diff = target->z - player->mo->z; - aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y)); + aim = atan(diff / (double)player->mo->AproxDistance(target)); player->mo->pitch = -(int)(aim * ANGLE_180/M_PI); } diff --git a/src/b_think.cpp b/src/b_think.cpp index 34baeee9c..73c5066ab 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -81,7 +81,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) int r; stuck = false; - dist = dest ? P_AproxDistance(player->mo->x-dest->x, player->mo->y-dest->y) : 0; + dist = dest ? player->mo->AproxDistance(dest) : 0; if (missile && ((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2))) @@ -96,14 +96,14 @@ void DBot::ThinkForMove (ticcmd_t *cmd) player->mo->pitch += 80; //HOW TO MOVE: - if (missile && (P_AproxDistance(player->mo->x-missile->x, player->mo->y-missile->y)mo->AproxDistance(missile)mo->x, player->mo->y, missile->x, missile->y); cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best. - if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000) + if ((player->mo->AproxDistance(oldx, oldy)<50000) && t_strafe<=0) { t_strafe = 5; @@ -156,7 +156,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) t_fight = AFTERTICS; if (t_strafe <= 0 && - (P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000 + (player->mo->AproxDistance(oldx, oldy)<50000 || ((pr_botmove()%30)==10)) ) { @@ -168,7 +168,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); if (player->ReadyWeapon == NULL || - P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) > + player->mo->AproxDistance(enemy) > player->ReadyWeapon->MoveCombatDist) { // If a monster, use lower speed (just for cooler apperance while strafing down doomed monster) @@ -208,7 +208,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y); - matedist = P_AproxDistance(player->mo->x - mate->x, player->mo->y - mate->y); + matedist = player->mo->AproxDistance(mate); if (matedist > (FRIEND_DIST*2)) cmd->ucmd.forwardmove = FORWARDRUN; else if (matedist > FRIEND_DIST) diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp index fdc0257cb..1182292e0 100644 --- a/src/g_doom/a_lostsoul.cpp +++ b/src/g_doom/a_lostsoul.cpp @@ -36,7 +36,7 @@ void A_SkullAttack(AActor *self, fixed_t speed) an = self->angle >> ANGLETOFINESHIFT; self->velx = FixedMul (speed, finecosine[an]); self->vely = FixedMul (speed, finesine[an]); - dist = P_AproxDistance (dest->x - self->x, dest->y - self->y); + dist = self->AproxDistance (dest); dist = dist / speed; if (dist < 1) diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 0600a59eb..90c6e0a51 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -102,10 +102,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // change slope - dist = P_AproxDistance (dest->x - self->x, - dest->y - self->y); - - dist = dist / self->Speed; + dist = self->AproxDistance (dest) / self->Speed; if (dist < 1) dist = 1; diff --git a/src/g_game.cpp b/src/g_game.cpp index 64e746cef..b7d10251b 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1479,8 +1479,7 @@ static fixed_t PlayersRangeFromSpot (FPlayerStart *spot) if (!playeringame[i] || !players[i].mo || players[i].health <= 0) continue; - distance = P_AproxDistance (players[i].mo->x - spot->x, - players[i].mo->y - spot->y); + distance = players[i].mo->AproxDistance (spot->x, spot->y); if (distance < closest) closest = distance; diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index dba16b622..75c05bf2b 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -91,8 +91,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) P_TraceBleed (newdam > 0 ? newdam : damage, target, self); return; } - dist = P_AproxDistance (self->x-target->x, self->y-target->y) - > 8*64*FRACUNIT; + dist = self->AproxDistance (target) > 8*64*FRACUNIT; randAttack = pr_atk (); if (randAttack < atkResolve1[dist]) { // Ice ball diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index a78b0b4c8..53ce08b50 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -141,7 +141,7 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) { // Must be monster, player, missile, touchy or vulnerable continue; } - dist = P_AproxDistance (self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance (mo); if (dist > radius) { // Out of range continue; diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 2b469e5af..73ffeac88 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -264,12 +264,11 @@ static void CHolyTailFollow (AActor *actor, fixed_t dist) { an = R_PointToAngle2(actor->x, actor->y, child->x, child->y)>>ANGLETOFINESHIFT; - oldDistance = P_AproxDistance (child->x-actor->x, child->y-actor->y); + oldDistance = child->AproxDistance (actor); if (P_TryMove (child, actor->x+FixedMul(dist, finecosine[an]), actor->y+FixedMul(dist, finesine[an]), true)) { - newDistance = P_AproxDistance (child->x-actor->x, - child->y-actor->y)-FRACUNIT; + newDistance = child->AproxDistance (actor)-FRACUNIT; if (oldDistance < FRACUNIT) { if (child->z < actor->z) @@ -425,7 +424,7 @@ static void CHolySeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) deltaZ = -15*FRACUNIT; } } - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); + dist = actor->AproxDistance (target); dist = dist / actor->Speed; if (dist < 1) { diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index fdf2428af..5b18c0d57 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -59,22 +59,16 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) angle = actor->angle>>ANGLETOFINESHIFT; actor->velx = FixedMul (actor->Speed, finecosine[angle]); actor->vely = FixedMul (actor->Speed, finesine[angle]); + dist = actor->AproxDistance (target) / actor->Speed; if (actor->z+actor->height < target->z || target->z+target->height < actor->z) { - dist = P_AproxDistance(target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; if (dist < 1) { dist = 1; } actor->velz = (target->z - actor->z)/dist; } - else - { - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; - } if (target->flags&MF_SHOOTABLE && pr_dragonseek() < 64) { // attack the destination mobj if it's attackable AActor *oldTarget; diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index c588dd2ae..b1cfafc0c 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -158,7 +158,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { self->special2 = 0; self->velx = self->vely = 0; - dist = P_AproxDistance (self->x - target->x, self->y - target->y); + dist = self->AproxDistance (target); if (dist < FIREDEMON_ATTACK_RANGE) { if (pr_firedemonchase() < 30) diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp index b827f666b..d1d39ddd4 100644 --- a/src/g_hexen/a_healingradius.cpp +++ b/src/g_hexen/a_healingradius.cpp @@ -37,7 +37,7 @@ bool AArtiHealingRadius::Use (bool pickup) if (playeringame[i] && players[i].mo != NULL && players[i].mo->health > 0 && - P_AproxDistance (players[i].mo->x - Owner->x, players[i].mo->y - Owner->y) <= HEAL_RADIUS_DIST) + players[i].mo->AproxDistance (Owner) <= HEAL_RADIUS_DIST) { // Q: Is it worth it to make this selectable as a player property? // A: Probably not - but it sure doesn't hurt. diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index 9ca0a70e8..498b4e955 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -665,8 +665,7 @@ void A_SorcOffense2(AActor *actor) if (mo) { mo->special2 = 35*5/2; // 5 seconds - dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y); - dist = dist/mo->Speed; + dist = mo->AproxDistance(dest) / mo->Speed; if(dist < 1) dist = 1; mo->velz = (dest->z - mo->z) / dist; } diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index 5323fb851..ca849dd97 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -388,8 +388,7 @@ void A_KSpiritSeeker (AActor *actor, angle_t thresh, angle_t turnMax) deltaZ = -15*FRACUNIT; } } - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; + dist = actor->AproxDistance (target) / actor->Speed; if (dist < 1) { dist = 1; @@ -495,8 +494,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); - dist = P_AproxDistance (dest->x - x, dest->y - y); - dist = dist/th->Speed; + dist = dest->AproxDistance (x, y, source) / th->Speed; if (dist < 1) { dist = 1; diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 0f9d9cd55..c0095226e 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -185,7 +185,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) { S_Sound (self, CHAN_WEAPON, "minotaur/sight", 1, ATTN_NORM); } - dist = P_AproxDistance (self->x-target->x, self->y-target->y); + dist = self->AproxDistance (target); if (target->z+target->height > self->z && target->z+target->height < self->z+self->height && dist < (friendly ? 16*64*FRACUNIT : 8*64*FRACUNIT) @@ -489,7 +489,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) mo = player->mo; if (mo == master) continue; if (mo->health <= 0) continue; - dist = P_AproxDistance(self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance(mo); if (dist > MINOTAUR_LOOK_DIST) continue; self->target = mo; break; @@ -514,7 +514,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) if (!(mo->flags3 & MF3_ISMONSTER)) continue; if (mo->health <= 0) continue; if (!(mo->flags & MF_SHOOTABLE)) continue; - dist = P_AproxDistance (self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance(mo); if (dist > MINOTAUR_LOOK_DIST) continue; if ((mo == master) || (mo == self)) continue; if ((mo->flags5 & MF5_SUMMONEDMONSTER) && (mo->tracer == master)) continue; diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index 3c8d704aa..195f3ccbf 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -129,7 +129,7 @@ void DEarthquake::Tick () AActor *victim = players[i].mo; fixed_t dist; - dist = P_AproxDistance (victim->x - m_Spot->x, victim->y - m_Spot->y); + dist = m_Spot->AproxDistance (victim, true); // Check if in damage radius if (dist < m_DamageRadius && victim->z <= victim->floorz) { @@ -242,8 +242,7 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger { if (quake->m_Spot != NULL) { - fixed_t dist = P_AproxDistance (victim->x - quake->m_Spot->x, - victim->y - quake->m_Spot->y); + fixed_t dist = quake->m_Spot->AproxDistance (victim, true); if (dist < quake->m_TremorRadius) { ++count; diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index fbfbbf550..d3994ed84 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -158,7 +158,7 @@ struct FSpotList while (true) { - distance = P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y); + distance = Spots[i]->AproxDistance(x, y); if ((distance >= mindist) && ((maxdist == 0) || (distance <= maxdist))) break; diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp index 7ef0b24a1..cf5f03a23 100644 --- a/src/g_strife/a_crusader.cpp +++ b/src/g_strife/a_crusader.cpp @@ -11,9 +11,9 @@ static bool CrusaderCheckRange (AActor *self) { - if (P_CheckSight (self, self->target) && self->reactiontime == 0) + if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { - return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; + return self->AproxDistance (self->target) < 264*FRACUNIT; } return false; } diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp index 70ca805f8..1a0739d36 100644 --- a/src/g_strife/a_inquisitor.cpp +++ b/src/g_strife/a_inquisitor.cpp @@ -20,7 +20,7 @@ bool InquisitorCheckDistance (AActor *self) { if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { - return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; + return self->AproxDistance (self->target) < 264*FRACUNIT; } return false; } @@ -85,7 +85,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) speed = self->Speed * 2/3; self->velx += FixedMul (speed, finecosine[an]); self->vely += FixedMul (speed, finesine[an]); - dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y); + dist = self->AproxDistance (self->target); dist /= speed; if (dist < 1) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 5291101a5..489fb107d 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -138,7 +138,7 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun for (actor = sec->thinglist; actor != NULL; actor = actor->snext) { if (actor != soundtarget && (!splash || !(actor->flags4 & MF4_NOSPLASHALERT)) && - (!maxdist || (P_AproxDistance(actor->x - emitter->x, actor->y - emitter->y) <= maxdist))) + (!maxdist || (actor->AproxDistance(emitter) <= maxdist))) { actor->LastHeard = soundtarget; } @@ -231,7 +231,7 @@ bool AActor::CheckMeleeRange () if (!pl) return false; - dist = P_AproxDistance (pl->x - x, pl->y - y); + dist = AproxDistance (pl); if (dist >= meleerange + pl->radius) return false; @@ -275,7 +275,7 @@ bool P_CheckMeleeRange2 (AActor *actor) return false; } mo = actor->target; - dist = P_AproxDistance (mo->x-actor->x, mo->y-actor->y); + dist = mo->AproxDistance (actor); if (dist >= MELEERANGE*2 || dist < MELEERANGE-20*FRACUNIT + mo->radius) { return false; @@ -348,8 +348,7 @@ bool P_CheckMissileRange (AActor *actor) // OPTIMIZE: get this from a global checksight // [RH] What? - dist = P_AproxDistance (actor->x-actor->target->x, - actor->y-actor->target->y) - 64*FRACUNIT; + dist = actor->AproxDistance (actor->target) - 64*FRACUNIT; if (actor->MeleeState == NULL) dist -= 128*FRACUNIT; // no melee attack, so fire more @@ -394,7 +393,7 @@ bool P_HitFriend(AActor * self) if (self->flags&MF_FRIENDLY && self->target != NULL) { angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); - fixed_t dist = P_AproxDistance (self->x - self->target->x, self->y - self->target->y); + fixed_t dist = self->AproxDistance (self->target); P_AimLineAttack (self, angle, dist, &linetarget, 0, true); if (linetarget != NULL && linetarget != self->target) { @@ -450,7 +449,7 @@ bool P_Move (AActor *actor) if ((actor->flags6 & MF6_JUMPDOWN) && target && !(target->IsFriend(actor)) && - P_AproxDistance(actor->x - target->x, actor->y - target->y) < FRACUNIT*144 && + actor->AproxDistance(target) < FRACUNIT*144 && pr_dropoff() < 235) { dropoff = 2; @@ -933,7 +932,7 @@ void P_NewChaseDir(AActor * actor) if (actor->flags3 & MF3_AVOIDMELEE) { bool ismeleeattacker = false; - fixed_t dist = P_AproxDistance(actor->x-target->x, actor->y-target->y); + fixed_t dist = actor->AproxDistance(target); if (target->player == NULL) { ismeleeattacker = (target->MissileState == NULL && dist < (target->meleerange + target->radius)*2); @@ -1151,7 +1150,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams fov = allaround ? 0 : ANGLE_180; } - fixed_t dist = P_AproxDistance (other->x - lookee->x, other->y - lookee->y); + fixed_t dist = lookee->AproxDistance (other); if (maxdist && dist > maxdist) return false; // [KS] too far @@ -1202,8 +1201,7 @@ bool P_LookForMonsters (AActor *actor) { // Not a valid monster continue; } - if (P_AproxDistance (actor->x-mo->x, actor->y-mo->y) - > MONS_LOOK_RANGE) + if (mo->AproxDistance (actor) > MONS_LOOK_RANGE) { // Out of range continue; } @@ -1703,10 +1701,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) || player->mo->flags3 & MF3_GHOST) { - if ((P_AproxDistance (player->mo->x - actor->x, - player->mo->y - actor->y) > 2*MELEERANGE) - && P_AproxDistance (player->mo->velx, player->mo->vely) - < 5*FRACUNIT) + if ((player->mo->AproxDistance (actor) > 2*MELEERANGE) + && P_AproxDistance (player->mo->velx, player->mo->vely) < 5*FRACUNIT) { // Player is sneaking - can't detect continue; } @@ -1903,8 +1899,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) } else { - dist = P_AproxDistance (targ->x - self->x, - targ->y - self->y); + dist = self->AproxDistance (targ); // [KS] If the target is too far away, don't respond to the sound. if (maxheardist && dist > maxheardist) @@ -1975,8 +1970,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) { if (self->flags & MF_AMBUSH) { - dist = P_AproxDistance (self->target->x - self->x, - self->target->y - self->y); + dist = self->AproxDistance (self->target); if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING) && (!minseedist || dist > minseedist) && (!maxseedist || dist < maxseedist)) @@ -2390,7 +2384,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->FastChaseStrafeCount = 0; actor->velx = 0; actor->vely = 0; - fixed_t dist = P_AproxDistance (actor->x - actor->target->x, actor->y - actor->target->y); + fixed_t dist = actor->AproxDistance (actor->target); if (dist < CLASS_BOSS_STRAFE_RANGE) { if (pr_chase() < 100) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7aeb9d115..58b4d2c1a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1075,8 +1075,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) abs(thing->y - tm.thing->y) < (thing->radius+tm.thing->radius)) { - fixed_t newdist = P_AproxDistance(thing->x - tm.x, thing->y - tm.y); - fixed_t olddist = P_AproxDistance(thing->x - tm.thing->x, thing->y - tm.thing->y); + fixed_t newdist = thing->AproxDistance(tm.x, tm.y, tm.thing); + fixed_t olddist = thing->AproxDistance(tm.thing); if (newdist > olddist) { @@ -1754,7 +1754,7 @@ void P_FakeZMovement(AActor *mo) { // float down towards target if too close if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT)) { - fixed_t dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y); + fixed_t dist = mo->AproxDistance(mo->target); fixed_t delta = (mo->target->z + (mo->height >> 1)) - mo->z; if (delta < 0 && dist < -(delta * 3)) mo->z -= mo->FloatSpeed; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3d0d8e072..3eeb7c71a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1669,8 +1669,7 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool preci if (actor->z + actor->height < target->z || target->z + target->height < actor->z) { // Need to seek vertically - dist = P_AproxDistance (target->x - actor->x, target->y - actor->y); - dist = dist / speed; + dist = actor->AproxDistance (target) / speed; if (dist < 1) { dist = 1; @@ -2380,7 +2379,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { // float down towards target if too close if (!(mo->flags & (MF_SKULLFLY | MF_INFLOAT))) { - dist = P_AproxDistance (mo->x - mo->target->x, mo->y - mo->target->y); + dist = mo->AproxDistance (mo->target); delta = (mo->target->z + (mo->height>>1)) - mo->z; if (delta < 0 && dist < -(delta*3)) mo->z -= mo->FloatSpeed; @@ -3392,7 +3391,7 @@ void AActor::Tick () if (health > 0 && !players[i].Bot->enemy && player ? !IsTeammate (players[i].mo) : true - && P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST + && AproxDistance (players[i].mo) < MAX_MONSTER_TARGET_DIST && P_CheckSight (players[i].mo, this, SF_SEEPASTBLOCKEVERYTHING)) { //Probably a monster, so go kill it. players[i].Bot->enemy = this; @@ -5788,7 +5787,7 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); - dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = source->AproxDistance (dest); if (th->Speed) dist = dist / th->Speed; if (dist < 1) @@ -5849,7 +5848,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PCl { an += pr_spawnmissile.Random2() << 20; } - dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = source->AproxDistance (dest); speed = GetDefaultSpeed (type); dist /= speed; velz = dist != 0 ? (dest->z - source->z)/dist : speed; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 918d07ed2..b7bc9a7b0 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -2225,7 +2225,7 @@ void DPusher::Tick () { int sx = m_X; int sy = m_Y; - int dist = P_AproxDistance (thing->x - sx,thing->y - sy); + 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 diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 89299e0fa..864641b0d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -670,7 +670,7 @@ void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) // No target - no jump if (!target) return; - if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist && + if (self->AproxDistance(target) < dist && (noz || ((self->z > target->z && self->z - (target->z + target->height) < dist) || (self->z <= target->z && target->z - (self->z + self->height) < dist)))) @@ -3342,8 +3342,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (target) { - FVector2 xyvec(target->x - x1, target->y - y1); - fixed_t distance = P_AproxDistance((fixed_t)xyvec.Length(), target->z - z1); + fixed_t xydist = self->Distance2D(target); + fixed_t distance = P_AproxDistance(xydist, target->z - z1); if (range && !(flags & CLOFF_CHECKPARTIAL)) { @@ -3372,11 +3372,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) } else if (flags & CLOFF_AIM_VERT_NOOFFSET) { - pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + offsetheight + target->height / 2); + pitch += R_PointToAngle2 (0,0, xydist, target->z - z1 + offsetheight + target->height / 2); } else { - pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2); + pitch += R_PointToAngle2 (0,0, xydist, target->z - z1 + target->height / 2); } } else if (flags & CLOFF_ALLOWNULL) @@ -3546,8 +3546,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) return; - fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); - distance = P_AproxDistance(distance, target->z - self->z); + fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) return; @@ -3635,8 +3634,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) return; - fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); - distance = P_AproxDistance(distance, target->z - self->z); + fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) return; @@ -5950,7 +5948,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) continue; //Make sure it's in range and respect the desire for Z or not. - if (P_AproxDistance(ref->x - mo->x, ref->y - mo->y) < distance && + if (ref->AproxDistance(mo) < distance && ((flags & CPXF_NOZ) || ((ref->z > mo->z && ref->z - (mo->z + mo->height) < distance) || (ref->z <= mo->z && mo->z - (ref->z + ref->height) < distance)))) From 2c0f64cf9fa06834cb10522e7399b950de486e19 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 20:46:26 +0100 Subject: [PATCH 2/7] - refactoring of R_PointToAngle2 when used to calculate direction between two actors. --- src/actor.h | 22 ++++++++++++++++- src/b_func.cpp | 11 ++++----- src/b_move.cpp | 2 +- src/b_think.cpp | 8 +++---- src/fragglescript/t_func.cpp | 4 ++-- src/g_doom/a_doomweaps.cpp | 8 ++----- src/g_doom/a_revenant.cpp | 2 +- src/g_doom/a_scriptedmarine.cpp | 5 ++-- src/g_heretic/a_chicken.cpp | 6 ++--- src/g_heretic/a_hereticweaps.cpp | 12 ++++------ src/g_hexen/a_blastradius.cpp | 4 ++-- src/g_hexen/a_clericholy.cpp | 3 +-- src/g_hexen/a_clericstaff.cpp | 4 ++-- src/g_hexen/a_dragon.cpp | 12 ++++------ src/g_hexen/a_fighterplayer.cpp | 2 +- src/g_hexen/a_firedemon.cpp | 2 +- src/g_hexen/a_flies.cpp | 2 +- src/g_hexen/a_hexenspecialdecs.cpp | 3 +-- src/g_hexen/a_korax.cpp | 2 +- src/g_hexen/a_magelightning.cpp | 2 +- src/g_raven/a_minotaur.cpp | 2 +- src/g_shared/sbar_mugshot.cpp | 2 +- src/g_strife/a_strifeweapons.cpp | 5 +--- src/p_conversation.cpp | 2 +- src/p_enemy.cpp | 18 +++++--------- src/p_interaction.cpp | 2 +- src/p_map.cpp | 6 ++--- src/p_mobj.cpp | 11 ++++----- src/p_spec.cpp | 2 +- src/p_things.cpp | 3 ++- src/thingdef/thingdef_codeptr.cpp | 38 ++++++++---------------------- 31 files changed, 92 insertions(+), 115 deletions(-) diff --git a/src/actor.h b/src/actor.h index 0cd87ec52..114dd1179 100644 --- a/src/actor.h +++ b/src/actor.h @@ -612,7 +612,7 @@ extern FDropItemPtrArray DropItemList; void FreeDropItemChain(FDropItem *chain); int StoreDropItemChain(FDropItem *chain); fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_local here... - +angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); // same reason here with r_defs.h // Map Object definition. @@ -889,6 +889,26 @@ public: return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length()); } + angle_t AngleTo(AActor *other, bool absolute = false) const + { + return R_PointToAngle2(x, y, other->x, other->y); + } + + angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const + { + return R_PointToAngle2(x, y, other->x + oxofs, other->y + oyofs); + } + + fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL) + { + return R_PointToAngle2(x, y, otherx, othery); + } + + fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false) + { + return R_PointToAngle2(myx, myy, other->x, other->y); + } + inline void SetFriendPlayer(player_t *player); bool IsVisibleToPlayer() const; diff --git a/src/b_func.cpp b/src/b_func.cpp index 87b1e5416..9594d29d8 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -123,7 +123,7 @@ bool DBot::Check_LOS (AActor *to, angle_t vangle) if (vangle == 0) return false; //Looker seems to be blind. - return absangle(R_PointToAngle2 (player->mo->x, player->mo->y, to->x, to->y) - player->mo->angle) <= vangle/2; + return absangle(player->mo->AngleTo(to) - player->mo->angle) <= vangle/2; } //------------------------------------- @@ -220,14 +220,14 @@ shootmissile: dist = player->mo->AproxDistance (enemy); m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed; bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); - angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y); + angle = player->mo->AngleTo(bglobal.body1); if (Check_LOS (enemy, SHOOTFOV)) no_fire = false; } else { //Other weapons, mostly instant hit stuff. - angle = R_PointToAngle2 (player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); aiming_penalty = 0; if (enemy->flags & MF_SHADOW) aiming_penalty += (pr_botdofire()%25)+10; @@ -263,7 +263,6 @@ shootmissile: cmd->ucmd.buttons |= BT_ATTACK; } //Prevents bot from jerking, when firing automatic things with low skill. - //player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); } bool FCajunMaster::IsLeader (player_t *player) @@ -518,7 +517,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) { if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) { - ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y); + ang = actor->AngleTo(bglobal.body1); return ang; } } @@ -528,7 +527,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) { if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST) { - ang = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + ang = player->mo->AngleTo(enemy); return ang; } } diff --git a/src/b_move.cpp b/src/b_move.cpp index c608c5d03..5cacd5664 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -35,7 +35,7 @@ void DBot::Roam (ticcmd_t *cmd) if (Reachable(dest)) { // Straight towards it. - angle = R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y); + angle = player->mo->AngleTo(dest); } else if (player->mo->movedir < 8) // turn towards movement direction if not there yet { diff --git a/src/b_think.cpp b/src/b_think.cpp index 73c5066ab..ced5b4b4e 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -99,7 +99,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) if (missile && (player->mo->AproxDistance(missile)mo->x, player->mo->y, missile->x, missile->y); + angle = player->mo->AngleTo(missile); cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best. @@ -165,7 +165,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) sleft = !sleft; } - angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); if (player->ReadyWeapon == NULL || player->mo->AproxDistance(enemy) > @@ -206,7 +206,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) goto roam; } - angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y); + angle = player->mo->AngleTo(mate); matedist = player->mo->AproxDistance(mate); if (matedist > (FRIEND_DIST*2)) @@ -241,7 +241,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) (pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy. else //hide while t_fight, but keep view at enemy. - angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); } //Just a monster, so kill it. else dest = enemy; diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index fdf904764..ceabc9ce5 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -3145,8 +3145,8 @@ void FParser::SF_MoveCamera(void) } // set step variables based on distance and speed - mobjangle = R_PointToAngle2(cam->x, cam->y, target->x, target->y); - xydist = R_PointToDist2(target->x - cam->x, target->y - cam->y); + mobjangle = cam->AngleTo(target); + xydist = cam->Distance2D(target); xstep = FixedMul(finecosine[mobjangle >> ANGLETOFINESHIFT], movespeed); ystep = FixedMul(finesine[mobjangle >> ANGLETOFINESHIFT], movespeed); diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 899f1f7d5..79dd6253f 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -59,10 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) if (linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); } } @@ -218,8 +215,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) // turn to face target if (!(Flags & SF_NOTURN)) { - angle = R_PointToAngle2(self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90 / 20)) diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 90c6e0a51..06fdfa6aa 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -77,7 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) return; // change angle - exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y); + exact = self->AngleTo(dest); if (exact != self->angle) { diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index be39b545b..6e75d80e6 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -276,7 +276,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); // turn to face target - angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90/20)) @@ -326,7 +326,8 @@ static void MarinePunch(AActor *self, int damagemul) if (linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); + self->angle = self->AngleTo(linetarget); + } } diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index 082774a3d..f4ad4c211 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -178,8 +178,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { - player->mo->angle = R_PointToAngle2 (player->mo->x, - player->mo->y, linetarget->x, linetarget->y); + player->mo->angle = player->mo->AngleTo(linetarget); } P_PlayPeck (player->mo); player->chickenPeck = 12; @@ -211,8 +210,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { - player->mo->angle = R_PointToAngle2 (player->mo->x, - player->mo->y, linetarget->x, linetarget->y); + player->mo->angle = player->mo->AngleTo(linetarget); } P_PlayPeck (player->mo); player->chickenPeck = 12; diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index afc4f6007..711bbd960 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -90,8 +90,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) { //S_StartSound(player->mo, sfx_stfhit); // turn to face target - self->angle = R_PointToAngle2 (self->x, - self->y, linetarget->x, linetarget->y); + self->angle = self->AngleTo(linetarget); } } @@ -307,8 +306,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM); } // turn to face target - angle = R_PointToAngle2 (self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle-self->angle > ANG180) { if ((int)(angle-self->angle) < -ANG90/20) @@ -648,8 +646,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) } else { // Seek - angle = R_PointToAngle2(self->x, self->y, - target->x, target->y); + self->angle = self->AngleTo(target); newAngle = true; } } @@ -662,8 +659,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) if (linetarget && self->target != linetarget) { self->tracer = linetarget; - angle = R_PointToAngle2 (self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); newAngle = true; break; } diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index 53ce08b50..c7fb17fef 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -33,13 +33,13 @@ void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor * Owner return; } - angle = R_PointToAngle2 (Owner->x, Owner->y, victim->x, victim->y); + angle = Owner->AngleTo(victim); angle >>= ANGLETOFINESHIFT; victim->velx = FixedMul (speed, finecosine[angle]); victim->vely = FixedMul (speed, finesine[angle]); // Spawn blast puff - ang = R_PointToAngle2 (victim->x, victim->y, Owner->x, Owner->y); + ang = victim->AngleTo(Owner); ang >>= ANGLETOFINESHIFT; x = victim->x + FixedMul (victim->radius+FRACUNIT, finecosine[ang]); y = victim->y + FixedMul (victim->radius+FRACUNIT, finesine[ang]); diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 73ffeac88..39fee109d 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -262,8 +262,7 @@ static void CHolyTailFollow (AActor *actor, fixed_t dist) child = actor->tracer; if (child) { - an = R_PointToAngle2(actor->x, actor->y, child->x, - child->y)>>ANGLETOFINESHIFT; + an = actor->AngleTo(child) >> ANGLETOFINESHIFT; oldDistance = child->AproxDistance (actor); if (P_TryMove (child, actor->x+FixedMul(dist, finecosine[an]), actor->y+FixedMul(dist, finesine[an]), true)) diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index b397fc12b..eeda968fa 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -73,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); if (linetarget != NULL) { - pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + pmo->angle = pmo->AngleTo(linetarget); if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) && (!(linetarget->flags2&(MF2_DORMANT|MF2_INVULNERABLE)))) { @@ -103,7 +103,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); if (linetarget != NULL) { - pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + pmo->angle = pmo->AngleTo(linetarget); if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) { newLife = player->health+(damage>>4); diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index 5b18c0d57..d33e7b07b 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -73,8 +73,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { // attack the destination mobj if it's attackable AActor *oldTarget; - if (absangle(actor->angle-R_PointToAngle2(actor->x, actor->y, - target->x, target->y)) < ANGLE_45/2) + if (absangle(actor->angle - actor->AngleTo(target)) < ANGLE_45/2) { oldTarget = actor->target; actor->target = target; @@ -99,8 +98,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { AActor *bestActor = NULL; bestAngle = ANGLE_MAX; - angleToTarget = R_PointToAngle2(actor->x, actor->y, - actor->target->x, actor->target->y); + angleToTarget = actor->AngleTo(actor->target); for (i = 0; i < 5; i++) { if (!target->args[i]) @@ -113,8 +111,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { continue; } - angleToSpot = R_PointToAngle2(actor->x, actor->y, - mo->x, mo->y); + angleToSpot = actor->AngleTo(mo); if (absangle(angleToSpot-angleToTarget) < bestAngle) { bestAngle = absangle(angleToSpot-angleToTarget); @@ -190,8 +187,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) self->target = NULL; return; } - angle = R_PointToAngle2(self->x, self->y, self->target->x, - self->target->y); + angle = self->AngleTo(self->target); if (absangle(self->angle-angle) < ANGLE_45/2 && self->CheckMeleeRange()) { int damage = pr_dragonflight.HitDice (8); diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 5df183901..82cb8bd05 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -30,7 +30,7 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget) angle_t angle; int difference; - angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + angle = pmo->AngleTo(linetarget); difference = (int)angle - (int)pmo->angle; if (abs(difference) > MAX_ANGLE_ADJUST) { diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index b1cfafc0c..c003dc21d 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -163,7 +163,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { if (pr_firedemonchase() < 30) { - ang = R_PointToAngle2 (self->x, self->y, target->x, target->y); + ang = self->AngleTo(target); if (pr_firedemonchase() < 128) ang += ANGLE_90; else diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp index 3c677d5cb..683cbebe1 100644 --- a/src/g_hexen/a_flies.cpp +++ b/src/g_hexen/a_flies.cpp @@ -79,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) return; } - angle_t ang = R_PointToAngle2(self->x, self->y, targ->x, targ->y); + angle_t ang = self->AngleTo(targ); self->angle = ang; self->args[0]++; ang >>= ANGLETOFINESHIFT; diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 9d0c098fe..ad10a464c 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -109,8 +109,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) if (playeringame[i]) { AActor *pmo = players[i].mo; - if (P_CheckSight (self, pmo) && (absangle(R_PointToAngle2 (pmo->x, - pmo->y, self->x, self->y) - pmo->angle) <= ANGLE_45)) + if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self) - pmo->angle) <= ANGLE_45)) { // Previous state (pottery bit waiting state) self->SetState (self->state - 1); return; diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index ca849dd97..a941f1a65 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -485,7 +485,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, z -= source->floorclip; th = Spawn (type, x, y, z, ALLOW_REPLACE); th->target = source; // Originator - an = R_PointToAngle2(x, y, dest->x, dest->y); + an = source->AngleXYTo(x, y, dest); if (dest->flags & MF_SHADOW) { // Invisible target an += pr_kmissile.Random2()<<21; diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index 9953cf1d0..a13e3a274 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -190,7 +190,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) } else { - self->angle = R_PointToAngle2(self->x, self->y, target->x, target->y); + self->angle = self->AngleTo(target); self->velx = 0; self->vely = 0; P_ThrustMobj (self, self->angle, self->Speed>>1); diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index c0095226e..c2348a9e3 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -390,7 +390,7 @@ void P_MinotaurSlam (AActor *source, AActor *target) fixed_t thrust; int damage; - angle = R_PointToAngle2 (source->x, source->y, target->x, target->y); + angle = source->AngleTo(target); angle >>= ANGLETOFINESHIFT; thrust = 16*FRACUNIT+(pr_minotaurslam()<<10); target->velx += FixedMul (thrust, finecosine[angle]); diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index b8f419ef0..ea1c8528e 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -366,7 +366,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) if (player->mo != NULL) { // The next 12 lines are from the Doom statusbar code. - badguyangle = R_PointToAngle2(player->mo->x, player->mo->y, player->attacker->x, player->attacker->y); + badguyangle = player->mo->AngleTo(player->attacker); if (badguyangle > player->mo->angle) { // whether right or left diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index a41058492..f5d4a3576 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -118,10 +118,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) S_Sound (self, CHAN_WEAPON, linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); self->flags |= MF_JUSTATTACKED; P_DaggerAlert (self, linetarget); } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 85edc53ab..db5fd400c 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1117,7 +1117,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang if (facetalker) { A_FaceTarget (npc); - pc->angle = R_PointToAngle2 (pc->x, pc->y, npc->x, npc->y); + pc->angle = pc->AngleTo(npc); } if ((npc->flags & MF_FRIENDLY) || (npc->flags4 & MF4_NOHATEPLAYERS)) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 489fb107d..7b7e27b2e 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -392,7 +392,7 @@ bool P_HitFriend(AActor * self) if (self->flags&MF_FRIENDLY && self->target != NULL) { - angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); + 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) @@ -1160,7 +1160,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams if (fov && fov < ANGLE_MAX) { - angle_t an = R_PointToAngle2 (lookee->x, lookee->y, other->x, other->y) - lookee->angle; + angle_t an = lookee->AngleTo(other) - lookee->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -2389,7 +2389,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi { if (pr_chase() < 100) { - angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + angle_t ang = actor->AngleTo(actor->target); if (pr_chase() < 128) ang += ANGLE_90; else ang -= ANGLE_90; actor->velx = 13 * finecosine[ang>>ANGLETOFINESHIFT]; @@ -2743,7 +2743,7 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a self->flags &= ~MF_AMBUSH; - angle_t other_angle = R_PointToAngle2 (self->x, self->y, other->x, other->y); + angle_t other_angle = self->AngleTo(other); // 0 means no limit. Also, if we turn in a single step anyways, no need to go through the algorithms. // It also means that there is no need to check for going past the other. @@ -2916,10 +2916,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) self->flags &= ~MF_AMBUSH; - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x, - self->target->y); + self->angle = self->AngleTo(self->target); self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target); if (linetarget == NULL) @@ -2932,10 +2929,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) } // Let the aim trail behind the player - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3); if (self->target->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE)) { diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b2e27adc8..240a77378 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1164,7 +1164,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } else { - ang = R_PointToAngle2 (origin->x, origin->y, target->x, target->y); + ang = origin->AngleTo(target); } // Calculate this as float to avoid overflows so that the diff --git a/src/p_map.cpp b/src/p_map.cpp index 58b4d2c1a..3381f763f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3066,7 +3066,7 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) if (!ontop) { fixed_t speed; - angle_t angle = R_PointToAngle2(BlockingMobj->x,BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8); + angle_t angle = BlockingMobj->AngleTo(mo) + 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; @@ -4084,7 +4084,7 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile) pitch = 0; } P_TraceBleed(damage, target->x, target->y, target->z + target->height / 2, - target, R_PointToAngle2(missile->x, missile->y, target->x, target->y), + target, missile->AngleTo(target), pitch); } @@ -4853,7 +4853,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo { velz *= 0.8f; } - angle_t ang = R_PointToAngle2(bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; + angle_t ang = bombspot->AngleTo(thing) >> ANGLETOFINESHIFT; thing->velx += fixed_t(finecosine[ang] * thrust); thing->vely += fixed_t(finesine[ang] * thrust); if (!(flags & RADF_NODAMAGE)) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3eeb7c71a..750cc18fb 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1556,7 +1556,7 @@ int P_FaceMobj (AActor *source, AActor *target, angle_t *delta) angle_t angle2; angle1 = source->angle; - angle2 = R_PointToAngle2 (source->x, source->y, target->x, target->y); + angle2 = source->AngleTo(target); if (angle2 > angle1) { diff = angle2 - angle1; @@ -2019,7 +2019,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) // Don't change the angle if there's THRUREFLECT on the monster. if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) { - angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); + angle = BlockingMobj->AngleTo(mo); bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle)); // Change angle for deflection/reflection @@ -3088,8 +3088,7 @@ bool AActor::IsOkayToAttack (AActor *link) // to only allow the check to succeed if the enemy was in a ~84� FOV of the player if (flags3 & MF3_SCREENSEEKER) { - angle_t angle = R_PointToAngle2(Friend->x, - Friend->y, link->x, link->y) - Friend->angle; + angle_t angle = Friend->AngleTo(link) - Friend->angle; angle >>= 24; if (angle>226 || angle<30) { @@ -5035,7 +5034,7 @@ AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t puff->target = source; - if (source != NULL) puff->angle = R_PointToAngle2(x, y, source->x, source->y); + if (source != NULL) puff->angle = puff->AngleTo(source); // If a puff has a crash state and an actor was not hit, // it will enter the crash state. This is used by the StrifeSpark @@ -5782,7 +5781,7 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const P_PlaySpawnSound(th, source); th->target = owner; // record missile's originator - th->angle = an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); + th->angle = an = source->AngleTo(dest); an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index b7bc9a7b0..698cf4f72 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -2233,7 +2233,7 @@ void DPusher::Tick () if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY))) { - angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy); + angle_t pushangle = thing->AngleTo(sx, sy); if (m_Source->GetClass()->TypeName == NAME_PointPusher) pushangle += ANG180; // away pushangle >>= ANGLETOFINESHIFT; diff --git a/src/p_things.cpp b/src/p_things.cpp index 7e38a3c68..631f1be5e 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -304,7 +304,8 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam } else { -nolead: mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y); +nolead: + mobj->angle = mobj->AngleTo(targ); aim.Resize (fspeed); mobj->velx = fixed_t(aim[0]); mobj->vely = fixed_t(aim[1]); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 864641b0d..b6575ee19 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1487,10 +1487,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (!(flags & CPF_NOTURN)) { // turn to face target - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); } if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; @@ -1614,10 +1611,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (aim) { - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x, - self->target->y); + 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) @@ -1631,9 +1625,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) // Let the aim trail behind the player if (aim) { - saved_angle = self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + saved_angle = self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3); if (aim == CRF_AIMDIRECT) { @@ -1642,9 +1634,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) self->x += Spawnofs_XY * finecosine[self->angle]; self->y += Spawnofs_XY * finesine[self->angle]; Spawnofs_XY = 0; - self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + self->angle = self->AngleTo(self->target,- self->target->velx * 3, -self->target->vely * 3); } if (self->target->flags & MF_SHADOW) @@ -3357,7 +3347,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { ang = self->angle; } - else ang = R_PointToAngle2 (x1, y1, target->x, target->y); + else ang = self->AngleTo (target); angle += ang; @@ -3576,11 +3566,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (viewport->x, - viewport->y, - target->x, - target->y) - - viewport->angle; + an = viewport->AngleTo(target) - viewport->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -3654,11 +3640,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (target->x, - target->y, - self->x, - self->y) - - target->angle; + an = target->AngleTo(self) - target->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -4588,7 +4570,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) // Target can dodge if it can see enemy - angle_t angle = R_PointToAngle2(self->target->x, self->target->y, self->x, self->y) - self->target->angle; + angle_t angle = self->target->AngleTo(self) - self->target->angle; angle >>= 24; bool dodge = (P_CheckSight(self->target, self) && (angle>226 || angle<30)); @@ -4627,7 +4609,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) dx = self->target->x; dy = self->target->y; dz = self->target->z + (self->target->height>>1); - angle = R_PointToAngle2(dx, dy, self->x, self->y); + angle = self->target->AngleTo(self); dx += FixedMul(self->target->radius, finecosine[angle>>ANGLETOFINESHIFT]); dy += FixedMul(self->target->radius, finesine[angle>>ANGLETOFINESHIFT]); @@ -4662,7 +4644,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) if (spawnblood) { P_SpawnBlood(dx, dy, dz, angle, newdam > 0 ? newdam : damage, self->target); - P_TraceBleed(newdam > 0 ? newdam : damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0); + P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self->AngleTo(dx, dy, self->target), 0); } } } From 918a2ed56231ecd7662a6fb46baea3e559877d10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 22:26:08 +0100 Subject: [PATCH 3/7] -fixed: Eternity-style skyboxes must check if some portal copy definitions have been set for them. --- src/g_shared/a_skies.cpp | 55 +++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 54661ea14..1915a260a 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -37,6 +37,7 @@ #include "p_local.h" #include "p_lnspec.h" #include "farchive.h" +#include "r_sky.h" // arg0 = Visibility*4 for this skybox @@ -87,6 +88,24 @@ void ASkyViewpoint::Destroy () class ASkyCamCompat : public ASkyViewpoint { DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint) + + // skyboxify all tagged sectors + // This involves changing their texture to the sky flat, because while + // EE works with any texture for its skybox portals, ZDoom doesn't. + void SkyboxifySector(sector_t *sector, int plane) + { + // plane: 0=floor, 1=ceiling, 2=both + if (plane == 1 || plane == 2) + { + sector->CeilingSkyBox = this; + sector->SetTexture(sector_t::ceiling, skyflatnum, false); + } + if (plane == 0 || plane == 2) + { + sector->FloorSkyBox = this; + sector->SetTexture(sector_t::floor, skyflatnum, false); + } + } public: void BeginPlay (); }; @@ -116,23 +135,35 @@ void ASkyCamCompat::BeginPlay () // Then, change the alpha alpha = refline->args[4]; - // Finally, skyboxify all tagged sectors - // This involves changing their texture to the sky flat, because while - // EE works with any texture for its skybox portals, ZDoom doesn't. FSectorTagIterator it(skybox_id); int secnum; while ((secnum = it.Next()) >= 0) { - // plane: 0=floor, 1=ceiling, 2=both - if (refline->args[2] == 1 || refline->args[2] == 2) + SkyboxifySector(§ors[secnum], refline->args[2]); + } + // and finally, check for portal copy linedefs + for (int j=0;jargs[2] || lines[j].args[2] == 3) && + lines[j].args[3] == skybox_id) { - sectors[secnum].CeilingSkyBox = this; - sectors[secnum].SetTexture(sector_t::ceiling, skyflatnum, false); - } - if (refline->args[2] == 0 || refline->args[2] == 2) - { - sectors[secnum].FloorSkyBox = this; - sectors[secnum].SetTexture(sector_t::floor, skyflatnum, false); + if (lines[j].args[0] == 0) + { + SkyboxifySector(lines[j].frontsector, refline->args[2]); + } + else + { + FSectorTagIterator itr(lines[j].args[0]); + int s; + while ((s = itr.Next()) >= 0) + { + SkyboxifySector(§ors[s], refline->args[2]); + } + } } } } From 4f0046105dd615eb88b1eab9f97b03acb5104b1f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 21:09:16 -0600 Subject: [PATCH 4/7] Change texture atlas display to show allocated rectangles --- src/win32/fb_d3d9.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 1641df365..474183086 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1833,8 +1833,8 @@ void D3DFB::DrawPackedTextures(int packnum) { D3DCOLOR empty_colors[8] = { - 0xFFFF9999, 0xFF99FF99, 0xFF9999FF, 0xFFFFFF99, - 0xFFFF99FF, 0xFF99FFFF, 0xFFFFCC99, 0xFF99CCFF + 0x80FF0000, 0x8000FF00, 0x800000FF, 0x80FFFF00, + 0x80FF00FF, 0x8000FFFF, 0x80FF8000, 0x800080FF }; Atlas *pack; int x = 8, y = 8; @@ -1869,7 +1869,14 @@ void D3DFB::DrawPackedTextures(int packnum) } AddColorOnlyRect(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0)); - AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); + int back = 0; + for (PackedTexture *box = pack->UsedList; box != NULL; box = box->Next) + { + AddColorOnlyQuad(x + box->Area.left, y + box->Area.top, + box->Area.right - box->Area.left, box->Area.bottom - box->Area.top, empty_colors[back]); + back = (back + 1) & 7; + } +// AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); CheckQuadBatch(); From 670058fa3c1afb9afababec32afad204dbb7216f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 21:54:28 -0600 Subject: [PATCH 5/7] Switch to the bottom-left picker for the Skyline Bin Packer --- src/SkylineBinPack.cpp | 69 +++++++++++++++++++++++++++++++++++++++++- src/SkylineBinPack.h | 3 ++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp index 33f862043..4e9de153e 100644 --- a/src/SkylineBinPack.cpp +++ b/src/SkylineBinPack.cpp @@ -119,7 +119,7 @@ Rect SkylineBinPack::Insert(int width, int height) return newNode; } - return InsertMinWaste(width, height); + return InsertBottomLeft(width, height); } bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y) const @@ -254,6 +254,73 @@ void SkylineBinPack::MergeSkylines() } } +Rect SkylineBinPack::InsertBottomLeft(int width, int height) +{ + int bestHeight; + int bestWidth; + int bestIndex; + Rect newNode = FindPositionForNewNodeBottomLeft(width, height, bestHeight, bestWidth, bestIndex); + + if (bestIndex != -1) + { + assert(disjointRects.Disjoint(newNode)); + // Perform the actual packing. + AddSkylineLevel(bestIndex, newNode); + + usedSurfaceArea += width * height; +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + else + memset(&newNode, 0, sizeof(Rect)); + + return newNode; +} + +Rect SkylineBinPack::FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const +{ + bestHeight = INT_MAX; + bestIndex = -1; + // Used to break ties if there are nodes at the same level. Then pick the narrowest one. + bestWidth = INT_MAX; + Rect newNode = { 0, 0, 0, 0 }; + for(unsigned i = 0; i < skyLine.Size(); ++i) + { + int y; + if (RectangleFits(i, width, height, y)) + { + if (y + height < bestHeight || (y + height == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + height; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = width; + newNode.height = height; + assert(disjointRects.Disjoint(newNode)); + } + } +/* if (RectangleFits(i, height, width, y)) + { + if (y + width < bestHeight || (y + width == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + width; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = height; + newNode.height = width; + assert(disjointRects.Disjoint(newNode)); + } + } +*/ } + + return newNode; +} + Rect SkylineBinPack::InsertMinWaste(int width, int height) { int bestHeight; diff --git a/src/SkylineBinPack.h b/src/SkylineBinPack.h index f93ddd29d..937c88de6 100644 --- a/src/SkylineBinPack.h +++ b/src/SkylineBinPack.h @@ -72,7 +72,10 @@ private: bool useWasteMap; GuillotineBinPack wasteMap; + Rect InsertBottomLeft(int width, int height); Rect InsertMinWaste(int width, int height); + + Rect FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const; Rect FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const; bool RectangleFits(int skylineNodeIndex, int width, int height, int &y) const; From aaac5ac7a122d7d0cae223964b0624ae3af3c02e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 22:01:29 -0600 Subject: [PATCH 6/7] Use not so brilliant backgrounds for allocated atlas backgrounds --- src/win32/fb_d3d9.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 474183086..bfb618b51 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1833,8 +1833,8 @@ void D3DFB::DrawPackedTextures(int packnum) { D3DCOLOR empty_colors[8] = { - 0x80FF0000, 0x8000FF00, 0x800000FF, 0x80FFFF00, - 0x80FF00FF, 0x8000FFFF, 0x80FF8000, 0x800080FF + 0x50FF0000, 0x5000FF00, 0x500000FF, 0x50FFFF00, + 0x50FF00FF, 0x5000FFFF, 0x50FF8000, 0x500080FF }; Atlas *pack; int x = 8, y = 8; From 42e9a6a711816bb2fce51166220cb7d8bc19f063 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 22:14:35 -0600 Subject: [PATCH 7/7] Make atlas size a macro definition and default it to 512x512 (was 256x256) --- src/win32/fb_d3d9.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index bfb618b51..4e3a14c18 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -85,6 +85,10 @@ // The number of quads we can batch together. #define MAX_QUAD_BATCH (NUM_INDEXES / 6) +// The default size for a texture atlas. +#define DEF_ATLAS_WIDTH 512 +#define DEF_ATLAS_HEIGHT 512 + // TYPES ------------------------------------------------------------------- IMPLEMENT_CLASS(D3DFB) @@ -1872,8 +1876,11 @@ void D3DFB::DrawPackedTextures(int packnum) int back = 0; for (PackedTexture *box = pack->UsedList; box != NULL; box = box->Next) { - AddColorOnlyQuad(x + box->Area.left, y + box->Area.top, - box->Area.right - box->Area.left, box->Area.bottom - box->Area.top, empty_colors[back]); + AddColorOnlyQuad( + x + box->Area.left * 256 / pack->Width, + y + box->Area.top * 256 / pack->Height, + (box->Area.right - box->Area.left) * 256 / pack->Width, + (box->Area.bottom - box->Area.top) * 256 / pack->Height, empty_colors[back]); back = (back + 1) & 7; } // AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); @@ -1980,8 +1987,8 @@ D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3D Rect box; bool padded; - // check for 254 to account for padding - if (w > 254 || h > 254 || wrapping) + // The - 2 to account for padding + if (w > 256 - 2 || h > 256 - 2 || wrapping) { // Create a new texture atlas. pack = new Atlas(this, w, h, format); pack->OneUse = true; @@ -2006,7 +2013,7 @@ D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3D } if (pack == NULL) { // Create a new texture atlas. - pack = new Atlas(this, 256, 256, format); + pack = new Atlas(this, DEF_ATLAS_WIDTH, DEF_ATLAS_HEIGHT, format); box = pack->Packer.Insert(w, h); } padded = true;