Game engine from previous project of mine.

This commit is contained in:
severak 2021-05-01 13:32:41 +02:00
parent 41693b0f5f
commit 278b48b68d
3 changed files with 705 additions and 0 deletions

8
fengari-web.js Normal file

File diff suppressed because one or more lines are too long

413
index.html Normal file
View File

@ -0,0 +1,413 @@
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Vlak ve 4:20</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
border-collapse: collapse;
}
body {
background-color: darkgrey;
font-family: "Lucida console", monospaced;
font-weight: bold;
font-size: 16px;
}
#all {
width: 642px;
height: 480px;
margin: auto;
background-color: #fff;
border: 1px solid #000;
}
#all:after {
content: "";
display: table;
clear: both;
}
#texty {
float: left;
width: 400px;
padding: 5px;
border: 1px solid black;
overflow: auto;
height: 480px;
}
#texty .error {
color: red;
}
#menu {
float: left;
width: 240px;
}
#menu a {
display: block;
color: #000;
text-decoration: none;
padding: 5px;
}
</style>
<script src="fengari-web.js" type="text/javascript"></script>
</head>
<body>
<div id="all">
<div id="texty">
<p>Demo hry vlak ve 4:20</p>
<p>Pokud se hra nespustí, dejte vědět Severákovi a napište mu, jaký prohlížeč používáte.</p>
</div>
<div id="menu">
</div>
</div>
<script>
var el_texty = document.getElementById("texty");
var el_menu = document.getElementById("menu");
function ui_p(txt)
{
el_texty.innerHTML += ("<p>" + txt + "</p>");
el_texty.scrollTop = el_texty.scrollHeight;
}
function ui_cls(txt)
{
el_texty.innerHTML = "";
}
function ui_add_menu(code, txt)
{
el_menu.innerHTML += ("<a href=\"#\" data-code=\""+code+"\">" + txt + "</p>");
}
function ui_cls_menu()
{
el_menu.innerHTML = "";
}
function ui_errormsg(txt)
{
el_texty.innerHTML += ("<p class=\"error\">" + txt.replace("\n", "<br/>") + "</p>");
el_texty.scrollTop = el_texty.scrollHeight;
}
</script>
<script type="application/lua">
local js = require "js"
local window = js.global
gamefile = "syrecky.lua"
-- Hagen game engine
-- (c) Severák 2019-2021
-- 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 = {}
issued_command = {}
-- API
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
room_ord[#room_ord+1] = def
return def
end
function item(def)
def.is_item = true
item_ord[#item_ord+1] = def
return def
end
function cls()
window:ui_cls()
end
local function split_lines(str)
local result = {}
for line in str:gmatch '[^\n]+' do
table.insert(result, line)
end
return result
end
function p(par)
par = par or ""
for line in par:gmatch '[^\n]+' do
window:ui_p(line)
end
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
function has(what)
return game[what].w=="me"
end
function location_of(what)
return game[what].w
end
function is_here(what)
return game[what].w==game.me.w
end
-- end of API
-- 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 show_verbs()
paramsNo = 0
currVerb = ""
params = {}
local here = game[game.me.w]
window:ui_cls_menu();
menu2codes={}
for i,verb in ipairs(verb_ord) do
if verb.always or here[verb.ref] or _has_subj_of(verb) then
local idx=#menu2codes+1
window:ui_add_menu(idx, verb.n);
menu2codes[idx] = verb.ref
end
end
end
function show_items()
local verb = game[currVerb]
local parCode = verb.params[#params+1]
-- print("parCode="..parCode)
window:ui_cls_menu();
menu2codes={}
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
local idx=#menu2codes+1
window:ui_add_menu(idx, item.n);
menu2codes[idx] = item.ref
end
end
if #menu2codes=="0" then
show_verbs() -- situace kdy není možné zobrazit další krok v menu
-- TODO - vyřešit nějak líp
end
end
function process_param(param)
if paramsNo == 0 then
currVerb = param
paramsNo = #game[currVerb].params
else
params[#params+1]=param
end
-- debug:
--[[
print("param="..param)
print("params="..table.concat(params," "))
print("currVerb="..currVerb)
print("paramsNo="..paramsNo)
print("#params="..#params)
print "---"
]]
if #params==paramsNo then
p ""
p("> " .. table.concat(issued_command, " "))
issued_command = {}
game[currVerb].act(table.unpack(params))
if game.round then
game.round()
end
show_verbs()
else
show_items()
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.",
ref = "intro"
},
void = room{
n="void",
d="YOU ARE IN A MAZE OF TWISTY LITTLE PASSAGES, ALL ALIKE.",
ref = "void"
},
vars = {}
}
-- utils
function read_config(filename)
filename = filename or ''
assert(type(filename) == 'string')
local ans,u,k,v,temp = {}, '_'
local f = io.open(filename)
if f then
f:close()
for line in io.lines(filename) do
temp = line:match('^%[(.+)%]$')
if temp ~= nil and u ~= temp then u = temp end
k,v = line:match('^([^=]+)=(.+)$')
if u ~= nil then
ans[u] = ans[u] or {}
if k ~= nil then
ans[u][k] = v
end
end
end
return ans
else
return {}
end
end
-- GUI
-- loads game
load_game, err = loadfile(gamefile, "t", setmetatable(game, {__index=_G}))
if err then
window:ui_errormsg(err)
-- os.exit(1)
end
load_game()
local refcnt = 0
-- 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
refcnt = refcnt + 1
end
end
-- stupid cyber arm glitching again!
for i,obj in ipairs(verb_ord) do
print("verb " .. obj.ref)
end
for i,obj in ipairs(room_ord) do
print("room " .. obj.ref)
end
for i,obj in ipairs(item_ord) do
print("item " .. obj.ref)
end
print("refcnt = " .. refcnt)
print("#verb_ord = " .. #verb_ord)
print("#room_ord = " .. #room_ord)
print("#item_ord = " .. #item_ord)
print("#sum_ord = " .. #verb_ord + #room_ord + #item_ord)
local ok, err = pcall(walk, "intro")
if not ok then
window:ui_errormsg(err)
end
window.document:getElementById("menu"):addEventListener("click", function(eL, ev)
local target = ev.target;
local code = target:getAttribute("data-code")
local text = target.innerText
local i = tonumber(code)
issued_command[#issued_command+1] = text
local ok, err = pcall(process_param, menu2codes[i])
if not ok then
window:ui_errormsg(err)
show_verbs()
end
ev:stopPropagation();
ev:preventDefault();
end)
</script>
</body>
</html>

284
syrecky.lua Normal file
View File

@ -0,0 +1,284 @@
-- Syrečky pro Hagen engine
-- (c) Severák 2015 - 2019
-- / port z ALAN verze
title = "Syrečky 2019"
-- utils
local function randomp(texty)
return function()
p(texty[math.random(1, #texty)])
end
end
-- slovesa
cont=verb{
n="pokračovat",
act = function()
walk(here().cont)
end
}
sever = verb{
n = "sever",
act = function()
walk(here().sever)
end
}
jih = verb{
n = "jih",
act = function()
walk(here().jih)
end
}
desc = verb{
n ="prozkoumej",
params = {"desc"},
act = function(what)
p("Zkoumáš " .. game[what].n .. ":")
local description = game[what].desc
if type(description)=='string' then
p(description)
elseif type(description)=='function' then
description()
end
end
}
open = verb{
n ="otevři",
params = {"open"},
act = function(what)
local description = game[what].open
if type(description)=='string' then
p(description)
elseif type(description)=='function' then
description()
end
end
}
give = verb{
n = "dej",
params = {"darovatelne", "komu"},
act = function(co, komu)
-- tohle je trošku hack
if komu=="naokno" then
p "Na okno raději nic dávat nebudu. Mohli by to unést holubi."
return
end
if co=="syrecky" then
p "Dáváš otci syrečky."
p "Otec: dík, synku."
p "Dokázal jsi to! Dal jsi otci syrečky."
p "Game over!"
move("syrecky", "otec")
else
p("Dáváš otci " .. game[co].n .. ".")
p "Otec: No co já s tím? Tohle nechci."
end
end
}
eat = verb{
n = "sněz",
params = {"jedle"},
act = function(co)
if co=="bageta" then
p "OK. Dám si bagetu."
p "* žvejk, žvejk, žvejk, žvejk"
p "Jo... Byla docela dobrá."
move("bageta", "void")
elseif co=="syrecky" then
p "Syrečky nesním:"
p "a) neuvěřitelně páchnou"
p "b) s plynovou maskou se dost blbě jí"
p "c) kdybych je snědl, nešlo by tuhle hru vyhrát"
end
end
}
-- předměty a lokace
-- OBÝVÁK
obyvak = room{
n="Obývák",
d="Normalní panelakový obývak. Na sever od něj je kuchyně.",
sever="kuchyn"
}
maska = item{
n="plynovou masku",
d="Plynova maska z dob ruske okupace.",
desc="Stará protiplynová maska, patrně ruské výroby. Nechápu co dělala v pohovce.",
w="pohovka",
darovatelne = true
}
pohovka = item{
n="pohovku",
d="Stará prašivá pohovka sotva drží. Pamatuje snad i druhou světovou.",
desc = function()
if maska.w=='pohovka' then
p "Z pohovky čouhá něco divného, zkusím to vytáhnout."
p "Wow! Je to plynová maska!"
move("maska", "me")
else
p "V pohovce je už jenom prach."
end
end,
w="obyvak"
}
otec = item{
n="otce",
d="Na pohovce se valí otec a kouka se na telku.",
desc="Tvůj fotr. Fešák.",
w="obyvak"
}
-- tohle je trošku hack - neumíme moc dobře skloňovat, tak máme pro otce speciální objekt na obdarovávání
otci = item{
n = "otci",
komu = true,
w = "obyvak"
}
televize = item{
n = "televizi",
desc = randomp{
"V telce běží zápas pražských S.",
"Fanoušci v televizi hážou dělobuchy.",
"Právě běží reklama.",
"V televizi je Horst Fuchs: A pokud zavoláte do deseti minut, dostanete ke každému noži koťátko zdarma."
},
w = "obyvak"
}
-- KUCHYNĚ
kuchyn = room{
n="Kuchyň",
d="Umakartová kuchyň z doby vrcholného komunismu. Na jih od ní je obyvák.",
jih="obyvak"
}
syrecky = item{
n = "syrečky",
desc = "Strašně smradlavé syrečky. Smrdí tak mocně, že je to cítit i přes igelit.",
w = "lednice",
darovatelne = true,
jedle = true
}
bageta = item{
n = "bagetu",
d = "Na kuchyňské lince leží bageta.",
desc = function()
p "Typická bageta z benzínky. Kupodivu ani není prošlá."
if game.bageta.w~="me" then
p "Beru ji sebou."
move("bageta", "me")
end
end,
darovatelne = true,
jedle = true,
w = "kuchyn"
}
lednice = item{
n="lednici",
d="Spořádaně tu vrní obstarožní lednice",
desc = "Obstarožní lednička značky CALEX. Hotová hrozba pro životní prostředí.",
open = function()
p "Otevíráš ledničku. Dveře vržou."
if syrecky.w=="lednice" then
if maska.w=="me" then
p "Syrečky strašne smrdí, bereš si na pomoc plynovou masku."
move("syrecky", "me")
p "Vypadáš přitom jak stalker ze stejnojmené počitačové hry, ale podařilo se ti vzít syrečky."
else
p "Strašlivý smrad syrečků tě donutil ledničku zase zavřít!"
end
else
p "V lednici však už je jen \"Příšera, která žila v lednici vedle majonézy a za zelným salátem\". A ta tě nezajímá."
end
end,
w="kuchyn"
}
vyhled = item{
n = "výhled",
d = "A je tu krásný výhled na Jihozápadní město",
w="kuchyn",
desc = randomp{
"Paneláky dnes vypadají patřičně depresivně.",
"Před barákem zrovna někomu kradou auto.",
"Před barákem zrovna policajti rozdávají pokuty.",
"Děti si hrajou na hřišti.",
"Důchodkyně pomlouvají tu dnešní mládež.",
"Vietnamc si šel zakouřit před večerku.",
"Gopnici ve vchodu tančí na hardbass.",
"Nikde nikdo s rouškou - není to tím, že je rok 1995?"
},
open="Okno raději otvírat nebudu, mohl by se sem dostat smog."
}
naokno = item{
n = "na okno",
komu = true,
w = "kuchyn"
}
-- META
local sledovani = randomp{
"Otec se napil piva.",
"GOOOOOOOOOOOOOOOL!!!!\nSparťani v televizi právě skórovali. Řve celé sídliště.",
"Otec se raduje, Sparta vede 1:0 .",
"Otec začína být nervózní.\nOtec: Tak kde jsou sakra ty syrečky?!"
}
local zrani = randomp{
"Otec spokojeně mlaská při žraní syrečků.",
"Otec: To je dobrota, to je dobrota.",
"Otec: Mňam, mňam...",
"Otec slastně mlaská při žraní syrečků.",
"Otec se olizuje až za ušima."
}
function round()
if here().ref=="obyvak" then
if syrecky.w=="otec" then
zrani()
else
sledovani()
end
end
end
intro = room{
d=[[SYREČKY 2019 - technologické demo
(verze z 17.8.2019)
(technicky aktualizováno v lednu 2021)
Tvým cílem je donést otci syrečky z kuchyně.
Hru navrhnul Petr Kain v roce 2010, potom sloužila jako česká obdoba Cloak of Darkness.]],
cont="obyvak",
auto_command = "pokračovat"
}