From 7d378648dc037a1cf5d4adab6475a1e2373011d3 Mon Sep 17 00:00:00 2001 From: paladin-t Date: Wed, 2 Mar 2016 13:44:34 +0800 Subject: [PATCH] +added a YARD sample. --- sample/yard/README.md | 23 ++++ sample/yard/entity.bas | 47 ++++++++ sample/yard/goal.bas | 20 ++++ sample/yard/level.bas | 259 ++++++++++++++++++++++++++++++++++++++++ sample/yard/map.bas | 95 +++++++++++++++ sample/yard/monster.bas | 12 ++ sample/yard/npc.bas | 20 ++++ sample/yard/player.bas | 15 +++ sample/yard/start.bas | 30 +++++ sample/yard/utils.bas | 83 +++++++++++++ 10 files changed, 604 insertions(+) create mode 100644 sample/yard/README.md create mode 100644 sample/yard/entity.bas create mode 100644 sample/yard/goal.bas create mode 100644 sample/yard/level.bas create mode 100644 sample/yard/map.bas create mode 100644 sample/yard/monster.bas create mode 100644 sample/yard/npc.bas create mode 100644 sample/yard/player.bas create mode 100644 sample/yard/start.bas create mode 100644 sample/yard/utils.bas diff --git a/sample/yard/README.md b/sample/yard/README.md new file mode 100644 index 0000000..0e64f7f --- /dev/null +++ b/sample/yard/README.md @@ -0,0 +1,23 @@ +**YARD (Yet Another RPG Dungeon)** + +Copyright (C) 2016 Wang Renxin. All rights reserved. + +Yet Another RPG Dungeon is a text based game. It's aimed to be a comprehensive example and or a tutorial which shows multiple concepts of MY-BASIC. + +Usage + +**Windows:** + + my_basic start.bas + +**OS X:** + + my_basic_mac start.bas + +**Others:** + + my_basic_bin start.bas + +It requires an importing directories information if the working directory of your interpreter is `my_basic/output/`: + + my_basic -f ../sample/yard/ ../sample/yard/start.bas diff --git a/sample/yard/entity.bas b/sample/yard/entity.bas new file mode 100644 index 0000000..848fcdf --- /dev/null +++ b/sample/yard/entity.bas @@ -0,0 +1,47 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +class entity + var name = "" + + var alive = true + + var hp = 0 + var atk = 0 + var defence = 0 + + var dead_handler = nil + + def tostring() + return "Entity [" + name + "]" + enddef + + def init(_hp, _atk, _def) + hp = _hp + atk = _atk + defence = _def + enddef + + def kill() + if dead_handler <> nil then + dead_handler(me) + endif + alive = false + enddef + + def hurt_by(e) + p = e.atk / defence + if p <= 0 then + p = 1 + endif + hp = hp - p + if hp < 0 then + hp = 0 + endif + if hp = 0 then + kill() + endif + enddef +endclass diff --git a/sample/yard/goal.bas b/sample/yard/goal.bas new file mode 100644 index 0000000..4d812cf --- /dev/null +++ b/sample/yard/goal.bas @@ -0,0 +1,20 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +import "entity.bas" + +class goal(entity) + var take_handler = nil + + def tostring() + return "Goal [" + name + "]" + enddef + + def take(e) + if take_handler <> nil then + take_handler(me) + endif + enddef +endclass diff --git a/sample/yard/level.bas b/sample/yard/level.bas new file mode 100644 index 0000000..68ba276 --- /dev/null +++ b/sample/yard/level.bas @@ -0,0 +1,259 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +import "goal.bas" +import "map.bas" +import "monster.bas" +import "npc.bas" + +class game_status + var invalid = 0 + var playing = 1 + var win = 2 + var lose = 3 +endclass + +class level + var status = game_status.invalid + var roads = new(map) + var role = nil + + def set_node(x, y, ...) + n = new(map_node) + roads.set_node(x, y, n) + n.set_valid_dirs(...) + + return n + enddef + + def get_node(x, y) + return roads.get_node(x, y) + enddef + + def create() + roads.set_size(3, 3) + + n = set_node(0, 0, dirs.right_dir) + + n = set_node(1, 0, dirs.left_dir, dirs.right_dir, dirs.up_dir) + + n = set_node(2, 0, dirs.left_dir, dirs.up_dir) + + m = new(monster) + m.name = "Skeleton" + m.init(7, 1, 1) + m.dead_handler = lambda (_) + ( + print "- " + _.name + " dead"; + ) + n.add_entity(m) + + n = set_node(0, 1, dirs.right_dir) + + n = set_node(1, 1, dirs.left_dir, dirs.up_dir, dirs.down_dir) + + m = new(monster) + m.name = "Slime" + m.init(5, 1, 1) + m.dead_handler = lambda (_) + ( + print "- " + _.name + " dead"; + ) + n.add_entity(m) + + n = set_node(2, 1, dirs.up_dir, dirs.down_dir) + + n = set_node(0, 2, dirs.right_dir) + + g = new(goal) + g.name = "Goal" + n.add_entity(g) + + n = set_node(1, 2, dirs.left_dir, dirs.right_dir, dirs.down_dir) + + m = new(monster) + m.name = "Dragon" + m.init(10, 5, 1) + m.dead_handler = lambda (_) + ( + print "- " + _.name + " dead"; + ) + n.add_entity(m) + + n = set_node(2, 2, dirs.left_dir, dirs.down_dir) + + c = new(npc) + c.name = "Therapist" + c.talk_handler = lambda (_) + ( + print "- " + _.name + ": give you 23 HP"; + _.alive = false + role.hp = role.hp + 23 + ) + n.add_entity(c) + enddef + + def start(r) + status = game_status.playing + role = r + role.pos.x = 0 + role.pos.y = 0 + enddef + + def format() + if status = game_status.win then + print "You Win"; + elseif status = game_status.lose then + print "Game Over"; + + return + elseif status = game_status.playing then + print "<" + str(role.pos.x) + ", " + str(role.pos.y) + ">"; + + n = roads.get_node(role.pos.x, role.pos.y) + + contains_goal = false + gl = n.get_entities(goal) + it = iterator(gl) + if move_next(it) then + contains_goal = true + ent = get(it) + print " ", ent; + it = nil + endif + + contains_npc = false + np = n.get_entities(npc) + it = iterator(np) + if move_next(it) then + contains_npc = true + ent = get(it) + print " ", ent; + it = nil + endif + + contains_monster = false + ms = n.get_entities(monster) + it = iterator(ms) + if move_next(it) then + contains_monster = true + ent = get(it) + print " ", ent; + it = nil + endif + + print "[Operations]"; + + if contains_goal then + print " G: Accomplish goal"; + endif + + if contains_npc then + print " T: Talk to " + ent.name; + endif + + if contains_monster then + print " A: Attack " + ent.name; + else + if bit_and(n.valid_dirs, dirs.left_dir) then + print " W: Go west"; + endif + + if bit_and(n.valid_dirs, dirs.right_dir) then + print " E: Go east"; + endif + + if bit_and(n.valid_dirs, dirs.up_dir) then + print " N: Go north"; + endif + + if bit_and(n.valid_dirs, dirs.down_dir) then + print " S: Go south"; + endif + endif + endif + + print " Q: Quit game"; + enddef + + def try_update_monster() + enddef + + def update(ipt) + if ipt = "q" then print "Bye." : end + + if status <> game_status.playing then + return false + endif + + n = roads.get_node(role.pos.x, role.pos.y) + + gl = n.get_entities(goal) + it = iterator(gl) + if ipt = "g" and move_next(it) then + ent = get(it) + it = nil + status = game_status.win + + return true + endif + + np = n.get_entities(npc) + it = iterator(np) + if ipt = "t" and move_next(it) then + ent = get(it) + it = nil + ent.talk(role) + + return true + endif + + contains_monster = false + ms = n.get_entities(monster) + it = iterator(ms) + if move_next(it) then + contains_monster = true + + if ipt = "a" then + ent = get(it) + it = nil + ent.hurt_by(role) + role.hurt_by(ent) + + return true + endif + endif + + if not contains_monster then + if ipt = "w" and bit_and(n.valid_dirs, dirs.left_dir) then + role.pos.x = role.pos.x - 1 + + return true + endif + + if ipt = "e" and bit_and(n.valid_dirs, dirs.right_dir) then + role.pos.x = role.pos.x + 1 + + return true + endif + + if ipt = "n" and bit_and(n.valid_dirs, dirs.up_dir) then + role.pos.y = role.pos.y + 1 + + return true + endif + + if ipt = "s" and bit_and(n.valid_dirs, dirs.down_dir) then + role.pos.y = role.pos.y - 1 + + return true + endif + endif + + print "Invalid input."; + + return false + enddef +endclass diff --git a/sample/yard/map.bas b/sample/yard/map.bas new file mode 100644 index 0000000..d8ba58d --- /dev/null +++ b/sample/yard/map.bas @@ -0,0 +1,95 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +import "utils.bas" + +class dirs + var none_dir = 0 + var left_dir = 1 + var right_dir = 2 + var up_dir = 4 + var down_dir = 8 +endclass + +class map_node + var pos = new(point) + var valid_dirs = dirs.none_dir + var entities = list() + + def tostring() + s = pos.tostring() + return "Map Node " + s + enddef + + def set_valid_dirs(...) + dir = 0 + while len(...) + dir = bit_or(dir, ...) + wend + valid_dirs = dir + enddef + + def add_entity(ent) + if exist(entities, ent) then + log.w("Already added " + ent.name) + + return false + endif + + push(entities, ent) + + return true + enddef + + def get_entities(y) + ret = list() + it = iterator(entities) + while move_next(it) + ent = get(it) + if ent is y and ent.alive then + push(ret, ent); + endif + wend + + return ret + enddef +endclass + +class map + var width = 0 + var height = 0 + + var nodes = dict() + + def tostring() + return "Map" + enddef + + def hash_pos(x, y) + return x + y * width + enddef + + def set_size(w, h) + width = w + height = h + + clear(nodes) + enddef + + def set_node(x, y, n) + h = hash_pos(x, y) + n.pos.x = x + n.pos.y = y + nodes(h) = n + + return n + enddef + + def get_node(x, y) + h = hash_pos(x, y) + + return nodes(h) + enddef +endclass diff --git a/sample/yard/monster.bas b/sample/yard/monster.bas new file mode 100644 index 0000000..281f781 --- /dev/null +++ b/sample/yard/monster.bas @@ -0,0 +1,12 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +import "entity.bas" + +class monster(entity) + def tostring() + return "Monster [" + name + "]" + enddef +endclass diff --git a/sample/yard/npc.bas b/sample/yard/npc.bas new file mode 100644 index 0000000..caa9d0f --- /dev/null +++ b/sample/yard/npc.bas @@ -0,0 +1,20 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +import "entity.bas" + +class npc(entity) + var talk_handler = nil + + def tostring() + return "NPC [" + name + "]" + enddef + + def talk(e) + if talk_handler <> nil then + talk_handler(me) + endif + enddef +endclass diff --git a/sample/yard/player.bas b/sample/yard/player.bas new file mode 100644 index 0000000..42c9d83 --- /dev/null +++ b/sample/yard/player.bas @@ -0,0 +1,15 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +import "entity.bas" +import "utils.bas" + +class player(entity) + var pos = new(point) + + def tostring() + return "Player [" + name + "]" + enddef +endclass diff --git a/sample/yard/start.bas b/sample/yard/start.bas new file mode 100644 index 0000000..98f18ad --- /dev/null +++ b/sample/yard/start.bas @@ -0,0 +1,30 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +import "level.bas" +import "player.bas" + +print "Welcome to Yet Another RPG Dungeon!"; + +level.create() +_role = new(player) +_role.init(10, 2, 1) +_role.dead_handler = lambda (_) +( + print "- You are dead"; + level.status = game_status.lose +) +level.start(_role) +_turn = 1 +while _role.alive + print "[---- Turn ", _turn, ", HP ", _role.hp, ", ATK ", _role.atk, " ----]"; + level.format() + input _i$ + cls() + if level.update(_i$) then + _turn = _turn + 1 + endif +wend +level.format() diff --git a/sample/yard/utils.bas b/sample/yard/utils.bas new file mode 100644 index 0000000..cc707b5 --- /dev/null +++ b/sample/yard/utils.bas @@ -0,0 +1,83 @@ +' Yet Another RPG Dungeon is a text based game. +' It's aimed to be a comprehensive example and or a tutorial of MY-BASIC. +' Copyright (C) 2016 Wang Renxin. All rights reserved. +' For more information about MY-BASIC, see https://github.com/paladin-t/my_basic/ + +def cls() + if os() = "WIN" then + sys("cls") + else + sys("clear") + endif +enddef + +def bit_and(a, b) + c = 0 + for i = 0 to 31 + if (a mod 2) and (b mod 2) then + t = 1 + else + t = 0 + endif + c = c + t * (2 ^ i) + a = fix(a / 2) + b = fix(b / 2) + next + + return c +enddef + +def bit_or(a, b) + c = 0 + for i = 0 to 31 + if (a mod 2) or (b mod 2) then + t = 1 + else + t = 0 + endif + c = c + t * (2 ^ i) + a = fix(a / 2) + b = fix(b / 2) + next + + return c +enddef + +def bit_xor(a, b) + c = 0 + for i = 0 to 31 + if (a mod 2) <> (b mod 2) then + t = 1 + else + t = 0 + endif + c = c + t * (2 ^ i) + a = fix(a / 2) + b = fix(b / 2) + next + + return c +enddef + +class point + var x = 0 + var y = 0 + + def tostring() + return "[" + str(x) + ", " + str(y) + "]" + enddef +endclass + +class log + def m(msg) + print "Message: " + msg; + enddef + + def w(msg) + print "Warning: " + msg; + enddef + + def e(msg) + print "Error: " + msg; + enddef +endclass