using System using Nemerle using Nemerle.Utility abstract class MapObject [Accessor] \ mutable map : WorldMap [Accessor] \ mutable x : int [Accessor] \ mutable y : int public abstract Draw () : void public virtual Init (map : WorldMap, x : int, y : int) : void this.map = map this.x = x this.y = y PostInit () protected virtual PostInit () : void {} public virtual CanEnter : bool get { false } public virtual MoveTo (x : int, y : int) : void Map [this.x, this.y] = Map [this.x, this.y].Filter (_ != this : object) this.x = x this.y = y Map [x, y] ::= this // returns distance squered public virtual DistanceTo (target : MapObject) : int def dx = X - target.X def dy = Y - target.Y dx * dx + dy * dy public virtual PerformMove () : void {} public abstract Name : string { get; } public virtual Attack (from : MapObject, _damage : int) : void when (from.IsPlayer) Map.Message ($ "You attack the $(Name). It doesn't seem to be impressed.") public virtual IsPlayer : bool { get { false } } class WorldMap width = 78 height = 20 mutable status : string = "" [Accessor (flags = WantSetter)] \ mutable show_all : bool = false map : array [2, list [MapObject]] [Accessor] \ mutable player : Player public Item [x : int, y : int] : list [MapObject] get if (x < 0 || y < 0 || x >= width || y >= height) [] else map [x, y] set { map [x, y] = value } public this () map = array (width, height) ResetMap () public IterMap (f : MapObject -> void) : void for (mutable y = 0; y < height; ++y) for (mutable x = 0; x < width; ++x) map [x, y].Iter (f) public ResetMap () : void def gen = MapGenerator (width, height) def bool_map = gen.Generate () for (mutable x = 0; x < width; ++x) for (mutable y = 0; y < height; ++y) def f = if (bool_map [x, y]) Floor () else Wall () map [x, y] = [f] f.Init (this, x, y) player = Player () player.Init (this, width / 2, height / 2) map [player.X, player.Y] ::= player def add_enemies (n) if (n < 0) {} else def x = Dice.Roll (width) - 1 def y = Dice.Roll (height) - 1 match (map [x, y]) | [_ is Floor] => def e = EnemyUnknown () map [x, y] ::= e e.Init (this, x, y) add_enemies (n - 1) | _ => add_enemies (n) add_enemies (5) public Message (msg : string) : void status += $"$msg " public Draw () : void ConsoleBuffer.Clear () for (mutable y = 0; y < height; ++y) for (mutable x = 0; x < width; ++x) ConsoleBuffer.Goto (x + 1, y + 1) map [x, y].Head.Draw () ConsoleBuffer.Goto(0, height) ConsoleBuffer.DrawString ($ "Vit: $(player.Vitality)($(player.MaxVitality)) " "Str: $(player.Strength) " "Sta: $(player.Stamina)", ConsoleColor.Green) ConsoleBuffer.Goto(0, height + 1) ConsoleBuffer.DrawString (status, ConsoleColor.Yellow) status = "" ConsoleBuffer.Flush () public PlayerCanSee (target : MapObject) : bool player.DistanceTo (target) < 15 public PerformMove () : void IterMap (fun (x) { unless (x.IsPlayer) x.PerformMove (); }) player.PerformMove () public MainLoop () : void try while (true) Draw () PerformMove () catch | e => Console.WriteLine (e) _ = Console.ReadLine () public static Main () : void def world = WorldMap () world.MainLoop ()