Exemplo n.º 1
0
        public void VileChase(Mobj actor)
        {
            if (actor.MoveDir != Direction.None)
            {
                // Check for corpses to raise.
                vileTryX = actor.X + actor.Info.Speed * xSpeed[(int)actor.MoveDir];
                vileTryY = actor.Y + actor.Info.Speed * ySpeed[(int)actor.MoveDir];

                var bm = world.Map.BlockMap;

                var maxRadius = GameConstants.MaxThingRadius * 2;
                var blockX1   = bm.GetBlockX(vileTryX - maxRadius);
                var blockX2   = bm.GetBlockX(vileTryX + maxRadius);
                var blockY1   = bm.GetBlockY(vileTryY - maxRadius);
                var blockY2   = bm.GetBlockY(vileTryY + maxRadius);

                for (var bx = blockX1; bx <= blockX2; bx++)
                {
                    for (var by = blockY1; by <= blockY2; by++)
                    {
                        // Call VileCheck to check whether object is a corpse that canbe raised.
                        if (!bm.IterateThings(bx, by, vileCheckFunc))
                        {
                            // Got one!
                            var temp = actor.Target;
                            actor.Target = vileTargetCorpse;
                            FaceTarget(actor);
                            actor.Target = temp;
                            actor.SetState(MobjState.VileHeal1);

                            world.StartSound(vileTargetCorpse, Sfx.SLOP);

                            var info = vileTargetCorpse.Info;
                            vileTargetCorpse.SetState(info.Raisestate);
                            vileTargetCorpse.Height <<= 2;
                            vileTargetCorpse.Flags    = info.Flags;
                            vileTargetCorpse.Health   = info.SpawnHealth;
                            vileTargetCorpse.Target   = null;

                            return;
                        }
                    }
                }
            }

            // Return to normal attack.
            Chase(actor);
        }
Exemplo n.º 2
0
        public void CPosRefire(Mobj actor)
        {
            // Keep firing unless target got out of sight.
            FaceTarget(actor);

            if (world.Random.Next() < 40)
            {
                return;
            }

            if (actor.Target == null ||
                actor.Target.Health <= 0 ||
                !world.VisibilityCheck.CheckSight(actor, actor.Target))
            {
                actor.SetState(actor.Info.SeeState);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Called when the missile hits something (wall or thing).
        /// </summary>
        public void ExplodeMissile(Mobj thing)
        {
            thing.MomX = thing.MomY = thing.MomZ = Fixed.Zero;

            thing.SetState(DoomInfo.MobjInfos[(int)thing.Type].DeathState);

            thing.Tics -= world.Random.Next() & 3;

            if (thing.Tics < 1)
            {
                thing.Tics = 1;
            }

            thing.Flags &= ~MobjFlags.Missile;

            if (thing.Info.DeathSound != 0)
            {
                world.StartSound(thing, thing.Info.DeathSound, SfxType.Misc);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Called when the target is killed.
        /// </summary>
        public void KillMobj(Mobj source, Mobj target)
        {
            target.Flags &= ~(MobjFlags.Shootable | MobjFlags.Float | MobjFlags.SkullFly);

            if (target.Type != MobjType.Skull)
            {
                target.Flags &= ~MobjFlags.NoGravity;
            }

            target.Flags |= MobjFlags.Corpse | MobjFlags.DropOff;
            target.Height = new Fixed(target.Height.Data >> 2);

            if (source != null && source.Player != null)
            {
                // Count for intermission.
                if ((target.Flags & MobjFlags.CountKill) != 0)
                {
                    source.Player.KillCount++;
                }

                if (target.Player != null)
                {
                    source.Player.Frags[target.Player.Number]++;
                }
            }
            else if (!world.Options.NetGame && (target.Flags & MobjFlags.CountKill) != 0)
            {
                // Count all monster deaths, even those caused by other monsters.
                world.Options.Players[0].KillCount++;
            }

            if (target.Player != null)
            {
                // Count environment kills against you.
                if (source == null)
                {
                    target.Player.Frags[target.Player.Number]++;
                }

                target.Flags &= ~MobjFlags.Solid;
                target.Player.PlayerState = PlayerState.Dead;
                world.PlayerBehavior.DropWeapon(target.Player);

                var am = world.AutoMap;

                if (target.Player.Number == world.Options.ConsolePlayer && am.Visible)
                {
                    // Don't die in auto map, switch view prior to dying.
                    am.Close();
                }
            }

            if (target.Health < -target.Info.SpawnHealth && target.Info.XdeathState != 0)
            {
                target.SetState(target.Info.XdeathState);
            }
            else
            {
                target.SetState(target.Info.DeathState);
            }

            target.Tics -= world.Random.Next() & 3;
            if (target.Tics < 1)
            {
                target.Tics = 1;
            }

            // Drop stuff.
            // This determines the kind of object spawned during the death frame of a thing.
            MobjType item;

            switch (target.Type)
            {
            case MobjType.Wolfss:
            case MobjType.Possessed:
                item = MobjType.Clip;
                break;

            case MobjType.Shotguy:
                item = MobjType.Shotgun;
                break;

            case MobjType.Chainguy:
                item = MobjType.Chaingun;
                break;

            default:
                return;
            }

            var mo = world.ThingAllocation.SpawnMobj(target.X, target.Y, Mobj.OnFloorZ, item);

            // Special versions of items.
            mo.Flags |= MobjFlags.Dropped;
        }
Exemplo n.º 5
0
        /// <summary>
        /// Damages both enemies and players.
        /// "inflictor" is the thing that caused the damage creature
        /// or missile, can be null (slime, etc).
        /// "source" is the thing to target after taking damage creature
        /// or null.
        /// Source and inflictor are the same for melee attacks.
        /// Source can be null for slime, barrel explosions and other
        /// environmental stuff.
        /// </summary>
        public void DamageMobj(Mobj target, Mobj inflictor, Mobj source, int damage)
        {
            if ((target.Flags & MobjFlags.Shootable) == 0)
            {
                // Shouldn't happen...
                return;
            }

            if (target.Health <= 0)
            {
                return;
            }

            if ((target.Flags & MobjFlags.SkullFly) != 0)
            {
                target.MomX = target.MomY = target.MomZ = Fixed.Zero;
            }

            var player = target.Player;

            if (player != null && world.Options.Skill == GameSkill.Baby)
            {
                // Take half damage in trainer mode.
                damage >>= 1;
            }

            // Some close combat weapons should not inflict thrust and
            // push the victim out of reach, thus kick away unless using the chainsaw.
            var notChainsawAttack =
                source == null ||
                source.Player == null ||
                source.Player.ReadyWeapon != WeaponType.Chainsaw;

            if (inflictor != null && (target.Flags & MobjFlags.NoClip) == 0 && notChainsawAttack)
            {
                var ang = Geometry.PointToAngle(
                    inflictor.X,
                    inflictor.Y,
                    target.X,
                    target.Y);

                var thrust = new Fixed(damage * (Fixed.FracUnit >> 3) * 100 / target.Info.Mass);

                // Make fall forwards sometimes.
                if (damage < 40 &&
                    damage > target.Health &&
                    target.Z - inflictor.Z > Fixed.FromInt(64) &&
                    (world.Random.Next() & 1) != 0)
                {
                    ang    += Angle.Ang180;
                    thrust *= 4;
                }

                target.MomX += thrust * Trig.Cos(ang);
                target.MomY += thrust * Trig.Sin(ang);
            }

            // Player specific.
            if (player != null)
            {
                // End of game hell hack.
                if (target.Subsector.Sector.Special == (SectorSpecial)11 && damage >= target.Health)
                {
                    damage = target.Health - 1;
                }

                // Below certain threshold, ignore damage in GOD mode, or with INVUL power.
                if (damage < 1000 && ((player.Cheats & CheatFlags.GodMode) != 0 ||
                                      player.Powers[(int)PowerType.Invulnerability] > 0))
                {
                    return;
                }

                int saved;

                if (player.ArmorType != 0)
                {
                    if (player.ArmorType == 1)
                    {
                        saved = damage / 3;
                    }
                    else
                    {
                        saved = damage / 2;
                    }

                    if (player.ArmorPoints <= saved)
                    {
                        // Armor is used up.
                        saved            = player.ArmorPoints;
                        player.ArmorType = 0;
                    }

                    player.ArmorPoints -= saved;
                    damage             -= saved;
                }

                // Mirror mobj health here for Dave.
                player.Health -= damage;
                if (player.Health < 0)
                {
                    player.Health = 0;
                }

                player.Attacker = source;

                // Add damage after armor / invuln.
                player.DamageCount += damage;

                if (player.DamageCount > 100)
                {
                    // Teleport stomp does 10k points...
                    player.DamageCount = 100;
                }
            }

            // Do the damage.
            target.Health -= damage;
            if (target.Health <= 0)
            {
                KillMobj(source, target);
                return;
            }

            if ((world.Random.Next() < target.Info.PainChance) &&
                (target.Flags & MobjFlags.SkullFly) == 0)
            {
                // Fight back!
                target.Flags |= MobjFlags.JustHit;

                target.SetState(target.Info.PainState);
            }

            // We're awake now...
            target.ReactionTime = 0;

            if ((target.Threshold == 0 || target.Type == MobjType.Vile) &&
                source != null &&
                source != target &&
                source.Type != MobjType.Vile)
            {
                // If not intent on another player, chase after this one.
                target.Target    = source;
                target.Threshold = baseThreshold;
                if (target.State == DoomInfo.States[(int)target.Info.SpawnState] &&
                    target.Info.SeeState != MobjState.Null)
                {
                    target.SetState(target.Info.SeeState);
                }
            }
        }
Exemplo n.º 6
0
        public void XYMovement(Mobj thing)
        {
            if (thing.MomX == Fixed.Zero && thing.MomY == Fixed.Zero)
            {
                if ((thing.Flags & MobjFlags.SkullFly) != 0)
                {
                    // The skull slammed into something.
                    thing.Flags &= ~MobjFlags.SkullFly;
                    thing.MomX   = thing.MomY = thing.MomZ = Fixed.Zero;

                    thing.SetState(thing.Info.SpawnState);
                }

                return;
            }

            var player = thing.Player;

            if (thing.MomX > maxMove)
            {
                thing.MomX = maxMove;
            }
            else if (thing.MomX < -maxMove)
            {
                thing.MomX = -maxMove;
            }

            if (thing.MomY > maxMove)
            {
                thing.MomY = maxMove;
            }
            else if (thing.MomY < -maxMove)
            {
                thing.MomY = -maxMove;
            }

            var moveX = thing.MomX;
            var moveY = thing.MomY;

            do
            {
                Fixed pMoveX;
                Fixed pMoveY;

                if (moveX > maxMove / 2 || moveY > maxMove / 2)
                {
                    pMoveX  = thing.X + moveX / 2;
                    pMoveY  = thing.Y + moveY / 2;
                    moveX >>= 1;
                    moveY >>= 1;
                }
                else
                {
                    pMoveX = thing.X + moveX;
                    pMoveY = thing.Y + moveY;
                    moveX  = moveY = Fixed.Zero;
                }

                if (!TryMove(thing, pMoveX, pMoveY))
                {
                    // Blocked move.
                    if (thing.Player != null)
                    {   // Try to slide along it.
                        SlideMove(thing);
                    }
                    else if ((thing.Flags & MobjFlags.Missile) != 0)
                    {
                        // Explode a missile.
                        if (currentCeilingLine != null &&
                            currentCeilingLine.BackSector != null &&
                            currentCeilingLine.BackSector.CeilingFlat == world.Map.SkyFlatNumber)
                        {
                            // Hack to prevent missiles exploding against the sky.
                            // Does not handle sky floors.
                            world.ThingAllocation.RemoveMobj(thing);
                            return;
                        }
                        world.ThingInteraction.ExplodeMissile(thing);
                    }
                    else
                    {
                        thing.MomX = thing.MomY = Fixed.Zero;
                    }
                }
            }while (moveX != Fixed.Zero || moveY != Fixed.Zero);

            // Slow down.
            if (player != null && (player.Cheats & CheatFlags.NoMomentum) != 0)
            {
                // Debug option for no sliding at all.
                thing.MomX = thing.MomY = Fixed.Zero;
                return;
            }

            if ((thing.Flags & (MobjFlags.Missile | MobjFlags.SkullFly)) != 0)
            {
                // No friction for missiles ever.
                return;
            }

            if (thing.Z > thing.FloorZ)
            {
                // No friction when airborne.
                return;
            }

            if ((thing.Flags & MobjFlags.Corpse) != 0)
            {
                // Do not stop sliding if halfway off a step with some momentum.
                if (thing.MomX > Fixed.One / 4 ||
                    thing.MomX < -Fixed.One / 4 ||
                    thing.MomY > Fixed.One / 4 ||
                    thing.MomY < -Fixed.One / 4)
                {
                    if (thing.FloorZ != thing.Subsector.Sector.FloorHeight)
                    {
                        return;
                    }
                }
            }

            if (thing.MomX > -stopSpeed &&
                thing.MomX < stopSpeed &&
                thing.MomY > -stopSpeed &&
                thing.MomY < stopSpeed &&
                (player == null || (player.Cmd.ForwardMove == 0 && player.Cmd.SideMove == 0)))
            {
                // If in a walking frame, stop moving.
                if (player != null && (player.Mobj.State.Number - (int)MobjState.PlayRun1) < 4)
                {
                    player.Mobj.SetState(MobjState.Play);
                }

                thing.MomX = Fixed.Zero;
                thing.MomY = Fixed.Zero;
            }
            else
            {
                thing.MomX = thing.MomX * friction;
                thing.MomY = thing.MomY * friction;
            }
        }
Exemplo n.º 7
0
        private bool CheckThing(Mobj thing)
        {
            if ((thing.Flags & (MobjFlags.Solid | MobjFlags.Special | MobjFlags.Shootable)) == 0)
            {
                return(true);
            }

            var blockDist = thing.Radius + currentThing.Radius;

            if (Fixed.Abs(thing.X - currentX) >= blockDist ||
                Fixed.Abs(thing.Y - currentY) >= blockDist)
            {
                // Didn't hit it.
                return(true);
            }

            // Don't clip against self.
            if (thing == currentThing)
            {
                return(true);
            }

            // Check for skulls slamming into things.
            if ((currentThing.Flags & MobjFlags.SkullFly) != 0)
            {
                var damage = ((world.Random.Next() % 8) + 1) * currentThing.Info.Damage;

                world.ThingInteraction.DamageMobj(thing, currentThing, currentThing, damage);

                currentThing.Flags &= ~MobjFlags.SkullFly;
                currentThing.MomX   = currentThing.MomY = currentThing.MomZ = Fixed.Zero;

                currentThing.SetState(currentThing.Info.SpawnState);

                // Stop moving.
                return(false);
            }

            // Missiles can hit other things.
            if ((currentThing.Flags & MobjFlags.Missile) != 0)
            {
                // See if it went over / under.
                if (currentThing.Z > thing.Z + thing.Height)
                {
                    // Overhead.
                    return(true);
                }

                if (currentThing.Z + currentThing.Height < thing.Z)
                {
                    // Underneath.
                    return(true);
                }

                if (currentThing.Target != null &&
                    (currentThing.Target.Type == thing.Type
                     //(||
                     //(currentThing.Target.Type == MobjType.Knight && thing.Type == MobjType.Bruiser) ||
                     //(currentThing.Target.Type == MobjType.Bruiser && thing.Type == MobjType.Knight))
                    ))
                {
                    // Don't hit same species as originator.
                    if (thing == currentThing.Target)
                    {
                        return(true);
                    }

                    if (thing.Type != MobjType.Player && !DoomInfo.DeHackEdConst.MonstersInfight)
                    {
                        // Explode, but do no damage.
                        // Let players missile other players.
                        return(false);
                    }
                }

                if ((thing.Flags & MobjFlags.Shootable) == 0)
                {
                    // Didn't do any damage.
                    return((thing.Flags & MobjFlags.Solid) == 0);
                }

                // Damage / explode.
                var damage = ((world.Random.Next() % 8) + 1) * currentThing.Info.Damage;
                world.ThingInteraction.DamageMobj(thing, currentThing, currentThing.Target, damage);

                // Don't traverse any more.
                return(false);
            }

            // Check for special pickup.
            if ((thing.Flags & MobjFlags.Special) != 0)
            {
                var solid = (thing.Flags & MobjFlags.Solid) != 0;
                if ((currentFlags & MobjFlags.PickUp) != 0)
                {
                    // Can remove thing.
                    world.ItemPickup.TouchSpecialThing(thing, currentThing);
                }
                return(!solid);
            }

            return((thing.Flags & MobjFlags.Solid) == 0);
        }
Exemplo n.º 8
0
        public void Look(Mobj actor)
        {
            // Any shot will wake up.
            actor.Threshold = 0;

            var target = actor.Subsector.Sector.SoundTarget;

            if (target != null && (target.Flags & MobjFlags.Shootable) != 0)
            {
                actor.Target = target;

                if ((actor.Flags & MobjFlags.Ambush) != 0)
                {
                    if (world.VisibilityCheck.CheckSight(actor, actor.Target))
                    {
                        goto seeYou;
                    }
                }
                else
                {
                    goto seeYou;
                }
            }

            if (!LookForPlayers(actor, false))
            {
                return;
            }

            // Go into chase state.
seeYou:
            if (actor.Info.SeeSound != 0)
            {
                int sound;

                switch (actor.Info.SeeSound)
                {
                case Sfx.POSIT1:
                case Sfx.POSIT2:
                case Sfx.POSIT3:
                    sound = (int)Sfx.POSIT1 + world.Random.Next() % 3;
                    break;

                case Sfx.BGSIT1:
                case Sfx.BGSIT2:
                    sound = (int)Sfx.BGSIT1 + world.Random.Next() % 2;
                    break;

                default:
                    sound = (int)actor.Info.SeeSound;
                    break;
                }

                if (actor.Type == MobjType.Spider || actor.Type == MobjType.Cyborg)
                {
                    // Full volume for boss monsters.
                    world.StartSound(null, (Sfx)sound);
                }
                else
                {
                    world.StartSound(actor, (Sfx)sound);
                }
            }

            actor.SetState(actor.Info.SeeState);
        }
Exemplo n.º 9
0
        public void Chase(Mobj actor)
        {
            if (actor.ReactionTime > 0)
            {
                actor.ReactionTime--;
            }

            // Modify target threshold.
            if (actor.Threshold > 0)
            {
                if (actor.Target == null || actor.Target.Health <= 0)
                {
                    actor.Threshold = 0;
                }
                else
                {
                    actor.Threshold--;
                }
            }

            // Turn towards movement direction if not there yet.
            if ((int)actor.MoveDir < 8)
            {
                actor.Angle = new Angle((int)actor.Angle.Data & (7 << 29));

                var delta = (int)(actor.Angle - new Angle((int)actor.MoveDir << 29)).Data;

                if (delta > 0)
                {
                    actor.Angle -= new Angle(Angle.Ang90.Data / 2);
                }
                else if (delta < 0)
                {
                    actor.Angle += new Angle(Angle.Ang90.Data / 2);
                }
            }

            if (actor.Target == null || (actor.Target.Flags & MobjFlags.Shootable) == 0)
            {
                // Look for a new target.
                if (LookForPlayers(actor, true))
                {
                    // Got a new target.
                    return;
                }

                actor.SetState(actor.Info.SpawnState);

                return;
            }

            // Do not attack twice in a row.
            if ((actor.Flags & MobjFlags.JustAttacked) != 0)
            {
                actor.Flags &= ~MobjFlags.JustAttacked;

                if (world.Options.Skill != GameSkill.Nightmare &&
                    !world.Options.FastMonsters)
                {
                    NewChaseDir(actor);
                }

                return;
            }

            // Check for melee attack.
            if (actor.Info.MeleeState != 0 && CheckMeleeRange(actor))
            {
                if (actor.Info.AttackSound != 0)
                {
                    world.StartSound(actor, actor.Info.AttackSound);
                }

                actor.SetState(actor.Info.MeleeState);

                return;
            }

            // Check for missile attack.
            if (actor.Info.MissileState != 0)
            {
                if (world.Options.Skill < GameSkill.Nightmare &&
                    !world.Options.FastMonsters &&
                    actor.MoveCount != 0)
                {
                    goto noMissile;
                }

                if (!CheckMissileRange(actor))
                {
                    goto noMissile;
                }

                actor.SetState(actor.Info.MissileState);
                actor.Flags |= MobjFlags.JustAttacked;

                return;
            }

noMissile:
            // Possibly choose another target.
            if (world.Options.NetGame &&
                actor.Threshold == 0 &&
                !world.VisibilityCheck.CheckSight(actor, actor.Target))
            {
                if (LookForPlayers(actor, true))
                {
                    // Got a new target.
                    return;
                }
            }

            // Chase towards player.
            if (--actor.MoveCount < 0 || !Move(actor))
            {
                NewChaseDir(actor);
            }

            // Make active sound.
            if (actor.Info.ActiveSound != 0 && world.Random.Next() < 3)
            {
                world.StartSound(actor, actor.Info.ActiveSound);
            }
        }