mirror of
https://github.com/Phantop/LADXHD.git
synced 2024-11-01 04:14:22 +00:00
371 lines
14 KiB
C#
371 lines
14 KiB
C#
using Microsoft.Xna.Framework;
|
|
using ProjectZ.Base;
|
|
using ProjectZ.Editor;
|
|
using ProjectZ.InGame.GameObjects.Base;
|
|
using ProjectZ.InGame.GameObjects.Base.Components;
|
|
using ProjectZ.InGame.GameObjects.Things;
|
|
using ProjectZ.InGame.Things;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace ProjectZ.InGame.Map
|
|
{
|
|
public class Map
|
|
{
|
|
public TileMap TileMap;
|
|
public TileMap HoleMap;
|
|
public string[,] DigMap;
|
|
|
|
public ObjectManager Objects;
|
|
|
|
public MapStates.FieldStates[,] StateMap;
|
|
public Vector2? CameraTarget;
|
|
|
|
private Point _lastFieldPosition;
|
|
public int[,] UpdateMap;
|
|
|
|
public Color LightColor;
|
|
|
|
public string MapName;
|
|
public string MapFileName;
|
|
|
|
// TODO_Opt: this is currently only set in dungeons
|
|
// this should probably be saved inside each mapfile
|
|
public string LocationName;
|
|
public string LocationFullName;
|
|
|
|
public float LightState;
|
|
|
|
public int MapWidth => TileMap.ArrayTileMap?.GetLength(0) ?? 0;
|
|
public int MapHeight => TileMap.ArrayTileMap?.GetLength(1) ?? 0;
|
|
|
|
public int MapOffsetX;
|
|
public int MapOffsetY;
|
|
|
|
public int[] MapMusic = new[] { -1, -1, -1 };
|
|
|
|
public float ShadowHeight;
|
|
public float ShadowRotation;
|
|
|
|
public bool Is2dMap;
|
|
public bool DungeonMode;
|
|
public bool UseLight;
|
|
public bool UseShadows;
|
|
public bool IsOverworld;
|
|
|
|
private List<GameObject> _digList = new List<GameObject>();
|
|
|
|
public Map()
|
|
{
|
|
TileMap = new TileMap();
|
|
HoleMap = new TileMap();
|
|
Objects = new ObjectManager(this);
|
|
}
|
|
|
|
public static Map CreateEmptyMap()
|
|
{
|
|
var emptyMap = new Map();
|
|
|
|
emptyMap.Objects.Clear();
|
|
emptyMap.Objects.LoadObjects();
|
|
|
|
emptyMap.StateMap = new MapStates.FieldStates[1, 1];
|
|
emptyMap.UpdateMap = new int[1, 1];
|
|
|
|
return emptyMap;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
CameraTarget = null;
|
|
Is2dMap = false;
|
|
IsOverworld = false;
|
|
DungeonMode = false;
|
|
LocationName = null;
|
|
UseLight = false;
|
|
MapMusic = new[] { -1, -1, -1 };
|
|
UseShadows = true;
|
|
LightState = 0;
|
|
|
|
ShadowHeight = Values.ShadowHeightDefault;
|
|
ShadowRotation = Values.ShadowRotationDefault;
|
|
}
|
|
|
|
public void SetFieldState(int posX, int posY, MapStates.FieldStates newState)
|
|
{
|
|
if (0 <= posX && posX < StateMap.GetLength(0) &&
|
|
0 <= posY && posY < StateMap.GetLength(1))
|
|
StateMap[posX, posY] = newState;
|
|
}
|
|
|
|
public void AddFieldState(int posX, int posY, MapStates.FieldStates addState)
|
|
{
|
|
if (0 <= posX && posX < StateMap.GetLength(0) &&
|
|
0 <= posY && posY < StateMap.GetLength(1))
|
|
StateMap[posX, posY] |= addState;
|
|
}
|
|
|
|
public void RemoveFieldState(int posX, int posY, MapStates.FieldStates removeState)
|
|
{
|
|
if (0 <= posX && posX < StateMap.GetLength(0) &&
|
|
0 <= posY && posY < StateMap.GetLength(1))
|
|
StateMap[posX, posY] &= ~removeState;
|
|
}
|
|
|
|
public MapStates.FieldStates GetFieldState(int posX, int posY)
|
|
{
|
|
if (0 <= posX && posX < StateMap.GetLength(0) &&
|
|
0 <= posY && posY < StateMap.GetLength(1))
|
|
return StateMap[posX, posY];
|
|
|
|
return MapStates.FieldStates.None;
|
|
}
|
|
|
|
public MapStates.FieldStates GetFieldState(Vector2 centerF)
|
|
{
|
|
if (centerF.X < 0 || centerF.Y < 0)
|
|
return MapStates.FieldStates.None;
|
|
|
|
var posX = (int)(centerF.X / 16);
|
|
var posY = (int)(centerF.Y / 16);
|
|
return GetFieldState(posX, posY);
|
|
}
|
|
|
|
public int GetUpdateState(Vector2 center)
|
|
{
|
|
var posX = (int)(center.X - MapOffsetX * Values.TileSize) / Values.FieldWidth;
|
|
var posY = (int)(center.Y - MapOffsetY * Values.TileSize) / Values.FieldHeight;
|
|
return GetUpdateState(posX, posY);
|
|
}
|
|
|
|
public int GetUpdateState(int posX, int posY)
|
|
{
|
|
if (0 <= posX && posX < UpdateMap.GetLength(0) &&
|
|
0 <= posY && posY < UpdateMap.GetLength(1))
|
|
return UpdateMap[posX, posY];
|
|
|
|
return 0;
|
|
}
|
|
|
|
public void ChangeUpdateState(int posX, int posY, int addition)
|
|
{
|
|
if (0 <= posX && posX < UpdateMap.GetLength(0) &&
|
|
0 <= posY && posY < UpdateMap.GetLength(1))
|
|
UpdateMap[posX, posY] += addition;
|
|
}
|
|
|
|
public void UpdateMapUpdateState()
|
|
{
|
|
var cameraPosition = new Vector2(MapManager.ObjLink.PosX, MapManager.ObjLink.PosY - 4);
|
|
var fieldPosition = new Point(
|
|
(int)(cameraPosition.X - MapOffsetX * Values.TileSize) / Values.FieldWidth,
|
|
(int)(cameraPosition.Y - MapOffsetY * Values.TileSize) / Values.FieldHeight);
|
|
|
|
// increment the update counter for the fields the player left
|
|
for (var y = _lastFieldPosition.Y - 2; y <= _lastFieldPosition.Y + 2; y++)
|
|
for (var x = _lastFieldPosition.X - 2; x <= _lastFieldPosition.X + 2; x++)
|
|
{
|
|
if (Math.Abs(x - fieldPosition.X) > 2 ||
|
|
Math.Abs(y - fieldPosition.Y) > 2)
|
|
{
|
|
ChangeUpdateState(x, y, 1);
|
|
ClearHoleMap(x, y);
|
|
}
|
|
}
|
|
|
|
_lastFieldPosition = fieldPosition;
|
|
}
|
|
|
|
private void ClearHoleMap(int posX, int posY)
|
|
{
|
|
if (HoleMap.ArrayTileMap == null)
|
|
return;
|
|
|
|
if (posX < 0 || HoleMap.ArrayTileMap.GetLength(0) < (posX + 1) * 10 ||
|
|
posY < 0 || HoleMap.ArrayTileMap.GetLength(1) < (posY + 1) * 8)
|
|
return;
|
|
|
|
for (var y = 0; y < 8; y++)
|
|
for (var x = 0; x < 10; x++)
|
|
{
|
|
HoleMap.ArrayTileMap[posX * 10 + x, posY * 8 + y, 0] = -1;
|
|
}
|
|
}
|
|
|
|
public void ResizeMap(int newWidth, int newHeight, int posX, int posY)
|
|
{
|
|
var newTileMap = new TileMap();
|
|
newTileMap.SetTileset(TileMap.SprTileset, TileMap.TileSize);
|
|
newTileMap.TilesetPath = TileMap.TilesetPath;
|
|
|
|
var depth = TileMap.ArrayTileMap.GetLength(2);
|
|
newTileMap.ArrayTileMap = new int[newWidth, newHeight, depth];
|
|
|
|
for (var z = 0; z < newTileMap.ArrayTileMap.GetLength(2); z++)
|
|
for (var y = 0; y < newTileMap.ArrayTileMap.GetLength(1); y++)
|
|
for (var x = 0; x < newTileMap.ArrayTileMap.GetLength(0); x++)
|
|
newTileMap.ArrayTileMap[x, y, z] = -1;
|
|
|
|
for (var z = 0; z < TileMap.ArrayTileMap.GetLength(2); z++)
|
|
{
|
|
for (var y = 0; y < TileMap.ArrayTileMap.GetLength(1); y++)
|
|
{
|
|
for (var x = 0; x < TileMap.ArrayTileMap.GetLength(0); x++)
|
|
{
|
|
if (0 <= posX + x && posX + x < newWidth &&
|
|
0 <= posY + y && posY + y < newHeight &&
|
|
0 <= z && z < depth)
|
|
newTileMap.ArrayTileMap[posX + x, posY + y, z] = TileMap.ArrayTileMap[x, y, z];
|
|
}
|
|
}
|
|
}
|
|
|
|
TileMap = newTileMap;
|
|
|
|
// @TODO: this does not set the new parts to ""
|
|
OffsetDigMap(newWidth, newHeight, posX, posY);
|
|
|
|
// offset the objects
|
|
ObjectEditorScreen.OffsetObjects(this, posX * Values.TileSize, posY * Values.TileSize);
|
|
}
|
|
|
|
private void OffsetDigMap(int newWidth, int newHeight, int posX, int posY)
|
|
{
|
|
var newDigMap = new string[newWidth, newHeight];
|
|
|
|
for (var y = 0; y < DigMap.GetLength(1); y++)
|
|
for (var x = 0; x < DigMap.GetLength(0); x++)
|
|
{
|
|
if (0 <= posX + x && posX + x < newWidth &&
|
|
0 <= posY + y && posY + y < newHeight)
|
|
newDigMap[posX + x, posY + y] = DigMap[x, y];
|
|
}
|
|
|
|
DigMap = newDigMap;
|
|
}
|
|
|
|
public Vector2 GetRoomCenter(float x, float y)
|
|
{
|
|
return new Vector2(
|
|
((int)((x - MapOffsetX * Values.TileSize) / Values.FieldWidth) + 0.5f) * Values.FieldWidth + MapOffsetX * Values.TileSize,
|
|
((int)((y - MapOffsetY * Values.TileSize) / Values.FieldHeight) + 0.5f) * Values.FieldHeight + MapOffsetY * Values.TileSize);
|
|
}
|
|
|
|
public Rectangle GetField(int x, int y, int margin)
|
|
{
|
|
return new Rectangle(
|
|
(x - MapOffsetX * Values.TileSize) / Values.FieldWidth * Values.FieldWidth + margin + MapOffsetX * Values.TileSize,
|
|
(y - MapOffsetY * Values.TileSize) / Values.FieldHeight * Values.FieldHeight + margin + MapOffsetY * Values.TileSize,
|
|
Values.FieldWidth - 2 * margin, Values.FieldHeight - 2 * margin);
|
|
}
|
|
|
|
public Rectangle GetField(int x, int y)
|
|
{
|
|
return GetField(x, y, 0);
|
|
}
|
|
|
|
public Box GetFieldBox(int x, int y, int height, int margin)
|
|
{
|
|
return new Box(
|
|
(x - MapOffsetX * Values.TileSize) / Values.FieldWidth * Values.FieldWidth + margin + MapOffsetX * Values.TileSize,
|
|
(y - MapOffsetY * Values.TileSize) / Values.FieldHeight * Values.FieldHeight + margin + MapOffsetY * Values.TileSize, 0,
|
|
Values.FieldWidth - 2 * margin, Values.FieldHeight - 2 * margin, height);
|
|
}
|
|
|
|
public Box GetFieldBox(int x, int y, int height)
|
|
{
|
|
return GetFieldBox(x, y, height, 0);
|
|
}
|
|
|
|
public bool CanDig(Point position)
|
|
{
|
|
// no grass or water? can dig? was already dug?
|
|
if (0 > position.X || position.X >= HoleMap.ArrayTileMap.GetLength(0) ||
|
|
0 > position.Y || position.Y >= HoleMap.ArrayTileMap.GetLength(1) ||
|
|
(StateMap[position.X, position.Y] | MapStates.FieldStates.UpperLevel) != MapStates.FieldStates.UpperLevel ||
|
|
HoleMap.ArrayTileMap[position.X, position.Y, 0] >= 0 ||
|
|
position.X < DigMap.GetLength(0) &&
|
|
position.Y < DigMap.GetLength(1) &&
|
|
string.IsNullOrEmpty(DigMap[position.X, position.Y]))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// check if there is something blocking the digging
|
|
_digList.Clear();
|
|
var digBox = new Box(position.X * 16 + 2, position.Y * 16 + 2, 0, 12, 12, 8);
|
|
Objects.GetComponentList(_digList, (int)digBox.X, (int)digBox.Y, 12, 12, CollisionComponent.Mask);
|
|
var collidingBox = Box.Empty;
|
|
foreach (var gameObject in _digList)
|
|
{
|
|
var collisionObject = gameObject.Components[CollisionComponent.Index] as CollisionComponent;
|
|
if (collisionObject.Owner.IsActive &&
|
|
(collisionObject.CollisionType & (Values.CollisionTypes.Normal | Values.CollisionTypes.Hole)) != 0 &&
|
|
collisionObject.Collision(digBox, 0, 0, ref collidingBox))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void Dig(Point position, Vector2 diggerPosition, int dir)
|
|
{
|
|
string strObject = null;
|
|
string strSaveKey = null;
|
|
|
|
var digTileIndex = 0;
|
|
|
|
var itemString = DigMap[position.X, position.Y];
|
|
if (int.TryParse(itemString, out int result))
|
|
{
|
|
var random = Game1.RandomNumber.Next(0, 100);
|
|
if (random < 6)
|
|
strObject = "ruby";
|
|
else if (random < 9)
|
|
strObject = "heart";
|
|
|
|
digTileIndex = result - 1;
|
|
}
|
|
else if (!string.IsNullOrEmpty(itemString))
|
|
{
|
|
var split = itemString.Split(':');
|
|
strObject = split[0];
|
|
if (split.Length >= 2)
|
|
strSaveKey = split[1];
|
|
if (split.Length >= 3)
|
|
{
|
|
if (int.TryParse(split[2], out int tileIndex))
|
|
digTileIndex = tileIndex - 1;
|
|
}
|
|
}
|
|
|
|
// spawn a heart or a ruby
|
|
if (strObject != null)
|
|
{
|
|
// calculate the item hop direction
|
|
var itemPosition = new Vector2(position.X * Values.TileSize + 8, position.Y * Values.TileSize + 12);
|
|
var direction = itemPosition - diggerPosition;
|
|
if (direction != Vector2.Zero)
|
|
direction.Normalize();
|
|
direction = direction * 0.75f + AnimationHelper.DirectionOffset[dir] * 0.75f;
|
|
|
|
var objItem = new ObjItem(this, 0, 0, "j", strSaveKey, strObject, null, true);
|
|
if (!objItem.IsDead)
|
|
{
|
|
objItem.EntityPosition.Set(itemPosition);
|
|
objItem.SetVelocity(new Vector3(direction.X, direction.Y, 1.25f));
|
|
Objects.SpawnObject(objItem);
|
|
}
|
|
}
|
|
|
|
Game1.GameManager.StartDialogPath("dig_dialog");
|
|
|
|
HoleMap.ArrayTileMap[position.X, position.Y, 0] = digTileIndex;
|
|
}
|
|
}
|
|
}
|