+added a YARD sample.
This commit is contained in:
parent
426bf04b81
commit
7d378648dc
23
sample/yard/README.md
Normal file
23
sample/yard/README.md
Normal file
@ -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
|
47
sample/yard/entity.bas
Normal file
47
sample/yard/entity.bas
Normal file
@ -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
|
20
sample/yard/goal.bas
Normal file
20
sample/yard/goal.bas
Normal file
@ -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
|
259
sample/yard/level.bas
Normal file
259
sample/yard/level.bas
Normal file
@ -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
|
95
sample/yard/map.bas
Normal file
95
sample/yard/map.bas
Normal file
@ -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
|
12
sample/yard/monster.bas
Normal file
12
sample/yard/monster.bas
Normal file
@ -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
|
20
sample/yard/npc.bas
Normal file
20
sample/yard/npc.bas
Normal file
@ -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
|
15
sample/yard/player.bas
Normal file
15
sample/yard/player.bas
Normal file
@ -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
|
30
sample/yard/start.bas
Normal file
30
sample/yard/start.bas
Normal file
@ -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()
|
83
sample/yard/utils.bas
Normal file
83
sample/yard/utils.bas
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user