362 lines
7.8 KiB
Lua
362 lines
7.8 KiB
Lua
|
||
-- Hagen game engine
|
||
-- (c) Sever k 2019
|
||
|
||
-- verze pro DOS
|
||
|
||
-- k¢d nedoporuŸuju nikomu Ÿ¡st, proto§e z rodek vzniknul bØhem jednoho odpoledne
|
||
|
||
-- inspirace
|
||
-- - hra Gateway od Legend entrertaiment
|
||
-- - textovky od Petra Kaina
|
||
-- - textovkovì engine INSTEAD
|
||
|
||
-- globals
|
||
|
||
paramsNo = 0
|
||
params = {}
|
||
currVerb = nil
|
||
|
||
verb_ord = {}
|
||
room_ord = {}
|
||
item_ord = {}
|
||
|
||
menu2codes = {}
|
||
text2codes = {}
|
||
|
||
-- constructors
|
||
|
||
function verb(def)
|
||
def.is_verb = true
|
||
def.params = def.params or {}
|
||
verb_ord[#verb_ord+1] = def
|
||
return def
|
||
end
|
||
|
||
function room(def)
|
||
def.is_room = true
|
||
return def
|
||
end
|
||
|
||
function item(def)
|
||
def.is_item = true
|
||
item_ord[#item_ord+1] = def
|
||
return def
|
||
end
|
||
|
||
-- utils from lua wiki
|
||
|
||
-- explode(seperator, string)
|
||
function explode(d,p)
|
||
local t, ll
|
||
t={}
|
||
ll=0
|
||
if(#p == 1) then
|
||
return {p}
|
||
end
|
||
while true do
|
||
l = string.find(p, d, ll, true) -- find the next d in the string
|
||
if l ~= nil then -- if "not not" found then..
|
||
table.insert(t, string.sub(p,ll,l-1)) -- Save it in our array.
|
||
ll = l + 1 -- save just after where we found it for searching next time.
|
||
else
|
||
table.insert(t, string.sub(p,ll)) -- Save what's left in our array.
|
||
break -- Break at end, as it should be, according to the lua manual.
|
||
end
|
||
end
|
||
return t
|
||
end
|
||
|
||
function wrap(str, limit, indent, indent1)
|
||
indent = indent or ""
|
||
indent1 = indent1 or indent
|
||
limit = limit or 72
|
||
local here = 1-#indent1
|
||
local function check(sp, st, word, fi)
|
||
if fi - here > limit then
|
||
here = st - #indent
|
||
return "\n"..indent..word
|
||
end
|
||
end
|
||
return indent1..str:gsub("(%s+)()(%S+)()", check)
|
||
end
|
||
|
||
function reflow(str, limit, indent, indent1)
|
||
return (str:gsub("%s*\n%s+", "\n")
|
||
:gsub("%s%s+", " ")
|
||
:gsub("[^\n]+",
|
||
function(line)
|
||
return wrap(line, limit, indent, indent1)
|
||
end))
|
||
end
|
||
|
||
-- global functions
|
||
|
||
function cls()
|
||
os.execute "cls"
|
||
end
|
||
|
||
function p(par)
|
||
if par==nil then
|
||
return -- not write nil
|
||
end
|
||
print(reflow(par, 80)) -- reflowing to 80 cols limit
|
||
end
|
||
|
||
function here()
|
||
return game[game.me.w]
|
||
end
|
||
|
||
function move(what, where)
|
||
game[what].w = where
|
||
end
|
||
|
||
function walk(where, nocls)
|
||
assert(game[where], "room " .. where .. " does not exist")
|
||
move("me", where)
|
||
if not nocls then
|
||
cls()
|
||
end
|
||
p(game[where].n)
|
||
p(game[where].d)
|
||
for i,item in ipairs(item_ord) do
|
||
if item.d and item.w==here().ref then
|
||
p(item.d)
|
||
end
|
||
end
|
||
show_verbs()
|
||
end
|
||
|
||
-- TODO - checkovat vçechny parametry
|
||
function _has_subj_of(verb)
|
||
local parCode = verb.params[#params+1]
|
||
for i,item in ipairs(item_ord) do
|
||
if item[parCode] and (verb.global_reach or item.w==here().ref or item.w=="me") then
|
||
return true
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
function odmezeruj(n)
|
||
return string.gsub(n, " ", "-")
|
||
end
|
||
|
||
function show_verbs()
|
||
paramsNo = 0
|
||
currVerb = ""
|
||
params = {}
|
||
text2codes = {}
|
||
local here = game[game.me.w]
|
||
menu2codes={}
|
||
for i,verb in ipairs(verb_ord) do
|
||
if verb.always or here[verb.ref] or _has_subj_of(verb) then
|
||
text2codes[odmezeruj(verb.n)] = verb.ref
|
||
end
|
||
end
|
||
end
|
||
|
||
function show_items()
|
||
local verb = game[currVerb]
|
||
for i,parCode in ipairs(verb.params) do
|
||
for i,item in ipairs(item_ord) do
|
||
if item[parCode] and (verb.global_reach or item.w==here().ref or item.w=="me") then
|
||
text2codes[odmezeruj(item.n)] = item.ref
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
function guess_code(prefix)
|
||
if text2codes[prefix] then
|
||
return text2codes[prefix]
|
||
end
|
||
|
||
local possible = {}
|
||
|
||
for word,code in pairs(text2codes) do
|
||
local at = string.find(word, prefix, 1, true)
|
||
if at==1 then
|
||
possible[#possible+1] = code
|
||
end
|
||
end
|
||
|
||
if #possible==1 then
|
||
return possible[1]
|
||
end
|
||
end
|
||
|
||
-- game defaults
|
||
|
||
game = {
|
||
title = "Emty game",
|
||
me = item{
|
||
w="intro"
|
||
},
|
||
intro = room{
|
||
n="void",
|
||
d="YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE."
|
||
},
|
||
void = room{
|
||
n="void",
|
||
d="YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE."
|
||
},
|
||
vars = {}
|
||
}
|
||
|
||
-- speci ln¡ cli pý¡kazy
|
||
|
||
game.refresh = verb{
|
||
n = "r",
|
||
always = true,
|
||
act = function()
|
||
walk(here().ref, true)
|
||
end
|
||
}
|
||
|
||
game.pomoc = verb{
|
||
n = "pomoc",
|
||
always = true,
|
||
act = function()
|
||
p "Hra se ovl d kl vesnic¡."
|
||
p "Pro pýehled slov, kterìm hra rozum¡ zadej pýikaz 'slova'."
|
||
p "Pý¡kaz 'r' znova vyp¡çe m¡stnost, pý¡kaz 'q' ukonŸ¡ hru."
|
||
p "Slova nen¡ nutn‚ zad vat cel , napý. 'pro tel' funguje stejnØ jako 'prozkoumej televizi'."
|
||
end
|
||
}
|
||
|
||
game.slova = verb{
|
||
n = "slova",
|
||
always = true,
|
||
act = function()
|
||
show_verbs()
|
||
|
||
local slova = {}
|
||
for text, code in pairs(text2codes) do
|
||
slova[#slova+1] = text
|
||
end
|
||
|
||
print "Platn slova:"
|
||
print(table.concat(slova, " "))
|
||
|
||
print "Napiçte sloveso, jeho§ parametry chcete vypsat: (Nic nic nevyp¡çe.)"
|
||
local sloveso = io.read()
|
||
|
||
if sloveso ~= "" and text2codes[sloveso] then
|
||
currVerb = text2codes[sloveso]
|
||
text2codes = {}
|
||
show_items()
|
||
local slova = {}
|
||
for text, code in pairs(text2codes) do
|
||
slova[#slova+1] = text
|
||
end
|
||
|
||
if #slova>0 then
|
||
print "Platn‚ parametry pý¡kazu:"
|
||
print(table.concat(slova, " "))
|
||
else
|
||
print "Pý¡kaz nem parametry."
|
||
end
|
||
show_verbs()
|
||
end
|
||
print ""
|
||
end
|
||
}
|
||
|
||
-- GUI loop
|
||
|
||
function gameloop()
|
||
while true do
|
||
io.stdout:write(">")
|
||
local inp = io.read()
|
||
|
||
if inp=="" and here().auto_command then
|
||
-- hack - auto pokraŸov n¡
|
||
inp = here().auto_command
|
||
print(">"..inp)
|
||
end
|
||
|
||
if inp == "?" then
|
||
inp = "pomoc"
|
||
end
|
||
|
||
if inp == "" then
|
||
-- continue
|
||
elseif inp == "q" or inp == "konec" or inp == "exit" then
|
||
return
|
||
else
|
||
show_verbs()
|
||
local words = explode(" ", inp)
|
||
local verb = guess_code(words[1])
|
||
if not verb then
|
||
print("Nerozum¡m slovesu '"..words[1].."'.")
|
||
else
|
||
local valid_input = true
|
||
currVerb = verb
|
||
show_items()
|
||
-- print("currVerb="..currVerb.."#")
|
||
params = {}
|
||
table.remove(words, 1)
|
||
|
||
if #game[currVerb].params > #words then
|
||
print "Pý¡kaz zýejmØ nen¡ celì."
|
||
end
|
||
|
||
for i,word in ipairs(words) do
|
||
-- TODO tady kontrolovat poýad¡ pý¡kaz…
|
||
local param = guess_code(word)
|
||
if not param then
|
||
print("Nerozum¡m slovu '" .. word .. "'.")
|
||
valid_input = false
|
||
else
|
||
params[#params+1] = param
|
||
end
|
||
end
|
||
|
||
if valid_input then
|
||
|
||
game[currVerb].act(table.unpack(params))
|
||
if game.round then
|
||
game.round()
|
||
end
|
||
|
||
print ""
|
||
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
|
||
local gamefile
|
||
if arg[1] then
|
||
gamefile = arg[1]
|
||
else
|
||
gamefile = "syrecky.lua"
|
||
|
||
|
||
end
|
||
|
||
|
||
-- loads game
|
||
load_game, err = loadfile(gamefile, "t", setmetatable(game, {__index=_G}))
|
||
|
||
if err then
|
||
print(err)
|
||
os.exit(1)
|
||
end
|
||
|
||
load_game()
|
||
|
||
-- add refs
|
||
for ref,obj in pairs(game) do
|
||
if type(obj)=='table' and (obj.is_verb or obj.is_room or obj.is_item) then
|
||
obj.ref = ref
|
||
end
|
||
end
|
||
|
||
|
||
walk("intro")
|
||
gameloop()
|