diff --git a/.gitignore b/.gitignore index 6935d1d..26d1615 100644 --- a/.gitignore +++ b/.gitignore @@ -397,3 +397,4 @@ FodyWeavers.xsd *.PAL *.exe *.pdb +bin/ \ No newline at end of file diff --git a/AnimatedWall.cs b/AnimatedWall.cs index 40d2f02..7a38c89 100644 --- a/AnimatedWall.cs +++ b/AnimatedWall.cs @@ -7,8 +7,7 @@ public class AnimatedWall : Tile int startSprite; public AnimatedWall(int start, int count) { - anim.current = new Animation(start, count, 1000 / count); - anim.index = start; + anim.LoadAnimation(new Animation(start, count, 1000 / count)); } public override void Create() { diff --git a/AnimationHandler.cs b/AnimationHandler.cs index b2bf350..a537be2 100644 --- a/AnimationHandler.cs +++ b/AnimationHandler.cs @@ -11,11 +11,15 @@ public sealed class AnimationFrame public sealed class Animation { + static int animCount = 0; + public int id; public int duration; //duration in ms public List frames = new List(); public bool loop; - public Animation(int start, int count, int duration, bool loop = true) + public Action onEnd; + + public Animation(int start, int count, int duration, bool loop = true, Action onEnd = null) { for (int i = start; i < start + count; i++) { @@ -24,6 +28,11 @@ public Animation(int start, int count, int duration, bool loop = true) frames.Add(anim); } + id = animCount; + animCount++; + + this.onEnd = onEnd; + this.duration = duration; this.loop = loop; } @@ -33,8 +42,32 @@ public sealed class AnimationHandler { public int index; - public Animation current; + int frameIndex = 0; + Animation current; float timer; + int currentID = -1; + + + //returns false if asked to play the same animation or if the current animation is not completed + public bool LoadAnimation(Animation anim) + { + + if(currentID == anim.id){return false;} + + if(currentID > -1) + { + //return if current anim is not done + if(frameIndex < current.frames.Count-1){return false;} + } + + + current = anim; + currentID = anim.id; + index = current.frames[0].index; + timer = 0; + frameIndex = 0; + return true; + } public void Update() { @@ -42,24 +75,24 @@ public void Update() if (timer > current.duration) { timer = 0; - int end = current.frames[current.frames.Count - 1].index; - int start = current.frames[0].index; - - index++; - if (index > end) + frameIndex++; + if (frameIndex >= current.frames.Count) { if (current.loop) { - index = current.frames[0].index; + frameIndex = 0; } else { - index = end; + frameIndex = current.frames.Count-1; } - } + current.onEnd?.Invoke(); + timer = 0; + } } + index = current.frames[frameIndex].index; } } } \ No newline at end of file diff --git a/Direction.cs b/Direction.cs index abc7203..6d79535 100644 --- a/Direction.cs +++ b/Direction.cs @@ -3,8 +3,12 @@ namespace Nitemare3D public enum Direction //never eat soggy waffles { North, + NorthEast, East, + SouthEast, South, - West + SouthWest, + West, + NorthWest } } \ No newline at end of file diff --git a/DirectionalGuard.cs b/DirectionalGuard.cs new file mode 100644 index 0000000..be6a7d1 --- /dev/null +++ b/DirectionalGuard.cs @@ -0,0 +1,162 @@ +using System; +namespace Nitemare3D +{ + + + public class DirectionalGuard : Entity, ISprite + { + public GuardType type; + byte angle; //8 possible angles; + + public int spriteIndex {get; set;} + public Vec2 spritePosition{get;set;} = new Vec2(); + public bool visible{get;set;} = true; + public float yOffset{get;set;} + + Vec2 velocity = new Vec2(); + Direction direction; + float speed = 1f; + + + + + + public DirectionalGuard(GuardType type, Direction dir) + { + switch (type) + { + case GuardType.HumanGreen: + texOffset = 482; + break; + case GuardType.HumanBlue: + texOffset = 434; + break; + case GuardType.Witch: + break; + case GuardType.Robot: + break; + case GuardType.Penelope: + break; + case GuardType.DRHammerstein: + break; + } + this.direction = dir; + Game.player.AddSprite(this); + } + + int texOffset; + + GuardState state = GuardState.patrol; + /* + Nitemare 3D has certain tiles used to guide the patrol state of certain guards, + pretty clever I think + */ + + + Vec2 MoveInCompassDirection() + { + switch (direction) + { + case Direction.NorthWest: + return new Vec2(-1, -1); + case Direction.North: + return new Vec2(0, -1); + case Direction.NorthEast: + return new Vec2(1, -1); + case Direction.East: + return new Vec2(1, 0); + case Direction.SouthEast: + return new Vec2(1, 1); + case Direction.South: + return new Vec2(0, 1); + case Direction.SouthWest: + return new Vec2(-1, 1); + case Direction.West: + return new Vec2(-1, 0); + default: + return new Vec2(); + } + + } + void UpdatePatrol() + { + var x = MathF.Round(position.X); + var y = MathF.Round(position.Y); + var tile = Level.tilemap[(int)x, (int)y]; + + //never eat soggy waffles + switch(tile.type) + { + case WallType.turningpointN: + direction = Direction.North; + break; + case WallType.turningpointNE: + direction = Direction.NorthEast; + break; + case WallType.turningpointNW: + direction = Direction.NorthWest; + break; + case WallType.turningpointE: + direction = Direction.East; + break; + case WallType.turningpointS: + direction = Direction.South; + break; + case WallType.turningpointSE: + direction = Direction.SouthEast; + break; + case WallType.turningpointSW: + direction = Direction.SouthWest; + break; + case WallType.turningpointW: + direction = Direction.West; + break; + + + } + velocity = MoveInCompassDirection(); + } + void UpdateGuard() + { + switch (state) + { + case GuardState.idle: + break; + case GuardState.chasing: + break; + case GuardState.attacking: + break; + case GuardState.dead: + break; + case GuardState.patrol: + UpdatePatrol(); + break; + } + } + + + + void HandleAnimation() + { + + } + + public override void Update() + { + //todo calculate direction from velocity + HandleAnimation(); + UpdateGuard(); + + + + position += velocity * speed * Time.dt; + + + spritePosition = position; + + spriteIndex = texOffset + (int)direction * 4; + + + } + } +} \ No newline at end of file diff --git a/DumbObject.cs b/DumbObject.cs index 3f421bc..35f5074 100644 --- a/DumbObject.cs +++ b/DumbObject.cs @@ -8,7 +8,7 @@ public class DumbObject : Entity, ISprite public bool visible{get;set;} = true; public float yOffset{get;set;} public bool raised = false; - public DumbObject(int index, bool raised = false) + public DumbObject(int index, bool raised = false, bool hasCollision = true) { spriteIndex = index; Game.player.AddSprite(this); @@ -18,6 +18,7 @@ public DumbObject(int index, bool raised = false) { yOffset = 64 + Img.current.entries[index].height; } + this.hasCollision = hasCollision; } diff --git a/Entity.cs b/Entity.cs index e7a5c76..f18606f 100644 --- a/Entity.cs +++ b/Entity.cs @@ -5,6 +5,8 @@ namespace Nitemare3D public class Entity { public Vec2 position = new Vec2(); + public int id; + static int entCount; public virtual void Update() { @@ -15,6 +17,8 @@ public virtual void Start() } + public bool hasCollision = true; + public static List entities = new List(); static List entityQueue = new List(); @@ -63,6 +67,8 @@ public static void UpdateEntites() } foreach (var entity in entityQueue) { + entity.id = entCount; + entCount++; entity.Start(); entities.Add(entity); } diff --git a/Game.cs b/Game.cs index 28353f9..32d745e 100644 --- a/Game.cs +++ b/Game.cs @@ -11,7 +11,7 @@ public class Game : Scene MidiConsts.MIDI_E1M1, MidiConsts.MIDI_INTERMISSION }; - + public const string gameTitle = "Nitemare 3D 0.46"; diff --git a/GameWindow.cs b/GameWindow.cs index 804530d..ecf769d 100644 --- a/GameWindow.cs +++ b/GameWindow.cs @@ -7,22 +7,47 @@ namespace Nitemare3D { public static class GameWindow { - public const int width = 320; - public const int height = 200; - static Image renderTarget = new Image(width, height); + public static uint width = 320; + public static uint height = 200; + static Image renderTarget; + public static float scale; public static byte[] pal = new byte[1924]; static Text sfText = new Text("DEBUG", new Font("data/FFFFORWA.TTF"), 7); - public static byte[,] frameBuffer = new byte[width, height]; - public static RenderWindow sfWindow = new RenderWindow(new VideoMode(320, 240), "Nitemare 3D"); + public static byte[,] frameBuffer; + public static RenderWindow sfWindow; + static RectangleShape rect; public static void Init() { - sfWindow.SetFramerateLimit(30); + + //load config + var config = File.ReadAllLines("config.ini"); + width = uint.Parse(config[0]); + uint fps = uint.Parse(config[1]); + + height = (uint)(width / 1.6f); + + //to simulate tall pixels + uint winHeight = (uint)(height * 1.2f); + + scale = width / 320; + + //init window + sfWindow = new RenderWindow(new VideoMode(width, winHeight), Game.gameTitle); + renderTarget = new Image(width, height); + sfWindow.SetFramerateLimit(fps); sfWindow.Closed += (sender, e) => sfWindow.Close(); sfWindow.Resized += (sender, e) => PreserveAspectRatio(); + rect = new RectangleShape(new Vector2f(width, winHeight)); + + //init framebuffer + frameBuffer = new byte[width, height]; + + + //load pal BinaryReader reader = new BinaryReader(File.OpenRead("data/GAME.PAL")); reader.BaseStream.Position = 1156; @@ -54,8 +79,9 @@ public static byte GetDarkenedPixel(byte pixel) //todo: bitmap fonts public static void DrawText(uint x, uint y, string text, int color) { - sfText.Position = new Vector2f(x, y); + sfText.Position = new Vector2f(x, y) * scale; sfText.DisplayedString = text; + sfText.Scale = new Vector2f(scale, scale); var r = pal[3 * (color)]; var g = pal[3 * (color) + 1]; var b = pal[3 * (color) + 2]; @@ -64,7 +90,7 @@ public static void DrawText(uint x, uint y, string text, int color) sfText.FillColor = new Color(r, g, b); sfWindow.Draw(sfText); } - static RectangleShape rect = new RectangleShape(new Vector2f(320, 240)); + public static void Clear() { @@ -83,9 +109,9 @@ public static void Clear() public static void DrawFrameBuffer() { - for (int x = 0; x < 320; x++) + for (int x = 0; x < width; x++) { - for (int y = 0; y < 200; y++) + for (int y = 0; y < height; y++) { var i = frameBuffer[x, y]; if (i == 0) { continue; } @@ -93,6 +119,8 @@ public static void DrawFrameBuffer() var g = pal[3 * (i) + 1]; var b = pal[3 * (i) + 2]; renderTarget.SetPixel((uint)x, (uint)y, new Color(r, g, b)); + + } } sfWindow.Draw(rect); @@ -152,7 +180,14 @@ public static void DrawImg(int id, Vec2i position) var i = img.data[tx, ty]; if (i == 31) { continue; } //white is transparent - frameBuffer[tx + position.X, ty + position.Y] = i; + + for(int px = (int)(tx * scale); px < (int)(tx * scale + scale); px++) + { + for(int py = (int)(ty * scale); py < (int)(ty * scale + scale); py++) + { + frameBuffer[(int)(position.X * scale) + px, (int)(position.Y * scale) + py] = i; + } + } } } @@ -167,7 +202,14 @@ public static void DrawPcx() { var i = Scene.currentScene.pcx.ImageData[x, y]; if (i == 0) { continue; } //don't draw black pixels - frameBuffer[x,y] = i; + + for(int px = (int)(x * scale); px < (int)(x * scale + scale); px++) + { + for(int py = (int)(y * scale); py < (int)(y * scale + scale); py++) + { + frameBuffer[px,py] = i; + } + } } } } diff --git a/Guard.cs b/Guard.cs index faf8690..5ab1c24 100644 --- a/Guard.cs +++ b/Guard.cs @@ -1,3 +1,4 @@ +using System; namespace Nitemare3D { public enum GuardType //theres probably other monster types I haven't played a full run in a while @@ -6,7 +7,8 @@ namespace Nitemare3D Bat, Mummy, Skeleton, - Human, + HumanGreen, + HumanBlue, Witch, Gargorle, Robot, @@ -19,7 +21,18 @@ public enum GuardState idle, chasing, attacking, - dead + dead, + patrol, + roar + } + + public enum GuardAnimation + { + idle, + walk, + roar, + die, + attack } public class Guard : Entity, ISprite @@ -41,40 +54,269 @@ public class Guard : Entity, ISprite static Animation[] animations = new Animation[] { new Animation(SPRITE_FRANKENSTEIN_START, 1, 125), //frankenstein idle - new Animation(SPRITE_FRANKENSTEIN_START + 1, 8, 125), //frankenstein walk - new Animation(SPRITE_FRANKENSTEIN_START + 9, 11, 333), //frankenstein die - new Animation(SPRITE_FRANKENSTEIN_START + 12, 15, 333), //frankenstein attack + new Animation(SPRITE_FRANKENSTEIN_START + 1, 6, 125), //frankenstein walk + new Animation(328, 3, 500, false), //frankenstein roar + new Animation(SPRITE_FRANKENSTEIN_START + 9, 11, 333, false), //frankenstein die + new Animation(SPRITE_FRANKENSTEIN_START + 12, 3, 333, true), //frankenstein attack + new Animation(SPRITE_BAT_START, 1, 125),//bat idle new Animation(SPRITE_BAT_START+1, 3, 125),//bat fly + new Animation(SPRITE_BAT_START, 1, 500, false), //bat roar + new Animation(SPRITE_BAT_START + 9, 11, 125, false), //bat die new Animation(SPRITE_BAT_START+4, 8, 125), //bat attack - new Animation(SPRITE_BAT_START + 9, 11, 125), //bat die + new Animation(SPRITE_MUMMY_START, 1, 125), //mummy idle - new Animation(SPRITE_MUMMY_START + 1, 6, 125), //mummy walk - new Animation(SPRITE_MUMMY_START + 7, 3, 125), //mummy die + new Animation(SPRITE_MUMMY_START, 6, 125), //mummy walk + new Animation(SPRITE_MUMMY_START, 6, 500), //mummy roar + new Animation(SPRITE_MUMMY_START + 7, 3, 125, false), //mummy die new Animation(SPRITE_MUMMY_START + 10, 2, 125), //mummy attack new Animation(SPRITE_SKELETON_START, 1, 125), //skeleton idle - new Animation(SPRITE_SKELETON_START, 4, 125), //skeleton walk - new Animation(SPRITE_SKELETON_START, 1, 125) + new Animation(SPRITE_SKELETON_START, 3, 125), //skeleton walk + new Animation(382, 4, 125, false), //skeleton die + new Animation(374, 3, 125, false), //skeleton roar + new Animation(378, 4, 125) //skeleton attack + }; - public void Attack() + bool PlayAnim(GuardAnimation animation) { - anim.current = animations[((int)type*4) + 1]; - anim.index = animations[(int)type+2].frames[0].index; + return anim.LoadAnimation(animations[(int)type * Enum.GetValues().Length + (int)animation]); } + + public Guard(GuardType type) { this.type = type; - Attack(); + PlayAnim(GuardAnimation.idle); Game.player.AddSprite(this); + + switch (type) + { + case GuardType.Frankenstein: + attackTime = 2.5f; + break; + case GuardType.Bat: + break; + case GuardType.Mummy: + break; + case GuardType.Skeleton: + attackRange = 10; + attackTime = 5; + break; + case GuardType.HumanGreen: + break; + case GuardType.HumanBlue: + break; + case GuardType.Witch: + break; + case GuardType.Gargorle: + break; + case GuardType.Robot: + break; + case GuardType.Penelope: + break; + case GuardType.DRHammerstein: + break; + } + + attackTimer = attackTime; + + } + + float roarTimer = 0; + float roarTime = .5f; + + float attackTime, attackTimer; + + + + int range = 3; + int attackRange = 1; + void UpdateIdle() + { + PlayAnim(GuardAnimation.idle); + var dist = Vec2.Distance(position, Game.player.position); + if(dist <= range) + { + state = GuardState.roar; + } + } + bool moving = false; + + + Vec2 CalcNextPoint() + { + Vec2 current = new Vec2((int)MathF.Round(position.X), (int)MathF.Round(position.Y)); + Vec2[] points = new Vec2[5]; + points[0] = new Vec2(0, -1); + points[1] = new Vec2(1, 0); + points[2] = new Vec2(0, 1); + points[3] = new Vec2(-1, 0); + + Vec2 closest = new Vec2(0,0); + float closestDist = float.MaxValue; + + + for(int i = 0; i < 4; i++) + { + if(Level.IsWalkable((int)current.X + (int)points[i].X, (int)current.Y + (int)points[i].Y, this)) + { + var dist = Vec2.Distance(new Vec2(current.X + points[i].X, current.Y + points[i].Y), Game.player.position); + if((int)dist < closestDist) + { + closestDist = dist; + closest = points[i]; + } + } + + + } + + return closest; + } + Vec2 nextPosition = new Vec2(); + Vec2 targetPos = new Vec2(); + void UpdateChase() + { + PlayAnim(GuardAnimation.walk); + + var dist = Vec2.Distance(position, Game.player.position); + if(dist <= attackRange) + { + state = GuardState.attacking; + return; + } + + moving = (targetPos.Equals(position.Rounded())); + if(!moving) + { + nextPosition = CalcNextPoint(); + targetPos = position + nextPosition; + } + + + position += nextPosition * Time.dt; + } + + + void PlayRoar() + { + int snd = SoundConsts.GUARD_MONSTER_ALERT01; + switch (type) + { + case GuardType.Frankenstein: + break; + case GuardType.Bat: + snd = SoundConsts.GUARD_BAT_ALERT; + break; + case GuardType.Mummy: + snd = SoundConsts.GUARD_MONSTER_ALERT02; + break; + case GuardType.Skeleton: + snd = SoundConsts.GUARD_SKELETON_ALERT; + break; + case GuardType.HumanGreen: + break; + case GuardType.HumanBlue: + break; + case GuardType.Witch: + snd = SoundConsts.GUARD_WITCH_ALERT01; + break; + case GuardType.Gargorle: + break; + case GuardType.Robot: + break; + case GuardType.Penelope: + break; + case GuardType.DRHammerstein: + break; + } + SoundEffect.PlaySound(snd); + } + + + public void ShootPlasma() + { + state = GuardState.dead; + } + + void UpdateAttack() + { + var dist = Vec2.Distance(position, Game.player.position); + if(dist > attackRange) + { + state = GuardState.chasing; + return; + } + + attackTimer += Time.dt; + + if(attackTimer > attackTime) + { + PlayAnim(GuardAnimation.attack); + SoundEffect.PlaySound(SoundConsts.ATTACK_FRANKENSTEIN); + attackTimer = 0; + }else{ + PlayAnim(GuardAnimation.idle); + } + + } + + + void UpdateDead() + { + SoundEffect.PlaySound(SoundConsts.GUARD_HUMAN_DIE01); + Entity.Remove(this); + visible = false; + } + + void UpdateState() + { + switch (state) + { + case GuardState.idle: + UpdateIdle(); + break; + case GuardState.chasing: + UpdateChase(); + break; + case GuardState.attacking: + UpdateAttack(); + break; + case GuardState.dead: + UpdateDead(); + //or super death if you're a skeleton + break; + case GuardState.patrol: + break; + case GuardState.roar: + PlayAnim(GuardAnimation.roar); + PlayRoar(); + roarTimer += Time.dt; + if(roarTimer > roarTime) + { + state = GuardState.chasing; + nextPosition = CalcNextPoint(); + moving = true; + roarTimer = 0; + } + break; + } } public override void Update() { + UpdateState(); anim.Update(); spriteIndex = anim.index; spritePosition = position; + + + if(type == GuardType.Bat && state != GuardState.idle) + { + yOffset += (32 - yOffset) * Time.dt; + } } } } \ No newline at end of file diff --git a/HiddenPanel.cs b/HiddenPanel.cs index 0a1aa29..571ccb2 100644 --- a/HiddenPanel.cs +++ b/HiddenPanel.cs @@ -9,6 +9,7 @@ public override void Start() current = Level.tilemap[(int)position.X, (int)position.Y]; current.thin = true; GetNeighbor(); + hasCollision = false; } void GetNeighbor() //checks if this is a double wide door diff --git a/Level.cs b/Level.cs index e93ab5a..0206891 100644 --- a/Level.cs +++ b/Level.cs @@ -67,10 +67,10 @@ static void SpawnMapObject(int id, int x, int y) ent = new DumbObject(199); break; case ObjectType.Globeceilinglamp: - ent = new DumbObject(200, true); + ent = new DumbObject(200, true, false); break; case ObjectType.Chandelierceilinglamp: - ent = new DumbObject(201, true); + ent = new DumbObject(201, true, false); break; case ObjectType.Livingroomstandardlamp: ent = new DumbObject(202); @@ -288,36 +288,52 @@ static void SpawnMapObject(int id, int x, int y) case ObjectType.VampiraW: break; case ObjectType.Baddie1NBluecoat: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.North); break; case ObjectType.Baddie1E: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.East); break; case ObjectType.Baddie1S: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.South); break; case ObjectType.Baddie1W: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.West); break; case ObjectType.Baddie1MN: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.North); break; case ObjectType.Baddie1ME: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.East); break; case ObjectType.Baddie1MS: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.South); break; case ObjectType.Baddie1MW: + ent = new DirectionalGuard(GuardType.HumanBlue, Direction.West); break; case ObjectType.Baddie2NGreencoat: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.North); break; case ObjectType.Baddie2E: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.East); break; case ObjectType.Baddie2S: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.South); break; case ObjectType.Baddie2W: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.West); break; case ObjectType.Baddie2MN: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.North); break; case ObjectType.Baddie2ME: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.East); break; case ObjectType.Baddie2MS: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.South); break; case ObjectType.Baddie2MW: + ent = new DirectionalGuard(GuardType.HumanGreen, Direction.West); break; case ObjectType.DraculaN: break; @@ -451,7 +467,7 @@ public static void HandleFlip(int x, int y) } - static public void CreateTile(int x, int y, int id) + public static void CreateTile(int x, int y, int id) { Tile tile = new Tile(); @@ -1012,6 +1028,7 @@ static public void CreateTile(int x, int y, int id) } tile.x = (byte)x; tile.y = (byte)y; + tile.type = type; tile.textureID = texture; tilemap[x,y] = tile; tilemap[x,y].Create(); @@ -1020,6 +1037,30 @@ static public void CreateTile(int x, int y, int id) } + //TODO: make entity collision detection less garbage + public static bool IsWalkable(int x, int y, Entity ent) + { + if(x < 0 || x > 63 || y < 0 || y > 64){return false;} + bool isEntity = false; + foreach(var entity in Entity.entities) + { + var ex = (int)MathF.Round(entity.position.X); + var ey = (int)MathF.Round(entity.position.Y); + if(entity.id == ent.id){continue;} //dont want to check collision on ourselves! + + + if (x == ex && ey == y) + { + if(entity.hasCollision) + { + isEntity = true; + break; + } + } + + } + return ((tilemap[x,y].textureID == -1)) && !isEntity; + } public static void LoadMap(int id, int episode) { diff --git a/Pickup.cs b/Pickup.cs index 7f9e854..1038b92 100644 --- a/Pickup.cs +++ b/Pickup.cs @@ -52,9 +52,42 @@ public class Pickup : Entity, ISprite public Pickup(PickupType type) { this.type = type; - anim.current = animations[(int)type]; + anim.LoadAnimation(animations[(int)type]); Game.player.AddSprite(this); anim.index = animations[(int)type].frames[0].index; + hasCollision = false; + switch (type) + { + case PickupType.RedKey: + break; + case PickupType.GreenKey: + break; + case PickupType.BlueKey: + break; + case PickupType.YellowKey: + break; + case PickupType.RedIDCard: + break; + case PickupType.YellowIDCard: + break; + case PickupType.RedPotion: + break; + case PickupType.BluePotion: + break; + case PickupType.Eyeball: + yOffset = 32; + break; + case PickupType.CrystallBall: + break; + case PickupType.PlasmaPistol: + break; + case PickupType.MagicWand: + break; + case PickupType.Pistol: + break; + case PickupType.AutoPlasmaPistol: + break; + } } public override void Update() diff --git a/Player.cs b/Player.cs index 9002fab..e569812 100644 --- a/Player.cs +++ b/Player.cs @@ -51,8 +51,8 @@ public class Player : Entity const int WallTextureSize = 64; - const int RayHeight = 152; - const int RayWidth = 304; + int RayHeight = 152; + int RayWidth = 304; int spriteCount = 0; const int maxSprites = 4096; public void AddSprite(ISprite sprite) @@ -66,10 +66,21 @@ public void AddSprite(ISprite sprite) spriteCount++; } + public override void Start() + { + weapons[0].hasWeapon = true; + + RayWidth = (int)(RayWidth * GameWindow.scale); + RayHeight = (int)(RayHeight * GameWindow.scale); + + zBuffer = new float[RayWidth]; + hasCollision = false; + } + ISprite[] sprites = new ISprite[maxSprites]; int[] spriteOrder = new int[maxSprites]; float[] spriteDistance = new float[maxSprites]; - float[] zBuffer = new float[RayWidth]; + float[] zBuffer; class DecendingComparer: IComparer @@ -333,7 +344,7 @@ public void RenderRaycaster() int spriteScreenX = (int)((RayWidth / 2) * (1 + transformX / transformY)); float uDiv = (64f / spriteW); float vDiv = (64f / spriteH); - float vMove = (64-spriteH) - sprite.yOffset; + float vMove = ((64-spriteH) - sprite.yOffset) * GameWindow.scale; int vMoveScreen = (int)(vMove / transformY); @@ -475,15 +486,21 @@ public override void Update() if (Input.IsKeyDown(KeyboardKey.Up)) { - if(!Level.tilemap[(int)(position.X + direction.X), (int)(position.Y)].obstacle) + var x = (int)(position.X + direction.X); + var y = (int)position.Y; + if(Level.IsWalkable(x, y, this)) { position.X += direction.X * (Time.dt * walkSpeed); } + + y = (int)(position.Y + direction.Y); + x = (int)position.X; - if(!Level.tilemap[(int)(position.X), (int)(position.Y + direction.Y)].obstacle) + if(Level.IsWalkable(x, y, this)) { position.Y += direction.Y * (Time.dt * walkSpeed); } + } diff --git a/Projectile.cs b/Projectile.cs index 97c786d..604b34d 100644 --- a/Projectile.cs +++ b/Projectile.cs @@ -1,3 +1,4 @@ +using System; namespace Nitemare3D { public enum ProjectileType @@ -29,9 +30,9 @@ public Projectile(Vec2 direction, ProjectileType type) { this.direction = direction; this.type = type; - anim.index = animations[(int)type].frames[0].index; - anim.current = animations[(int)type]; + anim.LoadAnimation(animations[(int)type]); Game.player.AddSprite(this); + hasCollision = false; } public override void Update() @@ -40,6 +41,28 @@ public override void Update() position += direction * speed * Time.dt; spritePosition = position; spriteIndex = anim.index; + + bool delete = false; + + + foreach(var entity in entities) + { + if(entity.id == id || entity.id == Game.player.id){continue;} + if(entity.position.Rounded().Equals(position.Rounded())) + { + delete = entity.hasCollision; + entity.SendMessage("ShootPlasma"); + return; + } + } + + if(!Level.IsWalkable((int)position.X, (int)position.Y, this)) + { + delete = true; + } + + if(delete){Entity.Remove(this); visible = false;} + } } } \ No newline at end of file diff --git a/SoundConsts.cs b/SoundConsts.cs index 793a9e5..2f075da 100644 --- a/SoundConsts.cs +++ b/SoundConsts.cs @@ -36,7 +36,7 @@ public static class SoundConsts public const int WEAPON_PLASMA = 65; public const int GUARD_BAT_ALERT = 66; public const int GUARD_BAT_DIE = 67; - public const int SND_68 = 68; + public const int GUARD_SKELETON_ATTACK = 68; public const int CURTAIN_OPEN = 69; public const int CURTAIN_CLOSE = 70; public const int HIDDENPANEL_OPEN = 71; @@ -58,14 +58,14 @@ public static class SoundConsts public const int GUARD_HUMAN_ALERT02 = 87; public const int GUARD_MONSTER_ALERT01 = 88; public const int GUARD_MONSTER_ALERT02 = 89; - public const int GUARD_HUMAN_ALERT03 = 90; - public const int SND_91 = 91; + public const int GUARD_MONSTER_ALERT03 = 90; + public const int GUARD_SKELETON_ALERT = 91; public const int SND_92 = 92; public const int SND_93 = 93; public const int SND_94 = 94; public const int SND_95 = 95; public const int SND_96 = 96; - public const int SND_97 = 97; + public const int ATTACK_FRANKENSTEIN = 97; public const int SND_98 = 98; public const int SND_99 = 99; public const int LEVEL_END = 100; diff --git a/SoundEditor.cs b/SoundEditor.cs index f47f99a..7a62897 100644 --- a/SoundEditor.cs +++ b/SoundEditor.cs @@ -36,7 +36,26 @@ public override void Update() names[index] = name; } GameWindow.DrawText(0, 230, "Press F5 to save, F1 to exit", 31); - name += Input.text; + + if(inputTimer > inputTime) + { + if(Input.text.Length > 0) + { + inputTimer = 0; + } + name += Input.text; + } + + if(Input.text.Length > 0) + { + if(inputTimer > inputTime) + { + name += Input.text; + inputTimer = 0; + } + } + + inputTimer += Time.dt; diff --git a/SoundEffect.cs b/SoundEffect.cs index 273a4c3..7c63f2d 100644 --- a/SoundEffect.cs +++ b/SoundEffect.cs @@ -8,7 +8,7 @@ namespace Nitemare3D public class SoundEffect { const int sampleRate = 10989; - const int volumeModifier = 80; + const int volumeModifier = 120; Sound sound; public const int soundOffset = 34;//everything before that is midi or blank(idk why there's blank entries) @@ -16,6 +16,8 @@ public class SoundEffect public static void PlaySound(int id) { + if(effects[id - soundOffset].sound == null){return;} + if(effects[id - soundOffset].sound.Status == SoundStatus.Playing){return;} effects[id - soundOffset].Play(); } diff --git a/Tile.cs b/Tile.cs index 7708229..23afefb 100644 --- a/Tile.cs +++ b/Tile.cs @@ -17,9 +17,11 @@ public class Tile public bool flip = false; float openAmount = 0; public TileState state = TileState.solid; + public WallType type; public void UpdateDoorState() { + switch (state) { case TileState.solid: diff --git a/Vec2.cs b/Vec2.cs index 039291a..5bcf0ea 100644 --- a/Vec2.cs +++ b/Vec2.cs @@ -48,6 +48,10 @@ public static bool linePoint(Vec2 start, Vec2 end, Vec2 point) return false; } + public Vec2 Rounded() + { + return new Vec2(MathF.Round(X), MathF.Round(Y)); + } public static Vec2 Down { @@ -82,7 +86,7 @@ public Vec2() public override bool Equals(object obj) { var vec = obj as Vec2; - return (vec.X == X && vec.Y == Y); + return (int)vec.X == (int)X && (int)vec.Y == (int)Y; } @@ -117,6 +121,31 @@ public static Vec2 Transform(Vec2 Point, float Angle) return new Vec2(A.X / B.X, A.Y / B.Y); } + public static Vec2 operator *(Vec2 A, Vec2 B) + { + return new Vec2(A.X * B.X, A.Y * B.Y); + } + + public static Vec2 operator +(Vec2 A, Vec2i B) + { + return new Vec2(A.X + B.X, A.Y + B.Y); + } + + public static Vec2 operator -(Vec2 A, Vec2i B) + { + return new Vec2(A.X - B.X, A.Y - B.Y); + } + + public static Vec2 operator /(Vec2 A, Vec2i B) + { + return new Vec2(A.X / B.X, A.Y / B.Y); + } + + public static Vec2 operator *(Vec2 A, Vec2i B) + { + return new Vec2(A.X * B.X, A.Y * B.Y); + } + public static Vec2 operator /(Vec2 A, float B) { return new Vec2(A.X / B, A.Y / B); @@ -161,6 +190,12 @@ public static Vec2 Transform(Vec2 Origin, Vec2 Point, float Angle) ) - Origin * 2; } + internal static float Dot(Vec2 a, Vec2 b) + { + return (a.X * b.X) + (a.Y * b.Y); + + } + public static float Magnitude(Vec2 A) { return (float)Math.Sqrt(A.X * A.X + A.Y * A.Y); diff --git a/bin/Debug/net5.0/Nitemare3D b/bin/Debug/net5.0/Nitemare3D index 43a6047..2bbd4ad 100755 Binary files a/bin/Debug/net5.0/Nitemare3D and b/bin/Debug/net5.0/Nitemare3D differ diff --git a/bin/Debug/net5.0/Nitemare3D.dll b/bin/Debug/net5.0/Nitemare3D.dll index 13539e9..6ea7ed9 100644 Binary files a/bin/Debug/net5.0/Nitemare3D.dll and b/bin/Debug/net5.0/Nitemare3D.dll differ diff --git a/bin/Debug/net5.0/Nitemare3D.pdb b/bin/Debug/net5.0/Nitemare3D.pdb index 1a49883..b34576a 100644 Binary files a/bin/Debug/net5.0/Nitemare3D.pdb and b/bin/Debug/net5.0/Nitemare3D.pdb differ diff --git a/bin/Debug/net5.0/ref/Nitemare3D.dll b/bin/Debug/net5.0/ref/Nitemare3D.dll index da13ae7..adf15f8 100644 Binary files a/bin/Debug/net5.0/ref/Nitemare3D.dll and b/bin/Debug/net5.0/ref/Nitemare3D.dll differ diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..61b2996 --- /dev/null +++ b/config.ini @@ -0,0 +1,2 @@ +640 +60 \ No newline at end of file diff --git a/obj/Debug/net5.0/Nitemare3D.csproj.AssemblyReference.cache b/obj/Debug/net5.0/Nitemare3D.csproj.AssemblyReference.cache index 9bc0966..a0c0355 100644 Binary files a/obj/Debug/net5.0/Nitemare3D.csproj.AssemblyReference.cache and b/obj/Debug/net5.0/Nitemare3D.csproj.AssemblyReference.cache differ diff --git a/obj/Debug/net5.0/Nitemare3D.csproj.CoreCompileInputs.cache b/obj/Debug/net5.0/Nitemare3D.csproj.CoreCompileInputs.cache index 4acb3ae..f688b15 100644 --- a/obj/Debug/net5.0/Nitemare3D.csproj.CoreCompileInputs.cache +++ b/obj/Debug/net5.0/Nitemare3D.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -a3e83c9cb11911519e34bc430072ea8ceec9df77 +2ce8da1ebaf8c6d86e8798b3849de047f841c3a1 diff --git a/obj/Debug/net5.0/Nitemare3D.dll b/obj/Debug/net5.0/Nitemare3D.dll index 13539e9..6ea7ed9 100644 Binary files a/obj/Debug/net5.0/Nitemare3D.dll and b/obj/Debug/net5.0/Nitemare3D.dll differ diff --git a/obj/Debug/net5.0/Nitemare3D.pdb b/obj/Debug/net5.0/Nitemare3D.pdb index 1a49883..b34576a 100644 Binary files a/obj/Debug/net5.0/Nitemare3D.pdb and b/obj/Debug/net5.0/Nitemare3D.pdb differ diff --git a/obj/Debug/net5.0/apphost b/obj/Debug/net5.0/apphost index 43a6047..2bbd4ad 100755 Binary files a/obj/Debug/net5.0/apphost and b/obj/Debug/net5.0/apphost differ diff --git a/obj/Debug/net5.0/ref/Nitemare3D.dll b/obj/Debug/net5.0/ref/Nitemare3D.dll index da13ae7..adf15f8 100644 Binary files a/obj/Debug/net5.0/ref/Nitemare3D.dll and b/obj/Debug/net5.0/ref/Nitemare3D.dll differ diff --git a/obj/Nitemare3D.csproj.nuget.dgspec.json b/obj/Nitemare3D.csproj.nuget.dgspec.json index a82eb0d..5e5375c 100644 --- a/obj/Nitemare3D.csproj.nuget.dgspec.json +++ b/obj/Nitemare3D.csproj.nuget.dgspec.json @@ -66,7 +66,7 @@ "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/5.0.301/RuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/5.0.302/RuntimeIdentifierGraph.json" } } } diff --git a/obj/project.assets.json b/obj/project.assets.json index 6a0f777..22dd512 100644 --- a/obj/project.assets.json +++ b/obj/project.assets.json @@ -631,7 +631,7 @@ "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/5.0.301/RuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/5.0.302/RuntimeIdentifierGraph.json" } } } diff --git a/obj/project.nuget.cache b/obj/project.nuget.cache index 6a52f13..10a5e44 100644 --- a/obj/project.nuget.cache +++ b/obj/project.nuget.cache @@ -1,6 +1,6 @@ { "version": 2, - "dgSpecHash": "SlmEBujSOGkafjrBIc0wGk65MwfTckuD+d03LDRkfjWMoivXQO0E4N70Hu5o6Q+BaiZ3aWhvVcROjL3zauJDjA==", + "dgSpecHash": "nJ+Fo+x52sN0/MBJoAg9sd7ciR2S1I3KzI/BIis+GqQqtivmaOuQFBCunpYd9c4cMt1YMmNXiO5hpG4G2GYOuw==", "success": true, "projectFilePath": "/home/bbq/GitHub/OpenNitemare3D/Nitemare3D.csproj", "expectedPackageFiles": [