· 8 years ago · Dec 07, 2017, 10:32 AM
1VERSION_NUMBER = '2.5'
2VERSION_NAME = 'Catalogos Horizontalis'
3os.loadAPI('utils')
4os.loadAPI('registry')
5os.loadAPI('tracker')
6os.loadAPI('json')
7
8
9local DEBUG_MODE = registry.DEBUG_MODE or true
10--local monitor = peripheral.wrap("right")
11
12--contains a list of all posible Buildzones (built a bit later)
13local LOCS = {}
14local cleanbuildzone = false
15
16--DOING build the spawnzone area:
17--DONE grid center is now the center of spawn zone and the computer is there
18--DONE spawn zone is 19 blocks from center = 39 blocks
19--DONE has a white glass fence all around
20--TODO spawn zone grid with 3x3 jump areas to tp into any available buildzone for playing (from 1 to 9)
21
22
23
24--
25--TODO place chunkloaders in a grid that would cover the play area and the catalogue area
26--TODO game area depends on:
27--TODO make a platfrom under the computer with the right dimensions - size of play area, size of catalogue, space between them from snow
28--TODO place color points for goal/rewards specification
29--TODO number the catalogue slots
30--TODO save a local file after successful creation to mark the used variables
31--TODO if upon start the settigns differ from the ones in the local file then delete and remodel from scratch, dont remove catalogue or play creations by players
32
33-- need a script to clean up the air above the game area and one to clean above the catalgoue area, both using the current settings in registry
34--we then need a new script to save old catalogues to external files
35-- and another script to restore old catalgoues to new catalogue slots from external file
36
37-- DONE remove the computer dependency on the monitor
38-- DONE draw the borders of grid slots
39-- DONE place the grid points along the area in sandstone
40-- DONE mark the play area in sandstone
41-- DONE mark the catalogue area for keys in sandstone
42-- DONE draw the grid points within the catalogue slots
43-- DONE draw the grid points and place the activator stones in the play area
44-- DONE move the code from 555-575 that verifies the voceb slots to a better suited location
45-- DONE also we need to save the changeable parameters from registry into a local file so that when people update they dont loose their settings (if parameter not in local registry then add it)
46
47
48----UTILITY FUNCTIONS
49
50local function BitAND(a,b)--Bitwise and
51 local p,c=1,0
52 while a>0 and b>0 do
53 local ra,rb=a%2,b%2
54 if ra+rb>1 then c=c+p end
55 a,b,p=(a-ra)/2,(b-rb)/2,p*2
56 end
57 return c
58end
59
60function lshift(x, by)
61 return x * 2 ^ by
62end
63
64function rshift(x, by)
65 return math.floor(x / 2 ^ by)
66end
67
68--sort table by random
69local function shuffleTable( t )
70 local rand = math.random
71 assert( t, "shuffleTable() expected a table, got nil" )
72 local iterations = #t
73 local j
74
75 for i = iterations, 2, -1 do
76 j = rand(i)
77 t[i], t[j] = t[j], t[i]
78 end
79end
80
81-- returns how many items are in a table/list
82function tablelength(T)
83 local count = 0
84 for _ in pairs(T) do count = count + 1 end
85 return count
86end
87
88--fills a region recursively even if it is bigger by the allowed number of blocks
89function fillSmart(material,x,y,z,sizeX,sizeY,sizeZ)
90 --check if volume is bigger than maximum blocks 32768
91 local limit = 32768
92 local w,h,l = sizeX, sizeY, sizeZ
93 --print("which is nil?", w,h,l)
94 if math.abs(w*l*h) <= limit then
95 --if not then do simple fill
96 --print("filling in one go:",x,y,z,x+w-(w/math.abs(w)),y+h-(h/math.abs(h)),z+l-(l/math.abs(l)),material)
97 commands.async.fill(x,y,z,x+w-(w/math.abs(w)),y+h-(h/math.abs(h)),z+l-(l/math.abs(l)),material)
98 return true
99 else
100 --divide in 8 sub-boxes and run again
101 local halfW = math.floor(w/2)
102 local restW = w-halfW
103 local halfH = math.floor(h/2)
104 local restH = h-halfH
105 local halfL = math.floor(l/2)
106 local restL = l-halfL
107 --check if one of them is zero
108 fillSmart(material, x+halfW, y+halfH, z+halfL, restW, restH, restL) --always run
109 --
110 if math.abs(halfW) > 0 then
111 fillSmart(material, x, y+halfH, z+halfL, halfW, restH, restL) --run if halfW is not zero
112 end
113 if math.abs(halfH) > 0 then
114 fillSmart(material, x+halfW, y, z+halfL, restW, halfH, restL) --run if halfH is not zero
115 end
116 if math.abs(halfL) > 0 then
117 fillSmart(material, x+halfW, y+halfH, z, restW, restH, halfL) --run if halfL is not zero
118 end
119 ---
120 if math.abs(halfW) > 0 and math.abs(halfH) > 0 then
121 fillSmart(material, x, y, z+halfL, halfW, halfH, restL) --run if halfs W and H are not zero
122 end
123 if math.abs(halfL) > 0 and math.abs(halfH) > 0 then
124 fillSmart(material, x+halfW, y, z, restW, halfH, halfL) --run if halfH and halfL are not zero
125 end
126 if math.abs(halfW) > 0 and math.abs(halfL) > 0 then
127 fillSmart(material, x, y+halfH, z, halfW, restH, halfL) -- run if half W and L are not zero
128 end
129 ---
130 if math.abs(halfW) > 0 and math.abs(halfH) > 0 and math.abs(halfL) > 0 then
131 fillSmart(material, x, y, z, halfW, halfH, halfL) --run if neither half is zero
132 end
133 return true
134 end
135 return false
136end
137
138--creates a ring of blocks using coordinates
139function fillRing(material,x,y,z,sizeX,sizeZ,height)
140 local h = 1
141 if height then
142 h = height
143 end
144 fillSmart(material,x,y,z,sizeX,h,1)
145 fillSmart(material,x,y,z,1,h,sizeZ)
146 fillSmart(material,x+sizeX-1,y,z,1,h,sizeZ)
147 fillSmart(material,x,y,z+sizeZ-1,sizeX,h,1)
148end
149
150--fills an offset region of the specified one
151--direction: true - outside; false - inside
152function fillSmartOffset(material,x,y,z,sizeX,sizeY,sizeZ,offset, direction)
153 if offset == 0 then
154 fillSmart(material,x,y,z,sizeX,sizeY,sizeZ)
155 return
156 end
157 local uX = sizeX/math.abs(sizeX)
158 local uY = sizeY/math.abs(sizeY)
159 local uZ = sizeZ/math.abs(sizeZ)
160 if direction then
161 --outside offset
162 fillSmart(material,x-uX*offset,y-uY*offset,z-uZ*offset,sizeX+2*uX*offset,sizeY+2*uY*offset,sizeZ+2*uZ*offset)
163 else
164 --inside offset
165 fillSmart(material,x+uX*offset,y+uY*offset,z+uZ*offset,sizeX-2*uX*offset,sizeY-2*uY*offset,sizeZ-2*uZ*offset)
166 end
167end
168
169--fills an offset region of the specified one
170-- offsets only along X and Z, doesnt offset vertically
171--direction: true - outside; false - inside
172function fillSmartOffsetXZ(material,x,y,z,sizeX,sizeY,sizeZ,offset, direction)
173
174 if offset == 0 then
175 fillSmart(material,x,y,z,sizeX,sizeY,sizeZ)
176 return
177 end
178 local uX = sizeX/math.abs(sizeX)
179 --local uY = sizeY/math.abs(sizeY)
180 local uZ = sizeZ/math.abs(sizeZ)
181 if direction then
182 --outside offset
183 fillSmart(material,x-uX*offset,y,z-uZ*offset,sizeX+2*uX*offset,sizeY,sizeZ+2*uZ*offset)
184 else
185 --inside offset
186 fillSmart(material,x+uX*offset,y,z+uZ*offset,sizeX-2*uX*offset,sizeY,sizeZ-2*uZ*offset)
187 end
188end
189
190-- fills a horizontal region with grid markers
191-- takes the grid settings from the registry
192-- grid origin is the main computer
193function fillGrid(material,x,y,z,sizeX,sizeZ)
194 local uX = sizeX/math.abs(sizeX)
195 local uZ = sizeZ/math.abs(sizeZ)
196 for ix = x, x+sizeX-uX, uX do
197 for iz = z, z+sizeZ - uZ, uZ do
198 --check if the coordinate is a grid point
199 if (ix-registry.computer.x) % registry.GRIDCELL_SIZE == 0 and (iz-registry.computer.z) % registry.GRIDCELL_SIZE == 0 then
200 commands.async.setblock(ix,y,iz,material)
201 end
202 end
203 end
204end
205
206--PARTICLE FUNCTIONS
207--particles shown to player while their shape is being checked for match
208function searchParticle(x,y,z)
209 commands.async.particle("fireworksSpark",x,y,z,0.01,3,0.01,0.01,100)
210end
211-- particles shown to player on successful vocab match
212function successParticle(x,y,z)
213 commands.async.particle("happyVillager",x,y,z,2,2,2,1,1000)
214 commands.async.playsound("random.levelup","@a",x,y,z,1,1.2)
215end
216--- particles shown to player on failed vocab match
217function failParticle(x,y,z)
218 commands.async.particle("reddust",x,y,z,0.1,0.1,1.5,1,200)
219 commands.async.particle("reddust",x,y,z,1.5,0.1,0.1,1,200)
220 commands.async.playsound("random.bowhit","@a",x,y,z,1,0.8)
221end
222
223----END OF UTILITY FUNCTIONS
224
225--creates a grid of absolute references (0,0) (1,0)
226--rename to buildGameField
227function buildGrid(w,h)
228 local grid = readGridFromFile()
229 if grid then
230 -- grid was read from the file successfully
231 else
232 --generate file from scratch
233 grid = {}
234 for z=0,h-1 do
235 for x=0,w-1 do
236 table.insert(grid,{x=x,z=z,played=false})
237 end
238 end
239 end
240 return grid
241end
242
243function readGridFromFile()
244 local result = nil
245 fs.makeDir("/records")
246 local filename = "/records/_buildzones-list.json"
247
248 if utils.file_exists(filename) then
249 ---read from file
250 result = json.decodeFromFile(filename)
251 end
252 return result
253end
254
255function writeGridToFile()
256 fs.makeDir("/records")
257 local filename = "/records/_buildzones-list.json"
258
259 local file = fs.open(filename,"w")
260 file.write(json.encodePretty(LOCS))
261 file.close()
262end
263
264--- Constructor for playerdata object
265-- @param name the player minecraft name as a string
266-- @param x the players current X coord
267-- @param y the players current Y coord
268-- @param z the players current Z coord
269-- @table p The new player object
270-- @return p The new player object
271function newPlayerData(name,x,y,z)
272 local p = {
273 name = name, -- the players minecraft name (String)
274 x = x, -- the players last X coord
275 y = y, -- the players last Y coord
276 z = z -- the players last Z coord
277 }
278 return p
279end
280
281--return a list of all players in the game world as player objects
282local function getAllPos(selector)
283 local result, message = commands.tp("@a["..selector.."]","~ ~ ~")
284 local names = {}
285 if result == true then
286 for i,result in ipairs(message) do
287 local wordpattern = "[^, ]+"
288 local numberpattern = "[%-% ]%d+[%.]%d+"
289 local words,numbers = {},{}
290
291 for word in string.gmatch(result, wordpattern) do
292 table.insert(words,word)
293 end
294
295 for number in string.gmatch(result, numberpattern) do
296 table.insert(numbers,number)
297 end
298
299 local coords = {
300 x = math.floor(numbers[1]),
301 y = math.floor(numbers[2]),
302 z = math.floor(numbers[3])
303 }
304 local name = words[2]
305 table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
306 end
307 end
308 return names
309end
310
311
312--returns a list of player objects containing all players who are standing on the given block, and who also are in the given selection
313local function getAllOnBlockType(block,selector)
314 local result, message = commands.exec("execute @a["..selector.."] ~ ~ ~ detect ~ ~-1 ~ "..block.." -1 tp @p[r=1] ~ ~ ~")
315 local names = {}
316 if result == true then
317 for i,result in ipairs(message) do
318 local wordpattern = "[^, ]+"
319 local numberpattern = "[%-% ]%d+[%.]%d+"
320 local words,numbers = {},{}
321
322 for word in string.gmatch(result, wordpattern) do
323 table.insert(words,word)
324 end
325 for number in string.gmatch(result, numberpattern) do
326 table.insert(numbers,number)
327 end
328
329 if numbers[1] and numbers[2] and numbers[3] then
330 local coords = {
331 x = math.floor(numbers[1]),
332 y = math.floor(numbers[2]),
333 z = math.floor(numbers[3])
334 }
335 local name = words[2]
336 table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
337 --print("Found a player - getOnBlock")
338 else
339 --print("Error: Coordinate Numbers were missing")
340 end
341 end
342 end
343 return names
344end
345
346---BEGIN HOMECOMER RELATED FUNCTIONS
347
348--gives a player a HOMECOMER egg with their name on it. Removes all spawn eggs first
349local function giveHomecomer(name)
350 commands.clear(name,'spawn_egg')
351
352 commands.give(name,'spawn_egg 1 '..registry.HOMECOMER_VALUE..' {CanPlaceOn:["'..registry.BLOCKS.PHVFLOOR.block..'","'..registry.BLOCKS.CAMP_FLOOR.block..'","'..registry.BLOCKS._matWhiteSmooth.block..'","'..registry.BLOCKS._matWhiteSmooth2.block..'","'..registry.BLOCKS._matYellowSmooth.block..'","'..registry.BLOCKS._matPinkSmooth.block..'","'..registry.BLOCKS._matBlueSmooth.block..'","'..registry.BLOCKS._matPurpleSmooth.block..'","'..registry.BLOCKS._matWhiteTextured.block..'","'..registry.BLOCKS._matYellowTextured.block..'","'..registry.BLOCKS._matPinkTextured.block..'","'..registry.BLOCKS._matBlueTextured.block..'","'..registry.BLOCKS._matPurpleTextured.block..'"],display:{Name:"HOMECOMER - '..name..'",Lore:[Use this on the floor to return to spawn]}}')
353end
354
355--returns a list of HOMECOMER entities and their names
356local function getHomecomers()
357 local result, message = commands.exec("execute @e[type="..registry.HOMECOMER_TYPE.."] ~ ~ ~ tp @e[r=1] ~ ~ ~")
358 local names = {}
359 if result == true then
360 for i,result in ipairs(message) do
361 local wordpattern = "[^, ]+"
362 local numberpattern = "[%-% ]%d+[%.]%d+"
363 local words,numbers = {},{}
364
365 for word in string.gmatch(result, wordpattern) do
366 table.insert(words,word) print(word)
367 end
368 for number in string.gmatch(result, numberpattern) do
369 table.insert(numbers,number)
370 end
371
372 if numbers[1] and numbers[2] and numbers[3] then
373 local coords = {
374 x = math.floor(numbers[1]),
375 y = math.floor(numbers[2]),
376 z = math.floor(numbers[3])
377 }
378 local name = words[4]
379 table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
380 --print("Found a player - getOnBlock "..name)
381 else
382 --print("Error: Coordinate Numbers were missing")
383 end
384 end
385 end
386 return names
387end
388
389--takes a list of homecomers and deals with all those players, moving them back to spawn and removing them from game
390--also gives them a new homecomer
391local function dealWithHomecomers(game, homecomers)
392 for _,homecomer in pairs(homecomers) do
393 --remove player from current game if in game
394 removePlayerFromKew(game,homecomer.name)
395 --teleport them back to spawn
396 movePlayerToSpawn(homecomer.name)
397 --give a new homecomer
398 giveHomecomer(homecomer.name)
399 --particle effects
400 --teleport message
401 end
402 --kill all homecomers
403 if #homecomers>0 then
404 commands.tp("@e[type="..registry.HOMECOMER_TYPE.."]",100000,200,100000)
405 commands.kill("@e[type="..registry.HOMECOMER_TYPE.."]")
406 os.sleep(#homecomers*0.2)
407 end
408end
409
410---
411function checkForHomecomers(game)
412 --execute on all homecomers
413 local homecomers = getHomecomers()
414 dealWithHomecomers(game,homecomers)
415end
416
417--- END OF HOMECOMER FUNCTIONS
418
419-- removes a player from a game queue
420local function removePlayerFromKew(game,playername)
421 for _,kew in pairs(game.queues) do
422 for index, player in ipairs(kew.playerlist) do
423 if player.name == playername then
424 table.remove(kew.playerlist,index)
425 end
426 end
427 if #kew.playerlist == 0 and kew.phase == 2 then
428 --game can be ended as no players are left
429 kew.timer = 0
430 end
431 end
432end
433
434--teleports a player ot the spawn area
435local function movePlayerToSpawn(playername)
436 respawnPlayer(playername)
437 commands.async.tp(playername,registry.SPAWN.x,registry.SPAWN.y,registry.SPAWN.z,registry.SPAWN.a1,registry.SPAWN.a2)
438 if registry.ANNOUNCE_ENGLISH then
439 commands.async.tellraw(playername,'["",{"text":"You used your HOMECOMER and TELEPORTED BACK TO SPAWN","color":"white"}]')
440 end
441 if registry.ANNOUNCE_GERMAN then
442 commands.async.tellraw(playername,'["",{"text":"Du hast den HEIMKEHRER benutzt um dich zurück zum Anfang zu teleportieren.","color":"gold"}]')
443 end
444end
445
446--creates a villager with special items
447local function spawnVillager(x,y,z)
448 commands.summon("Villager",x,y,z,'{Invulnerable:1,CustomName:Wool_Seller,Profession:2,Career:1,CareerLevel:6,Offers:{Recipes:[ {buy:{id:emerald,Count:1},sell:{id:wool,Count:'..registry.WOOL_PER_EMERALD..',tag:{CanPlaceOn:["minecraft:diamond_block","minecraft:clay","minecraft:wool","minecraft:stained_hardened_clay"]}}}, {buy:{id:emerald,Count:1},sell:{id:stone_pickaxe,Count:1,Damage:'..131-registry.PICKAXE_USES..',tag:{CanDestroy:["minecraft:wool"]}}} ]}}')
449end
450
451
452--displays a time as experience points to a selection of players
453local function displayTime(selector,minutes,seconds)
454 --commands.title("@a["..selector.."]","subtitle",'{text:"Time left: '..minutes..":"..seconds..'",color:red,bold:false,underlined:false,italic:false,strikethrough:false,obfuscated:false}')
455 commands.async.xp("-1000000L","@a["..selector.."]")
456 local secondstot = (minutes * 60) + seconds
457 commands.async.xp(tostring(secondstot).."L","@a["..selector.."]")
458end
459
460--simply runs displayTime on a list of players
461local function displayTimeToGroup(playerlist,minutes,seconds)
462 for i,player in ipairs(playerlist) do
463 displayTime("name="..player.name,minutes,seconds)
464 end
465end
466
467--displays a title to a selection of players
468local function displayTitle(selector,text)
469 commands.async.title("@a["..selector.."]","title",'{text:"'..text..'"}')
470end
471
472--simply runs displayTitle on a list of players
473local function displayTitleToGroup(playerlist,text)
474 for i,player in ipairs(playerlist) do
475 displayTitle("name="..player.name,text)
476 end
477end
478
479--teleports a list of players to an exact place and sends them a message about it
480local function teleportToPoint(x,y,z,playerlist,clear,textEN, textDE)
481 for i,player in ipairs(playerlist) do
482 player.x = x
483 player.y = y
484 player.z = z
485 commands.async.gamemode(2,player.name)
486 if clear then
487 commands.async.clear(player.name,"wool")
488 commands.async.clear(player.name,"stone_pickaxe")
489 end
490 commands.tp("@a[name="..player.name.."]",x,y,z)
491 if registry.ANNOUNCE_ENGLISH then
492 commands.async.tellraw(player.name,'["",{"text":"'..textEN..'","color":"white"}]')
493 end
494 if registry.ANNOUNCE_GERMAN then
495 commands.async.tellraw(player.name,'["",{"text":"'..textDE..'","color":"gold"}]')
496 end
497 end
498end
499
500--teleports a list of players to a given buildzone
501local function teleportToZone(buildzone,playerlist,textEN, textDE)
502 teleportToPoint(buildzone.x+2+(buildzone.w/2),buildzone.y+5,buildzone.z+2+(buildzone.w/2),playerlist,true,textEN, textDE)
503
504end
505
506--gives the same list of items to a list of players
507local function giveItems(playerlist,itemlist)
508 print("Giving initial inventory items to players")
509 local given = 0
510 for i,player in ipairs(playerlist) do
511 --commands.async.clear(player.name)
512 for j,item in ipairs(itemlist) do
513 commands.async.give("@a[name="..player.name.."]",item)
514 given = given +1
515 end
516 giveHomecomer(player.name)
517 end
518 print("Giving initial inventory items to players...DONE!")
519 return given
520end
521
522--[[
523--vocab constructor. Enforces some data structure
524--obsolete - see next function newCatalogueElement
525function newVocabZone(x,y,z,w,id, reward,nameEN, nameDE, typeEN, typeDE, height, slots,green,greenSlots, rewardUrban, rewardCount)
526 local nvz = {}
527 nvz.x ,nvz.y ,nvz.z ,nvz.w = x,y,z,w
528
529 nvz.cx = nvz.x - nvz.w - 2
530 nvz.cy = nvz.y
531 nvz.cz = nvz.z
532 nvz.nameEN = nameEN
533 nvz.reward = reward
534 --- new stuff
535 nvz.id = id
536 nvz.nameDE = nameDE
537 nvz.typeEN = typeEN
538 nvz.typeDE = typeDE
539 nvz.height = height
540 nvz.slots = slots
541 nvz.green = green
542 nvz.greenSlots = greenSlots
543 nvz.rewardUrban = rewardUrban
544 nvz.rewardCount = rewardCount
545
546 return nvz
547
548end
549--]]
550
551--a catalogue slot constructor. Enforces some data structure
552function newCatalogueElement(id, x,y,z,sizeX, sizeZ) --, reward,nameEN, nameDE, typeEN, typeDE, height, slots,green,greenSlots, rewardUrban, rewardCount)
553 local nvz = {}
554 nvz.id = id
555 nvz.keyX ,nvz.keyY ,nvz.keyZ = x,y,z
556 nvz.sizeX, nvz.sizeZ = sizeX, sizeZ
557 nvz.elementX = nvz.keyX - nvz.sizeX - registry.GRIDCELL_SIZE --
558 nvz.elementY = nvz.keyY
559 nvz.elementZ = nvz.keyZ
560 nvz.elementCenterX = nvz.elementX + math.floor ( nvz.sizeX/2 )
561 nvz.elementCenterY = nvz.elementY
562 nvz.elementCenterZ = nvz.elementZ + math.floor ( nvz.sizeZ/2 )
563 nvz.keyCenterX = nvz.keyX + math.floor ( nvz.sizeX/2 )
564 nvz.keyCenterY = nvz.keyY
565 nvz.keyCenterZ = nvz.keyZ + math.floor ( nvz.sizeZ/2 )
566
567 -- nvz.nameEN = nameEN
568-- nvz.reward = reward
569-- --- new stuff
570--
571-- nvz.nameDE = nameDE
572-- nvz.typeEN = typeEN
573-- nvz.typeDE = typeDE
574-- nvz.height = height
575-- nvz.slots = slots
576-- nvz.green = green
577-- nvz.greenSlots = greenSlots
578-- nvz.rewardUrban = rewardUrban
579-- nvz.rewardCount = rewardCount
580--
581 --print(json.encodePretty(nvz))
582 return nvz
583
584end
585
586--a multi builder which uses the vocab constructor to create sets of vocab
587--OBSOLETE - see next function initCatalogueElements
588--[[
589local function makeVocabZones(quant,w) --OBSOLETE
590 local x,y,z = registry.FIRSTVOCAB.x, registry.FIRSTVOCAB.y, registry.FIRSTVOCAB.z
591 local result = {}
592 local id = 1
593 for i=0,quant-1 do
594 for k=0,3 do
595 local zpos = i-4
596 local ypos = k
597 --print("vocab at X")
598 --print(x-(2*w)-6)
599 --print("and Z")
600 --print(z+((w+1)*zpos))
601 local nextVocab = newVocabZone(
602 x-(2*w)-6,y+(ypos*(registry.VOCAB_HEIGHT+3)),
603 z+((w+1)*zpos),
604 w,
605 id,
606 registry.REWARDS[id] or registry.DEFAULT_REWARD,
607 registry.VOCABS_DATA[id].nameEN or registry.DEFAULT_NAME,
608 registry.VOCABS_DATA[id].nameDE or registry.DEFAULT_NAME,
609 registry.VOCABS_DATA[id].typeEN,
610 registry.VOCABS_DATA[id].typeDE,
611 registry.VOCABS_DATA[id].height,
612 registry.VOCABS_DATA[id].slots,
613 registry.VOCABS_DATA[id].green,
614 registry.VOCABS_DATA[id].greenSlots,
615 registry.VOCABS_DATA[id].rewardUrban,
616 registry.VOCABS_DATA[id].rewardCount
617 )
618 table.insert(result,nextVocab)
619 id = id +1
620 end
621 end
622
623 return result
624end
625--]]
626--a multi builder which uses the vocab constructor to create sets of vocab
627local function initCatalogueElements(countX, countZ, sizeX, sizeZ)
628 local x,y,z = registry.FIRST_ELEMENT.x, registry.FIRST_ELEMENT.y, registry.FIRST_ELEMENT.z
629 local result = {}
630 local id = 1
631 for i=0,countZ-1 do
632 for k=0,countX-1 do
633
634 local xpos = x - k * ( registry.GRIDCELL_SIZE * ( 2*registry.CATALOGUE_SLOTSIZE.x + 2 + registry.CATALOGUE_SLOT_OFFSET))
635 local ypos = y
636 local zpos = z + i*( registry.GRIDCELL_SIZE * ( registry.CATALOGUE_SLOTSIZE.z + 1 + registry.CATALOGUE_SLOT_OFFSET))
637 --print("adding an element",i,k)
638 local nextElement = newCatalogueElement(
639 id,
640 xpos,ypos,zpos,
641 sizeX, sizeZ
642 )
643
644 -- registry.REWARDS[id] or registry.DEFAULT_REWARD,
645 -- registry.VOCABS_DATA[id].nameEN or registry.DEFAULT_NAME,
646 -- registry.VOCABS_DATA[id].nameDE or registry.DEFAULT_NAME,
647 -- registry.VOCABS_DATA[id].typeEN,
648 -- registry.VOCABS_DATA[id].typeDE,
649 -- registry.VOCABS_DATA[id].height,
650 -- registry.VOCABS_DATA[id].slots,
651 -- registry.VOCABS_DATA[id].green,
652 -- registry.VOCABS_DATA[id].greenSlots,
653 -- registry.VOCABS_DATA[id].rewardUrban,
654 -- registry.VOCABS_DATA[id].rewardCount
655 -- )
656 table.insert(result,nextElement)
657 id = id +1
658 end
659 end
660 --print(json.encodePretty(result))
661 return result
662end
663
664--- Finds the next free location for a buildzone in a given list of spots.
665-- Searches each zone in zones for an empty location.
666-- Zone are absolute positions (0,0),(0,1) ect.
667-- This uses the coords of FIRST_ZONE as given in the registry to determine
668-- the position of the zones for checking.
669-- @param zones A list of zones from BuildLocs()
670-- @param force Boolean. True will mean it returns the first location no matter what
671-- @return x The X value of the next unused location in world-coordinates
672-- @return y The Y value of the next unused location in world-coordinates
673-- @return z The Z value of the next unused location in world-coordinates
674-- @return locid The index of the returned zone
675local function findNextLoc(zones,force)
676 local x,y,z,locid = 0,0,0,1
677 for i,loc in ipairs(LOCS) do
678 locid = i
679 -- these are the coordinates of this LOC in the minecraft world
680 x = registry.FIRST_ZONE.x+(loc.x*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE))
681 y = registry.FIRST_ZONE.y
682 z = registry.FIRST_ZONE.z+(loc.z*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE))
683 --print("testing for available zone at: "..x..", "..y..", "..z)
684 --print("which is at grid cell at: "..loc.x..", "..loc.z)
685 --local result,message = commands.testforblock(x,y+registry.BUILDZONE_FLOOR_HEIGHT,z,"minecraft:air") -- this was used for the testing based on the minecraft model
686 local result = true
687 if loc.played then
688 result = false
689 --print("zone has been played")
690 end
691 --print("testing done")
692 --force the first zone to be selected unless it is taken in the "zones" parameter
693 if force then result = true end
694 --checks if the zone is already in the list of unavailable zones passed as parameter
695 local zonefree = true
696 for i,zone in ipairs(zones) do
697 if zone.x == x and zone.z == z then
698 zonefree = false
699 end
700 end
701 --print("next position free is ",loc.x*width,oy,loc.z*width)
702 --if result then print("true") else print("false") end
703 if result and zonefree then
704 print("using loc: ",loc.x,loc.y,loc.z)
705 print("with locid: ",locid)
706 return x,y,z,locid --returns the coordinates of the new zone, plus its id in the LOCS table
707 end
708 end
709 return nil,nil,nil, nil --returns empty if no zone is available
710
711end
712
713
714--- Assigns the next unused available play area to an abstract buildzone object
715-- This takes a Buildzone and an array of Absolute references
716-- from BuildGrid(). It find the next area by using FindNextLoc().
717-- When we change a buildzones coords it is important to update locid and
718-- the selector so that all systems know where the buildzone is.
719-- @param buildzone the buildzone object to be moved
720-- @param zones a list of zones to choose from
721-- @return a boolean result. True if the buildzone was moved
722function moveBuildzone(buildzone,zones)
723 local x,y,z,locid = findNextLoc(zones)
724 if x and y and z and locid then
725 --print("moved buildzone from "..buildzone.x..","..buildzone.z.." to "..x..","..y)
726 local w = buildzone.w
727 buildzone.x,buildzone.y,buildzone.z = x,y,z
728 buildzone.locid = locid --reassign the location id corresponding to the LOCS item for the grid cell of the moved zone
729 buildzone.selector = "x="..x..",y="..tostring(y-1)..",z="..z..",dx="..w..",dy=256,dz="..w
730 ---buildzone.structures = {} --a list of all vocabularies which have been contructed
731 return true
732 end
733 return false
734end
735
736--multi builder to create sets of buildzones using the buildzone constructor
737local function initBuildzones(quant,elements)--,width)--,floorHeight)
738 local result = {}
739 for i=1,quant do
740 --print("locating available slot")
741 local x,y,z,locid = findNextLoc(result)
742 if x and y and z and locid then
743 print("Created a new Buildzone at",x,y,z)
744 table.insert(result,newBuildZone(x,y,z,elements,locid))
745 else
746 --print("failed to make new buildzone")
747 end
748 end
749
750 local remaining = registry.NUMBER_OF_BUILDZONES - #result
751 --print("doing this remaining thing")
752 for i=1, remaining do
753 local x,y,z,locid = findNextLoc(result,true)
754 if x and y and z and locid then
755 --print("forced new buildzone at",x,y,z)
756 table.insert(result,newBuildZone(x,y,z,elements,locid))
757 else
758 --print("failed to force new buildzone")
759 end
760 end
761
762
763 return result
764end
765
766
767
768--- Buildzone constructor. Enforces some data structure
769-- Buildzones record information about the structures which are built
770-- inside them, as well as which elements of the catalogue are
771-- available to be built in them. Buildzones record where they are in
772-- three ways (locid, selector and coords). Buildzones do not know
773-- who is playing in them right now, or how long is left in a game
774-- @param x Where you first want to place the buildzone
775-- @param y Where you first want to place the buildzone
776-- @param z Where you first want to place the buildzone
777-- @param elementZones An array of catalogue items that can be built here
778-- @param locid The buildzones starting location in the buildLocs() array
779function newBuildZone(x,y,z,elementZones,locid)
780 local nbz = {}
781 nbz.x ,nbz.y ,nbz.z ,nbz.w = x,y,z,registry.BUILDZONE_WIDTH
782 nbz.selector = "x="..nbz.x..",y="..(nbz.y-1)..",z="..nbz.z..",dx="..nbz.w..",dy=256,dz="..nbz.w
783 --nbz.structures = {} --a list of all vocabularies names which have been contructed
784 nbz.buildings = {} --a list of all vocabularies with full data (x,y,z,id,name) which have been contructed
785 --nbz.filledSlots = 0 --to count how many slots have been filled with buildings. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
786 --nbz.greenSlots = 0 --to count how many of the slots are green. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
787 --nbz.variety = {} -- this stores how many buildings of each type are there. it is indexed on vocab.id and the value is the number of buildings from type vocab.id
788 nbz.waitingForCheck = {}
789 nbz.highest = 0
790 nbz.elements = elementZones
791 nbz.locid = locid
792 return nbz
793end
794
795--- Kew constructor. Enforces some data structure
796-- Kews are used for timekeeping and to record which players are
797-- interacting where. Each queue can only have 1 buildzone, but may have
798-- many players. Buildzones may move location, but Kews do not.
799-- @param buildzone The buildzone object to associate with this Kew
800-- @param maxplayers How many players are allowed to play in the buildzone
801-- @return The constructed Kew Object
802function newQueue(buildzone,maxplayers)
803 local q = {}
804 q.timer = 1
805 q.phase = 1
806
807 q.victory = false
808 q.phases = {
809 {
810 name = "Selecting Players",
811 length = registry.PHASE_LENGTH_WAIT,
812 displaylength = 15 --this field is not used
813 },
814 {
815 name = "Game In Progress",
816 length = registry.PHASE_LENGTH_GAME,
817 displaylength = 70 --this field is not used
818 },
819 {
820 name = "Round Complete",
821 length = registry.PHASE_LENGTH_OVER,
822 displaylength = 5 --this field is not used
823 }
824 }
825 q.playerlist = {}
826 q.maxplayers = maxplayers
827 q.buildzone = buildzone
828 local timestamp = math.floor(os.clock())
829 q.filename = timestamp.."at"..q.buildzone.x.."_"..q.buildzone.z
830 return q
831end
832
833--checks if the game has been run, if the game area has been created already and if it there is a change of the paramteres that define it
834function checkForGameAreaParametersChanges()
835 --1. assemble a json object of the current settings
836 local currentSettings = {}
837 currentSettings.versionNumber = VERSION_NUMBER
838 currentSettings.versionName = VERSION_NAME
839 currentSettings.computer = registry.computer
840 --spawn area
841 currentSettings.spawnzoneSize = registry.SPAWNZONE_SIZE
842 --currentSettings.spawnzoneOffset = registry.SPAWNZONE_OFFSET
843 --currentSettings.spawnzoneDistance = registry.SPAWNZONE_DISTANCE
844 --play area
845 currentSettings.gridCellSize = registry.GRIDCELL_SIZE
846 currentSettings.gridCellCount = registry.GRIDCELL_COUNT
847 --[[
848 PLAY_AREA_OFFSET.x
849 PLAY_AREA_OFFSET.z
850 TRENCHES.DEPTH
851 GAME_FIELD.CountX
852 GAME_FIELD.CountZ
853 BUILDZONE_OFFSET
854
855 -- catalogue area
856 CATALOGUE_SLOTCOUNT.x
857 CATALOGUE_SLOTCOUNT.z
858 CATALOGUE_SLOTSIZE.x
859 CATALOGUE_SLOTSIZE.z
860 CATALOGUE_SLOT_OFFSET
861 --]]
862
863 --2. open a file and
864 --3. read a json object of the settigns used last time
865
866 --4. compare the two json objects
867 local result = 14
868 --if file doenst exist make result = 14 and return
869 --if file exists and there is change in catalogue area add 8 to result for partial rebuild only the catalogue areas
870 --if file exists and there is change in play area add 4 to result for partial rebuild only the play areas
871 --if file exists and there is change in spawn area add 2 to result for partial rebuild only the spawn areas
872 --if file exist and no change return result as 0 for no action
873 return result
874end
875
876--- Creates a game object and initializes game management functions
877-- This function is a bit large, and should be placed in its own module
878-- at some point.
879-- The game object creates and stores the complete Catalogue
880-- The game object creates and stores a complete list of all Buildzones
881-- The game object creates and stores a complete list of all Kews
882-- The game object only tracks players who are NOT in a Kew
883-- The game object knows where the spawn is
884-- This function rebuilds the Catalogue and Buildzones in the gameworld
885-- if any settings have changed.
886-- This function adds scoreboards to your Minecraft world so that 20kb
887-- operates correctly.
888-- This function runs GameRule commands to set up your Minecraft world.
889-- If DEBUG_MODE is on, then Kews are fixed to Play Phase with a large
890-- time limit
891-- This function kills all Villagers; it is the only way to be sure.
892-- @return game The Game container object.
893function setup()
894 print("Starting Setup function.")
895 local ox,oy,oz = commands.getBlockPosition()
896 print("Computer Co-ordinates ",ox,oy,oz)
897
898 local registryOK = registry.checkRegistryIntegrity()
899 if not registryOK then
900 --if not registry.FINE then
901 print("setup failed")
902 return false
903 end
904 --print ("actual SPAWNZONE_OFFSET is:", registry.SPAWNZONE_OFFSET)
905
906 local game = {}
907 game.elements = {}
908 game.builds = {}
909 game.queues = {}
910 game.waitlist = {}
911 game.spawn = registry.SPAWN
912 game.lastClock = os.clock()
913 game.nowTime = os.clock()
914
915 ---SETTINGS = registry.loadCustomSettings()
916
917 print("Game object created")
918
919 --SET UP THE GAME AREA
920 print("setting up game area...")
921 --do a file check to see if setting up the game area is needed
922 print("checking for changed settings...NOT YET IMPLEMENTED")
923 local rebuild = checkForGameAreaParametersChanges()
924
925 --set up chunk loaders
926 --commands.setblock(-71, 56, -511, "neotech:chunkLoader", 0, "replace", '{id:"neotech:chunkLoader", Diameter:1}')
927
928 --the total size of game area
929 --spawn zones
930 --main spawn zone
931 --check if spawn area needs rebuilding
932 if BitAND(rebuild,2)==2 then
933 print("building spawn areas...")
934 --rebuild spawn area
935 fillSmartOffsetXZ(registry.BLOCKS.AIR.block,
936 registry.MAIN_SPAWN.x,
937 registry.MAIN_SPAWN.y,
938 registry.MAIN_SPAWN.z,
939 registry.MAIN_SPAWN.w,
940 -registry.TRENCHES.DEPTH,
941 registry.MAIN_SPAWN.l,
942 registry.TRENCHES.WIDTH,
943 true
944 )
945 fillSmart(registry.BLOCKS.DARK_GRID.block,
946 registry.MAIN_SPAWN.x,
947 registry.MAIN_SPAWN.y,
948 registry.MAIN_SPAWN.z,
949 registry.MAIN_SPAWN.w,
950 -registry.MAIN_SPAWN.y,
951 registry.MAIN_SPAWN.l
952 )
953 --fill the grid
954 fillGrid(registry.BLOCKS.WHITE_GRID.block,
955 registry.MAIN_SPAWN.x,
956 registry.MAIN_SPAWN.y,
957 registry.MAIN_SPAWN.z,
958 registry.SPAWNZONE_SIZE,
959 registry.MAIN_SPAWN.l
960 )
961
962 --fill the glass border
963 fillRing(registry.BLOCKS.SPAWNZONE_FENCE.block,
964 registry.MAIN_SPAWN.x,
965 registry.MAIN_SPAWN.y+1,
966 registry.MAIN_SPAWN.z,
967 registry.MAIN_SPAWN.w,
968 registry.MAIN_SPAWN.l,
969 registry.MAIN_SPAWN.h
970 )
971
972 local padx = registry.computer.x + math.floor(registry.SPAWNZONE_SIZE/2) + registry.LAUNCH_PADS.offset
973 local pady = registry.computer.y - 1
974 local padz = registry.computer.z - math.floor(registry.GAME_FIELD_MAX.countZ/2) * registry.LAUNCH_PADS.offset - math.floor((registry.GAME_FIELD_MAX.countZ/2) * registry.LAUNCH_PADS.size)
975 for ix = 0, registry.GAME_FIELD_MAX.countZ - 1 do
976 for iz=0, registry.GAME_FIELD_MAX.countZ - 1 do
977
978 local xpos = padx + ix * (registry.LAUNCH_PADS.offset + registry.LAUNCH_PADS.size)
979 local ypos = pady
980 local zpos = padz + iz * (registry.LAUNCH_PADS.offset + registry.LAUNCH_PADS.size)
981 --print("making pads", ix, iz, xpos, ypos, zpos)
982 if registry.GAME_FIELD.countZ > iz and registry.GAME_FIELD.countX > ix then
983 --create the tp pads openings
984 fillSmart( registry.BLOCKS.AIR.block, xpos, ypos, zpos, registry.LAUNCH_PADS.size, 1, registry.LAUNCH_PADS.size )
985 --create the tp pads
986 fillSmart( registry.BLOCKS.DETECT.block, xpos, ypos-1, zpos, registry.LAUNCH_PADS.size, 1, registry.LAUNCH_PADS.size )
987 --place the tp pad markers
988 fillSmart( registry.BLOCKS.DETECT.block, xpos+math.floor(registry.LAUNCH_PADS.size/2), ypos, zpos+math.floor(registry.LAUNCH_PADS.size/2), 1, 1, 1 )
989 else
990 --mark the builzone pad as inactive
991 fillSmart( registry.BLOCKS.WHITE_GRID.block, xpos, ypos, zpos, registry.LAUNCH_PADS.size, 1, registry.LAUNCH_PADS.size )
992 end
993 end
994 end
995 end
996
997
998 --this section below is the actual creation of the catalogue slots in the world
999 --check if catalogue area needs rebuilding
1000 if BitAND(rebuild,8)==8 then
1001 print("building catalogue slots...")
1002 local x,y,z = registry.FIRST_ELEMENT.x, registry.FIRST_ELEMENT.y, registry.FIRST_ELEMENT.z
1003 fillSmartOffsetXZ(
1004 registry.BLOCKS.AIR.block,
1005 registry.CATALOG_AREA.x ,
1006 registry.CATALOG_AREA.y,
1007 registry.CATALOG_AREA.z,
1008 registry.CATALOG_AREA.dx,
1009 -registry.TRENCHES.DEPTH,
1010 registry.CATALOG_AREA.dz,
1011 registry.TRENCHES.WIDTH,
1012 true
1013 )
1014 print("catalog area:",registry.CATALOG_AREA.x ,
1015 registry.CATALOG_AREA.y,
1016 registry.CATALOG_AREA.z,
1017 registry.CATALOG_AREA.dx,
1018 registry.CATALOG_AREA.dz)
1019 fillSmart(
1020 registry.BLOCKS.DARK_GRID.block,
1021 registry.CATALOG_AREA.x ,
1022 registry.CATALOG_AREA.y,
1023 registry.CATALOG_AREA.z,
1024 registry.CATALOG_AREA.dx,
1025 -registry.CATALOG_AREA.y,
1026 registry.CATALOG_AREA.dz
1027 )
1028 fillGrid(
1029 registry.BLOCKS.WHITE_GRID.block,
1030 registry.CATALOG_AREA.x ,
1031 registry.CATALOG_AREA.y,
1032 registry.CATALOG_AREA.z,
1033 registry.CATALOG_AREA.dx,
1034 registry.CATALOG_AREA.dz
1035 )
1036 --print("element size",registry.ELEMENT.sizeX )
1037 for i=0,registry.CATALOGUE_SLOTCOUNT.z - 1 do
1038 for k=0,registry.CATALOGUE_SLOTCOUNT.x - 1 do
1039 --local xpos = x - k*( 2*registry.ELEMENT.sizeX + registry.GRIDCELL_SIZE + 2 )
1040 local xpos = x - k * ( registry.GRIDCELL_SIZE * ( 2*registry.CATALOGUE_SLOTSIZE.x + 2 + registry.CATALOGUE_SLOT_OFFSET))
1041
1042 local ypos = y - 1
1043 local zpos = z + i*( registry.GRIDCELL_SIZE * ( registry.CATALOGUE_SLOTSIZE.z + 1 + registry.CATALOGUE_SLOT_OFFSET))
1044
1045 --fill white grid ring slot
1046 fillRing(
1047 registry.BLOCKS.WHITE_GRID.block,
1048 xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1-math.floor(registry.GRIDCELL_SIZE/2),
1049 ypos,
1050 zpos-1-math.floor(registry.GRIDCELL_SIZE/2),
1051 2*(registry.CATALOGUE_SLOTSIZE.x+1)*registry.GRIDCELL_SIZE + 1,
1052 (registry.CATALOGUE_SLOTSIZE.x + 1)*registry.GRIDCELL_SIZE + 1
1053 )
1054 fillRing(
1055 registry.BLOCKS.WHITE_GRID.block,
1056 xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1-math.floor(registry.GRIDCELL_SIZE/2),
1057 ypos,
1058 zpos-1-math.floor(registry.GRIDCELL_SIZE/2),
1059 (registry.CATALOGUE_SLOTSIZE.x + 1)*registry.GRIDCELL_SIZE + 1,
1060 (registry.CATALOGUE_SLOTSIZE.x + 1)*registry.GRIDCELL_SIZE + 1
1061 )
1062 --fill white grid ring element
1063 fillRing(
1064 registry.BLOCKS.WHITE_GRID.block,
1065 xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1,
1066 ypos,
1067 zpos-1,
1068 registry.ELEMENT.sizeX+2,
1069 registry.ELEMENT.sizeZ+2 )
1070 --fill white grid key
1071 fillSmart(registry.BLOCKS.WHITE_GRID.block, xpos, ypos, zpos, registry.ELEMENT.sizeX, 1, registry.ELEMENT.sizeZ )
1072 --fill dark grid slot
1073 fillGrid(
1074 registry.BLOCKS.DARK_GRID.block,
1075 xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1-math.floor(registry.GRIDCELL_SIZE/2),
1076 ypos,
1077 zpos-1-math.floor(registry.GRIDCELL_SIZE/2),
1078 2*(registry.CATALOGUE_SLOTSIZE.x+1)*registry.GRIDCELL_SIZE + 1,
1079 (registry.CATALOGUE_SLOTSIZE.x + 1)*registry.GRIDCELL_SIZE + 1
1080 )
1081 --fill plug grid key
1082 fillGrid(registry.BLOCKS.PLUG.block, xpos, ypos, zpos, registry.ELEMENT.sizeX, registry.ELEMENT.sizeZ )
1083 --fill plug grid element
1084 fillGrid(
1085 registry.BLOCKS.PLUG.block,
1086 xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1,
1087 ypos,
1088 zpos-1,
1089 registry.ELEMENT.sizeX+2,
1090 registry.ELEMENT.sizeZ+2 )
1091 --fillSmart(registry.BLOCKS.VOCAB_REPLACE.block, xpos, ypos, zpos, registry.ELEMENT.sizeX, 1, registry.ELEMENT.sizeZ)
1092 --fillSmart(registry.BLOCKS.VOCAB_DETECT.block, xpos - registry.ELEMENT.sizeX - 1, ypos, zpos, registry.ELEMENT.sizeX, 1, registry.ELEMENT.sizeZ)
1093 end
1094 end
1095 --fillSmart(registry.BLOCKS.RING.block, registry.FIRST_ELEMENT.x, registry.FIRST_ELEMENT.y-1, registry.FIRST_ELEMENT.z, 1, 1, 1)
1096 end
1097
1098 if BitAND(rebuild,4)==4 then
1099 print("building play area...")
1100 fillSmartOffsetXZ(
1101 registry.BLOCKS.AIR.block,
1102 registry.PLAY_AREAS.x ,
1103 registry.PLAY_AREAS.y,
1104 registry.PLAY_AREAS.z,
1105 registry.PLAY_AREAS.dx,
1106 -registry.TRENCHES.DEPTH,
1107 registry.PLAY_AREAS.dz,
1108 registry.TRENCHES.WIDTH,
1109 true
1110 )
1111 fillSmart(
1112 registry.BLOCKS.DARK_GRID.block,
1113 registry.PLAY_AREAS.x ,
1114 registry.PLAY_AREAS.y,
1115 registry.PLAY_AREAS.z,
1116 registry.PLAY_AREAS.dx,
1117 -registry.PLAY_AREAS.y,
1118 registry.PLAY_AREAS.dz
1119 )
1120 local x,y,z = registry.FIRST_ZONE.x, registry.FIRST_ZONE.y, registry.FIRST_ZONE.z
1121 for i=0,registry.GAME_FIELD.countZ - 1 do
1122 for k=0,registry.GAME_FIELD.countX - 1 do
1123 local xpos = x + k*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE)
1124 local ypos = y
1125 local zpos = z + i*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE)
1126 fillRing(registry.BLOCKS.WHITE_GRID.block,xpos,ypos,zpos,registry.BUILDZONE_WIDTH,registry.BUILDZONE_WIDTH)
1127 --[[
1128 fillSmart(
1129 registry.BLOCKS.WHITE_GRID.block,
1130 xpos ,
1131 ypos,
1132 zpos,
1133 registry.BUILDZONE_WIDTH,
1134 1,
1135 registry.BUILDZONE_WIDTH
1136 )
1137 ]]--
1138 end
1139 end
1140 fillGrid(
1141 registry.BLOCKS.WHITE_GRID.block,
1142 registry.PLAY_AREAS.x ,
1143 registry.PLAY_AREAS.y,
1144 registry.PLAY_AREAS.z,
1145 registry.PLAY_AREAS.dx,
1146 registry.PLAY_AREAS.dz
1147 )
1148 end
1149
1150 --vocabzone creation
1151 print("initializing catalogue elements...")
1152 --the following is a set of abstract objects, not the actual creating of the catalgoue slots in the world
1153 --it should run always
1154
1155 game.elements = initCatalogueElements(
1156 registry.CATALOGUE_SLOTCOUNT.x,
1157 registry.CATALOGUE_SLOTCOUNT.z,
1158 registry.ELEMENT.sizeX,
1159 registry.ELEMENT.sizeZ
1160 )
1161
1162 print("Testing for properly setup catalogue elements")
1163 for i,vz in ipairs(game.elements) do
1164 local detector, message1 = commands.testforblock(vz.keyCenterX,vz.keyCenterY,vz.keyCenterZ,registry.BLOCKS.DETECT.block)
1165 local blocker, message2 = commands.testforblock(vz.keyCenterX,vz.keyCenterY,vz.keyCenterZ,registry.BLOCKS.DETECT_DEAD.block)
1166 --print("element",i,message1, message2)
1167 if not (detector or blocker) then
1168 commands.setblock(vz.keyCenterX,vz.keyCenterY,vz.keyCenterZ,registry.BLOCKS.DETECT_DEAD.block)
1169 end
1170 --commands.setblock(vz.elementCenterX,vz.elementCenterY,vz.elementCenterZ,registry.BLOCKS.DARK_GRID.block)
1171 --commands.setblock(vz.keyX,vz.keyY,vz.keyZ,registry.BLOCKS.DARK_GRID.block)
1172 --commands.setblock(vz.elementX,vz.elementY,vz.elementZ,registry.BLOCKS.WHITE_GRID.block)
1173 end
1174
1175 --[[
1176
1177 if true then
1178 return
1179 end
1180
1181 ]]--
1182
1183 --generate catalogue rewards
1184 for i=1,#registry.VOCABS_DATA do
1185 if registry.VOCABS_DATA[i].rewardUrban then
1186 registry.REWARDS[i] = registry.houseBlock(registry.VOCABS_DATA[i].rewardCount)
1187 else
1188 registry.REWARDS[i] = registry.gardenBlock(registry.VOCABS_DATA[i].rewardCount)
1189 end
1190 end
1191 print("Catalogue definitions successfully initialized!")
1192
1193 --kill all villagers
1194 commands.exec("kill @e[type=Villager]")
1195 print("Villagers destroyed")
1196
1197 --buildzone creation
1198 print("Making building zone objects.")
1199 --game.builds appears to store the games currently in progress
1200 game.builds = initBuildzones(registry.NUMBER_OF_BUILDZONES,game.elements,registry.BUILDZONE_WIDTH)--,registry.BUILDZONE_FLOOR_HEIGHT)
1201
1202 for i,build in ipairs(game.builds) do
1203 table.insert(game.queues,newQueue(build, registry.MAX_PLAYERS_PER_GAME))
1204 end
1205
1206 ----
1207 print("Adding scoreboards.")
1208 --print(#registry.VOCABS_DATA)
1209 for i=1,#registry.VOCABS_DATA do
1210 commands.scoreboard("objectives","add","building_"..i,"dummy")
1211 end
1212 commands.scoreboard("objectives","add","highscores","dummy","Best Neighbourhoods")
1213 if registry.SHOW_HIGHSCORES then
1214 commands.scoreboard("objectives","setdisplay","sidebar","highscores")
1215 end
1216 commands.scoreboard("objectives","add","VillagerLife","dummy")
1217 commands.scoreboard("objectives","add","built","dummy", "Structures Built")
1218 commands.scoreboard("objectives","add","highest","dummy", "Personal Highest")
1219 commands.scoreboard("objectives","add","played","dummy","Games Played")
1220 commands.scoreboard("objectives","setdisplay","list","played")
1221
1222 commands.title("@a","times",0,30,30) -- what does this do?
1223
1224 ----
1225 print("setting the needed preferences of the minecraft world.")
1226 commands.gamerule("doDaylightCycle",false) -- this is included in the spawn controller script
1227 commands.gamerule("keepInventory",true)
1228 --commands.gamerule("doTileDrops",false) -- this is included in the spawn controller script
1229 commands.gamerule("sendCommandFeedback", true)
1230 commands.gamerule("logAdminCommands",false) -- this is included in the spawn controller script
1231 commands.gamerule("commandBlockOutput",false) -- this is included in the spawn controller script
1232 commands.time("set",6000) -- this is included in the spawn controller script
1233
1234 ---
1235 math.randomseed( os.time() )
1236 print("Computer clock is: "..os.clock())
1237
1238 if DEBUG_MODE then
1239 for i,build in ipairs(game.builds) do
1240 build.phase = 2
1241 build.timer = 500
1242 end
1243 end
1244
1245 print("20.000 BLOCKS is ready to run!")
1246
1247 return game
1248end
1249
1250--- Runs a single step of the game loop
1251-- Runs the game object through each of these update steps in order.
1252-- See the comments on each of the steps.
1253-- @param game The game object as created in setup()
1254function update(game)
1255 local elapsed = updateClock(game)
1256 --update players
1257 checkPlayers(game)
1258 doTimerUpdates(game,elapsed)
1259 doPhaseUpdates(game)
1260 doPhaseEnds(game)
1261 checkBoundaries(game)
1262 checkForHomecomers(game)
1263 if #game.waitlist > 0 then allocateWaiters(game) end
1264end
1265
1266--- Calculates elapsed time during a game tick
1267-- Updates the given game objects clock using the operating system time
1268-- @param game The game object as created in setup()
1269-- @return elapsed How much time has elapsed since time was updated
1270function updateClock(game)
1271 game.nowTime = os.clock()
1272 local elapsed = game.nowTime - game.lastClock
1273 game.lastClock = game.nowTime
1274 return elapsed
1275end
1276
1277--- Updates all kews in the game object based on elapsed time
1278-- Since Kews do the timekeeping, let them know how much time as elapsed.
1279-- @param game The game object as created in setup()
1280-- @param elapsed Seconds as calculated by updateClock()
1281function doTimerUpdates(game,elapsed)
1282 for i,kew in ipairs(game.queues) do
1283 kew.timer = kew.timer - elapsed
1284 end
1285end
1286
1287--- Deal with players who should be in Buildzones
1288-- Checks all Kews (and therefore Buildzones). If the Kew is in Phase 2
1289-- (Play Phase), then check on all players. If those players are out
1290-- of bounds, move them back to the closest edge of the buildzone.
1291-- This also sends them a bi-lingual warning if there were moved.
1292-- @param game The game object as created in setup()
1293function checkBoundaries(game)
1294 for i,kew in ipairs(game.queues) do
1295 if kew.phase ==2 then
1296 --boundaries
1297 local x_min = kew.buildzone.x
1298 local x_max = kew.buildzone.x+kew.buildzone.w
1299 local z_min = kew.buildzone.z
1300 local z_max = kew.buildzone.z+kew.buildzone.w
1301
1302 --local toBeCorrected = {}
1303
1304 for j,player in ipairs(kew.playerlist) do
1305 local listOfOne = getAllPos('m=2,name='..player.name)
1306 if listOfOne and listOfOne[1] then
1307 player.x = listOfOne[1].x
1308 player.y = listOfOne[1].y
1309 player.z = listOfOne[1].z
1310 local changed = false
1311 if player.x > x_max then
1312 changed = true
1313 player.x = x_max-2
1314 end
1315 if player.x < x_min then
1316 changed = true
1317 player.x = x_min+2
1318 end
1319 if player.z > z_max then
1320 changed = true
1321 player.z = z_max-2
1322 end
1323 if player.z < z_min then
1324 changed = true
1325 player.z = z_min+2
1326 end
1327 if changed then
1328 teleportToPoint(player.x,kew.buildzone.y,player.z,{player},false,
1329 "TELEPORTED BACK TO GAME: Please stay inside the building zone or use HOMECOMER to leave the game!",
1330 "Zurück ins Spiel teleportiert: Bitte bleib innerhalb des Baufeldes oder nutze den HEIMKEHRER um das Spiel zu verlassen!")
1331 end
1332 end
1333 end
1334 end
1335 end
1336end
1337
1338
1339--- Check if a Buildzone is worth saving
1340-- Many plays of a buildzone will be junk. Here you can set the logic
1341-- which determines if a buildzone was valuable.
1342-- Currently always returns that the zone is valuable.
1343-- @param buildzone The buildzone to check.
1344-- @return True is the buildzone was junk
1345function checkIfBuildzoneIsCrap(buildzone)
1346 print("Buildzone was ok")
1347 return false
1348end
1349
1350
1351--- Everything that happens when the Play Phase finishes due to time limit.
1352-- Removes the ring which denotes a game in progress.
1353-- Removes Detector Blocks and then fills the floor in.
1354-- Checks if the buildzone was valuable and if so it will clean it.
1355-- Sets the zone played state based on value. A played zone will not be
1356-- overwritten by future buildzones.
1357-- Bilingual messages are sent to players to let them know what happened.
1358-- @param kew A kew object that contains a Buildzone
1359function cleanAfterGameOver(kew)
1360 local buildzone = kew.buildzone
1361 commands.async.setblock(buildzone.x,buildzone.y,buildzone.z,registry.BLOCKS.VICTORY_MARKER.block)
1362 fillRing(buildzone.x,buildzone.y,buildzone.z,buildzone.w,"minecraft:air",0,"replace",registry.BLOCKS.CONSTRUCTION.block,registry.BLOCKS.CONSTRUCTION.data)
1363 --for each level remove playing blocks like detectors
1364 for h=0,256-buildzone.y do
1365 commands.async.fill(buildzone.x,buildzone.y+h,buildzone.z,buildzone.x+buildzone.w,buildzone.y+h,buildzone.z+buildzone.w,"minecraft:air 0","replace",registry.BLOCKS.DETECT.block,registry.BLOCKS.DETECT.data)
1366 commands.async.fill(buildzone.x,buildzone.y+h,buildzone.z,buildzone.x+buildzone.w,buildzone.y+h,buildzone.z+buildzone.w,"minecraft:air 0","replace",registry.BLOCKS.PLUG.block,registry.BLOCKS.PLUG.data)
1367 commands.async.fill(buildzone.x,buildzone.y+h,buildzone.z,buildzone.x+buildzone.w,buildzone.y+h,buildzone.z+buildzone.w,"minecraft:air 0","replace",registry.BLOCKS.BUILDING_GARDEN.block,registry.BLOCKS.BUILDING_GARDEN.data)
1368 commands.async.fill(buildzone.x,buildzone.y+h,buildzone.z,buildzone.x+buildzone.w,buildzone.y+h,buildzone.z+buildzone.w,"minecraft:air 0","replace",registry.BLOCKS.BUILDING_HOUSE.block,registry.BLOCKS.BUILDING_HOUSE.data)
1369 end
1370 --replaces air on the bottom level with flooring to show the area is completed
1371 commands.async.fill(buildzone.x,buildzone.y-1,buildzone.z,buildzone.x+buildzone.w,buildzone.y-1,buildzone.z+buildzone.w,registry.BLOCKS.CAMP_FLOOR.block,registry.BLOCKS.CAMP_FLOOR.data,"replace",registry.BLOCKS.PLUG.block,registry.BLOCKS.PLUG.data)
1372 commands.async.fill(buildzone.x,buildzone.y,buildzone.z,buildzone.x+buildzone.w,buildzone.y,buildzone.z+buildzone.w,registry.BLOCKS.PHVFLOOR.block,registry.BLOCKS.PHVFLOOR.data,"replace","minecraft:air","0")
1373
1374 ---add here a message to the players that they can see their finished game on the webviewer OR that their game was not save because they built too little
1375
1376 local wasCrap = checkIfBuildzoneIsCrap(buildzone)
1377 local gameovermessageEN
1378 local gameovermessageDE
1379 if wasCrap then
1380 --mark this buildzone for replacement
1381 --change the flag to played=false
1382 print("cleanAfterGameOver if crap", buildzone.locid)
1383 updateZonePlayedState(buildzone,false)
1384 gameovermessageEN = "Thank you for playing IBA_GAME! This game will be discarded because you built less than "..registry.MIN_BUILDINGS.." buildings. Play another game or check what others have built at: www.20000blocks.com"
1385 gameovermessageDE = "Vielen Dank, dass du IBA_GAME gespielt hast! Diese Runde wird verworfen, da weniger als "..registry.MIN_BUILDINGS.." Gebäude gebaut wurden. Starte eine neue Runde oder schau dir die Spielergebnisse anderer Spieler an unter: www.2000blocks.com"
1386
1387 else
1388 --change the flag to played=true
1389 print("cleanAfterGameOver otherwise", buildzone.locid)
1390 updateZonePlayedState(buildzone,true)
1391
1392 gameovermessageEN = "Thank you for playing IBA_GAME! Play another game or look for your game result at: www.20000blocks.com"
1393 gameovermessageDE = "Vielen Dank, dass du IBA_GAME gespielt hast! Starte eine neue Runde oder schau dir deine Spielergebnisse an unter: www.20000blocks.com"
1394 end
1395
1396 for _, player in ipairs(kew.playerlist) do
1397 if registry.ANNOUNCE_ENGLISH then
1398 -- announce success in English
1399 commands.async.tellraw(player.name,'["",{"text":"'..gameovermessageEN..'","color":"white"}]')
1400 end
1401 if registry.ANNOUNCE_GERMAN then
1402 -- announce success in German
1403 commands.async.tellraw(player.name,'["",{"text":"'..gameovermessageDE..'","color":"gold"}]')
1404 end
1405 end
1406
1407end
1408
1409--- Changes a given locid to played.
1410-- Strange that the LOCS object is a global and not in the registry.
1411-- That is probably bad. This function also saves the given location to
1412-- file.
1413-- @param buildzone The buildzone that was just finished
1414-- @param newstate Boolean Has the location been played successfully?
1415function updateZonePlayedState(buildzone, newstate)
1416 --change the flag to played=newstate
1417 LOCS[buildzone.locid].played = newstate
1418 --and write the LOCS object to the json file
1419 writeGridToFile()
1420end
1421
1422--- Process timekeeping and update Phases of Kews.
1423-- Run every game step. Iterate over all Kews and update their phase
1424-- based on the remaining time in kew.timer.
1425-- If the kew is on the Play Phase, then do the gameplay logic
1426-- stored in updatePlayedZone().
1427-- Update player timers (xp bar timer) and give players a large warning
1428-- title if the game is almost over.
1429-- @param game The game object as created by setup()
1430function doPhaseUpdates(game)
1431 for i,kew in ipairs(game.queues) do
1432
1433 local minutes = string.format("%02d",math.floor(kew.timer/60))
1434 local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
1435 if kew.timer <= 0 then
1436 minutes = "00"
1437 seconds = "00"
1438 end
1439
1440 if kew.phase == 1 then
1441 --waiting phase
1442 if #kew.playerlist == kew.maxplayers and kew.timer > 5 then kew.timer = 5 end
1443 if not DEBUG_MODE and #kew.playerlist == 0 then kew.timer = kew.phases[1].length end
1444
1445 displayTitleToGroup(kew.playerlist,"Game starting!")
1446 displayTimeToGroup(kew.playerlist,minutes,seconds)
1447 --show countdown
1448 elseif kew.phase == 2 then
1449 --playing phase
1450 if #kew.playerlist == 0 then timer = 0 end -- finish if all players quit
1451 -- do vocab logic
1452 local victory = updatePlayedZone(kew) --currently victory updatePlayedZone returns always false
1453 --
1454 displayTimeToGroup(kew.playerlist,minutes,seconds)
1455
1456 elseif kew.phase == 3 then
1457 --end phase
1458 displayTitleToGroup(kew.playerlist,"Use HOMECOMER to return")
1459 --displayTimeToGroup(kew.playerlist,minutes,seconds)
1460
1461
1462 end
1463 end
1464end
1465
1466--- Update the Minecraft Scoreboards based on what players built.
1467-- This runs after a buildzone is completed it currently rewards all
1468-- participants with more played score.
1469-- @param kew A Kew object which has just moved from Phase 2 to 3.
1470function processHighscores(kew)
1471 local buildzone = kew.buildzone
1472 for _,player in ipairs(kew.playerlist) do
1473 commands.async.scoreboard("players","add",player.name,"played",1)
1474 end
1475end
1476
1477--- Export a Kews buildzone detail once it is complete
1478-- Requires a kew so it can access the playerlist.
1479-- @param kew The Kew object which contains players and a buildzone
1480-- @param saveOnline Boolean true: save the game also online to the database; false: save only in a file locally
1481local function exportKewData(kew, saveOnline)
1482 local buildzone = kew.buildzone
1483 local saved = {}
1484 saved.position =
1485 {
1486 x=buildzone.x,
1487 y=buildzone.y,
1488 z=buildzone.z
1489 }
1490
1491 saved.players = {}
1492 for _, player in ipairs(kew.playerlist) do
1493 table.insert(saved.players,player.name)
1494 end
1495 --saved.structures = buildzone.structures
1496 saved.buildings = buildzone.buildings
1497 saved.totals = tracker.tallyTable(buildzone.buildings)
1498 --saved.highest = buildzone.highest
1499 saved.stats = {
1500 cityVersion = registry.CITY_VERSION,
1501 height = buildzone.highest,
1502 densityIndex = math.floor(100*buildzone.filledSlots/49), -- the density index is made from built area (filledSlots) over the ground area (7x7 slots = 49)
1503 greenIndex = math.floor(100*buildzone.greenSlots/49), --the green index is made from green area (greenSlots) over the ground area (7x7 slots = 49)
1504 variety = tablelength(buildzone.variety),
1505 timeCompleted = timestamp,
1506 gameLength = registry.PHASE_LENGTH_GAME
1507 }
1508
1509 fs.makeDir("/records")
1510 local file = fs.open("/records/"..kew.filename..".json","w")
1511 filecontent = json.encodePretty(saved)
1512 file.write(filecontent)
1513 file.close()
1514
1515 if saveOnline then --for now this is disabled until we figure out how things look in the webGL viewer
1516 --writeToDatabase(kew.filename,filecontent,saved.position.x,saved.position.z)
1517 end
1518end
1519
1520-- this function writes to the online database that we use to display models in the webGL viewer
1521local function writeToDatabase(name,data,x,z)
1522
1523 -- the user agent needs to be renamed otherwise the dfeult one is Java and that is blocked by the .htaccess file on the website
1524 local headers = {
1525 [ "User-Agent" ] = "20.000 BLOCKS"
1526 }
1527
1528 local link = http.post(
1529 "http://www.20000blocks.com/DatabaseAccess/UploadModel.php",
1530 "name="..textutils.urlEncode(name).."&"..
1531 "content="..textutils.urlEncode(data).."&"..
1532 "x="..x.."&"..
1533 "z="..z,
1534 headers
1535 )
1536 local linkURL = link.readAll()
1537 if linkURL then
1538 --message texts
1539 local msg_EN = 'The latest game result has been uploaded to the webviewer.\n'
1540 local msg_DE = 'Die neueste Runde wurde in den Webviewer geladen.\n'
1541 local linkText_EN = 'See it and share it!'
1542 local linkText_DE = 'Schau es und teile es!'
1543 local hoverText_EN = 'Click here to see and share the last game!'
1544 local hoverText_DE = 'Click here to see and share the last game!'
1545 --message text with the link
1546 local linkmsg_EN = '["",{"text":"'..msg_EN..'","color":"white","bold":false},{"text":"'..linkText_EN..'","color":"blue","underlined":true,"clickEvent":{"action":"open_url","value":"'..linkURL..'"},"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"'..hoverText_EN..'","color":"gold"}]}},"bold":false}]'
1547
1548 local linkmsg_DE = '["",{"text":"'..msg_DE..'","color":"gold","bold":false},{"text":"'..linkText_DE..'","color":"blue","underlined":true,"clickEvent":{"action":"open_url","value":"'..linkURL..'"},"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"'..hoverText_DE..'","color":"gold"}]}},"bold":false}]'
1549 -- announce success in English
1550 commands.async.tellraw("@a",linkmsg_EN)
1551 if registry.ANNOUNCE_GERMAN then
1552 --announce success in German
1553 commands.async.tellraw("@a",linkmsg_DE)
1554 end
1555 end
1556end
1557
1558function switchVersion(id, relative) --id is the new version, relative is whether it is incrmenting the last version (true means the number in id will be added to the current version, false is id is the new version number)
1559 http.post(
1560 "http://www.20000blocks.com/DatabaseAccess/SwitchVersion.php",
1561 "id="..textutils.urlEncode(id).."&"..
1562 "relative="..textutils.urlEncode(relative)
1563 )
1564end
1565
1566--- Move from the Wait Phase to the Play Phase
1567-- Anything that needs to be done ONCE before the Play Phase starts
1568-- happens here.
1569-- The buildzone is moved to a clean area.
1570-- The players in the Kew are moved to the buildzone.
1571-- The buildzone is cleaned up (now that the chunks are loaded
1572-- The buildzone is prepares (detector blocks placed)
1573-- Players recieve starting items
1574-- A friendly message is shown for them to begin
1575-- Kew Phase and Timer are updated
1576-- @param kew The Kew to update
1577function endWaitPhase(kew, game)
1578 moveBuildzone(kew.buildzone,game.builds)
1579 teleportToZone(kew.buildzone,kew.playerlist,"Your game has started! BUILD A HOUSE!", "Das Spiel hat begonnen! BAUE EIN HAUS!")--teleport selected players
1580 cleanBuildzone(kew.buildzone)
1581 prepareBuildzone(kew.buildzone)--prepare build zone
1582 giveItems(kew.playerlist,registry.STARTING_ITEMS) --give starting items
1583 displayTitle(kew.buildzone.selector,"BUILD!")
1584 kew.victory = false
1585 --displayTime(kew.buildzone.selector,0,0)
1586 kew.phase = 2
1587 kew.timer = kew.phases[kew.phase].length
1588end
1589
1590--- Move from the Play Phase to the End Phase
1591-- Anything that needs to be done ONCE before the End Phase starts
1592-- happens here.
1593-- Player highscores are updated
1594-- The Kew and Buildzone data is saved to file
1595-- The buildzone is given a clean and checked for value
1596-- Kew Phase and Timer are updated
1597-- @param kew The Kew to update
1598function endPlayPhase(kew)
1599 processHighscores(kew)
1600 exportKewData(kew,true) -- saves the final state of the game and writes it to the online database
1601 cleanAfterGameOver(kew)
1602 kew.phase = 3
1603 --displayTime(kew.buildzone.selector,0,0)
1604 kew.timer = kew.phases[kew.phase].length
1605end
1606
1607--- Move from the End Phase to the Wait Phase
1608-- Anything that needs to be done ONCE before the End Phase starts
1609-- happens here.
1610-- Players are removed from the Kews playerlist
1611-- Kew Phase and Timer are updated
1612-- @param kew The Kew to update
1613function endEndPhase(kew)
1614 removePlayersFromKew(kew)
1615 kew.phase = 1
1616 --displayTime(kew.buildzone.selector,0,0)
1617 kew.timer = kew.phases[kew.phase].length
1618end
1619
1620--- Calculate end of Phase and change to next Phase
1621-- This code runs ONCE at the end of each phase and what actually
1622-- happens is specific to which phase the given kew is in.
1623-- Kew timers are filled and Kew Phases are updated here only.
1624-- @param game The game object as created in setup()
1625function doPhaseEnds(game)
1626 for i,kew in ipairs(game.queues) do
1627 if kew.timer <= 0 then
1628 if kew.phase == 1 then
1629 --waiting phase ends goto play phase
1630 endWaitPhase(kew, game)
1631 elseif kew.phase == 2 then
1632 --playing phase ends goto end phase
1633 endPlayPhase(kew)
1634 elseif kew.phase == 3 then
1635 --end phase ends goto waiting phase
1636 endEndPhase(kew)
1637 end
1638 end
1639 end
1640end
1641
1642
1643-- Replaces important blocks such as Detectors
1644-- Replaces everything that is needed to start the game. Does not
1645-- rebuild the floor, or clear anything away. based on the settings it
1646-- creates a full grid, or a partial grid, or no grid of Detectors
1647-- it also places the ring, although this is disabled for now
1648-- @param buildzone The buildzone to prepare
1649function prepareBuildzone(buildzone)
1650 print("Preparing buildzone...")
1651 local bz = buildzone
1652 local x,y,z,w = bz.x,bz.y,bz.z,bz.w
1653
1654 --place the white grid accross the full buildzone as a base
1655 --commands.async.fill(x,y,z,x+w,y,z+w,registry.BLOCKS.CAMP_FLOOR.block)
1656 fillSmart(registry.BLOCKS.CAMP_FLOOR.block, x,y,z,w,1,w)
1657 --fillRing(buildzone.x,buildzone.y-1,buildzone.z,buildzone.w,registry.BLOCKS.CONSTRUCTION.block) --this draws the construction stripe around the buildzone
1658 --create the grid of detectors surrounded by plus plugs
1659 if registry.DO_GRID then
1660 --fillGrid()
1661 for x=0,registry.GRIDCELL_COUNT-1 do
1662 for z=0,registry.GRIDCELL_COUNT-1 do
1663 local rand = math.random()*100
1664 if rand > registry.GRID_HOLE_CHANCE then --and result then
1665 local halfCell = math.floor(registry.GRIDCELL_SIZE/2)
1666 commands.async.setblock(bz.x+(x*registry.GRIDCELL_SIZE)+halfCell,bz.y+1,bz.z+(z*registry.GRIDCELL_SIZE)+halfCell,registry.BLOCKS.DETECT.block,registry.BLOCKS.DETECT.data,"replace","minecraft:air")
1667 commands.async.fill(bz.x+(x*registry.GRIDCELL_SIZE)+halfCell-registry.PLUG_LENGTH, bz.y,bz.z+(z*registry.GRIDCELL_SIZE)+halfCell,bz.x+(x*registry.GRIDCELL_SIZE)+halfCell+registry.PLUG_LENGTH,bz.y,bz.z+(z*registry.GRIDCELL_SIZE)+halfCell,registry.BLOCKS.PLUG.block)
1668 commands.async.fill(bz.x+(x*registry.GRIDCELL_SIZE)+halfCell,bz.y,bz.z+(z*registry.GRIDCELL_SIZE)+halfCell-registry.PLUG_LENGTH,bz.x+(x*registry.GRIDCELL_SIZE)+halfCell,bz.y,bz.z+(z*registry.GRIDCELL_SIZE)+halfCell+registry.PLUG_LENGTH,registry.BLOCKS.PLUG.block)
1669 end
1670 end
1671 end
1672 end
1673 --mark the game in the LOCS array as not available anymore, and save the updated game grid to the grid file
1674 --change the flag to played=true
1675 print("prepareBuildzone", buildzone.locid)
1676 updateZonePlayedState(buildzone,true)
1677 print("Preparing buildzone...DONE!")
1678end
1679
1680-- Removes everything in a buildzone
1681-- Literally replaces every block inside the buildzone with air and
1682-- then removes all floating items.
1683-- @param buildzone A buildzone to clean
1684function cleanBuildzone(buildzone)
1685 print("Cleaning buildzone...")
1686 --for each level, remove all blocks
1687 fillSmart(registry.BLOCKS.AIR.block, buildzone.x, buildzone.y, buildzone.z, buildzone.w, 256-buildzone.y, buildzone.w)
1688 --for h=buildzone.y,255 do
1689 -- commands.async.fill(buildzone.x,h,buildzone.z,buildzone.x+buildzone.w,h,buildzone.z+buildzone.w,"minecraft:air")
1690 --end
1691 --remove all floating items in the loaded part of the world
1692 commands.async.kill("@e[type=item]")
1693 print("Cleaning buildzone...DONE!")
1694end
1695
1696--- Takes players out of a Kews playerlist
1697-- Gives all players a message telling them to return to spawn and
1698-- then removes them from the playerlist. This releases them from being
1699-- trapped in the buildzone boundary.
1700-- @param kew The Kew to clear players from
1701function removePlayersFromKew(kew)
1702 for _, player in ipairs(kew.playerlist) do
1703 if registry.ANNOUNCE_ENGLISH then
1704 -- announce success in English
1705 commands.async.tellraw(player.name,'["",{"text":"TIME OUT! GAME COMPLETE! Use your HOMECOMER to return to spawn.","color":"white"}]')
1706 end
1707 if registry.ANNOUNCE_GERMAN then
1708 -- announce success in German
1709 commands.async.tellraw(player.name,'["",{"text":"ENDE! SPIEL ABGESCHLOSSEN! Nutze den HEIMKEHRER um zum Anfang zurück zu kehren.","color":"gold"}]')
1710 end
1711 end
1712 kew.playerlist = {}
1713end
1714
1715--- Resets a player to be harmless
1716-- Use this when you want to be sure a player cannot modify blocks
1717-- and that they have no wool to place. You can also send them a friendly
1718-- message about why you took their stuff!
1719-- @param playername String of the players name
1720-- @param message String A friendly message for the given player
1721function respawnPlayer(playername,message)
1722 commands.tell(playername,message)
1723 commands.async.gamemode(2,playername)
1724 commands.async.clear(playername,"minecraft:wool")
1725 commands.async.clear(playername,"minecraft:stone_pickaxe")
1726end
1727
1728--- Checks if given player is in a buildzone
1729-- Uses a playerdata object and the buildzone selector
1730-- @param player A playerdata object from newPlayerData()
1731-- @param buildzone A buildzone object to get the selector from
1732-- @return result True if the player is in the buildzone
1733function checkForPlayerInBuildzone(player,buildzone)
1734 local result,message = commands.testfor('@a[name='..player.name..','..buildzone.selector..']')
1735 return result
1736end
1737
1738--- Checks if a given player is in the waiting area
1739-- Builds a selector for the waitzone as given in the registry module.
1740-- @param player A playerdata object from newPlayerData()
1741-- @return result True if the player is in the wait area
1742function checkForPlayerInWaitzone(player)
1743 local selector = "x="..registry.WAITZONE.x..",y="..registry.WAITZONE.y..",z="..registry.WAITZONE.z..",dx="..registry.WAITZONE.w..",dy=256,dz="..registry.WAITZONE.l
1744 local result,message = commands.testfor('@a[name='..player.name..','..selector..']')
1745 return result
1746end
1747
1748--- Updates our information on all players we think are in the game
1749-- Checks the waitlist and all kews. Each player is checked if they are
1750-- still online and if they are playing in a buildzone.
1751-- @param game A game object as created by setup()
1752function checkPlayers(game)
1753 local selector = "x="..registry.WAITZONE.x..",y="..registry.WAITZONE.y..",z="..registry.WAITZONE.z..",dx="..registry.WAITZONE.w..",dy=256,dz="..registry.WAITZONE.l
1754 local loggedIn = getAllPos('m=2,'..selector)
1755 --refresh waitlist
1756 game.waitlist = loggedIn
1757 --check currently playing players
1758 for l,kew in ipairs(game.queues) do
1759 for i,builder in ipairs(kew.playerlist) do
1760 local isPlaying = checkForPlayerInBuildzone(builder,kew.buildzone)
1761 --remove players who are already in kews from the waitlist
1762 for j, player in ipairs(loggedIn) do
1763 if player.name == builder.name then
1764 table.remove(loggedIn,j)
1765 end
1766 end
1767 --if the game is in progress and the player is not found then remove them from the gamekew
1768 if not isPlaying and kew.phase == 2 then
1769 --table.remove(kew.playerlist,i)
1770 --print("Removed "..builder.name.." from game in progress")
1771 end
1772 end
1773 end
1774end
1775
1776-- Adds waiting players to Kew playerlists
1777-- Currently adds players in order with no randomization.
1778-- First generates a list of free slots from our kews
1779-- Then adds a player from the waitlist to one of those slots until
1780-- there are no more slots or no more waiters. High Tech!
1781-- @param game the game object as created by setup()
1782function allocateWaiters(game)
1783 --find free slots
1784 local freeslots = {}
1785 for i, kew in ipairs(game.queues) do
1786 if kew.phase == 1 and #kew.playerlist < kew.maxplayers then
1787 local slots = kew.maxplayers - #kew.playerlist
1788 for j=1,slots do
1789 table.insert(freeslots,kew)
1790 end
1791 end
1792 end
1793
1794 --RE-ENABLE SECOND SHUFFLETABLE IF YOU WANT RANDOM PLAYER MATCHUPS
1795 shuffleTable(game.waitlist)
1796 --shuffleTable(freeslots)
1797
1798 while #freeslots > 0 and #game.waitlist > 0 do
1799 local player = table.remove(game.waitlist,1)
1800 local freeslot = table.remove(freeslots,1).playerlist
1801 table.insert(freeslot,player)
1802 end
1803end
1804
1805--- Adds a new request to check a Detector Block safely
1806-- Makes sure that incoming check requests dont exist already
1807-- Players can still have multiple requests, but no two requests from
1808-- the same tile will exist. Requests are processed at a rate of one per
1809-- game step, so its important that we dont have duplicates as it slows
1810-- the game loop down a lot.
1811-- @param player A playerdata Object as created by newPlayerData().
1812-- @param buildzone A buildzone to which the request should be added.
1813function addToChecklist(player,buildzone)
1814 for _, detector in ipairs(buildzone.waitingForCheck) do
1815 if detector.x == player.x and detector.y == player.y and detector.z == player.z then
1816 return false
1817 end
1818 end
1819 table.insert(buildzone.waitingForCheck,player)
1820 return true
1821end
1822
1823--- Cleans barriers from a buildzone
1824-- removes all barrier blocks from a buildzone which are used to
1825-- carve space in Elements. This should be updated to only clean a given
1826-- area.
1827-- @param buildzone A buildzone that should be cleaned
1828function cleanBarriers(buildzone)
1829 for h=0,200 do
1830 commands.async.fill(buildzone.x,buildzone.y+h,buildzone.z,buildzone.x+buildzone.w,buildzone.y+h,buildzone.z+buildzone.w,"minecraft:air",0,"replace","minecraft:barrier")
1831 end
1832end
1833
1834--- Update a buildzone that is in the Play Phase
1835-- Detection and Game Logic is mostly kept here. Meat and Potatoes time.
1836-- Wow, actually most of this is disabled for now.
1837-- If there are waiting requests for checking a detector block, do
1838-- the first one in the list.
1839-- Check it against the catalogue we have stored in the buildzone
1840-- (not the complete catalogue). If it matches then clone in the new
1841-- Building, give Rewards and clean Barriers.
1842-- Currently always returns False for victory.
1843-- @param kew a Kew object which contains a Buildzone
1844-- @return victory Boolean, Did this placement cause a victory?
1845function updatePlayedZone(kew)
1846 local buildzone = kew.buildzone
1847 local victory = false
1848 local buildzoneSelector = buildzone.selector
1849 --get all players on a detector block, add them to the list of things to check
1850 local detectLocations = getAllOnBlockType(registry.BLOCKS['DETECT'].block,buildzoneSelector)
1851 --print(#detectLocations.." Players standing on detectors")
1852 for _, player in ipairs(detectLocations) do
1853 addToChecklist(player,buildzone)
1854 end
1855
1856 --DEAL WITH THE DETECTOR AT THE TOP OF THE LIST IF THERE IS ONE
1857 if #buildzone.waitingForCheck > 0 then
1858 --DO PARTICLE EFFECTS IF A DETECTING BLOCK THAT IS DETECTING
1859 for i,loc in ipairs(buildzone.waitingForCheck) do
1860 searchParticle(loc.x,loc.y+1,loc.z)
1861 end
1862 local totalResult = false
1863 local checked = table.remove(buildzone.waitingForCheck,1)
1864 local x,y,z,name = checked.x,checked.y,checked.z,checked.name
1865 for i,element in pairs(buildzone.elements) do
1866 local result,message = commands.testforblocks( element.keyX, element.keyY, element.keyZ, element.keyX+element.sizeX, element.keyY+registry.VOCAB_HEIGHT, element.keyZ+element.sizeZ, x-math.floor(element.sizeX/2), y-1, z-math.floor(element.sizeZ/2),"masked")
1867 if result then
1868 --clone in the correct vocab
1869 local cloneres,clonemes = commands.clone( element.elementX, element.elementY, element.elementZ, element.elementX+element.sizeX, element.elementY+registry.VOCAB_HEIGHT, element.elementZ+element.sizeZ, x-math.floor(element.sizeX/2), y-1, z-math.floor(element.sizeZ/2),"masked")
1870 if DEBUG_MODE then
1871 print(clonemes[1])
1872 end
1873 commands.async.give(name,element.reward)
1874 -- announce success in English
1875 local rewardType = 'nature'
1876 local rewardTypeDE = 'grüne'
1877 if element.rewardUrban then
1878 rewardType = 'urban'
1879 rewardTypeDE = 'urbane'
1880 end
1881
1882 if registry.ANNOUNCE_ENGLISH then
1883 --announce success in English
1884 commands.async.tellraw(name,'["",{"text":"You built a '..element.nameEN.. ' ('..element.typeEN..'), which is '..element.height..'m tall and gives '..element.slots..' density pts, '..element.greenSlots..' green pts and '..element.rewardCount..'x '..rewardType..' resource!","color":"white"}]')
1885 end
1886 if registry.ANNOUNCE_GERMAN then
1887 -- announce success in German
1888 commands.async.tellraw(name,'["",{"text":"Du hast ein '..element.typeDE..' | '..element.nameDE.. ' gebaut, das '..element.height..' Meter hoch ist und dir '..element.slots..' Punkte für die Dichte einbringt, jedoch '..element.greenSlots..' Punkte für Grünflächen und '..element.rewardCount..' '..rewardTypeDE..' Ressourcen!","color":"gold"}]')
1889 end
1890
1891 --clear out barrier blocks
1892 cleanBarriers(buildzone)
1893
1894 --ADD THE NEW STRUCTURE TO THE RECORDS
1895 --table.insert(buildzone.structures,element.nameEN)
1896 --record the place of the element as x, y, z and element id
1897 local building = {id=element.id,xpos=x,ypos=y-1,zpos=z,name=element.nameEN,time=os.clock(),player=name}
1898 table.insert(buildzone.buildings, building)
1899
1900 --[[ DISABLED UNTIL THE NEW GOAL SYSTEM IS IMPLEMENTED
1901
1902 buildzone.greenSlots = buildzone.greenSlots + element.greenSlots
1903
1904 buildzone.filledSlots = buildzone.filledSlots + element.slots
1905 local newHeight = y + element.height - buildzone.y-1 -- the Y coordinate of the highest block above the ground. Our world has its ground at 55 which is in buildzone.y, subtracting 1 to compensate for player height
1906 if newHeight > buildzone.highest then
1907 buildzone.highest = newHeight
1908 end
1909
1910 -- count variety
1911 local varietyId = element.id -- we use a variety id instead of the element id because vocab id 1,2,3,4 for example are all houses so it is the same variety
1912 --we add only one type of house, one type of green house, one type of garden and one type of extension and we skip the two risers
1913 --]]
1914 --[[
1915 if vocab.id == 2 or vocab.id == 3 or vocab.id == 4 then varietyId = 1 end-- only one type for the 4 different orientations of the house
1916 if vocab.id == 14 or vocab.id == 15 or vocab.id == 16 then varietyId = 13 end-- only one type for the 4 different orientations of the house extension
1917 if vocab.id == 26 or vocab.id == 27 or vocab.id == 28 then varietyId = 25 end-- only one type for the 4 different orientations of the house garden extension
1918 if vocab.id == 38 or vocab.id == 39 or vocab.id == 40 then varietyId = 37 end-- only one type for the 4 different orientations of the green roof house
1919 if varietyId ~= 17 and varietyId ~= 18 then --skip the two riser as they are not buildings
1920 --]]
1921 --[[
1922 if buildzone.variety[varietyId] then
1923 --print("increasing existing item")
1924 buildzone.variety[varietyId] = buildzone.variety[varietyId] + 1
1925 else
1926 --print("adding new item")
1927 buildzone.variety[varietyId] = 1
1928 end
1929 --end
1930
1931 --save the game incrementally
1932 exportKewData(kew,false) -- saves the new state of the game locally to a file, doenst write to the database yet
1933
1934 --- CHECK FOR PERSONAL RECORDS
1935 --- check if the new structure is the highest
1936 --- CHANGE here to live detect the contribution of the new structure to the 4 goals and update them
1937
1938 local personalbest = tracker.getScore(name,"highest")
1939 if personalbest.count < newHeight then
1940 --commands.async.tell(name,"You just topped your personal record for highest structure!")
1941 commands.async.scoreboard("players","add",name,"highest",1)
1942 if registry.ANNOUNCE_ENGLISH then
1943 -- announce success in English
1944 commands.async.tellraw(name,'["",{"text":"You just topped your personal record for highest neighbourhood!","color":"green"}]')
1945 end
1946 if registry.ANNOUNCE_GERMAN then
1947 -- announce success in German
1948 commands.async.tellraw(name,'["",{"text":"Du hast soeben deinen persönlichen Rekord für die höchste Nachbarschaft gebrochen!","color":"gold"}]')
1949 end
1950 end
1951
1952 ---
1953 ---
1954 -- CHECK if placing the current structure would result in beating a server-wide record on the 4 goals
1955 --calculate total slots - FOR GOAL "DENSEST NEIGHBOURHOOD"
1956 local most = tracker.getScore("Densest_[points]","highscores")
1957 local Kint = math.floor(100 * buildzone.filledSlots / 49) -- Kint is the density index made from built area (filledSlots) over ground area (7x7 slots = 49)
1958 if Kint > most.count then
1959 commands.async.scoreboard("players","set","Densest_[points]","highscores",Kint)
1960 if registry.ANNOUNCE_ENGLISH then
1961 -- announce success in English
1962 commands.async.tellraw("@a",'["",{"text":"Great! '..name.. ' just topped the record for the DENSEST NEIGHBOURHOOD!","color":"green"}]')
1963 end
1964 if registry.ANNOUNCE_GERMAN then
1965 -- announce success in German
1966 commands.async.tellraw("@a",'["",{"text":"Sehr gut! '..name.. ' hat einen neuen Rekord für die DICHTESTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
1967 end
1968 end
1969
1970 -- FOR THE GOAL "MOST DIVERSE NEIGHBOURHOOD"
1971 -- here we need to count how many varieties of buildings there are
1972 --local structures = tracker.tallyTable(buildzone.structures) -- this counts the variety of buildings in a game
1973 local mostDiverse = tracker.getScore("Most-Diverse_[out-of-26]","highscores")
1974 local typeCount = tablelength(buildzone.variety)
1975 --print("variety count is: "..typeCount)
1976 if typeCount > mostDiverse.count then
1977 commands.async.scoreboard("players","set","Most-Diverse_[out-of-26]","highscores", typeCount)
1978 if registry.ANNOUNCE_ENGLISH then
1979 -- announce success in English
1980 commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' just topped the record for the MOST DIVERSE NEIGHBOURHOOD!","color":"green"}]')
1981 end
1982 if registry.ANNOUNCE_GERMAN then
1983 -- announce success in German
1984 commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' hat soeben einen neuen Rekord für die VIELSEITIGSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
1985 end
1986 end
1987
1988 -- FOR THE GOAL "GREENEST NEIGHBOURHOOD"
1989 -- here we need to count the number of green vocabs
1990 local greenest = tracker.getScore("Greenest_[points]","highscores")
1991 local Gint = math.floor(100*buildzone.greenSlots/49) --Gint is the green index, made from green area (greenSlots) over ground area (7x7 slots = 49)
1992 if Gint > greenest.count then
1993 commands.async.scoreboard("players","set","Greenest_[points]","highscores",Gint)
1994 if registry.ANNOUNCE_ENGLISH then
1995 -- announce success in English
1996 commands.async.tellraw("@a",'["",{"text":"Awesome! '..name.. ' just topped the record for the GREENEST NEIGHBOURHOOD!","color":"green"}]')
1997 end
1998 if registry.ANNOUNCE_GERMAN then
1999 -- announce success in German
2000 commands.async.tellraw("@a",'["",{"text":"Klasse! '..name.. ' hat einen neuen Rekord für die GRÜNSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
2001 end
2002 end
2003
2004 --calculate highest placement -- FOR THE GOAL "TALLEST NEIGHBOURHOOD"
2005 local highest = tracker.getScore("Tallest_[meters]","highscores")
2006 if buildzone.highest > highest.count then
2007 commands.async.scoreboard("players","set","Tallest_[meters]","highscores",buildzone.highest)
2008 if registry.ANNOUNCE_ENGLISH then
2009 -- announce success in English
2010 commands.async.tellraw("@a",'["",{"text":"Incredible! '..name..' just topped the record for TALLEST NEIGHBOURHOOD!","color":"green"}]')
2011 end
2012 if registry.ANNOUNCE_GERMAN then
2013 -- announce success in German
2014 commands.async.tellraw("@a",'["",{"text":"Unglaublich! '..name..' hat einen neuen Rekord für die HÖCHSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
2015 end
2016 end
2017
2018
2019 --increase the "how many structures did i build" score for the building player
2020 commands.async.scoreboard("players","add",name,"built",1)
2021 commands.async.scoreboard("players","add",name,"building_"..element.id,1)
2022 --]]
2023 totalResult = true
2024 break
2025
2026 end
2027 end
2028 if totalResult then
2029 --yey win, do a happy time
2030 successParticle(x,y,z)
2031 else
2032 --no vocab found so do a fail particle
2033 --announce in English
2034 commands.async.tellraw(name,'["",{"text":"The shape you have built does not match any shape in the catalogue, try a different one.","color":"red"}]')
2035 if registry.ANNOUNCE_GERMAN then
2036 -- announce in German
2037 commands.async.tellraw(name,'["",{"text":"Die Kombination, die du gebaut hast passt leider zu keinem Gebäude, versuche es mit einer anderen Form.","color":"gold"}]')
2038 end
2039 failParticle(x,y-1,z)
2040 end
2041 end
2042 return victory
2043end
2044
2045--- Display game information on the monitor
2046-- Slated for removal
2047function debugDisplay(game)
2048 local blink = true
2049 monitor.clear()
2050 if blink then
2051 monitor.setCursorPos(1,1)
2052 monitor.setTextColor(colors.red)
2053 monitor.write("Running")
2054 monitor.setTextColor(colors.white)
2055 redstone.setOutput("top",true)
2056 blink = false
2057 else
2058 redstone.setOutput("top",false)
2059 blink = true
2060 end
2061 local line = 2
2062
2063 for i,kew in ipairs(game.queues) do
2064 monitor.setCursorPos(1,line)
2065 local minutes = string.format("%02d",math.floor(kew.timer/60))
2066 local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
2067 monitor.write("Buildzone "..i.." | Phase: "..kew.phase.." | Time: "..minutes..":"..seconds)
2068 monitor.setCursorPos(1,line+1)
2069 for i,player in ipairs(kew.playerlist) do
2070 monitor.write(player.name.." ")
2071 end
2072 line = line +2
2073 end
2074
2075 monitor.setCursorPos(1,10)
2076 for i,player in ipairs(game.waitlist) do
2077 monitor.write(player.name.." ")
2078 end
2079end
2080
2081
2082-- the main function
2083function MAIN()
2084 local symbols = {
2085 "(X) ",
2086 "(-) "
2087 }
2088 local spin = 1
2089
2090 --print("Lua version:".._G._VERSION)
2091 term.clear()
2092 term.setTextColor(colors.blue)
2093 print("Starting 20.000 Blocks")
2094 print("Version: "..VERSION_NUMBER.." - "..VERSION_NAME)
2095 term.setTextColor(colors.white)
2096
2097
2098
2099
2100
2101 --[[
2102 --sets where and how big the PHV area is
2103 --second number is along the long edge of PHV starting at the spawn side
2104 --first number is along the short edge of PHV starting from the park side
2105 if DEBUG_MODE then
2106
2107 registry.FIRSTZONE = registry.DEBUG_ZONE
2108
2109 LOCS = buildGrid(1,1)
2110 else
2111 LOCS = buildGrid(11,27)
2112 end
2113 --]]
2114
2115 LOCS = buildGrid(registry.GAME_FIELD.countX, registry.GAME_FIELD.countZ)
2116
2117 local game = setup()
2118 if not game then
2119 return
2120 end
2121
2122 local skip = true
2123 if not skip then
2124 while true do
2125 --[[
2126 term.clear()
2127 term.setTextColor(colors.green)
2128 print("20,000 Blocks is active "..symbols[spin])
2129 term.setTextColor(colors.white)
2130 spin = spin +1
2131 if spin > #symbols then spin = 1 end
2132 --]]
2133
2134 update(game)
2135
2136 commands.async.weather("clear",10000)
2137
2138 --[[
2139 if monitor then
2140 debugDisplay(game)
2141 end
2142 local resetbutton = redstone.getInput("left")
2143 if resetbutton then
2144 print("reset!")
2145 for i,kew in ipairs(game.queues) do
2146 if kew.phase == 2 then
2147 kew.timer = 5
2148 end
2149 end
2150 end
2151 ]]--
2152 sleep(0.1)
2153 end
2154 end
2155end
2156
2157-- process command line parameters
2158local tArgs = { ... } -- get the command line arguments
2159if #tArgs == 1 then
2160 cleanbuildzone = tArgs[1]
2161elseif #tArgs > 1 then
2162 print("Usage: play <true(cleans buildzone)/false(default, doesnt clean)>")
2163 return
2164end
2165-- run the game
2166MAIN()