Skip to content

Instantly share code, notes, and snippets.

@kenwebb
Last active October 27, 2018 11:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kenwebb/40731e8f7a7ece0236e656fb24036e4a to your computer and use it in GitHub Desktop.
Save kenwebb/40731e8f7a7ece0236e656fb24036e4a to your computer and use it in GitHub Desktop.
Island B3
<?xml version="1.0" encoding="UTF-8"?>
<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Sat Oct 27 2018 07:51:12 GMT-0400 (Eastern Daylight Time)-->
<XholonWorkbook>
<Notes><![CDATA[
Xholon
------
Title: Island B3
Description:
Url: http://www.primordion.com/Xholon/gwt/
InternalName: 40731e8f7a7ece0236e656fb24036e4a based on 4f97c3f2934147b99e1245dc0c6316cb based on bdd87230bacc981ec836786bfcf82cd0
Keywords:
My Notes
--------
October 13, 2018
Island B3 (based on Island B1 and Island B2)
This workbook was started just after the Oct 12 testing at the Carleton lab.
TODO
<Volleyball roleName="Wilson"><Icon>https://upload.wikimedia.org/wikipedia/en/f/fb/Wilson_The_Volleyball.jpg</Icon></Volleyball>
To capture the IndexedDB data at the end:
----------------------------------------
var db;
var request = indexedDB.open("IslandGameDB");
request.onerror = function(event) {
console.log("Oops");
};
request.onsuccess = function(event) {
db = event.target.result;
var objectStore = db.transaction("session").objectStore("session");
objectStore.getAll().onsuccess = function(event) {
var jsonStr = JSON.stringify(event.target.result).trim();
jsonStr = jsonStr.substring(1, jsonStr.length-1); // remove [ and ]
results = jsonStr.replace(/},{/gi, "}\n{");
console.log(results);
};
var objectStore = db.transaction("avastate").objectStore("avastate");
objectStore.getAll().onsuccess = function(event) {
var jsonStr = JSON.stringify(event.target.result).trim();
jsonStr = jsonStr.substring(1, jsonStr.length-1); // remove [ and ]
results = jsonStr.replace(/},{/gi, "}\n{");
console.log(results);
};
};
webrtc test
------
Schweiz (drag into StGallen) this works
<DataExport>
<Attribute_String roleName="SessionData">test 123</Attribute_String>
<Attribute_String roleName="AvastateData">test 456</Attribute_String>
</DataExport>
OR this works
<DataExport>
<Attribute_String roleName="SessionData">[
{"sessionid":"X1539969929087","gameid":"Island B3","gamerev":"12","islandID":"0"},
{"sessionid":"X1539970416390","gameid":"Island B3","gamerev":"12","islandID":"2"},
{"sessionid":"X1539974532327","gameid":"Island B3","gamerev":"12","islandID":"0"},
{"sessionid":"X1539975404066","gameid":"Island B3","gamerev":"12","islandID":"2"},
{"sessionid":"X1539976100255","gameid":"Island B3","gamerev":"12","islandID":"1"},
{"sessionid":"X1539978066439","gameid":"Island B3","gamerev":"12","islandID":"1"},
{"sessionid":"X1539978402618","gameid":"Island B3","gamerev":"12","islandID":"2"},
{"sessionid":"X1539978546341","gameid":"Island B3","gamerev":"12","islandID":"0"},
{"sessionid":"X1539980933947","gameid":"Island B3","gamerev":"12","islandID":"2"},
{"sessionid":"X1539981118827","gameid":"Island B3","gamerev":"12","islandID":"1"},
{"sessionid":"X1539983932871","gameid":"Island B3","gamerev":"12","islandID":"1"},
{"sessionid":"X1539984165053","gameid":"Island B3","gamerev":"12","islandID":"0"}
]</Attribute_String>
<Attribute_String roleName="AvastateData">[
{"timestep":1,"state":"CoastalCell (Castaway)","energy":"100","sessionid":"X1539970416390"},
{"timestep":16,"state":"LandCell (Castaway)","energy":"99","sessionid":"X1539970416390"},
{"timestep":23,"state":"LandCell (Castaway)","energy":"98","sessionid":"X1539970416390"},
{"timestep":25,"state":"LandCell (Castaway)","energy":"97","sessionid":"X1539970416390"},
{"timestep":27,"state":"LandCell (Castaway)","energy":"96","sessionid":"X1539970416390"},
{"timestep":32,"state":"LandCell (RedTree (PricklyFruit*10 Thorn*10 Vine*10) Castaway)","energy":"95","sessionid":"X1539970416390"},
{"timestep":45,"state":"LandCell (RedTree (PricklyFruit*10 Thorn*9 Vine*10) Castaway (Thorn))","energy":"95","sessionid":"X1539970416390"},
{"timestep":54,"state":"LandCell (RedTree (PricklyFruit*10 Thorn*9 Vine*9) Castaway (Thorn Vine))","energy":"95","sessionid":"X1539970416390"},
{"timestep":74,"state":"LandCell (Castaway (Thorn Vine))","energy":"94","sessionid":"X1539970416390"},
{"timestep":76,"state":"CoastalCell (Castaway (Thorn Vine))","energy":"93","sessionid":"X1539970416390"},
{"timestep":78,"state":"LandCell (Castaway (Thorn Vine))","energy":"92","sessionid":"X1539970416390"},
{"timestep":83,"state":"LandCell (Castaway (Thorn Vine))","energy":"91","sessionid":"X1539970416390"},
{"timestep":85,"state":"LandCell (GreenTree (Fruit*10 JuicyBerry*10 Stick*10) Castaway (Thorn Vine))","energy":"90","sessionid":"X1539970416390"},
{"timestep":94,"state":"LandCell (GreenTree (Fruit*10 JuicyBerry*10 Stick*9) Castaway (Thorn Vine Stick))","energy":"90","sessionid":"X1539970416390"},
{"timestep":261,"state":"CoastalCell (Castaway (Fruit Stick))","energy":"69","sessionid":"X1539976100255"},
{"timestep":264,"state":"CoastalCell (Ottawa (Carleton (Library (Starbucks (IslandControlCentre Troll) Ken) Able) Baker Jen) Castaway (Fruit Stick))","energy":"68","sessionid":"X1539976100255"},
{"timestep":265,"state":"CoastalCell (Ottawa (Carleton (Library (Starbucks (IslandControlCentre (Troll)) Ken) Able) Baker Jen) Castaway (Fruit Stick))","energy":"68","sessionid":"X1539976100255"},
{"timestep":266,"state":"CoastalCell (Ottawa (Carleton (Library (Starbucks (IslandControlCentre (Troll) Ken)) Able) Baker Jen) Castaway (Fruit Stick))","energy":"68","sessionid":"X1539976100255"},
{"timestep":28,"state":"LandCell (GreenTree (Fruit*10 JuicyBerry*10 Stick*10) Castaway)","energy":"93","sessionid":"X1539984165053"},
{"timestep":34,"state":"LandCell (Castaway)","energy":"92","sessionid":"X1539984165053"}
]</Attribute_String>
</DataExport>
Canada (drag into Avatar in Ontario) this works
<script>
var a = this.parent();
a.action("script;\ngo port0;\ntakeclone dataExport;\ngo port0;\ndrop dataExport;\n");
</script>
http://127.0.0.1:8888/XholonWebRTC.html?app=Island+B3&apprev=17&src=lstr&gui=none&hide=xhtop,xhtabs,xhsvg,xhfooter&localid0=Daniel101
I can reuse my "WebRTC complex Schweiz 2018" app to test interaction with "Island B3":
http://www.primordion.com/Xholon/gwt/XholonWebRTC.html?app=9c111d1ffac80a6905964d9433a532b7&src=gist&gui=none&remoteid0=Daniel101&remoteid2=Charlie101
Authors of books about island castaways:
AuthorName BookName localid0
----------------- --------------------- ---------
Daniel Defoe Robinson Crusoe Daniel101
Johann David Wyss Swiss Family Robinson Johann101
Jules Verne Mysterious Island Jules101
To export the complete contents of a Avatar's GridCell (Dev Tools)
---------
var ava = xh.avatar();
var xprt = xh.xport("Xml", ava.parent(), "{}", false, true);
console.log(xprt);
result:
<?xml version="1.0" encoding="UTF-8"?>
<LandCell NeighType="2" NumNeighbors="4" MaxPorts="8">
<Avatar roleName="Castaway" speechOut="0" calories="62" islandID="1"></Avatar>
</LandCell>
<?xml version="1.0" encoding="UTF-8"?>
<CoastalCell NeighType="2" NumNeighbors="4" MaxPorts="8">
<TreasureChest>
<Stick maxClones="1"></Stick>
<Vine maxClones="1"></Vine>
<Thorn maxClones="1"></Thorn>
<CatTreat maxClones="10"></CatTreat>
<Volleyball roleName="Wilson" maxClones="1">
<Annotation>https://en.wikipedia.org/wiki/Cast_Away</Annotation>
</Volleyball>
</TreasureChest>
<Avatar roleName="Castaway" speechOut="0" calories="51" menu="menu" islandID="1"></Avatar>
</CoastalCell>
To drag in a new TreasureChest
------------------------------
<TreasureChest>
<Stick maxClones="1"></Stick>
<Vine maxClones="1"></Vine>
<Thorn maxClones="1"></Thorn>
<CatTreat maxClones="10"></CatTreat>
<Volleyball roleName="Wilson" maxClones="1"/>
</TreasureChest>
To convert number of milliseconds to a human-readable date
----------------------------------------------------------
var date = new Date(1540573802858);
console.log(date);
github Revisions (Island B1)
----------------
1. initial commit to github
An inheritance hierarchy (IH) with Jen's types, plus Xholon framework types and other types suggested by Ken.
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/d0785bc7c703cc805a02e0b7bf912f585e597e94
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/d0785bc7c703cc805a02e0b7bf912f585e597e94&src=gist&gui=clsc
2. added github ID bdd87230bacc981ec836786bfcf82cd0
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/6095937648822299f6db0643eea9be8e8243c028
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/6095937648822299f6db0643eea9be8e8243c028#file-xholonworkbook-xml
3. added Class Details: colors, symbols, default content
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/997758bafa41704f2fa91e669ce36f4724a32486
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/997758bafa41704f2fa91e669ce36f4724a32486&src=gist&gui=clsc
4. added basic Composite Structure Hierarchy: grid with grid cells, GridCellPatterns that describe each island, other nodes needed by the Xholon framework
Running the app shows a large blue rectangle, an ocean with nothing in it yet.
The islands won't display until I write a JavaScript behavior.
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/ad2f00d5aaffc281471260448bc40df6a48f9334
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/ad2f00d5aaffc281471260448bc40df6a48f9334&src=gist&gui=none
5. added the Ocean and Island part of the CSH
View this entire subtree using d3cp, to confirm that everything is being created and that the colors are OK.
There are still no JavaScript behaviors, so Ocean and Island nodes have not yet been added to the grid.
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/8bc4a6fac2086ed5929af7b99907ab62cbd06e7a
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/8bc4a6fac2086ed5929af7b99907ab62cbd06e7a&src=gist&gui=none
6. added a simple MinecraftStyleRecipeBook, with recipes for making FishingRod and Hut
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/f69f07c3ff662cfdbc225cfdc3120051d8c6bd28
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/f69f07c3ff662cfdbc225cfdc3120051d8c6bd28&src=gist&gui=none
7. added default SVG
8. added JavaScript behaviors
These are mostly the same behaviors in "Island 3".
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/e670b7428bb36ea641d3f6bb840ec39db99a411e
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/e670b7428bb36ea641d3f6bb840ec39db99a411e&src=gist&gui=none
9. added Minecraft-style recipe for Hut. It requires 3 sticks and 3 vines.
use multi-line string to define avatarKeyMap
added separate "Whack" keys in avatarKeyMap to clone: "c" Stick, "k" Vine, "o" Thorn
start the app with the "out" tab displayed
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/0d1b36a3682deef91983239dbaec7ac636a0f351
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/0d1b36a3682deef91983239dbaec7ac636a0f351&src=gist&gui=none
10.added a JsonRulesEngineRecipeBook with a recipe for FishingRod (not yet active)
added //ava.action('param recipebook JsonRulesEngineRecipeBook-Island;');
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/70e411ad49af0c0f974be64ac28f0e5ac3cf40d3
11.added "NOSCROLL":"true" to avatarKeyMap, to prevent entire screen from scrolling when player presses arrow and space keys
added avatarKeyMap keys for "help commands" and "help keymap"
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/7f13e0f40c942f081333fad6b3f6e13488eaac36
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/7f13e0f40c942f081333fad6b3f6e13488eaac36&src=gist&gui=none
12.player's Avatar needs to be able to "die" if calories == 0
to get started on this, I've added the following IFLang code to all 4 arrow keys in the avatarKeyMap ";ifeq xpath(Avatar) calories 0 exit Space;"
and when the Avatar eats something, the ";become this calories +=50"
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/8b63a450ea1f3960f631b5a58b2a7cad2dd695a4
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/8b63a450ea1f3960f631b5a58b2a7cad2dd695a4&src=gist&gui=none
13.misc
14.Avatar Logger
15.Avatar Logger
16.Avatar Logger
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/9adb7710268260462f5447f8d145fd15fbd931c1
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/9adb7710268260462f5447f8d145fd15fbd931c1&src=gist&gui=none
17.//ava.action('param meteorattr one,two,three,calories'); // testing
"E":"eat;become this calories +=50", "e":"eat xpath(*);become this calories +=25"
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/be479fc0ddfd65861be4a0eb0a7d757d1fa43742
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/be479fc0ddfd65861be4a0eb0a7d757d1fa43742&src=gist&gui=none
18.Spring, FreshWater
Avatar can exit to FieldRow if not near *Tree when presses "c" key; I fixed this for all materials
be able to make Basket out of 2 vines; "b" key
changed Vine key to "v"
place Avatar on a specified island
- give each GridCellPattern (GCP) an islandID starting with 0
- GCP should create a data structure that can later be used to place Avatar in a CoastalCell of a specified island
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/0a4a8d84be155a497a69ac8767d912971cf870a4
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/0a4a8d84be155a497a69ac8767d912971cf870a4&src=gist&gui=none
19.use GridCellPatterns as a container for all GridCellPattern instances
generate array in GridCellPatterns to hold random CoastalCell for each island
avatarKeyMap "0":"out transcript 0;go link0;step", \ etc.
start Avatar as a child of GridCellPatterns
display an initial menu where player can specify which island the Avatar inhabits
commented out these 3 lines:
var ix = $wnd.Math.floor($wnd.Math.random() * coastalCellArr.length);
var fcell = coastalCellArr[ix];
fcell.append(ava.remove());
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/c5fc2799ce4e0d50c88d119dea7a759445452aa9
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/c5fc2799ce4e0d50c88d119dea7a759445452aa9&src=gist&gui=none
20.add a third island
add ShiftMenuHandler node, to handle Shift-D Shift-E Shift-T (Drop Eat Take)
these 3 keys will set an Avatar property "shiftkey" ex: become this shiftkey D
ShiftMenuHandler.act() will check if Avatar["shiftkey"] has a value, and if so then it will present a menu of things to drop eat take
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/ebfe5d790bc5949a71c1390083d20cc985a74a75
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/ebfe5d790bc5949a71c1390083d20cc985a74a75&src=gist&gui=none
21.show maxClones for Material and other cloneable nodes
add Shift-C to select from among cloneable materials such as Stick, Vine, Thorn, FreshWater
https://gist.github.com/kenwebb/bdd87230bacc981ec836786bfcf82cd0/c3b16443c1a7dd9a59e201821e584d4e394cf628
https://xholon.meteorapp.com/Xholon.html?app=bdd87230bacc981ec836786bfcf82cd0/c3b16443c1a7dd9a59e201821e584d4e394cf628&src=gist&gui=none
22.fiddling with this and that
23.added caption just above grid, to show current game state
caption updates with each change, including each arrow movement
made Avatar color more distinct from Ocean color
24. final
Island B2
---------
August 30, 2018
This is an extension of "Island B1", based on our meeting and testing of August 16, 2018.
github Revisions (Island B2)
----------------
1. initial commit to github
same content as Island B1 revision 24
2. added github ID 4f97c3f2934147b99e1245dc0c6316cb
3. new avatarKeyMap scheme
use "menu" rather than "shiftkey" to specify a menu (ex: become this menu take)
https://xholon.meteorapp.com/Xholon.html?app=4f97c3f2934147b99e1245dc0c6316cb&src=gist&gui=none
4. combine "take" and "clone" into a single "take" menu
able to dynamically create a list of recipes using the RecipeService; see MenuHandler makeRecipesStr()
5. able to create a list of recipes based on the ingredients currently in the Avatar's inventory
6. new recipes for YokeCarrier and Backpack
7. got d3cp animation (<Animate/>) working, where animRoot is ava.parent(); but I've commented it out for now
8. be able to add menu text in the white space to the right of the canvas
9. clean-up the menu area
10. able to move things around using d3cp interface; ex: take drop without pausing and without pressing any keys; using mouse but touch move not working
11. different layout of canvas grid, d3cp structure, menus
12. tested URLs:
https://xholon.meteorapp.com/Xholon.html?app=4f97c3f2934147b99e1245dc0c6316cb&src=gist&gui=none&hide=xhtop,xhtabs,xhsvg,xhfooter
http://127.0.0.1:8888/Xholon.html?app=Island+B2&src=lstr&gui=none&hide=xhtop,xhtabs,xhsvg,xhfooter
we may want to still show xhtop
display "Welcome" message and Island selection menu in menus div, rather than in xhtabs out tab
the user can press the F11 key for full-screen, without computer and browser headers
13. exploring the use of Xholon subtrees; see notes above
see my "Subtrees" workbook c12c030f739cf8127313b6dbe920aa50
I'm enabling TestTool
I can drag the contents of a file (SubtreesReporter.js) in Xholon/script/javascript, into any model, to report on subtrees. Drag the XML+code into the Avatar.
Example of processing TestTool:
var ava = xh.avatar();
ava.action("param debug true;");
ava.action("drop subtree(ToolsST)TestTool");
14. fixed bug
15. specify an app-specific set of Avatar subtrees
16. app crashes if I do ava.action("vanish"); see AvatarLoggerbehavior.js ava.parent(); change all ava.parent() to ava.obj()
commented out all node.print() and node.println()
removed all "out transcript ..."
tested making Avatar invisible in grid, by adding <Avatar><Symbol>GPSHAPE_NOSHAPE</Symbol></Avatar> to xholonClassDetails; I've commented this out for now
17. fix menus, as agreed at Oct 4 meeting
- DONE remove "*:all"
- DONE add to MENU menu: n:enter (optional) and x:exit (optional)
- DONE add to MENU menu: 4 arrow keys
- DONE add to MENU menu: p:pause or unpause s:step
- DONE p:none is confusing; use p:backout or p:continue
- DONE there is no need to mention "<" and ">" on any menu
- DONE show generic MENU menu once the user has selected an island
- DONE show generic MENU menu once the user has selected an item from the current detailed menu
- DONE remove "?-"
- DOME disable all numbered commands as soon as the user selects one numbered command from a menu
fix bugs that send player to strange places
remove the "f" and "F" follow and unfollow commans ?
add &hide=xhtop,xhtabs,xhsvg,xhfooter to URL
DONE at start of game, do not allow "p" or "s" or any other command before user selects an Island (by pressing a valid number key)
- do this in MenuHandlerbehavior.js ?
18. DONE when a submenu (d e r t) is visible, player should only be able to press those keys shown on the menu (no arrow keys, etc.)
perhaps, menu selection numbers should be 1-9 (or 1-0 where 0 means 10), rather than the current 0-9 ???
don't allow taking cloneable nodes (nodes such as children of RedTree, GreenTree, Spring), nodes with a "maxClones) JS attribute
when the game is paused, the only key available to the player should be "p" for "unpause" or "continue"
DONE if player runs out of calories, the player's avatar should go to a GameOver node
19. to follow a fish, the key map should best be "f":"follow nextprev" rather than "f":"follow prev"
20. TODO save caption JSON strings to IndexedDB
final - this is the final revision of Island B2, the version used in the Oct 12, 2018 testing (2 testers at the Carleton lab)
github Revisions (Island B3)
----------------
1. initial commit to github
2. added github ID 40731e8f7a7ece0236e656fb24036e4a
3. DONE add Cat behavior suggested by tester P.
- add CatTreat to TreasureChest; maxClones=100
- player can take CatTreats
- player can drop them anywhere
- if Cat is co-located with a CatTreat, it will eat it
- if Cat is also co-located with Avatar, it will start to follow the player, at least for a period of time
DONE Spring should be a circle
4. DONE suggestion by test observer B.
- from movie "Cast Away"
- <Volleyball roleName="Wilson"><Icon>https://upload.wikimedia.org/wikipedia/en/f/fb/Wilson_The_Volleyball.jpg</Icon></Volleyball>
5. DONE Volleyball roleName="Wilson" image is now circular
- ImageMagick terminal commands:
convert Wilson_The_Volleyball.jpg \( +clone -threshold -1 -negate -fill white -draw "circle 90,75 84,16" \) -alpha off -compose copy_opacity -composite Wilson_circ.png
convert Wilson_circ.png -transparent white Wilson_circ_transparent.png
6. DONE at the beginning of the game, label each Island in the grid with its numeric islandID
- use $wnd.xh.postStep()
7. DONE Improve initial "Welcome" menu.
DONE Change cell size from 8 to 7 ?
DONE Start d3cp showing Avatar in GridCellPatterns
DONE Remove 2 internal Ocean nodes, that were in one of the GridCellPattern nodes
8. DONE If I click the mouse button within the canvas, then keystrokes no longer get to the Avatar
- the following code works, from Dev Tools
var canvas = document.querySelector("div#xhcanvas > canvas");
canvas.onmousedown = function(event) {event.preventDefault();};
9. DONE Disable click, contextmenu, dblclick, drag n drop events.
- The player can now only use the arrow and other movements keys, and the app-specific menus.
10. DONE The Recipe menu should show all recipes, including those where the ingredients are not yet all available
- only those that are currently possible will be numbered and player-selectable
11. DONE Draw a circle around the Avatar's current grid cell, whether it's on the surface or inside of something at that grid cell
- this will help players to see where there Avatar is located; it answers the question "where am I"
12. DONE change "calories" to "energy" in caption line, which is also the DB record
DONE DataBase (DB) Session record
- gameid the value of URL app parameter ex: 40731e8f7a7ece0236e656fb24036e4a OR Island+B3
- gamerev the value of URL apprev parameter ex: 12
- sessionid gameid + "_" + gamerev
http://127.0.0.1:8888/Xholon.html?app=40731e8f7a7ece0236e656fb24036e4a&apprev=12&src=gist&gui=none&hide=xhtop,xhtabs,xhsvg,xhfooter
http://127.0.0.1:8888/Xholon.html?app=Island+B3&apprev=12&src=lstr&gui=none&hide=xhtop,xhtabs,xhsvg,xhfooter
13. DONE export data to PRE elements on the web page, or to Dev Tools
14. DONE fixed menu message when export data
15. DONE fixed JSON formatting; tested with JSON formatting tool
16. webrtc test
test a concept where Island game can interact with a separate app through WebRTC to retrieve game data
see Canada - Schweiz example above
17. webrtc
18. handle display and removal of exported data on screen
19. Change number of ports betweeen grid cells, from 8 to 4 (Gmt to Gvt, NEIGHBORHOOD_MOORE to NEIGHBORHOOD_VON_NEUMANN)
20. Add HTML links to Island documentation
Have the links open in a new browser tab
21. when I run this workbook with primordion.com, the Island numbers on the canvas, are in a solid black rectangle
22. debugging: I commented out the HTML links. This does not fix the problem.
23. I uncommented the HTMML links.
24. Added Jen's actual HTML links
http://www.jensplanet.com/islandsgame/recipecatalogue.html
http://www.jensplanet.com/islandsgame/objectcatalogue.html
http://www.jensplanet.com/islandsgame/playermanual.html
25. Various "how to do" notes after the Oct 26 testing
26. final - this is the final revision of Island B3, the version used in the Oct 26, 2018 testing (3 testers at the Carleton lab)
References
----------
(1) https://gist.github.com/kenwebb/4f97c3f2934147b99e1245dc0c6316cb
The main URL for the latest revision of this workbook (source code) at github.
(2) https://xholon.meteorapp.com/Xholon.html?app=4f97c3f2934147b99e1245dc0c6316cb&src=gist&gui=none
URL to run the latest revision of this workbook as a Meteor app.
(3) https://xholondev.meteorapp.com/Xholon.html?app=4f97c3f2934147b99e1245dc0c6316cb&src=gist&gui=none
temporary development version to test things
]]></Notes>
<_-.XholonClass>
<!-- Types of things needed by the Xholon framework =============================================== -->
<IslandSystem/>
<!-- containers for objects that will be placed in the Ocean and Island parts of the grid; only used for initial setup -->
<Ocean/>
<Island/>
<!-- DO NOT SPECIFY these two Xholon classes; GridGenerator will create them
<Space/>
<FieldRow/>
-->
<!-- GridGenerator requires that these NOT have a superclass such as IslandGridCell -->
<!--<IslandGridCell>-->
<OceanCell/> <!-- OceanCell is the default -->
<LandCell/>
<CoastalCell/>
<!--</IslandGridCell>-->
<GridCellPattern superClass="Attribute_String"/>
<GridCellPatterns/>
<!-- containers for behaviors -->
<PlantBehaviors/>
<FishBehaviors/>
<AnimalBehaviors/> <!-- ex: cat behaviors -->
<!-- end of Types of things needed by the Xholon framework =============================================== -->
<!-- Jen's List =============================================== -->
<!-- <Cell/> see IslandGridCell above -->
<Plant>
<Tree>
<GreenTree/>
<RedTree/>
</Tree>
<!-- <Weed/> -->
</Plant>
<Produce>
<Fruit/>
<PricklyFruit/>
</Produce>
<Berry>
<JuicyBerry/>
</Berry>
<!-- <Flower>
<ChewyFlower/>
</Flower> -->
<Material>
<Stick/>
<Thorn/>
<Vine/>
<!-- <Leaves/> Ken ? -->
<FreshWater/>
</Material>
<Animal>
<Fish/>
</Animal>
<Artifact>
<Tool>
<FishingRod/>
<Basket/>
<YokeCarrier/> <!-- see https://en.wikipedia.org/wiki/Carrying_pole -->
<Backpack/>
</Tool>
<Structure>
<Hut/>
</Structure>
</Artifact>
<GeoFeature> <!-- Geography -->
<Spring/> <!-- a place where fresh water might be located -->
</GeoFeature>
<!-- end of Jen's List =============================================== -->
<!-- Other things that Ken needs or is experimenting with =========================== -->
<!-- environment -->
<Weather/>
<!-- Ken's black cat Licorice who insists on being part of any project Ken works on. He aimlessly wanders around on the land, and has no effect other than being visible and sometimes annoying. -->
<Cat/>
<!-- Island Control Centre; a hidden place -->
<City/>
<University/>
<Library/>
<CoffeeShop/>
<IslandControlCentre/>
<!-- an artifact that provides some useful items for free, for now -->
<TreasureChest/>
<TreasureChests/>
<!-- a node I can create to test <Symbol>js:...</Symbol> -->
<Jackal/>
<!-- use TestTool to test the Avatar apply command; TestTool has to be a GWT behavior -->
<TestTool superClass="Script"/>
<!-- Island 4 - experimental: try to parse Ceptre syntax into JavaScript objects -->
<stageCeptre/>
<StageCeptreRunner/>
<!-- log Avatar state and actions -->
<AvatarLogger/>
<!-- handle menus for keys d e r t (drop eat recipe take) -->
<MenuHandler/>
<GameOver/>
<CatTreat/>
<Volleyball/>
<!-- for use with WebRTC-based collection of game results; IndexedDB data exports will go here -->
<DataExport/>
<DataExports/>
</_-.XholonClass>
<xholonClassDetails>
<LandCell implName="org.primordion.xholon.base.GridEntity"><Color>PaleGoldenRod</Color></LandCell> <!-- PaleGoldenRod -->
<CoastalCell implName="org.primordion.xholon.base.GridEntity"><Color>#d0c883</Color></CoastalCell> <!-- #d0c883(olive) -->
<Avatar><Color>RoyalBlue</Color></Avatar>
<!--<Avatar><Symbol>GPSHAPE_NOSHAPE</Symbol></Avatar>-->
<GameOver><Color>black</Color></GameOver>
<Volleyball>
<!--<Icon>https://upload.wikimedia.org/wikipedia/en/f/fb/Wilson_The_Volleyball.jpg</Icon>-->
<Icon>images/castaway/Wilson_circ_transparent.png</Icon>
</Volleyball>
<GreenTree><DefaultContent><![CDATA[
<_-.treedc>
<Fruit maxClones="10"/>
<JuicyBerry maxClones="10"/>
<Stick maxClones="10"/>
</_-.treedc>
]]></DefaultContent></GreenTree>
<RedTree><DefaultContent><![CDATA[
<_-.treedc>
<PricklyFruit maxClones="10"/>
<Thorn maxClones="10"/>
<Vine maxClones="10"/>
</_-.treedc>
]]></DefaultContent></RedTree>
<TreasureChest><DefaultContent><![CDATA[
<_-.tcdc>
<Stick maxClones="1"/>
<Vine maxClones="1"/>
<Thorn maxClones="1"/>
<CatTreat maxClones="10"/>
<Volleyball roleName="Wilson" maxClones="1"><Annotation>https://en.wikipedia.org/wiki/Cast_Away</Annotation></Volleyball>
</_-.tcdc>
]]></DefaultContent></TreasureChest>
<Spring><DefaultContent><![CDATA[
<_-.springdc>
<FreshWater maxClones="100"/>
</_-.springdc>
]]></DefaultContent></Spring>
<Stick>
<!-- Symbol + Color -->
<Symbol>Triangle</Symbol>
<Color>Sienna</Color>
</Stick>
<Fish><Symbol>LRTriangle</Symbol><Color>SteelBlue</Color></Fish> <!-- Tuna silver,SteelBlue -->
<GreenTree><Symbol>Circle</Symbol><Color>Green</Color></GreenTree>
<RedTree><Symbol>Circle</Symbol><Color>Red</Color></RedTree>
<Vine><Symbol>SmallRectangle</Symbol><Color>DarkGreen</Color></Vine>
<Thorn><Symbol>SmallCircle</Symbol><Color>DarkOliveGreen</Color></Thorn>
<Fruit><Symbol>Cross</Symbol><Color>Orange</Color></Fruit>
<PricklyFruit><Symbol>Cross</Symbol><Color>DeepPink</Color></PricklyFruit>
<JuicyBerry><Symbol>ReverseTriangle</Symbol><Color>Violet</Color></JuicyBerry>
<Cat><Symbol>Wye</Symbol><Color>black</Color></Cat>
<City>
<Color>gold</Color>
<Symbol>js:ctx.fillRect(x+1,y+1,cellSize-2,cellSize-2);</Symbol> <!-- this works; it uses the fillStyle specified in <Color> -->
</City>
<Hut>
<Color>DarkGoldenRod</Color>
<!--<Symbol>js:ctx.fillRect(x,y,3,3);ctx.fillRect(x+5,y,3,3);ctx.fillRect(x,y+5,3,3);ctx.fillRect(x+5,y+5,3,3);</Symbol>--> <!-- this works -->
<Symbol>
js:ctx.fillStyle='rgba(255,0,0,1.0)';ctx.fillRect(x,y,3,3);
ctx.fillStyle='rgba(0,255,0,1.0)';ctx.fillRect(x+5,y,3,3);
ctx.fillStyle='rgba(0,0,255,1.0)';ctx.fillRect(x,y+5,3,3);
ctx.fillStyle='rgba(255,255,0,1.0)';ctx.fillRect(x+5,y+5,3,3);
</Symbol> <!-- this works -->
</Hut>
<FishingRod><Color>Orange</Color></FishingRod>
<Basket><Color>Coral</Color></Basket>
<YokeCarrier><Color>Coral</Color></YokeCarrier>
<Backpack><Color>Coral</Color></Backpack>
<Spring><Symbol>Circle</Symbol><Color>Chocolate</Color></Spring>
<FreshWater><Color>Aqua</Color></FreshWater>
<CatTreat><Symbol>SmallRectangle</Symbol><Color>Brown</Color></CatTreat>
<GridCellPattern><Color>yellow</Color></GridCellPattern>
<TreasureChest>
<Color>Fuchsia</Color>
<Symbol>js:ctx.fillRect(x+1,y+1,cellSize-2,cellSize-2);</Symbol>
</TreasureChest>
<Jackal>
<Color>purple</Color>
<Symbol>js:ctx.fillRect(x+1,y+1,cellSize-2,cellSize-2);</Symbol>
</Jackal>
<TestTool><DefaultContent><![CDATA[
var me, beh = {
postConfigure: function() {
me = this.cnode;
$wnd.console.log(me.name());
},
processReceivedSyncMessage: function(msg) {
var data = msg.data;
$wnd.console.log(data);
var str = "TestTool received message";
if (data && (data.length)) {
for (var i = 0; i < data.length; i++) {
str += " " + data[i];
}
}
return str;
}
}
]]></DefaultContent></TestTool>
<DataExports xhType="XhtypePureActiveObject">
<port name="trop" index="0" connector="RemoteNodeService-PeerJS,localid0,delete,3,delete,9000,/"/>
</DataExports>
</xholonClassDetails>
<IslandSystem>
<!-- rows and cols must be same as const ROWS and const COLS in Behaviors -->
<GridGenerator rows="80" cols="120" gridType="Gvt" names="Space,FieldRow,OceanCell" columnColor="171c8f" gridViewerParams="IslandSystem/Space,7,Island Viewer,true" cellsCanSupplyOwnColor="true">
<Attribute_String>TODO CellPattern ?</Attribute_String>
</GridGenerator>
<!-- L = LandCell C = CoastalCell # = LandCell(where the islandID will be printed at start of game) -->
<GridCellPatterns roleName="Isles ">
<GridCellPattern roleName="Isle 0" xpos="20" ypos="15" islandID="0"><![CDATA[
..CCCCCCCCCCCC
..CLLCLLLCCLLC
CCCCLLLLLLLLCCCC
CLLLLLLLLLLLLLLC
CLLLLLLLLLLLLLLC
CCCCLLLLLLLLLCCC
..CCCCCLLLLCCC
..CLLLLLLLLLC
.CCCLLLLLLLLC
.CLLLLLLLLLLCCC
.CCLLL#LLLLLLLCCCCCCCCC
..CCCLLLLLLLLLLLLLLLLLC
...CLLLLLLLLLLLLLLLLCCC
...CCCLLLLLLLLLLLLLCC
...CLLLLLLLLLCCCCCCC
..CCCCCLLLLCCC
..CLLLLLLLLLLC
CCCCLLLLLLLLCCCC
CLLLLLLLLLLLLLLC
CLLLLLLLLLLLLLLC
CCCCLLLLLLLLLCCC
...CCCCLLLLCCC
......CCCCCC
]]></GridCellPattern>
<GridCellPattern roleName="Isle 1" xpos="50" ypos="40" islandID="1"><![CDATA[
..........CCCCC.CCC..CCCCCCC
.........CCLCLCCCLCCCCLCCLLCC
........CCCLLLLLLLLLLLLLLLLLC
......CCCLLLLLLLLLLLLLLLLLCCC
......CLLLLLLLLLLLLLLLLLCCC
..CCCCCCLLLLLLLLLLLLLLLLLLCC
CCCLLLLLLLLLLLLLLLLLLLLLLLLCCC
CLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCCCCCC
CCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCC
.CCLLLLLLLLLLLLLL#LLLLLLLLLLLLLLLLLLLLLC
..CCCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCCCC
...CLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCC
...CCCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCC
...CLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCCC
...CCCCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCC
......CCCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLC
.......CLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCC
.......CCCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCC
.......CLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCC
.......CCCCCCCLLLLLLLLLLLLLLLLLLLLLCCCC
............CLLLLLLLLLLLLLLLLLLLLLLLC
............CCCLLLCCCCCCCCCCCCLLLLCCC
..............CCCCC..........CCCCCC
]]></GridCellPattern>
<GridCellPattern roleName="Isle 2" xpos="80" ypos="5" islandID="2"><![CDATA[
..CCCCCCCCCCCC
..CLLCLLLCCLLC
CCCCLLLLLLLLCCCC
CLLLLLLLLLLLLLLC
CLLLLLLLLLLLLLLC
CCCCLLLLLLLLLCCC
..CCCCCLLLLCCC
..CLLLLLLLLLC
.CCCLLLLLLLLC
.CLLLLLLLLLLCCC
.CCLLL#LLLLLLLCCCCCCCCC
..CCCLLLLLLLLLLLLLLLLLC
...CLLLLLLLLLLLLLLLLCCC
...CCCLLLLLLLLLLLLLCC
...CLLLLLLLLLCCCCCCC
..CCCCCLLLLCCC
..CLLLLLLLLLLC
CCCCLLLLLLLLCCCC
CLLLLLLLLLLLLLLC
CLLLLLLLLLLLLLLC
CCCCLLLLLLLLLCCC
...CCCCLLLLCCC
......CCCCCC
]]></GridCellPattern>
</GridCellPatterns>
<!-- each PlantBehavior and FishBehavior node moves itself into one of these containers at runtime -->
<PlantBehaviors/>
<FishBehaviors/>
<AnimalBehaviors/>
<!-- see Xml2Xholon - DefaultContent only works if I include RoomModel somewhere before I need to use DefaultContent -->
<RoomModel/>
<Ocean>
<Fish multiplicity="100"/>
<Island>
<Cat roleName="Licorice"/>
<!-- TODO multiplicity causes DefaultContent content to be duplicated in each instance node -->
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<GreenTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<RedTree/>
<Spring/>
<Spring/>
<Spring/>
<Spring/>
<Spring/>
<Spring/>
<Spring/>
<Spring/>
<Spring/>
<Spring/>
<City roleName="Ottawa">
<University roleName="Carleton">
<Library>
<CoffeeShop roleName="Starbucks">
<!-- param caption #xhgraph; works -->
<Avatar roleName="Troll" params="param transcript false;param repeat true;param debug false;param speech false;param caption false;"><Attribute_String><![CDATA[
[Troll will repeatedly look for and take students from anywhere in the city, and will drop them in the IslandControlCentre];
wait 1;
exit;
take *treeWanderer;
exit;
wait 1;
enter library;
wait 1;
enter *coffeeShop;
wait 1;
enter islandControlCentre;
drop *treeWanderer;
wait 1;
exit;
wait 1;
]]></Attribute_String></Avatar>
<IslandControlCentre/>
</CoffeeShop>
</Library>
</University>
<!-- TreeWanderer nodes must be last children -->
<TreeWanderer prob="0.1,0.1,0.05,0.05" roleName="Able" exclude="Avatar,TreeWanderer"/>
<TreeWanderer prob="0.1,0.1,0.05,0.05" roleName="Baker" exclude="Avatar,TreeWanderer"/>
<TreeWanderer prob="0.1,0.1,0.05,0.05" roleName="Jen" exclude="Avatar,TreeWanderer"/>
<TreeWanderer prob="0.1,0.1,0.05,0.05" roleName="Ken" exclude="Avatar,TreeWanderer"/>
</City>
<TreasureChests>
<TreasureChest/>
<TreasureChest/>
<TreasureChest/>
<TreasureChest/>
<TreasureChest/>
</TreasureChests>
</Island>
</Ocean>
<Weather state="sunny and windy"/>
<MinecraftStyleRecipeBook roleName="Island"><Attribute_String><![CDATA[
{
"FishingRod": [
{
"ingredients": [
"Stick",
"Vine",
"Thorn"
],
"result": {
"multiplicity": 1,
"xhc": "FishingRod"
}
}
],
"Hut": [
{
"ingredients": [
"Stick",
"Stick",
"Stick",
"Vine",
"Vine",
"Vine"
],
"result": {
"multiplicity": 1,
"xhc": "Hut",
"role": "Cottage"
}
}
],
"Basket": [
{
"ingredients": [
"Vine",
"Vine"
],
"result": {
"multiplicity": 1,
"xhc": "Basket"
}
}
],
"YokeCarrier": [
{
"ingredients": [
"Basket",
"Basket",
"Stick"
],
"result": {
"multiplicity": 1,
"xhc": "YokeCarrier"
}
}
],
"Backpack": [
{
"ingredients": [
"Basket",
"Vine"
],
"result": {
"multiplicity": 1,
"xhc": "Backpack"
}
}
]
}
]]></Attribute_String></MinecraftStyleRecipeBook>
<!-- this is not active yet -->
<JsonRulesEngineRecipeBook roleName="Island"><Attribute_String><![CDATA[
[
{
"conditions": {
"any": [{
"all": [{
"fact": "inventory",
"operator": "contains",
"value": "Stick",
"fate": "remove"
}, {
"fact": "inventory",
"operator": "contains",
"value": "Vine",
"fate": "remove"
}, {
"fact": "inventory",
"operator": "contains",
"value": "Thorn",
"fate": "remove"
}, {
"fact": "wants",
"operator": "equal",
"value": "FishingRod"
}]
}]
},
"event": {
"type": "fishingRod",
"params": {
"message": "A FishingRod can be created."
}
}
}
]
]]></Attribute_String></JsonRulesEngineRecipeBook>
<AvatarLogger formatName="_other,SExpression"/> <!-- _other,Newick _other,SExpression -->
<MenuHandler/>
<!--<TestTool/> have Avatar build this -->
<!-- Prevent children and siblings from running their act(), to prevent navigating through the large grid each timestep. -->
<ActRegulator val="1.0"/>
<!-- the Space grid is inserted here at runtime -->
<GameOver/>
<DataExports>
<!-- test data -->
<DataExport>
<Attribute_String roleName="SessionData">test 123</Attribute_String>
<Attribute_String roleName="AvastateData">test 456</Attribute_String>
</DataExport>
</DataExports>
<!-- work-around - use "pointer-events: none;" to prevent d3 gui from searching the entire tree when the mouse is hovering; NOT NEEDED ANYMORE -->
<Animate selection="#xhcanvas &gt; div#d3cp" xpath="./IslandSystem/GridCellPatterns" duration="0.1" cssStyle="stroke-width: {0px;}" efParams="{&quot;selection&quot;:&quot;#xhcanvas &gt; div#d3cp&quot;,&quot;sort&quot;:&quot;disable&quot;,&quot;width&quot;:500,&quot;height&quot;:500,&quot;mode&quot;:&quot;tween&quot;,&quot;labelContainers&quot;:true,&quot;includeId&quot;:true,&quot;shape&quot;:&quot;circle&quot;,&quot;useIcons&quot;:true,&quot;maxChars&quot;:6,&quot;togglePortColors&quot;:false,&quot;supportTouch&quot;:false,&quot;supportClick&quot;:false,&quot;supportContextmenu&quot;:false,&quot;supportDblclick&quot;:false}"/>
</IslandSystem>
<IslandSystembehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
const ROWS = 80; // same as value in GridGenerator
const COLS = 120; // same as value in GridGenerator
const GRID_CELL_SIZE = 7; // same as value in GridGenerator gridViewerParams
//$wnd.xh.param("RandomNumberSeed", "123"); // the effect happens too late
$wnd.xh.seed(234); // 200 12345
$wnd.xh.param("TimeStepInterval","100"); // "500" "100"
$wnd.xh.param("AppM","true");
if ($wnd.xh.html["selectTab"]) {
$wnd.xh.html.selectTab(0); // display contents of the "out" tab
}
$wnd.xh.css.style("#xhchart {font-family: monospace; font-size: 13.3333px; font-weight: 400;}");
// commands for built-in Avatar
var akm = '{ \
"SHIFT":"true", \
"NOSCROLL":"true", \
"UP":"go port0;if xpath(Avatar/ancestor::OceanCell) go port2;become this calories --;ifeq xpath(Avatar) calories 0 go xpath(ancestor::IslandSystem/GameOver);", \
"DOWN":"go port2;if xpath(Avatar/ancestor::OceanCell) go port0;become this calories --;ifeq xpath(Avatar) calories 0 go xpath(ancestor::IslandSystem/GameOver);", \
"LEFT":"if xpath(preceding-sibling::OceanCell) wait else prev;become this calories --;ifeq xpath(Avatar) calories 0 go xpath(ancestor::IslandSystem/GameOver);", \
"RIGHT":"if xpath(following-sibling::OceanCell) wait else next;become this calories --;ifeq xpath(Avatar) calories 0 go xpath(ancestor::IslandSystem/GameOver);", \
"d":"become this menu drop", \
"e":"become this menu eat", \
"f":"follow nextprev", \
"F":"unfollow", \
"m":"become this menu menu", \
"n":"enter nextprev", \
"p":"pause;become this menu menu", \
"r":"become this menu recipe", \
"s":"step", \
" ":"step", \
"t":"become this menu take", \
"x":"if xpath(../../FieldRow) wait else exit", \
"z":"param transcript toggle;", \
"<":"flip prev", \
">":"flip next", \
",":"flip prev", \
".":"flip next", \
"?":"help keymap", \
"/":"help commands", \
"0":"go link0;pause;become this menu menu", \
"1":"go link1;pause;become this menu menu", \
"2":"go link2;pause;become this menu menu", \
"3":"go link3;pause;become this menu menu", \
"4":"go link4;pause;become this menu menu", \
"5":"go link5;pause;become this menu menu", \
"$":"become this menu exportdata" \
}';
$wnd.xh.avatarKeyMap(akm);
var ava = $wnd.xh.avatar();
//ava.action('enter;enter space_;enter;enter;appear;');
ava.action('param transcript false;');
ava.action('param caption #xhchart;out caption Castaway;');
ava.action('param meteor true;');
//ava.action('param meteormove true;');
//ava.action('param meteorattr one,two,three,calories'); // testing
//ava.action('param recipebook Island;');
ava.action('param recipebook MinecraftStyleRecipeBook-Island;');
//ava.action('param recipebook JsonRulesEngineRecipeBook-Island;');
ava.action('become this role Castaway;');
ava.action('become this calories 100;'); // 1000
ava.action('enter;enter *gridCellPatterns;appear;');
// Add a TestTool to Avatar's inventory, and use ava.subtrees
ava.action("build TestTool; take testTool;");
ava.action('param subtrees true EdiblesST,WaterST,ToolsST,BehaviorsST,MaterialsST'); // will create ava["subtrees"] with the specified IXholon subtrees
var testTool = ava.last();
var toolsST = null;
if (ava["subtrees"]) {
toolsST = ava.subtree('ToolsST');
}
if (testTool && toolsST) {
toolsST.append(testTool.remove()); // move the instance of TestTool into the ToolsST subtree
}
else {
testTool.remove();
}
ava.action('step');
// allow player to select which island their Avatar will inhabit
/*ava.println("Welcome castaway. Which Island would you like to inhabit.");
var gcps = $wnd.xh.root().first().xpath("GridCellPatterns");
var gcp = gcps.first();
while (gcp) {
if (gcp.xhc().name() == "GridCellPattern") {
ava.println("" + gcp.islandID + ": inhabit Island " + gcp.islandID);
}
gcp = gcp.next();
}
ava.print("?- ");*/
// fix problem where if I click within the canvas, then keystrokes don't get to the Avatar (see Island B3 workbook, rev 8)
var canvas = $doc.querySelector("div#xhcanvas > canvas");
canvas.onmousedown = function(event) {event.preventDefault();};
// prevent display of Xholon context menu (right-click)
canvas.oncontextmenu = function(event) {event.preventDefault();};
// disable context menu for the entire screen
$doc.oncontextmenu = function(event) {event.preventDefault();};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specify Plant behavior
$wnd.xh.Plantbehavior = function Plantbehavior() {}
$wnd.xh.Plantbehavior.prototype.postConfigure = function() {
this.plant = this.cnode.parent();
this.plant.calories = 0;
this.plant.xpath("ancestor::IslandSystem/PlantBehaviors").append(this.cnode.remove());
};
$wnd.xh.Plantbehavior.prototype.act = function() {
//this.plant.println("I am " + this.plant.name() + " calories:" + this.plant.calories);
if (this.plant.parent() == null) {
// I've been eaten, so remove this behavior from the simulation
this.cnode.remove();
}
else if (this.plant.parent().xhc().name() == "Avatar") {
// I've been picked
this.plant.calories--;
if (this.plant.calories <= 0) {
// I've gone bad
this.plant.remove();
this.cnode.remove();
}
}
else if (this.plant.parent().xhc().name() == "Island") {
this.plant.calories++;
this.moveSelfToGrid();
}
else {
this.plant.calories++;
}
};
$wnd.xh.Plantbehavior.prototype.moveSelfToGrid = function() {
// DO NOT run this code in postConfigure(); it prevents a next Plant node from obtaining a Plantbehavior
// move this.plant to a random position within the land part of the grid
var ix = $wnd.Math.floor($wnd.xh.random() * landCellArr.length);
var fcell = landCellArr[ix];
fcell.append(this.plant.remove());
};
// specify Fruit behavior
//$wnd.xh.Fruitbehavior = function Fruitbehavior() {};
//$wnd.xh.Fruitbehavior.prototype = $wnd.Object.create($wnd.xh.Plantbehavior.prototype);
// specify Vegetables behavior
//$wnd.xh.Vegetablesbehavior = function Vegetablesbehavior() {};
//$wnd.xh.Vegetablesbehavior.prototype = $wnd.Object.create($wnd.xh.Plantbehavior.prototype);
// specify Lumber behavior
//$wnd.xh.Lumberbehavior = function Lumberbehavior() {};
//$wnd.xh.Lumberbehavior.prototype = $wnd.Object.create($wnd.xh.Plantbehavior.prototype);
// specify GreenTree behavior
$wnd.xh.GreenTreebehavior = function GreenTreebehavior() {};
$wnd.xh.GreenTreebehavior.prototype = $wnd.Object.create($wnd.xh.Plantbehavior.prototype);
// specify RedTree behavior
$wnd.xh.RedTreebehavior = function RedTreebehavior() {};
$wnd.xh.RedTreebehavior.prototype = $wnd.Object.create($wnd.xh.Plantbehavior.prototype);
// specify Spring behavior; for now make it a type of plant
$wnd.xh.Springbehavior = function Springbehavior() {};
$wnd.xh.Springbehavior.prototype = $wnd.Object.create($wnd.xh.Plantbehavior.prototype);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specify Fish Grow behavior
$wnd.xh.FishGrowbehavior = function FishGrowbehavior() {}
$wnd.xh.FishGrowbehavior.prototype.postConfigure = function() {
this.fish = this.cnode.parent();
this.fish.calories = 0;
this.fish.xpath("ancestor::IslandSystem/FishBehaviors").append(this.cnode.remove());
};
$wnd.xh.FishGrowbehavior.prototype.act = function() {
//this.fish.println("I am " + this.fish.name() + " calories:" + this.fish.calories);
if (this.fish.parent() == null) {
// I've been eaten, so remove this behavior from the simulation
this.cnode.remove();
}
else if (this.fish.parent().xhc().name() == "Avatar") {
// I've been caught
this.fish.calories--;
if (this.fish.calories <= 0) {
// I've gone bad
this.fish.remove();
this.cnode.remove();
}
}
else if (this.fish.parent().xhc().name() == "Ocean") {
this.fish.calories++;
//this.moveSelfToGrid();
}
else if (this.fish.parent().xhc().name() == "OceanCell") {
this.fish.calories++;
//this.moveSelfToGrid();
}
else {
// I've probably been caught and am now somewhere on land in a hut, or maybe in a boat
this.fish.calories--;
if (this.fish.calories <= 0) {
// I've gone bad :-(
this.fish.remove();
this.cnode.remove();
}
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specify Fish Move behavior
$wnd.xh.FishMovebehavior = function FishMovebehavior() { // (destCellTypeNot) {
//$wnd.xh.FishMovebehavior.destCellTypeNot = destCellTypeNot;
}
$wnd.xh.FishMovebehavior.prototype.postConfigure = function() {
this.fish = this.cnode.parent();
this.fish.xpath("ancestor::IslandSystem/FishBehaviors").append(this.cnode.remove());
};
$wnd.xh.FishMovebehavior.prototype.act = function() {
//this.fish.println("I am " + this.fish.name() + " moving");
if (this.fish.parent() == null) {
// I've been eaten, so remove this behavior from the simulation
this.cnode.remove();
return;
}
var pname = this.fish.parent().xhc().name();
if (pname == "Ocean") {
this.moveSelfToGrid();
}
else if ((pname == "OceanCell") || (pname == "CoastalCell")) {
// move randomly in the grid
if (!this.nibble()) {
this.move();
}
}
else if (pname == "Avatar") {
// I've been caught, so don't move
}
else {
//$wnd.console.log("ERROR " + this.fish.parent().name()); // Hut, LandCell, etc.
}
};
$wnd.xh.FishMovebehavior.prototype.moveSelfToGrid = function() {
// DO NOT run this code in postConfigure(); it prevents a next Fish node from obtaining a Fishbehavior
// move this.fish to a random position within the ocean part of the grid
var ix = $wnd.Math.floor($wnd.xh.random() * oceanCellArr.length);
var fcell = oceanCellArr[ix];
fcell.append(this.fish.remove());
};
$wnd.xh.FishMovebehavior.prototype.nibble = function() {
// a fish nibbles everything it's near, to see if it's food
// there's a higher probability of stopping to nibble if the Avatar has a FishingRod, than if the Avatar has no FishingRod
var neighbor = this.fish.prev();
if (!neighbor) {return false;}
var rnum = $wnd.xh.random();
var fishingRod = null;
var nname = neighbor.xhc().name();
switch (nname) {
case "Avatar": // possibly nibble the avatar/player
//this.fish.println("rnum: " + rnum);
fishingRod = neighbor.xpath("FishingRod");
if (fishingRod) {
if (rnum > 0.99) { // 0.9
return false;
}
}
else {
if (rnum > 0.9) { // 0.5
return false;
}
}
break;
//case "FishingRod":
// //this.fish.println("rnum: " + rnum);
// if (rnum > 0.99) { // 0.9
// return false;
// }
// break;
default:
//this.fish.println(this.fish.name() + " is co-located with " + neighbor.name());
return false;
}
//this.fish.println(this.fish.name() + " is nibbling a " + nname + (fishingRod ? " who is using a fishing rod" : ""));
// become the first child in the current cell, making it possible for the Avatar to "take prev;"
//this.fish.parent().prepend(this.fish.remove());
return true;
};
$wnd.xh.FishMovebehavior.prototype.move = function() {
var foundNewLocation = false;
var count = 0;
while ((!foundNewLocation) && (count < 1)) { // 10
var moveX = $wnd.Math.floor($wnd.xh.random() * 3) - 1;
var moveY = $wnd.Math.floor($wnd.xh.random() * 3) - 1;
if ((moveX == 0) && (moveY == 0)) {
return;
}
var portX = -1;
var portY = -1;
if (moveX > 0) {
portX = 1; //IGrid.P_EAST
}
else {
portX = 3; //IGrid.P_WEST
}
if (moveY > 0) {
portY = 0; //IGrid.P_NORTH
}
else {
portY = 2; //IGrid.P_SOUTH
}
count++;
var destination = this.fish.parent();
if (moveX != 0) {
destination = destination.port(portX);
}
if (moveY != 0) {
destination = destination.port(portY);
}
if (destination && (destination.xhc().name() != "LandCell")) { //$wnd.xh.FishMovebehavior.destCellTypeNot)) {
destination.append(this.fish.remove());
foundNewLocation = true;
}
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specify Cat Move behavior
$wnd.xh.CatMovebehavior = function CatMovebehavior() {}
$wnd.xh.CatMovebehavior.prototype.postConfigure = function() {
this.cat = this.cnode.parent();
this.cat.xpath("ancestor::IslandSystem/AnimalBehaviors").append(this.cnode.remove());
this.cat.avatar = null; // this is for later use, if an Avatar gives the Cat a treat
};
$wnd.xh.CatMovebehavior.prototype.act = function() {
//this.cat.println("I am " + this.cat.name() + " moving");
if (this.cat.parent() == null) {
// I've been eaten, so remove this behavior from the simulation
this.cnode.remove();
}
else if (this.cat.parent().xhc().name() == "Island") {
this.moveSelfToGrid();
}
else if (this.cat.prev() && (this.cat.prev().xhc().name() == "CatTreat")) {
this.cat.append(this.cat.prev().remove());
// TODO stick close to Avatar if there is also a co-located Avatar
if (this.cat.prev() && (this.cat.prev().xhc().name() == "Avatar")) {
this.cat.avatar = this.cat.prev();
}
}
else if (this.cat.parent().xhc().name().endsWith("Cell")) { // FieldCell OceanCell LandCell
// move randomly in the grid
this.move();
}
else if (this.cat.parent().xhc().name() == "Avatar") {
// I've been caught, so don't move
}
else {
$wnd.console.log("ERROR " + this.cat.parent().name());
}
this.beFriendly();
};
$wnd.xh.CatMovebehavior.prototype.moveSelfToGrid = function() {
// DO NOT run this code in postConfigure(); it prevents a next Cat node from obtaining a Catbehavior
// move this.cat to a random position within the ocean part of the grid
var ix = $wnd.Math.floor($wnd.xh.random() * landCellArr.length);
var fcell = landCellArr[ix];
fcell.append(this.cat.remove());
};
$wnd.xh.CatMovebehavior.prototype.move = function() {
var foundNewLocation = false;
var count = 0;
while ((!foundNewLocation) && (count < 1)) { // 10
var moveX = $wnd.Math.floor($wnd.xh.random() * 3) - 1;
var moveY = $wnd.Math.floor($wnd.xh.random() * 3) - 1;
if ((moveX == 0) && (moveY == 0)) {
return;
}
var portX = -1;
var portY = -1;
if (moveX > 0) {
portX = 1; //IGrid.P_EAST
}
else {
portX = 3; //IGrid.P_WEST
}
if (moveY > 0) {
portY = 0; //IGrid.P_NORTH
}
else {
portY = 2; //IGrid.P_SOUTH
}
count++;
var destination = this.cat.parent();
if (moveX != 0) {
destination = destination.port(portX);
}
if (moveY != 0) {
destination = destination.port(portY);
}
if (destination && (destination.xhc().name() != "OceanCell")) {
destination.append(this.cat.remove());
foundNewLocation = true;
}
}
};
$wnd.xh.CatMovebehavior.prototype.beFriendly = function() {
if (this.cat.avatar && (this.cat.first() && this.cat.first().xhc().name() == "CatTreat")) {
// the cat is friendly with an Avatar, and the cat still remembers (is carrying) the CatTreat
if (Math.random() < 0.01) {
// cat decides to leave the avatar
this.cat.avatar = null;
this.cat.first().remove();
}
else {
if (!(this.cat.avatar == this.cat.next())) {
this.cat.avatar.before(this.cat.remove());
}
}
}
};
var oceanCellArr = [];
var landCellArr = [];
var coastalCellArr = [];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specify behavior to add all Cell nodes into class-specific arrays, for use by moveSelfToGrid functions
// position system Avatar
$wnd.xh.CellArraybehavior = function CellArraybehavior() {}
$wnd.xh.CellArraybehavior.prototype.postConfigure = function() {
this.isys = this.cnode.parent();
var space = this.isys.xpath("Space");
var row = space.first();
while (row) {
var cell = row.first();
while (cell) {
switch (cell.xhc().name()) {
case "OceanCell":
oceanCellArr.push(cell);
break;
case "LandCell":
landCellArr.push(cell);
break;
case "CoastalCell":
coastalCellArr.push(cell);
break;
default: break;
}
cell = cell.next();
}
row = row.next();
}
//ava.action('go xpath()');
// each Avatar should go in it's own random coastalCell, so use Math.random() rather than xh.random()
//var ix = $wnd.Math.floor($wnd.Math.random() * coastalCellArr.length);
//var fcell = coastalCellArr[ix];
//fcell.append(ava.remove());
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specify City behavior
$wnd.xh.Citybehavior = function Citybehavior() {}
$wnd.xh.Citybehavior.prototype.postConfigure = function() {
this.city = this.cnode.parent();
//this.plant.calories = 0;
//this.plant.xpath("ancestor::IslandSystem/PlantBehaviors").append(this.cnode.remove());
var ix = $wnd.Math.floor($wnd.xh.random() * coastalCellArr.length);
var ccell = coastalCellArr[ix];
ccell.append(this.city.remove());
this.cnode.remove();
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specify TreasureChests behavior
$wnd.xh.TreasureChestsbehavior = function TreasureChestsbehavior() {}
$wnd.xh.TreasureChestsbehavior.prototype.postConfigure = function() {
this.treasureChests = this.cnode.parent();
var tchest = this.treasureChests.first();
while (tchest && tchest.xhc().name() == "TreasureChest") {
var ix = $wnd.Math.floor($wnd.xh.random() * coastalCellArr.length);
var ccell = coastalCellArr[ix];
var tchestNext = tchest.next();
ccell.append(tchest.remove());
tchest = tchestNext;
}
this.cnode.remove();
};
var canvas = $doc.querySelector("div#xhcanvas > canvas");
var ctx = canvas.getContext("2d");
var xyMult = GRID_CELL_SIZE;
var xyAdd = GRID_CELL_SIZE / 2;
var radius = 6;
var startAngle = 0;
var endAngle = 2 * Math.PI;
var anticlockwise = false;
// draw a circle around the Avatar's current location in the grid
$wnd.xh.postStep2 = function() {
var ancestorNode = ava.obj();
var rcObj = null;
while (ancestorNode) {
if (ancestorNode.xhc() && ancestorNode.xhc().name().endsWith("Cell")) { // OceanCell LandCell CoastalCell
rcObj = ancestorNode.obj();
break;
}
ancestorNode = ancestorNode.parent();
}
if (rcObj) {
ctx.strokeStyle = "blue";
var x = rcObj.col * xyMult + xyAdd;
var y = rcObj.row * xyMult + xyAdd;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
ctx.stroke();
}
}
// this should run once at the beginning, to label each Island with it's numeric islandID
$wnd.xh.postStep = function() {
//var canvas = $doc.querySelector("div#xhcanvas > canvas");
//var ctx = canvas.getContext("2d");
ctx.font = '48px monospace';
ctx.fillStyle = "black";
var arr = $wnd.xh.islandIDNodes; // created by GridCellPatternbehavior.js
if (arr) {
for (var i = 0; i < arr.length; i++) {
var islandIDNode = arr[i];
var str = islandIDNode.str;
var x = islandIDNode.x * GRID_CELL_SIZE;
var y = islandIDNode.y * GRID_CELL_SIZE;
ctx.fillText(str, x, y);
}
$wnd.xh.postStep = $wnd.xh.postStep2; // null;
}
}
// add HTML links to documentation for Island game
var xhgraph = $doc.querySelector("div#xhgraph");
xhgraph.innerHTML =
'<div>' +
'<h3>Read the Island documentation:</h3>' +
'<p><a href="http://www.jensplanet.com/islandsgame/recipecatalogue.html" target="_blank">Recipe Catalogue</a></p>' +
'<p><a href="http://www.jensplanet.com/islandsgame/objectcatalogue.html" target="_blank">Object Catalogue</a></p>' +
'<p><a href="http://www.jensplanet.com/islandsgame/playermanual.html" target="_blank">Player Manual</a></p>' +
'</div>'
;
//# sourceURL=IslandSystembehavior.js
]]></IslandSystembehavior>
<GreenTreebehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.GreenTreebehavior();
//# sourceURL=GreenTreebehavior.js
]]></GreenTreebehavior>
<RedTreebehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.RedTreebehavior();
//# sourceURL=RedTreebehavior.js
]]></RedTreebehavior>
<Fishbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.FishGrowbehavior();
//# sourceURL=FishGrowbehavior.js
]]></Fishbehavior>
<Fishbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.FishMovebehavior(); //("LandCell");
//# sourceURL=FishMovebehavior.js
]]></Fishbehavior>
<Catbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.CatMovebehavior();
//# sourceURL=CatMovebehavior.js
]]></Catbehavior>
<Springbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.Springbehavior();
//# sourceURL=Springbehavior.js
]]></Springbehavior>
<GridCellPatternbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, beh = {
postConfigure: function() {
me = this.cnode.parent();
var pNode = me.parent(); // GridCellPatterns node
this.cnode.remove();
//me.println("xpos:" + me.xpos + " ypos:" + me.ypos);
var gcpstr = me.text().trim();
var gcparr = gcpstr.split("\n");
var row = me.xpath("../../Space/FieldRow[" + me.ypos + "]");
var fcol = row.xpath("OceanCell[" + me.xpos + "]");
var col = fcol;
var ccArr = []; // cache CoastalCells
for (var i = 0; i < gcparr.length; i++) {
var gcpline = gcparr[i].trim();
//me.println(gcpline);
for (var j = 0; j < gcpline.length; j++) {
switch (gcpline[j]) {
case "L":
col.xhc("LandCell");
break;
case "#":
col.xhc("LandCell");
// cache the node where the islandID will be printed at the start of the game
if (!$wnd.xh.islandIDNodes) {
$wnd.xh.islandIDNodes = [];
}
var islandIDNode = {};
islandIDNode.x = Number(me.xpos) + j;
islandIDNode.y = Number(me.ypos) + i;
islandIDNode.str = me.islandID;
$wnd.xh.islandIDNodes.push(islandIDNode);
break;
case "C":
col.xhc("CoastalCell");
ccArr.push(col);
break;
default: // "."
break;
}
col = col.next();
}
fcol = fcol.port(2);
col = fcol;
}
// randomly select a CoastalCell where Avatar might start
var ccNode = ccArr[Math.floor(Math.random() * ccArr.length)];
if (!pNode["avatarStartArr"]) {
pNode["avatarStartArr"] = [];
}
pNode["avatarStartArr"].push(ccNode);
}
}
//# sourceURL=GridCellPatternbehavior.js
]]></GridCellPatternbehavior>
<IslandSystembehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.CellArraybehavior();
//# sourceURL=IslandSystembehavior2.js
]]></IslandSystembehavior>
<Citybehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.Citybehavior();
//# sourceURL=Citybehavior.js
]]></Citybehavior>
<TreasureChestsbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var beh = new $wnd.xh.TreasureChestsbehavior();
//# sourceURL=TreasureChestsbehavior.js
]]></TreasureChestsbehavior>
<IslandControlCentrebehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, count, beh = {
postConfigure: function() {
me = this.cnode.parent();
count = 0;
//this.cnode.remove();
//$wnd.console.log("IslandControlCentrebehavior starting...");
},
act: function() {
// don't let Meteor start until the app has a chance to deploy everything to their initial/default GridCells
if (count < 2) {
//$wnd.console.log("IslandControlCentrebehavior waiting...");
count++;
}
else if (count >= 2) {
//$wnd.console.log("IslandControlCentrebehavior ReadyForMeteor true");
$wnd.xh.param("ReadyForMeteor","true");
this.cnode.remove();
}
}
}
//# sourceURL=IslandControlCentrebehavior.js
]]></IslandControlCentrebehavior>
<AvatarLoggerbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
const DB_NAME = "IslandGameDB";
const DB_VERSION = 1;
const DB_SESSION_STORE_NAME = "session";
const DB_SESSION_STORE_KEY = ["sessionid"];
const DB_AVASTATE_STORE_NAME = "avastate";
const DB_AVASTATE_STORE_KEY = ["sessionid","timestep"];
var me, ava, newState, prevState, newCalories, prevCalories, animate, idbs, idbssetup, idbsobj, sessionRecord, beh = {
postConfigure: function() {
me = this.cnode.parent();
idbs = $wnd.xh.service("IndexedDBService");
idbssetup = false;
sessionRecord = null;
ava = $wnd.xh.avatar();
// formatName, node, efParams, writeToTab, returnString
//prevState = this.getXport();
newState = "";
this.hashifySXpres(ava.obj());
prevState = newState;
newCalories = ava.calories;
prevCalories = newCalories;
var jsonStr = '"timestep":"' + $wnd.xh.param("TimeStep") + '",';
jsonStr += '"state":"' + prevState + '",';
jsonStr += '"energy":"' + prevCalories + '"';
animate = me.xpath("../Animate"); // d3cp Animate node
this.saveToDB("{" + jsonStr + "}");
},
act: function() {
if (!sessionRecord) {
var session = this.makeSessionRecord();
//$wnd.console.log(session);
var rc = this.saveSessionToDB(session);
if (rc) {
sessionRecord = session;
$wnd.console.log(sessionRecord);
// now create data store for Avatar state records
//var avastateObj = idbsobj.setup(DB_NAME, DB_AVASTATE_STORE_NAME, DB_AVASTATE_STORE_KEY);
}
}
newState = "";
newCalories = ava.calories;
this.hashifySXpres(ava.obj()); //parent());
if ((newState != prevState) || (prevCalories != newCalories)) {
prevState = newState;
prevCalories = newCalories;
var jsonStr = '"timestep":"' + $wnd.xh.param("TimeStep") + '",';
jsonStr += '"state":"' + prevState + '",';
jsonStr += '"energy":"' + ava.calories + '"';
this.saveToDB("{" + jsonStr + "}");
}
},
makeSessionRecord: function() {
var playerid = "X"; // TODO get this from the human player
var session = {};
var params = $wnd.location.search;
session.sessionid = playerid + Date.now(); // key
session.gameid = new URLSearchParams(params).get("app");
session.gamerev = new URLSearchParams(params).get("apprev") || "00";
session.islandID = ava.islandID;
return session;
},
saveSessionToDB: function(session) {
var rc = false;
idbsobj = idbs.obj();
if (idbsobj && !idbssetup) {
idbsobj.setup(DB_NAME, [DB_SESSION_STORE_NAME, DB_AVASTATE_STORE_NAME], [DB_SESSION_STORE_KEY, DB_AVASTATE_STORE_KEY]);
idbssetup = true;
}
if (idbsobj) {
idbsobj.update(DB_NAME, DB_SESSION_STORE_NAME, DB_SESSION_STORE_KEY, session);
rc = true;
}
return rc;
},
/**
* Recursively hashify a Xholon subtree, with output in a Lisp S-expression format.
* @param node A node in the Xholon hierarchy.
* @param sb A String instance.
*/
hashifySXpres: function(node) {
newState += node.name("R^^^^^");
if (node.xhc().name() == "Space") {
newState += (" (Avatar)");
}
else if (node.first()) {
newState += " (";
var childNode = node.first();
while (childNode != null) {
this.hashifySXpres(childNode);
childNode = childNode.next();
if (childNode != null) {
newState += " ";
}
}
newState += ")";
}
else if (node["maxClones"] && (node.parent().xhc().name() != "Avatar")) {
newState += "*" + node["maxClones"];
}
},
saveToDB: function(str) {
if (ava.obj().xhc().name() == "GridCellPatterns") {
//var session = this.makeSessionRecord();
//$wnd.console.log(session);
//this.saveSessionToDB(session);
}
else {
//me.println(str);
ava.action("out caption " + str);
if (animate) {
//$wnd.console.log($wnd.xh.root());
//$wnd.console.log(ava.obj());
var animRoot = $wnd.xh.xpathExpr(ava.obj(), $wnd.xh.root().first());
//$wnd.console.log(animRoot);
animate.attr("AnimRoot", animRoot);
}
if (idbsobj && sessionRecord) {
var jsObj = JSON.parse(str);
jsObj.sessionid = sessionRecord.sessionid;
jsObj.timestep = Number(jsObj.timestep); //$wnd.xh.param("TimeStep");
idbsobj.update(DB_NAME, DB_AVASTATE_STORE_NAME, DB_AVASTATE_STORE_KEY, jsObj);
}
}
}
}
//# sourceURL=AvatarLoggerbehavior.js
]]></AvatarLoggerbehavior>
<MenuHandlerbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
// default Avatar name template "r:c_i^"
var me, ava, xhcanvas, akmObj, initialized, menuDiv, cachedAkmObj, gameOver, dataExportsNode, dataExportedToPage, beh = {
postConfigure: function() {
me = this.cnode.parent();
ava = $wnd.xh.avatar();
ava["menu"] = null;
initialized = false;
gameOver = false;
dataExportsNode = $wnd.xh.root().first().xpath("DataExports");
dataExportedToPage = false;
// #xhcanvas
xhcanvas = $doc.querySelector("#xhcanvas");
xhcanvas.style.display = "flex";
xhcanvas.style.alignItems = "start";
// #xhcanvas > div#d3cp
var d3cpDiv = $doc.createElement("DIV");
d3cpDiv.id = "d3cp";
xhcanvas.appendChild(d3cpDiv);
// #xhcanvas > div#menu
menuDiv = $doc.createElement("DIV");
menuDiv.id = "menu";
//menuDiv.innerText = "menus";
xhcanvas.appendChild(menuDiv);
$wnd.xh.css.style("#xhcanvas > div#menu {font-family: monospace; font-size: 16px; font-weight: 400; margin-left: 5px;}"); // 13.3333px;
// temporarily, at the start of the game, only allow numbered commands that can be used to select an Island
cachedAkmObj = $wnd.JSON.parse($wnd.xh.avatarKeyMap());
akmStr = '{';
// allow player to select which island their Avatar will inhabit
var welcome = "Welcome castaway.\n\nWhere will you live?\nPlease type a number:\n--------------------\n";
var gcps = $wnd.xh.root().first().xpath("GridCellPatterns");
var gcp = gcps.first();
var akmComma = ''; // no comma the first time
while (gcp) {
if (gcp.xhc().name() == "GridCellPattern") {
welcome += "" + gcp.islandID + ": Island " + gcp.islandID + "\n";
akmStr += akmComma + '"' + gcp.islandID + '":"become this islandID ' + gcp.islandID + ';go link' + gcp.islandID + ';pause;become this menu menu"';
akmComma = ',';
}
gcp = gcp.next();
}
//welcome += "?- ";
menuDiv.innerText = welcome;
akmStr += '}';
$wnd.xh.avatarKeyMap(akmStr);
},
act: function() {
if (!initialized && (ava.obj().xhc().name() != "GridCellPatterns")) {
akmObj = cachedAkmObj;
cachedAkmObj = null;
// remove all the numbered keys in the key map
for (var i = 0; i < 10; i++) {
akmObj[i] = "";
}
$wnd.xh.avatarKeyMap($wnd.JSON.stringify(akmObj));
initialized = true;
}
if (!gameOver && (ava.obj().xhc().name() == "GameOver")) {
akmObj = {p:"pause;become this menu menu"};
cachedAkmObj = null;
$wnd.xh.avatarKeyMap($wnd.JSON.stringify(akmObj));
gameOver = true;
}
if (dataExportedToPage) {
var xhdiv = $doc.querySelector("div#xhimg");
if (xhdiv) {
//arrMsg = "data is being written to web page";
xhdiv.innerHTML = null;
}
dataExportedToPage = false;
}
var key = ava["menu"];
if (key) {
if (cachedAkmObj) {
// restore cached avatarKeyMap
akmObj = cachedAkmObj;
cachedAkmObj = null;
$wnd.xh.avatarKeyMap($wnd.JSON.stringify(akmObj));
}
akmObj = $wnd.JSON.parse($wnd.xh.avatarKeyMap());
// remove all the numbered keys in the key map
for (var i = 0; i < 10; i++) {
akmObj[i] = "";
// TODO cache the current menu
}
var arr = null;
switch (key) {
case "drop": // "drop;"
this.cacheAndClearMenu();
ava.action("pause;");
arr = ["DROP"];
this.makeInventoryStr("drop", "", arr);
arr.push("p:continue");
if (menuDiv) {menuDiv.innerText = arr.join("\n");}
break;
case "eat": // "eat;become this calories +=50"
this.cacheAndClearMenu();
ava.action("pause;");
arr = ["EAT"];
this.makeInventoryStr("eat", "become this calories +=25;", arr);
arr.push("p:continue");
if (menuDiv) {menuDiv.innerText = arr.join("\n");}
break;
case "recipe": // "recipe;"
this.cacheAndClearMenu();
ava.action("pause;");
arr = ["RECIPE"];
this.makeRecipesStr("recipe", arr);
arr.push("p:continue");
//arr.push("?- ");
if (menuDiv) {menuDiv.innerText = arr.join("\n");}
break;
case "take": // "take;" or "takeclone;"
this.cacheAndClearMenu();
ava.action("pause;");
arr = ["TAKE"];
this.makeSiblingsStr("take", arr);
arr.push("p:continue");
if (menuDiv) {menuDiv.innerText = arr.join("\n");}
break;
case "menu": // menu of menus
ava.action("pause;");
arr = ["MENUS"];
arr.push("d:DROP menu");
arr.push("e:EAT menu");
arr.push("r:RECIPE menu");
arr.push("t:TAKE menu");
arr.push("");
arr.push("MOVING");
arr.push("four arrow keys");
arr.push("n:enter (optional)");
arr.push("x:exit (optional)");
// "<" and ">" ?
arr.push("");
arr.push("OTHER");
arr.push("p:pause or unpause");
arr.push("s:step");
arr.push("$:export data");
if (menuDiv) {menuDiv.innerText = arr.join("\n");}
ava.action("pause");
break;
case "exportdata": //
this.cacheAndClearMenu();
ava.action("pause;");
arr = ["EXPORT DATA"];
this.exportData(arr);
dataExportedToPage = true;
arr.push("p:continue");
if (menuDiv) {menuDiv.innerText = arr.join("\n");}
break;
default: break;
}
ava["menu"] = null;
$wnd.xh.avatarKeyMap($wnd.JSON.stringify(akmObj));
}
},
// cache the current menu, and then set current menu to {}
cacheAndClearMenu: function() {
cachedAkmObj = akmObj;
akmObj = {};
akmObj["p"] = "pause;become this menu menu";
},
// export data to Dev Tools console
exportData: function(arr) {
var arrMsg = "data is being exported";
var xhdiv = $doc.querySelector("div#xhimg");
if (xhdiv) {
arrMsg = "data is being written to web page";
}
else {
arrMsg = "data has been written to Dev Tools";
}
arr.push(arrMsg);
arr.push("session data is ready for WebRTC Island Admin");
arr.push("avatar-state data is ready for WebRTC Island Admin");
var dataExportNode = null;
if (dataExportsNode) {
// remove any existing data
var denode = dataExportsNode.first();
while (denode) {
var denodeNext = denode.next();
denode.remove();
denode = denodeNext;
}
dataExportsNode.append('<DataExport></DataExport>');
dataExportNode = dataExportsNode.last();
}
var db;
var request = indexedDB.open("IslandGameDB");
request.onerror = function(event) {
console.log("Oops");
};
request.onsuccess = function(event) {
db = event.target.result;
var objectStore = db.transaction("session").objectStore("session");
objectStore.getAll().onsuccess = function(event) {
var jsonStr = JSON.stringify(event.target.result).trim();
jsonStr = jsonStr.substring(1, jsonStr.length-1); // remove [ and ]
var results = "[\n" + jsonStr.replace(/},{/gi, "},\n{") + "\n]";
if (xhdiv) {
var sessionDiv = $doc.createElement("PRE");
xhdiv.appendChild(sessionDiv);
sessionDiv.innerHTML = results;
}
else {
console.log(results);
}
if (dataExportNode) {
var xmlStr = '<Attribute_String roleName="SessionData">' + results + '</Attribute_String>';
dataExportNode.append(xmlStr);
}
};
var objectStore = db.transaction("avastate").objectStore("avastate");
objectStore.getAll().onsuccess = function(event) {
var jsonStr = JSON.stringify(event.target.result).trim();
jsonStr = jsonStr.substring(1, jsonStr.length-1); // remove [ and ]
var results = "[\n" + jsonStr.replace(/},{/gi, "},\n{") + "\n]";
if (xhdiv) {
var avastateDiv = $doc.createElement("PRE");
xhdiv.appendChild(avastateDiv);
avastateDiv.innerHTML = results;
}
else {
console.log(results);
}
if (dataExportNode) {
var xmlStr = '<Attribute_String roleName="AvastateData">' + results + '</Attribute_String>';
dataExportNode.append(xmlStr);
}
};
};
},
// drop 0:fish 1:fishingRod 2:fish 3:stick
makeInventoryStr: function(command, extras, arr) {
var item = ava.first();
var counter = 0;
while (item) {
arr.push(counter + ":" + item.name("R^^^^^"));
akmObj[counter] = command + " " + item.name("r:c_i^") + ";" + extras + "start;become this menu menu;";
counter++;
item = item.next();
}
},
makeSiblingsStr: function(command, arr) {
var item = ava.obj().first();
var counter = 0;
while (item) {
if (item != ava && (item.first()) && (item.first())["maxClones"]) {
var cloneable = item.first();
while (cloneable) {
if (cloneable["maxClones"]) {
arr.push(counter + ":" + cloneable.name("R^^^^^"));
akmObj[counter] = "enter " + item.name("r:c_i^") + ";" + "takeclone" + " " + cloneable.name("r:c_i^") + ";exit;start;become this menu menu;";
counter++;
}
cloneable = cloneable.next();
}
}
else if (item != ava) {
arr.push(counter + ":" + item.name("R^^^^^"));
akmObj[counter] = command + " " + item.name("r:c_i^") + ";start;become this menu menu;";
counter++;
}
item = item.next();
}
},
// recipe 0:basket 1:fishingRod 2:hut
makeRecipesStr: function(command, arr) {
var counter = 0;
var recipeService = $wnd.xh.service("RecipeService");
var nmsg = recipeService.call(-3895, "RecipeService-MinecraftStyleRecipeBook-Island", me);
var namesStr = null;
if (nmsg) {
namesStr = nmsg.data;
}
if (namesStr) {
var namesArr = namesStr.split(",");
var potentialsArr = []; // recipes that currently lack sufficient ingredients
for (var i = 0; i < namesArr.length; i++) {
var name = namesArr[i];
var imsg = recipeService.call(-3896, ["RecipeService-MinecraftStyleRecipeBook-Island", name], me); // get ingredients
if (imsg && imsg.data && imsg.data[0]) {
var ingredients = imsg.data[0]["ingredients"];
var ingredientsStr = ingredients.join(",");
var bool = ava.includes(ingredientsStr, "^^C^^^", ",");
var istr = ingredientsStr.replace(/,/gi, '+');
if (bool) {
var nameLcase = name.charAt(0).toLowerCase() + name.substring(1);
arr.push(counter + ":" + name + " = " + istr);
akmObj[counter] = command + " " + name + ";take " + nameLcase + ";start;become this menu menu;";
counter++;
}
else {
potentialsArr.push(name + " = " + istr);
}
}
}
// put the potential recipes after those that are currently actionable
Array.prototype.push.apply(arr, potentialsArr);
}
}
}
//# sourceURL=MenuHandlerbehavior.js
]]></MenuHandlerbehavior>
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml,
<svg width="180" height="10" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Ocean</title>
<rect id="IslandSystem/Ocean" fill="#98FB98" height="10" width="50" x="0" y="0"/>
<g>
<title>Island</title>
<rect id="IslandSystem/Ocean/Island" fill="#6AB06A" height="10" width="10" x="55" y="0"/>
</g>
<g>
<title>PlantBehaviors</title>
<rect id="IslandSystem/PlantBehaviors" fill="orange" height="10" width="10" x="75" y="0"/>
</g>
<g>
<title>FishBehaviors</title>
<rect id="IslandSystem/FishBehaviors" fill="orange" height="10" width="10" x="95" y="0"/>
</g>
<g>
<title>GridCellPatterns</title>
<rect id="IslandSystem/GridCellPatterns" fill="blue" height="10" width="10" x="115" y="0"/>
</g>
<g>
<title>City</title>
<rect id="IslandSystem/Space/descendant::City" fill="purple" height="10" width="10" x="135" y="0"/>
</g>
</g>
</svg>
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient>
</XholonWorkbook>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment