212 lines
9.4 KiB
C#
212 lines
9.4 KiB
C#
using System;
|
|
using Decimation.Content.Tiles.ShrineoftheMoltenOne;
|
|
using Microsoft.Xna.Framework;
|
|
using Terraria;
|
|
using Terraria.ID;
|
|
using Terraria.ModLoader;
|
|
|
|
namespace Decimation.Content.NPCs
|
|
{
|
|
// Check line 43861 of NPC.cs
|
|
internal class CoreSpider : ModNPC
|
|
{
|
|
private const int AnimationFps = 10;
|
|
private const int AnimationFrameCount = 8;
|
|
private readonly int shootFrame = 120;
|
|
private int _frame;
|
|
|
|
private int Direction
|
|
{
|
|
get => (int) npc.ai[0];
|
|
set => npc.ai[0] = value;
|
|
}
|
|
|
|
public override void SetStaticDefaults()
|
|
{
|
|
DisplayName.SetDefault("Core Spider");
|
|
Main.npcFrameCount[npc.type] = AnimationFrameCount;
|
|
}
|
|
|
|
public override void SetDefaults()
|
|
{
|
|
npc.width = 72;
|
|
npc.height = 26;
|
|
npc.aiStyle = -1;
|
|
npc.damage = 130;
|
|
npc.lifeMax = 750;
|
|
npc.knockBackResist = 0.25f;
|
|
npc.lavaImmune = true;
|
|
npc.buffImmune[20] = true;
|
|
npc.buffImmune[31] = false;
|
|
npc.buffImmune[BuffID.OnFire] = true;
|
|
npc.buffImmune[BuffID.Burning] = true;
|
|
npc.timeLeft = NPC.activeTime * 2;
|
|
}
|
|
|
|
public override void FindFrame(int frameHeight)
|
|
{
|
|
if (++npc.frameCounter >= 60f / AnimationFps)
|
|
{
|
|
npc.frameCounter = 0;
|
|
|
|
npc.frame.Y += frameHeight;
|
|
if (npc.frame.Y / frameHeight >= AnimationFrameCount) npc.frame.Y = 0;
|
|
}
|
|
}
|
|
|
|
public override void AI()
|
|
{
|
|
if (npc.target >= 255) npc.TargetClosest();
|
|
Player target = Main.player[npc.target];
|
|
if (npc.Distance(target.position) > 480) npc.target = 255;
|
|
if (Math.Abs(target.position.Y - npc.position.Y) > 80) npc.target = 255;
|
|
if (!Collision.CanHitLine(npc.position, npc.width, npc.height, target.position, target.width, target.height)) npc.target = 255;
|
|
bool hasTarget = npc.target < 255 && target.active && !target.dead;
|
|
|
|
// Walking
|
|
if (hasTarget) Direction = target.position.X - npc.position.X > 0 ? 1 : -1;
|
|
npc.velocity.X = 2 * Direction;
|
|
|
|
Vector2 position = npc.position;
|
|
position.X += npc.velocity.X;
|
|
int frontTileX = (int) (position.X + npc.width / 2f + (npc.width / 2f + 1f) * Direction) / 16;
|
|
int frontTileY = (int) (position.Y + npc.height - 1) / 16;
|
|
Tile frontTile = Main.tile[frontTileX, frontTileY];
|
|
Tile frontTileY1 = Main.tile[frontTileX, frontTileY - 1];
|
|
Tile frontTileY2 = Main.tile[frontTileX, frontTileY - 2];
|
|
Tile frontTileY3 = Main.tile[frontTileX, frontTileY - 3];
|
|
Tile frontTileY4 = Main.tile[frontTileX, frontTileY - 4];
|
|
Tile topTileY3 = Main.tile[frontTileX - Direction, frontTileY - 3];
|
|
Tile bottomTile = Main.tile[frontTileX - Direction, frontTileY + 1];
|
|
Tile frontTileX1 = Main.tile[frontTileX + Direction, frontTileY];
|
|
Tile frontTileX1Y1 = Main.tile[frontTileX + Direction, frontTileY - 1];
|
|
|
|
if (frontTile == null) frontTile = new Tile();
|
|
if (frontTileY1 == null) frontTileY1 = new Tile();
|
|
if (frontTileY2 == null) frontTileY2 = new Tile();
|
|
if (frontTileY3 == null) frontTileY3 = new Tile();
|
|
if (frontTileY4 == null) frontTileY4 = new Tile();
|
|
if (topTileY3 == null) topTileY3 = new Tile();
|
|
if (bottomTile == null) bottomTile = new Tile();
|
|
if (frontTileX1 == null) frontTileX1 = new Tile();
|
|
if (frontTileX1Y1 == null) frontTileX1Y1 = new Tile();
|
|
|
|
if (frontTileX * 16 < position.X + npc.width && frontTileX * 16 + 16 > position.X &&
|
|
(frontTile.nactive() && !frontTile.topSlope() && !frontTileY1.topSlope() &&
|
|
Main.tileSolid[frontTile.type] && !Main.tileSolidTop[frontTile.type] ||
|
|
frontTileY1.halfBrick() && frontTileY1.nactive()) &&
|
|
(!frontTileY1.nactive() || !Main.tileSolid[frontTileY1.type] || Main.tileSolidTop[frontTileY1.type] ||
|
|
frontTileY1.halfBrick() && (!frontTileY4.nactive() || !Main.tileSolid[frontTileY4.type] ||
|
|
Main.tileSolidTop[frontTileY4.type])) &&
|
|
(!frontTileY2.nactive() || !Main.tileSolid[frontTileY2.type] || Main.tileSolidTop[frontTileY2.type]) &&
|
|
(!frontTileY3.nactive() || !Main.tileSolid[frontTileY3.type] || Main.tileSolidTop[frontTileY3.type]) &&
|
|
(!topTileY3.nactive() || !Main.tileSolid[topTileY3.type]))
|
|
{
|
|
float newYPosition = frontTileY * 16;
|
|
if (frontTile.halfBrick()) newYPosition += 8f;
|
|
if (frontTileY1.halfBrick()) newYPosition -= 8f;
|
|
if (newYPosition < position.Y + npc.height)
|
|
{
|
|
float yDifference = position.Y + npc.height - newYPosition;
|
|
if (yDifference < 24.1f)
|
|
{
|
|
npc.gfxOffY += npc.position.Y + npc.height - newYPosition;
|
|
npc.position.Y = newYPosition - npc.height;
|
|
|
|
if (yDifference < 9f) npc.stepSpeed = 1f;
|
|
else npc.stepSpeed = 2f;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((frontTile.nactive() && !frontTile.topSlope() && Main.tileSolid[frontTile.type] &&
|
|
!Main.tileSolidTop[frontTile.type] &&
|
|
(frontTileY1.nactive() && !frontTileY1.topSlope() && Main.tileSolid[frontTileY1.type] &&
|
|
!Main.tileSolidTop[frontTileY1.type] || frontTileY1.nactive() && frontTileY1.halfBrick()) ||
|
|
frontTileX1.nactive() && !frontTileX1.topSlope() && Main.tileSolid[frontTileX1.type] &&
|
|
!Main.tileSolidTop[frontTileX1.type] &&
|
|
(frontTileX1Y1.nactive() && !frontTileX1Y1.topSlope() && Main.tileSolid[frontTileX1Y1.type] &&
|
|
!Main.tileSolidTop[frontTileX1Y1.type] ||
|
|
frontTileX1Y1.nactive() && frontTileX1Y1.halfBrick())
|
|
) && bottomTile.nactive() && (Main.tileSolid[bottomTile.type] || Main.tileSolidTop[bottomTile.type] ||
|
|
bottomTile.halfBrick()))
|
|
{
|
|
if (!hasTarget &&
|
|
frontTileY2.nactive() && !frontTileY2.topSlope() && Main.tileSolid[frontTileY2.type] &&
|
|
!Main.tileSolidTop[frontTileY2.type] &&
|
|
frontTileY3.nactive() && !frontTileY3.topSlope() && Main.tileSolid[frontTileY3.type] &&
|
|
!Main.tileSolidTop[frontTileY3.type] &&
|
|
frontTileY4.nactive() && !frontTileY4.topSlope() && Main.tileSolid[frontTileY4.type] &&
|
|
!Main.tileSolidTop[frontTileY4.type] && !frontTileY4.halfBrick()
|
|
)
|
|
{
|
|
// Turn around
|
|
Direction *= -1;
|
|
}
|
|
else
|
|
{
|
|
// Jump
|
|
npc.velocity.Y -= 1;
|
|
}
|
|
}
|
|
|
|
if (npc.velocity.X < 0f) npc.spriteDirection = -1;
|
|
else if (npc.velocity.X > 0f) npc.spriteDirection = 1;
|
|
|
|
int currentTileX = (int) npc.Center.X / 16;
|
|
int currentTileY = (int) npc.Center.Y / 16;
|
|
bool onWall = false;
|
|
for (int x = currentTileX - 1; x <= currentTileX + 1; x++)
|
|
{
|
|
for (int y = currentTileY - 1; y <= currentTileY + 1; y++)
|
|
{
|
|
if (Main.tile[x, y].wall > 0) onWall = true;
|
|
}
|
|
}
|
|
|
|
if (onWall) npc.Transform(ModContent.NPCType<CoreSpiderWall>());
|
|
|
|
if (Main.expertMode && hasTarget)
|
|
{
|
|
if (_frame >= shootFrame)
|
|
{
|
|
if (Main.rand.Next(4) == 0)
|
|
{
|
|
Vector2 mouthPos = npc.Center + new Vector2(npc.width / 2f * Direction, 0);
|
|
Vector2 projSpeed = new Vector2(5 * Direction, 0);
|
|
|
|
Projectile.NewProjectile(mouthPos, projSpeed, ProjectileID.Fireball, 130, 30);
|
|
}
|
|
|
|
_frame = 0;
|
|
}
|
|
else
|
|
{
|
|
_frame++;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override float SpawnChance(NPCSpawnInfo spawnInfo)
|
|
{
|
|
int x = (int) Main.LocalPlayer.position.X / 16;
|
|
int y = (int) Main.LocalPlayer.position.Y / 16;
|
|
|
|
int validBlockCount = 0;
|
|
for (int i = -50 + x; i <= 50 + x; i++)
|
|
for (int j = -50 + y; j <= 50 + y; j++)
|
|
if (i >= 0 && i <= Main.maxTilesX && j >= 0 && j <= Main.maxTilesY)
|
|
if (Main.tile[i, j].type == ModContent.TileType<ShrineBrick>() ||
|
|
Main.tile[i, j].type == ModContent.TileType<LockedShrineDoor>() ||
|
|
Main.tile[i, j].type == ModContent.TileType<ShrineDoorClosed>() ||
|
|
Main.tile[i, j].type == ModContent.TileType<ShrineDoorOpened>() ||
|
|
Main.tile[i, j].type == ModContent.TileType<RedHotSpike>())
|
|
validBlockCount++;
|
|
|
|
|
|
if (validBlockCount >= 15 && Main.hardMode)
|
|
return SpawnCondition.Underworld.Chance * 2;
|
|
return 0;
|
|
}
|
|
}
|
|
} |