antonsavov

play v2.5

Dec 7th, 2017
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 113.08 KB | None | 0 0
  1. VERSION_NUMBER = '2.7.2'
  2. VERSION_NAME = 'the blockswapping paradigm'
  3. os.loadAPI('utils')
  4. os.loadAPI('registry')
  5. os.loadAPI('tracker')
  6. os.loadAPI('json')
  7.  
  8.  
  9.  
  10. --restore creative to those who had it
  11. --clear experience points upon using the homecomer or reseting
  12. --make game to autostart
  13.  
  14.  
  15. --contains a list of all posible Buildzones (built a bit later)
  16. local LOCS = {}
  17. local cleanbuildzone = false
  18. local debug_log = {} --keep all messages of debug log here
  19. local catalogue_elements = {} --keep the initialized catalogue elements here instead of in the game object to avoid recursive containment in the table "game"
  20. local buildzones = {} --keep the initialized buildzones here instead of in the game object to avoid recursive containment in the table "game"
  21.  
  22. local number_of_players_adventure --will keep the number of players in adventure mode on the server
  23. local number_of_players_creative --will keep the number of players in creative mode on the server
  24.  
  25. ----UTILITY FUNCTIONS
  26.  
  27. local function debugT(_message) --, print)
  28.     --local fullmsg = json.encode(debug.traceback())..": "..message
  29.     ---print(debug.getinfo(1, "n").name)
  30.     if _message == nil then return end
  31.     local fullmsg = tostring(_message)
  32.  
  33.     --print("logging...:"..fullmsg)
  34.     --[[
  35.     if registry.DEBUG_MODE then
  36.         term.setTextColor(colors.red)
  37.         --print("DEBUG: "..fullmsg)
  38.         term.setTextColor(colors.white)
  39.     end
  40.     --]]
  41.     local timestamp = os.clock()
  42.     table.insert(debug_log, {time=timestamp,message=fullmsg})
  43.    
  44.     local logfilename = "log.txt"
  45.    
  46.     --save message to logfile
  47.     if #debug_log == 1 then
  48.         --if it is the first message then reset the log file   
  49.         local file = fs.open(logfilename, "w")
  50.         file.write(timestamp..": "..fullmsg.."\n")
  51.         file.close()
  52.     else
  53.         --append it to the log file
  54.         local file = fs.open(logfilename, "a")
  55.         file.write(timestamp..": "..fullmsg.."\n")
  56.         file.close()
  57.     end
  58.     --]]
  59.     --print("logged:"..fullmsg)
  60. end
  61.  
  62. --[[
  63. local function BitAND(a,b)--Bitwise and
  64.     local p,c=1,0
  65.     while a>0 and b>0 do
  66.         local ra,rb=a%2,b%2
  67.         if ra+rb>1 then c=c+p end
  68.         a,b,p=(a-ra)/2,(b-rb)/2,p*2
  69.     end
  70.     return c
  71. end
  72.  
  73. function lshift(x, by)
  74.   return x * 2 ^ by
  75. end
  76.  
  77. function rshift(x, by)
  78.   return math.floor(x / 2 ^ by)
  79. end
  80. --]]
  81.  
  82. --sort table by random
  83. local function shuffleTable( t )
  84.     local rand = math.random
  85.     assert( t, "shuffleTable() expected a table, got nil" )
  86.     local iterations = #t
  87.     local j
  88.    
  89.     for i = iterations, 2, -1 do
  90.         j = rand(i)
  91.         t[i], t[j] = t[j], t[i]
  92.     end
  93. end
  94.  
  95. -- returns how many items are in a table/list
  96. function tablelength(T)
  97.   local count = 0
  98.   for _ in pairs(T) do count = count + 1 end
  99.   return count
  100. end
  101.  
  102. --- Fills a region recursively even if it is bigger by the allowed number of blocks.
  103. -- @param x
  104. -- @param y
  105. -- @param z
  106. -- @param sizeX
  107. -- @param sizeY
  108. -- @param sizeZ
  109. -- @param fill_material A table with field .block and .variant
  110. -- @param replace Optional, Boolean
  111. -- @param replace_material Optional, A table with field .block and .variant
  112.  
  113. function fillSmart(x,y,z,sizeX,sizeY,sizeZ, fill_material,replace,replace_material)
  114.     --check if volume is bigger than maximum blocks 32768
  115.     local limit = registry.FILL_LIMIT
  116.     local w,h,l = sizeX, sizeY, sizeZ
  117.     --print("which is nil?", w,h,l)
  118.     if math.abs(w*l*h) <= limit then
  119.         --if not then do simple fill
  120.         --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)
  121.         if replace and replace_material then
  122.             commands.async.fill(x,y,z,x+w-(w/math.abs(w)),y+h-(h/math.abs(h)),z+l-(l/math.abs(l)),fill_material.block, fill_material.variant, "replace", replace_material.block, replace_material.variant)
  123.         else
  124.             commands.async.fill(x,y,z,x+w-(w/math.abs(w)),y+h-(h/math.abs(h)),z+l-(l/math.abs(l)),fill_material.block, fill_material.variant )
  125.         end
  126.         return true
  127.     else
  128.         --divide in 8 sub-boxes and run again
  129.         local halfW = math.floor(w/2)
  130.         local restW = w-halfW
  131.         local halfH = math.floor(h/2)
  132.         local restH = h-halfH
  133.         local halfL = math.floor(l/2)
  134.         local restL = l-halfL      
  135.         --check if one of them is zero
  136.         fillSmart(x+halfW, y+halfH, z+halfL, restW, restH, restL, fill_material,replace,replace_material) --always run
  137.         --
  138.         if math.abs(halfW) > 0 then
  139.             fillSmart(x, y+halfH, z+halfL, halfW, restH, restL, fill_material,replace,replace_material) --run if halfW is not zero
  140.         end
  141.         if math.abs(halfH) > 0 then
  142.             fillSmart(x+halfW, y, z+halfL, restW, halfH, restL, fill_material,replace,replace_material) --run if halfH is not zero
  143.         end
  144.         if math.abs(halfL) > 0 then
  145.             fillSmart( x+halfW, y+halfH, z, restW, restH, halfL, fill_material,replace,replace_material) --run if halfL is not zero
  146.         end
  147.         ---
  148.         if math.abs(halfW) > 0 and math.abs(halfH) > 0 then    
  149.             fillSmart( x, y, z+halfL, halfW, halfH, restL, fill_material,replace,replace_material) --run if halfs W and H are not zero
  150.         end
  151.         if math.abs(halfL) > 0 and math.abs(halfH) > 0 then    
  152.             fillSmart( x+halfW, y, z, restW, halfH, halfL, fill_material,replace,replace_material)--run if halfH and halfL are not zero
  153.         end
  154.         if math.abs(halfW) > 0 and math.abs(halfL) > 0 then    
  155.             fillSmart( x, y+halfH, z, halfW, restH, halfL, fill_material,replace,replace_material) -- run if half W and L are not zero
  156.         end
  157.         ---
  158.         if math.abs(halfW) > 0 and math.abs(halfH) > 0 and math.abs(halfL) > 0 then
  159.             fillSmart( x, y, z, halfW, halfH, halfL, fill_material,replace,replace_material) --run if neither half is zero     
  160.         end
  161.         return true
  162.     end
  163.     return false
  164. end
  165.  
  166. --creates a ring of blocks using coordinates
  167. function fillSmartRing(x,y,z,sizeX,sizeY,sizeZ, fill_material,replace,replace_material)
  168.     --local h = 1
  169.     --if height then
  170.     --  h = height
  171.     --end
  172.     --debugT("fillSmart from inside fillSmartRing")
  173.     fillSmart(x,y,z,sizeX,sizeY,1, fill_material,replace,replace_material)
  174.     fillSmart(x,y,z,1,sizeY,sizeZ, fill_material,replace,replace_material)
  175.     fillSmart(x+sizeX-1,y,z,1,sizeY,sizeZ, fill_material,replace,replace_material)
  176.     fillSmart(x,y,z+sizeZ-1,sizeX,sizeY,1, fill_material,replace,replace_material)
  177.     --debugT("fillSmart from inside fillSmartRing done")
  178. end
  179.  
  180. --fills an offset region of the specified one
  181. --direction: true - outside; false - inside
  182. function fillSmartOffset(x,y,z,sizeX,sizeY,sizeZ,offset, direction, fill_material,replace,replace_material)
  183.     --debugT("fillSmart from inside fillSmartOffset")
  184.     if offset == 0 then
  185.         fillSmart(x,y,z,sizeX,sizeY,sizeZ, fill_material,replace,replace_material)
  186.         return
  187.     end
  188.     local uX = sizeX/math.abs(sizeX)
  189.     local uY = sizeY/math.abs(sizeY)
  190.     local uZ = sizeZ/math.abs(sizeZ)
  191.     if direction then
  192.         --outside offset
  193.         fillSmart(x-uX*offset,y-uY*offset,z-uZ*offset,sizeX+2*uX*offset,sizeY+2*uY*offset,sizeZ+2*uZ*offset, fill_material,replace,replace_material)
  194.     else
  195.         --inside offset
  196.         fillSmart(x+uX*offset,y+uY*offset,z+uZ*offset,sizeX-2*uX*offset,sizeY-2*uY*offset,sizeZ-2*uZ*offset, fill_material,replace,replace_material)
  197.     end
  198. end
  199.  
  200. --fills an offset region of the specified one
  201. -- offsets only along X and Z, doesnt offset vertically
  202. --direction: true - outside; false - inside
  203. function fillSmartOffsetXZ(x,y,z,sizeX,sizeY,sizeZ,offset, direction, fill_material,replace,replace_material)
  204.     --debugT("fillSmart from inside fillSmartOffset")
  205.     if offset == 0 then
  206.         fillSmart(x,y,z,sizeX,sizeY,sizeZ, fill_material,replace,replace_material)
  207.         return
  208.     end
  209.     local uX = sizeX/math.abs(sizeX)
  210.     --local uY = sizeY/math.abs(sizeY)
  211.     local uZ = sizeZ/math.abs(sizeZ)
  212.     if direction then
  213.         --outside offset
  214.         fillSmart(x-uX*offset,y,z-uZ*offset,sizeX+2*uX*offset,sizeY,sizeZ+2*uZ*offset, fill_material,replace,replace_material)
  215.     else
  216.         --inside offset
  217.         fillSmart(x+uX*offset,y,z+uZ*offset,sizeX-2*uX*offset,sizeY,sizeZ-2*uZ*offset, fill_material,replace,replace_material)
  218.     end
  219. end
  220.  
  221. -- fills a horizontal region with grid markers
  222. -- takes the grid settings from the registry
  223. -- grid origin is the main computer
  224. function fillGrid(x,y,z,sizeX,sizeZ,fill_material)
  225.     local uX = sizeX/math.abs(sizeX)
  226.     local uZ = sizeZ/math.abs(sizeZ)
  227.     for ix = x, x+sizeX-uX, uX do
  228.         for iz = z, z+sizeZ - uZ, uZ do
  229.             --check if the coordinate is a grid point
  230.             if (ix-registry.computer.x) % registry.GRIDCELL_SIZE == 0 and (iz-registry.computer.z) % registry.GRIDCELL_SIZE == 0 then
  231.                 commands.async.setblock(ix,y,iz,fill_material.block, fill_material.variant)
  232.             end
  233.         end
  234.     end
  235. end
  236.  
  237.  
  238.  
  239. --- Clones an area even if it is bigger than the minecraft limit
  240. -- @param maskMode from registry.CLONE_MASK_MODE
  241. -- @param cloneMode from registry.CLONE_MODE
  242. -- @param filteredMaterial table with .block and .variant
  243. function cloneSmart(from_x,from_y,from_z,sizeX,sizeY,sizeZ, to_x, to_y, to_z, maskMode, cloneMode, filteredMaterial)
  244.     -- clone command works as this: https://www.digminecraft.com/game_commands/clone_command.php
  245.     -- /clone <x1> <y1> <z1>  <x2> <y2> <z2>  <x> <y> <z> [maskMode] [cloneMode] [tileName] [tileData]
  246.     --check if volume is bigger than maximum blocks 32768
  247.     local limit = registry.FILL_LIMIT
  248.     local w,h,l = sizeX, sizeY, sizeZ
  249.     --print("which is nil?", w,h,l)
  250.     if math.abs(w*l*h) <= limit then
  251.         --if not then do simple fill
  252.         --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)
  253.         --if replace and replace_material then
  254.         --commands.async.fill(x,y,z,x+w-(w/math.abs(w)),y+h-(h/math.abs(h)),z+l-(l/math.abs(l)),fill_material.block, fill_material.variant, "replace", replace_material.block, replace_material.variant)
  255.         if filteredMaterial then
  256.             commands.clone(
  257.                 from_x, from_y, from_z,
  258.                 from_x+w-(w/math.abs(w)), from_y+h-(h/math.abs(h)), from_z+l-(l/math.abs(l)),
  259.                 to_x, to_y, to_z,
  260.                 maskMode or registry.CLONE_MASK_MODE.REPLACE, cloneMode or registry.CLONE_MODE.NORMAL, filteredMaterial.block, filteredMaterial.variant)   
  261.         else
  262.             commands.clone(
  263.                 from_x, from_y, from_z,
  264.                 from_x+w-(w/math.abs(w)), from_y+h-(h/math.abs(h)), from_z+l-(l/math.abs(l)),
  265.                 to_x, to_y, to_z,
  266.                 maskMode or registry.CLONE_MASK_MODE.REPLACE, cloneMode or registry.CLONE_MODE.NORMAL)
  267.         end
  268.            
  269.         --end
  270.         --else
  271.         --commands.async.fill(x,y,z,x+w-(w/math.abs(w)),y+h-(h/math.abs(h)),z+l-(l/math.abs(l)),fill_material.block, fill_material.variant )
  272.         --end
  273.         return true
  274.     else
  275.         --divide in 8 sub-boxes and run again
  276.        
  277.         local halfW = math.floor(w/2)
  278.         local restW = w-halfW
  279.         local halfH = math.floor(h/2)
  280.         local restH = h-halfH
  281.         local halfL = math.floor(l/2)
  282.         local restL = l-halfL
  283.         --always run
  284.         cloneSmart(from_x+halfW, from_y+halfH, from_z+halfL, restW, restH, restL, to_x+halfW, to_y+halfH, to_z+halfL, maskMode, cloneMode, filteredMaterial)
  285.         --
  286.         --check if one of the halves is zero
  287.         if math.abs(halfW) > 0 then
  288.             --run if halfW is not zero
  289.             cloneSmart(from_x, from_y+halfH, from_z+halfL, halfW, restH, restL, to_x, to_y+halfH, to_z+halfL, maskMode, cloneMode, filteredMaterial)
  290.         end
  291.         if math.abs(halfH) > 0 then
  292.              --run if halfH is not zero
  293.             cloneSmart(from_x+halfW, from_y, from_z+halfL, restW, halfH, restL, to_x+halfW, to_y, to_z+halfL, maskMode, cloneMode, filteredMaterial)
  294.         end
  295.         if math.abs(halfL) > 0 then
  296.              --run if halfL is not zero
  297.             cloneSmart( from_x+halfW, from_y+halfH, from_z, restW, restH, halfL, to_x+halfW, to_y+halfH, to_z, maskMode, cloneMode, filteredMaterial)
  298.         end
  299.         ---
  300.         if math.abs(halfW) > 0 and math.abs(halfH) > 0 then    
  301.              --run if halfs W and H are not zero
  302.             cloneSmart( from_x, from_y, from_z+halfL, halfW, halfH, restL, to_x, to_y, to_z+halfL, maskMode, cloneMode, filteredMaterial)
  303.         end
  304.         if math.abs(halfL) > 0 and math.abs(halfH) > 0 then    
  305.             --run if halfH and halfL are not zero
  306.             cloneSmart( from_x+halfW, from_y, from_z, restW, halfH, halfL, to_x+halfW, to_y, to_z, maskMode, cloneMode, filteredMaterial)
  307.         end
  308.         if math.abs(halfW) > 0 and math.abs(halfL) > 0 then    
  309.              -- run if half W and L are not zero
  310.             cloneSmart( from_x, from_y+halfH, from_z, halfW, restH, halfL, to_x, to_y+halfH, to_z, maskMode, cloneMode, filteredMaterial)
  311.         end
  312.         ---
  313.         if math.abs(halfW) > 0 and math.abs(halfH) > 0 and math.abs(halfL) > 0 then
  314.              --run if neither half is zero     
  315.             cloneSmart( from_x, from_y, from_z, halfW, halfH, halfL, to_x, to_y, to_z, maskMode, cloneMode, filteredMaterial)
  316.         end
  317.         return true
  318.     end
  319.     return false
  320. end
  321.  
  322. --PARTICLE FUNCTIONS
  323. --particles shown to player while their shape is being checked for match
  324. function searchParticle(x,y,z)
  325.     commands.async.particle("fireworksSpark",x,y,z,0.01,3,0.01,0.01,100)
  326. end
  327. -- particles shown to player on successful vocab match
  328. function successParticle(x,y,z)
  329.     commands.async.particle("happyVillager",x,y,z,2,2,2,1,1000)
  330.     commands.async.playsound("random.levelup","@a",x,y,z,1,1.2)
  331. end
  332. --- particles shown to player on failed vocab match
  333. function failParticle(x,y,z)
  334.     commands.async.particle("reddust",x,y,z,0.1,0.1,1.5,1,200)
  335.     commands.async.particle("reddust",x,y,z,1.5,0.1,0.1,1,200)
  336.     commands.async.playsound("random.bowhit","@a",x,y,z,1,0.8)
  337. end
  338.  
  339. ----END OF UTILITY FUNCTIONS
  340.  
  341. --creates a grid of absolute references (0,0) (1,0)
  342. --rename to buildGameField
  343. function buildGrid(w,h)
  344.     debugT("creating the LOCS table with all buildzones in this game...")
  345.     local grid = readGridFromFile()
  346.     if grid then
  347.         -- grid was read from the file successfully
  348.         debugT("LOCS table read from the local file")
  349.     else
  350.         --generate file from scratch
  351.        
  352.         grid = {}
  353.         for z=0,h-1 do
  354.             for x=0,w-1 do
  355.                 table.insert(grid,{x=x,z=z,played=false})
  356.             end
  357.         end
  358.         debugT("LOCS table created from scratch and saved to a file")
  359.     end
  360.    
  361.     return grid
  362. end
  363.  
  364. function readGridFromFile()
  365.     local result = nil
  366.     --fs.makeDir("/records")
  367.     --local filename = "/records/_buildzones-list.json"
  368.     --local filename = "_buildzones-list.json"
  369.     --local filename_with_path = registry.RECORDS_FOLDER.."/"..filename
  370.    
  371.    
  372.     if utils.file_exists(registry.BUILDZONES_LIST_FILE) then
  373.         ---read from file
  374.         result = json.decodeFromFile(registry.BUILDZONES_LIST_FILE)
  375.     end
  376.     return result  
  377. end
  378.  
  379. function writeGridToFile()
  380.     fs.makeDir(registry.RECORDS_FOLDER)
  381.     --local filename = "_buildzones-list.json"
  382.     --local filename_with_path = registry.RECORDS_FOLDER.."/"..filename
  383.  
  384.     local file = fs.open(registry.BUILDZONES_LIST_FILE,"w")
  385.     file.write(json.encodePretty(LOCS))
  386.     file.close()
  387. end
  388.  
  389. --- Constructor for playerdata object
  390. -- @param name the player minecraft name as a string
  391. -- @param x the players current X coord
  392. -- @param y the players current Y coord
  393. -- @param z the players current Z coord
  394. -- @table p The new player object
  395. -- @return p The new player object
  396. function newPlayerData(name,x,y,z)
  397.     local p = {
  398.         name = name, -- the players minecraft name (String)
  399.         x = x, -- the players last X coord
  400.         y = y, -- the players last Y coord
  401.         z = z -- the players last Z coord
  402.     }
  403.     return p
  404. end
  405.  
  406. --return a list of all players in the game world as player objects
  407. local function getAllPos(selector)
  408.     --debugT("starting getAllPos with selector: "..selector)
  409.     --commands.gamerule("logAdminCommands",true) --it seems we need this to be on for successful tp message back
  410.     --os.sleep(2)
  411.     local result, message = commands.tp("@a["..selector.."]","~ ~ ~")
  412.     --commands.gamerule("logAdminCommands",false) --and then disable back off to prevent the game from flooding the chat log
  413.     --local result, message = commands.exec("tp @a["..selector.."] ~ ~ ~")
  414.     local names = {}
  415.     if result == true then
  416.         for i,result in ipairs(message) do
  417.             --debugT("starting message decoding: "..result)
  418.             local wordpattern = "[^, ]+"
  419.             local numberpattern = "[%-% ]%d+[%.]%d+"
  420.             local words,numbers = {},{}
  421.             --debugT("finding words: "..result)
  422.             for word in string.gmatch(result, wordpattern) do
  423.                 table.insert(words,word)
  424.             end
  425.             --debugT("finding numbers: "..result)
  426.             for number in string.gmatch(result, numberpattern) do
  427.                 table.insert(numbers,number)
  428.             end
  429.  
  430.             local coords = {
  431.                 x = math.floor(numbers[1]),
  432.                 y = math.floor(numbers[2]),
  433.                 z = math.floor(numbers[3])
  434.                 }
  435.             local name = words[2]
  436.             --debugT("inserting into names list: "..name)
  437.             table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
  438.         end
  439.     end
  440.     --debugT("getAllPos completed")
  441.     return names
  442. end
  443.  
  444.  
  445. --returns a list of player objects containing all players who are standing on the given block, and who also are in the given selection
  446. local function getAllOnBlockType(block,selector)
  447.     local result, message = commands.exec("execute @a["..selector.."] ~ ~ ~ detect ~ ~-1 ~ "..block.." -1 tp @p[r=1] ~ ~ ~")
  448.     local names = {}
  449.     if result == true then
  450.         for i,result in ipairs(message) do
  451.             local wordpattern = "[^, ]+"
  452.             local numberpattern = "[%-% ]%d+[%.]%d+"
  453.             local words,numbers = {},{}
  454.  
  455.             for word in string.gmatch(result, wordpattern) do
  456.                 table.insert(words,word)
  457.             end
  458.             for number in string.gmatch(result, numberpattern) do
  459.                 table.insert(numbers,number)
  460.             end
  461.            
  462.             if numbers[1] and numbers[2] and numbers[3] then
  463.                 local coords = {
  464.                         x = math.floor(numbers[1]),
  465.                         y = math.floor(numbers[2]),
  466.                         z = math.floor(numbers[3])
  467.                     }
  468.                 local name = words[2]
  469.                 table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
  470.                 --print("Found a player - getOnBlock")
  471.                 debugT("player "..name.." is on "..block.." at: "..coords.x..", "..coords.y..", "..coords.z)
  472.             else
  473.                 debugT("Error in getAllOnBlockType: Coordinate Numbers were missing")
  474.             end
  475.         end
  476.     end
  477.     return names
  478. end
  479.  
  480. ---BEGIN HOMECOMER RELATED FUNCTIONS
  481.  
  482. --gives a player a HOMECOMER egg with their name on it. Removes all spawn eggs first
  483. local function giveHomecomer(name)
  484.     commands.clear(name,'spawn_egg')
  485.    
  486.     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]}}')
  487. end
  488.  
  489. --returns a list of HOMECOMER entities and their names  
  490. local function getHomecomers()
  491.     local result, message = commands.exec("execute @e[type="..registry.HOMECOMER_TYPE.."] ~ ~ ~ tp @e[r=1] ~ ~ ~")
  492.     local names = {}
  493.     if result == true then
  494.         for i,result in ipairs(message) do
  495.             local wordpattern = "[^, ]+"
  496.             local numberpattern = "[%-% ]%d+[%.]%d+"
  497.             local words,numbers = {},{}
  498.  
  499.             for word in string.gmatch(result, wordpattern) do
  500.                 table.insert(words,word)
  501.                 --print(word)
  502.             end
  503.             for number in string.gmatch(result, numberpattern) do
  504.                 table.insert(numbers,number)
  505.             end
  506.            
  507.             if numbers[1] and numbers[2] and numbers[3] then
  508.                 local coords = {
  509.                     x = math.floor(numbers[1]),
  510.                     y = math.floor(numbers[2]),
  511.                     z = math.floor(numbers[3])
  512.                     }
  513.                 local name = words[4]
  514.                 table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
  515.                 debugT("homecomer '"..name.."' is at: "..coords.x..", "..coords.y..", "..coords.z)
  516.             else
  517.                 --print("Error: Coordinate Numbers were missing")
  518.             end
  519.         end
  520.     end
  521.     return names
  522. end
  523.  
  524. --- Counts active players
  525. -- Now that we changed how player lists work, just counting the length
  526. -- does not reveal how many players are currently playing
  527. -- we need to count based on status
  528. -- @param kew A Kew object
  529. -- @return result The playercount as an Int
  530. local function countActivePlayers(kew)
  531.     local result = 0
  532.     for name, playerdata in pairs(kew.playerlist) do
  533.         if playerdata.status == registry.PLAYER_STATUS.IN_GAME then
  534.             result = result + 1
  535.         end
  536.     end
  537.     return result
  538. end
  539.  
  540. --- Removes a player from a game queue
  541. -- As playerlists are now playername indexed, we can just check if the
  542. -- player is in the list. If the player is in the list, we want to change
  543. -- his status to 1 (left with Homecomer). End the phase if this was the
  544. -- last player.
  545. -- @param game The game object
  546. -- @param playername The players name as a string
  547. local function removePlayerFromKew(game,playername)
  548.     for _,kew in pairs(game.queues) do
  549.         if (kew.playerlist[playername]) then
  550.             debugT("changing status for player '"..playername.."' at buildzone "..kew.buildzone.locid.." to 1 - left-with-homemcomer")
  551.             kew.playerlist[playername].status = registry.PLAYER_STATUS.LEFT_WITH_HOMECOMER
  552.         end
  553.         local number_of_active_players = countActivePlayers(kew)
  554.         debugT("players left in buildzone "..kew.buildzone.locid..": "..number_of_active_players)
  555.         if number_of_active_players == 0 and kew.phase == registry.QUEUE_PHASE.PLAYING then
  556.             --game can be ended as no players are left
  557.             kew.timer = 0
  558.         end
  559.     end
  560. end
  561.  
  562. --teleports a player ot the spawn area
  563. local function movePlayerToSpawn(playername)
  564.     resetPlayer(playername)
  565.     --print("before TP")
  566.     commands.tp(playername,registry.SPAWN.x,registry.SPAWN.y,registry.SPAWN.z,registry.SPAWN.a1,registry.SPAWN.a2)
  567.     --print("after TP")
  568.     if registry.ANNOUNCE_ENGLISH then
  569.         commands.async.tellraw(playername,'["",{"text":"You used your HOMECOMER and TELEPORTED BACK TO SPAWN","color":"white"}]')
  570.     end
  571.     if registry.ANNOUNCE_GERMAN then
  572.         commands.async.tellraw(playername,'["",{"text":"Du hast den HEIMKEHRER benutzt um dich zurück zum Anfang zu teleportieren.","color":"gold"}]')
  573.     end
  574. end
  575.  
  576. --takes a list of homecomers and deals with all those players, moving them back to spawn and removing them from game
  577. --also gives them a new homecomer
  578. local function dealWithHomecomers(game, homecomers)
  579.     for _,homecomer in pairs(homecomers) do
  580.         --remove player from current game if in game
  581.         removePlayerFromKew(game,homecomer.name)
  582.         --teleport them back to spawn
  583.         movePlayerToSpawn(homecomer.name)
  584.         --give a new homecomer
  585.         giveHomecomer(homecomer.name)
  586.         --particle effects
  587.         --teleport message
  588.     end
  589.     --kill all homecomers
  590.     if #homecomers>0 then
  591.         commands.tp("@e[type="..registry.HOMECOMER_TYPE.."]",100000,200,100000)
  592.         commands.kill("@e[type="..registry.HOMECOMER_TYPE.."]")
  593.         os.sleep(#homecomers*0.2)
  594.     end
  595. end
  596.  
  597. ---
  598. function checkForHomecomers(game)
  599.     --execute on all homecomers
  600.     local homecomers = getHomecomers()
  601.     dealWithHomecomers(game,homecomers)
  602. end
  603.  
  604. --- END OF HOMECOMER FUNCTIONS
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612. --creates a villager with special items
  613. local function spawnVillager(x,y,z)
  614.     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"]}}}  ]}}')
  615. end
  616.  
  617.  
  618. --displays a time as experience points to a selection of players
  619. local function displayTime(selector,minutes,seconds)
  620.     --commands.title("@a["..selector.."]","subtitle",'{text:"Time left:  '..minutes..":"..seconds..'",color:red,bold:false,underlined:false,italic:false,strikethrough:false,obfuscated:false}')
  621.     commands.async.xp("-1000000L","@a["..selector.."]")
  622.     local secondstot = (minutes * 60) + seconds
  623.     commands.async.xp(tostring(secondstot).."L","@a["..selector.."]")
  624. end
  625.  
  626. --simply runs displayTime on a list of players
  627. local function displayTimeToGroup(playerlist,minutes,seconds)
  628.     for name,player in pairs(playerlist) do
  629.         displayTime("name="..player.name,minutes,seconds)
  630.     end
  631. end
  632.  
  633. --- Updates the Time (XP bar) for players in a buildzone
  634. --Uses a new playerlist object to only send the time to the active players
  635. -- @param A new playerlist object
  636. -- @param minutes How many minutes left
  637. -- @param seconds How many seconds are left
  638. local function displayTimeToPlayers(playerlist,minutes,seconds)
  639.   local activeList = {}
  640.   for name,player in pairs(playerlist) do
  641.     if player.status == registry.PLAYER_STATUS.IN_GAME then
  642.       table.insert(activeList,player)
  643.     end
  644.   end
  645.   displayTimeToGroup(activeList,minutes,seconds)
  646. end
  647.  
  648. local function playerListToString(playerlist)
  649.     --debugT("converting list to string: "..json.encode(playerlist))
  650.     local s = ""
  651.     if tablelength(playerlist) > 0 then
  652.         --debugT("it comes to the for loop")
  653.         for name, player in pairs(playerlist) do
  654.             --debugT("adding name: "..player.name)
  655.             if (player.status) then
  656.                 s = s..", "..player.name.."["..player.status.."]"
  657.             else
  658.                 s = s..", "..player.name
  659.             end
  660.         end
  661.     end
  662.     --if
  663.     --string.sub(m, 4)
  664.     return s:sub(3)
  665. end
  666.  
  667. --displays a title to a selection of players
  668. local function displayTitle(selector,text,subtext)
  669.     commands.async.title("@a["..selector.."]","subtitle",'{text:"'..subtext..'"}')
  670.     commands.async.title("@a["..selector.."]","title",'{text:"'..text..'"}')
  671. end
  672.  
  673. --simply runs displayTitle on a list of players
  674. local function displayTitleToGroup(playerlist,text,subtext)
  675.     debugT("displayTitleToGroup: "..text.."-"..subtext)
  676.     for name,player in pairs(playerlist) do
  677.         displayTitle("name="..player.name,text,subtext)
  678.     end
  679. end
  680.  
  681. --- Sends a title message to active players in a buildzone
  682. --Uses a new playerlist object to only send the title to the active players
  683. -- @param A new playerlist object
  684. -- @param text The message to send
  685. local function displayTitleToPlayers(playerlist,text,subtext)
  686.     debugT("displayTitleToPlayers: "..text.."-"..subtext)
  687.     local activeList = {}
  688.     for name,player in pairs(playerlist) do
  689.         if player.status == registry.PLAYER_STATUS.IN_GAME then
  690.             table.insert(activeList,player)
  691.         end
  692.     end
  693.     displayTitleToGroup(activeList,text,subtext)
  694. end
  695.  
  696. --teleports a list of players to an exact place and sends them a message about it
  697. local function teleportToPoint(x,y,z,playerlist,clear,textEN, textDE)
  698.     for name,player in pairs(playerlist) do
  699.         player.x = x
  700.         player.y = y
  701.         player.z = z
  702.         --commands.async.gamemode(2,player.name)
  703.         if clear then
  704.             commands.async.clear(player.name,"wool")
  705.             commands.async.clear(player.name,"stone_pickaxe")
  706.         end
  707.         commands.tp("@a[name="..player.name.."]",x,y,z)
  708.         if registry.ANNOUNCE_ENGLISH then
  709.             --print("text is: ", textEN)
  710.             commands.async.tellraw(player.name,'["",{"text":"'..textEN..'","color":"white"}]')
  711.         end
  712.         if registry.ANNOUNCE_GERMAN then
  713.             commands.async.tellraw(player.name,'["",{"text":"'..textDE..'","color":"gold"}]')
  714.         end
  715.     end
  716. end
  717.  
  718. --- Teleports a list of players randomly about a buildzone
  719. -- @param buildzone the target buildzone object
  720. -- @param playerlist a name or number indexed playerlist
  721. -- @param textEN An english message to send to english players
  722. -- @param textEN An german message to send to german players
  723. local function scatterIntoZone(buildzone,playerlist,textEN, textDE)
  724.     debugT("teleporting to buildzone #"..buildzone.locid.." the players: "..playerListToString(playerlist))
  725.     local minX = buildzone.x
  726.     local minZ = buildzone.z
  727.     local maxX = buildzone.x+buildzone.w
  728.     local maxZ = buildzone.z+buildzone.w
  729.     for name,player in pairs(playerlist) do
  730.         local targetX = math.floor(math.random(minX,maxX))
  731.         local targetZ = math.floor(math.random(minZ,maxZ))
  732.         --print("targetX", targetX)
  733.         --print("targetZ", targetZ)
  734.         --print("buildzone.y+5", (buildzone.y+5))
  735.         --print("player ",player)
  736.         --print(json.encodePretty(player))
  737.         --print("textEN", textEN)
  738.         --print("textDE", textDE)
  739.         --debugT("teleport from scatterIntoZone")
  740.         teleportToPoint(targetX, buildzone.y+5, targetZ, {player}, false, textEN, textDE)
  741.     end
  742.     debugT("teleporting players to buildzone #"..buildzone.locid.." complete")
  743. end
  744.  
  745. --- Teleports a list of players to the centre of a given buildzone
  746. -- @param buildzone the target buildzone object
  747. -- @param playerlist a name or number indexed playerlist
  748. -- @param textEN An english message to send to english players
  749. -- @param textEN An german message to send to german players
  750. local function teleportToZone(buildzone,playerlist,textEN, textDE)
  751.     teleportToPoint(buildzone.x+2+(buildzone.w/2),buildzone.y+5,buildzone.z+2+(buildzone.w/2),playerlist,true,textEN, textDE)
  752.  
  753. end
  754.  
  755. --gives the same list of items to a list of players
  756. local function giveItems(playerlist,itemlist)
  757.     debugT("Giving initial inventory items to players: "..playerListToString(playerlist))
  758.     local given = 0
  759.     for name,player in pairs(playerlist) do
  760.         --commands.async.clear(player.name)
  761.         for j,item in ipairs(itemlist) do
  762.             debugT("giving item >"..item.."<")
  763.             commands.async.give("@a[name="..player.name.."]",item)
  764.             given = given +1
  765.         end
  766.         giveHomecomer(player.name)
  767.         debugT("Gave initial inventory items to '"..player.name.."'")
  768.     end
  769.     debugT("Giving initial inventory items to players...DONE!")
  770.     return given
  771. end
  772.  
  773. --a catalogue slot constructor. Enforces some data structure
  774. function newCatalogueElement(id, x,y,z,sizeX, sizeZ) --, reward,nameEN, nameDE, typeEN, typeDE, height, slots,green,greenSlots, rewardUrban, rewardCount)
  775.     local nvz = {}
  776.     nvz.id = id
  777.     nvz.keyX ,nvz.keyY ,nvz.keyZ = x,y,z
  778.     nvz.sizeX, nvz.sizeZ = sizeX, sizeZ
  779.     nvz.elementX = nvz.keyX - nvz.sizeX - registry.GRIDCELL_SIZE --
  780.     nvz.elementY = nvz.keyY
  781.     nvz.elementZ = nvz.keyZ
  782.     nvz.elementCenterX = nvz.elementX + math.floor ( nvz.sizeX/2 )
  783.     nvz.elementCenterY = nvz.elementY
  784.     nvz.elementCenterZ = nvz.elementZ + math.floor ( nvz.sizeZ/2 )
  785.     nvz.keyCenterX = nvz.keyX + math.floor ( nvz.sizeX/2 )
  786.     nvz.keyCenterY = nvz.keyY
  787.     nvz.keyCenterZ = nvz.keyZ + math.floor ( nvz.sizeZ/2 )
  788.    
  789.     -- nvz.nameEN = nameEN
  790. --  nvz.reward = reward
  791. --  --- new stuff
  792. --
  793. --  nvz.nameDE = nameDE
  794. --  nvz.typeEN = typeEN
  795. --  nvz.typeDE = typeDE
  796. --  nvz.height = height
  797. --  nvz.slots = slots
  798. --  nvz.green = green
  799. --  nvz.greenSlots = greenSlots
  800. --  nvz.rewardUrban = rewardUrban
  801. --  nvz.rewardCount = rewardCount
  802. --
  803.     --print(json.encodePretty(nvz))
  804.     return nvz
  805.    
  806. end
  807.  
  808.  
  809. --a multi builder which uses the vocab constructor to create sets of vocab
  810. local function initCatalogueElements(countX, countZ, sizeX, sizeZ)
  811.     local x,y,z = registry.FIRST_ELEMENT.x, registry.FIRST_ELEMENT.y, registry.FIRST_ELEMENT.z
  812.     local result = {}
  813.     local id = 1
  814.     for i=0,countZ-1 do
  815.         for k=0,countX-1 do
  816.  
  817.             local xpos = x - k * ( registry.GRIDCELL_SIZE * ( 2*registry.CATALOGUE_SLOTSIZE.x + 2 + registry.CATALOGUE_SLOT_OFFSET))
  818.             local ypos = y
  819.             local zpos = z + i*( registry.GRIDCELL_SIZE * ( registry.CATALOGUE_SLOTSIZE.z + 1 + registry.CATALOGUE_SLOT_OFFSET))
  820.             --print("adding an element",i,k)
  821.             local nextElement = newCatalogueElement(
  822.                 id,
  823.                 xpos,ypos,zpos,
  824.                 sizeX, sizeZ
  825.             )
  826.                
  827.                 -- registry.REWARDS[id] or registry.DEFAULT_REWARD,
  828.     --          registry.VOCABS_DATA[id].nameEN or registry.DEFAULT_NAME,
  829.     --          registry.VOCABS_DATA[id].nameDE or registry.DEFAULT_NAME,
  830.     --          registry.VOCABS_DATA[id].typeEN,
  831.     --          registry.VOCABS_DATA[id].typeDE,
  832.     --          registry.VOCABS_DATA[id].height,
  833.     --          registry.VOCABS_DATA[id].slots,
  834.     --          registry.VOCABS_DATA[id].green,
  835.     --          registry.VOCABS_DATA[id].greenSlots,
  836.     --          registry.VOCABS_DATA[id].rewardUrban,
  837.     --          registry.VOCABS_DATA[id].rewardCount
  838.     --      )
  839.             table.insert(result,nextElement)
  840.             id = id +1
  841.         end
  842.     end
  843.     --print(json.encodePretty(result))
  844.     return result
  845. end
  846.  
  847. --- Finds the next free location for a buildzone in a given list of spots.
  848. -- Searches each zone in zones for an empty location.
  849. -- Zone are absolute positions (0,0),(0,1) ect.
  850. -- This uses the coords of FIRST_ZONE as given in the registry to determine
  851. -- the position of the zones for checking.
  852. -- @param zones A list of zones from BuildLocs()
  853. -- @param force Boolean. True will mean it returns the first location no matter what
  854. -- @return x The X value of the next unused location in world-coordinates
  855. -- @return y The Y value of the next unused location in world-coordinates
  856. -- @return z The Z value of the next unused location in world-coordinates
  857. -- @return locid The index of the returned zone
  858. local function findNextLoc(zones,force)
  859.     local x,y,z,locid = 0,0,0,1
  860.     for i,loc in ipairs(LOCS) do
  861.         locid = i
  862.         -- these are the coordinates of this LOC in the minecraft world
  863.         x = registry.FIRST_ZONE.x+(loc.x*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE))
  864.         y = registry.FIRST_ZONE.y
  865.         z = registry.FIRST_ZONE.z+(loc.z*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE))
  866.         --print("testing for available zone at: "..x..", "..y..", "..z)
  867.         --print("which is at grid cell at: "..loc.x..", "..loc.z)
  868.         --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
  869.         local result = true
  870.         if loc.played then
  871.             result = false
  872.             --print("zone has been played")
  873.         end
  874.         --print("testing done")
  875.         --force the first zone to be selected unless it is taken in the "zones" parameter
  876.         if force then result = true end
  877.         --checks if the zone is already in the list of unavailable zones passed as parameter
  878.         local zonefree = true
  879.         for i,zone in ipairs(zones) do
  880.             if zone.x == x and zone.z == z then
  881.                 zonefree = false
  882.             end
  883.         end
  884.         --print("next position free is ",loc.x*width,oy,loc.z*width)
  885.         --if result then print("true") else print("false") end
  886.         if result and zonefree then
  887.             debugT("Using loc at: "..x..", "..y..", "..z.." with locid: "..locid)
  888.             return x,y,z,locid --returns the coordinates of the new zone, plus its id in the LOCS table
  889.         end
  890.     end
  891.     debugT("ERROR: findNextLoc failed")
  892.     return nil,nil,nil, nil --returns empty if no zone is available
  893.    
  894. end
  895.  
  896. --[[ looks like the moveBuildzone is not used anymore
  897. --- Assigns the next unused available play area to an abstract buildzone object
  898. -- This takes a Buildzone and an array of Absolute references
  899. -- from BuildGrid(). It finds the next area by using FindNextLoc().
  900. -- When we change a buildzones coords it is important to update locid and
  901. -- the selector so that all systems know where the buildzone is.
  902. -- @param buildzone the buildzone object to be moved
  903. -- @param zones a list of zones to choose from
  904. -- @return a boolean result. True if the buildzone was moved
  905. function moveBuildzone(buildzone,zones)
  906.     local x,y,z,locid = findNextLoc(zones)
  907.     if x and y and z and locid then
  908.         --print("moved buildzone from "..buildzone.x..","..buildzone.z.." to "..x..","..y)
  909.         local w = buildzone.w
  910.         buildzone.x,buildzone.y,buildzone.z = x,y,z
  911.         buildzone.locid = locid --reassign the location id corresponding to the LOCS item for the grid cell of the moved zone
  912.         buildzone.selector = "x="..x..",y="..tostring(y-1)..",z="..z..",dx="..w..",dy=256,dz="..w
  913.         ---buildzone.structures = {} --a list of all vocabularies which have been contructed
  914.     return true
  915.     end
  916.   return false
  917. end
  918. --]]
  919.  
  920. --multi builder to create sets of buildzones using the buildzone constructor
  921. local function initBuildzones(quant,elements)--,width)--,floorHeight)
  922.     local result = {}
  923.     for i=1,quant do
  924.         --print("locating available slot")
  925.         local x,y,z,locid = findNextLoc(result)
  926.         if x and y and z and locid then    
  927.            
  928.             table.insert(result,newBuildZone(x,y,z,elements,locid))
  929.             debugT("Created a new Buildzone #"..locid.." at:"..x..", "..y..", "..z)
  930.         else
  931.             --print("failed to make new buildzone")
  932.         end
  933.     end
  934.    
  935.     local remaining = registry.NUMBER_OF_BUILDZONES - #result
  936.     --print("doing this remaining thing")
  937.     for i=1, remaining do
  938.         local x,y,z,locid = findNextLoc(result,true)
  939.         if x and y and z and locid then    
  940.             debugT("forced new buildzone #"..locid.." at:"..x..", "..y..", "..z)
  941.             table.insert(result,newBuildZone(x,y,z,elements,locid))
  942.         else
  943.             debugT("failed to force init a new buildzone")
  944.         end
  945.     end
  946.    
  947.    
  948.     return result
  949. end
  950.  
  951.  
  952.  
  953. --- Buildzone constructor. Enforces some data structure
  954. -- Buildzones record information about the structures which are built
  955. -- inside them, as well as which elements of the catalogue are
  956. -- available to be built in them. Buildzones record where they are in
  957. -- three ways (locid, selector and coords). Buildzones do not know
  958. -- who is playing in them right now, or how long is left in a game
  959. -- @param x Where you first want to place the buildzone
  960. -- @param y Where you first want to place the buildzone
  961. -- @param z Where you first want to place the buildzone
  962. -- @param elementZones An array of catalogue items that can be built here
  963. -- @param locid The buildzones starting location in the buildLocs() array
  964. function newBuildZone(x,y,z,elementZones,locid)
  965.     local nbz = {}
  966.     nbz.x ,nbz.y ,nbz.z ,nbz.w = x,y,z,registry.BUILDZONE_WIDTH
  967.     nbz.selector = "x="..(nbz.x-2)..",y="..(nbz.y-3)..",z="..(nbz.z-2)..",dx="..(nbz.w+4)..",dy=256,dz="..(nbz.w+4)
  968.     nbz.structures = {} --a list of all vocabularies names which have been contructed
  969.     nbz.buildings = {} --a list of all vocabularies with full data (x,y,z,id,name) which have been contructed
  970.     nbz.filledSlots = 0 --to count how many slots have been filled with buildings. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
  971.     nbz.greenSlots = 0 --to count how many of the slots are green. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
  972.     --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
  973.     nbz.waitingForCheck = {}
  974.     nbz.highest = 0
  975.     nbz.elements = elementZones
  976.     nbz.locid = locid
  977.     return nbz
  978. end
  979.  
  980. --- Kew constructor. Enforces some data structure
  981. -- Kews are used for timekeeping and to record which players are
  982. -- interacting where. Each queue can only have 1 buildzone, but may have
  983. -- many players. Buildzones may move location, but Kews do not.
  984. -- @param buildzone The buildzone object to associate with this Kew
  985. -- @param maxplayers How many players are allowed to play in the buildzone
  986. -- @return The constructed Kew Object
  987. function newQueue(buildzone,maxplayers,portal)
  988.     debugT("creating a new game queue for buildzone #"..buildzone.locid)
  989.     local q = {}
  990.     q.timer = 1
  991.     q.phase = registry.QUEUE_PHASE.DORMANT
  992.    
  993.     q.victory = false
  994.     q.phases = {
  995.         {
  996.             name = "Selecting Players",
  997.             length = registry.PHASE_LENGTH_WAIT
  998.             --displaylength = 15 --this field is not used
  999.         },
  1000.         {
  1001.             name = "Game In Progress",
  1002.             length = registry.PHASE_LENGTH_GAME
  1003.             --displaylength = 70 --this field is not used
  1004.         },
  1005.         {
  1006.             name = "Round Complete",
  1007.             length = registry.PHASE_LENGTH_OVER
  1008.             --displaylength = 5 --this field is not used
  1009.         }
  1010.     }
  1011.     q.playerlist = {}
  1012.     q.maxplayers = maxplayers
  1013.     q.portal = portal
  1014.     q.buildzone = buildzone
  1015.     local timestamp = math.floor(os.clock())
  1016.     q.filename = timestamp.."at"..q.buildzone.x.."_"..q.buildzone.z
  1017.     return q
  1018. end
  1019.  
  1020. --- Checks if there is a change of the parameters that define the game area geometry since the last run
  1021. -- Currently if there is a change it returns the redo_everything result
  1022. -- TODO if game has been run and there is change affecting the catalogue area add 8 to result for partial rebuild only the catalogue areas
  1023. -- TODO if game has been run and there is change affecting the play area add 4 to result for partial rebuild only the play areas
  1024. -- TODO if game has been run and there is change affecting the spawn area add 2 to result for partial rebuild only the spawn areas
  1025. function checkForGameAreaParametersChanges()
  1026.     --local redo_nothing = 0
  1027.     --local redo_spawn_area = 2
  1028.     --local redo_play_area = 4
  1029.     --local redo_catalogue = 8
  1030.     --local redo_everything = redo_spawn_area + redo_play_area + redo_catalogue
  1031.     --
  1032.     --local result = redo_nothing
  1033.     local result = {}
  1034.     result.redo_everything = false
  1035.     result.redo_spawn_area = false
  1036.     result.redo_play_area = false
  1037.     result.redo_catalogue = false          
  1038.     --
  1039.     -- assemble a table of the current settings that affect the world design
  1040.     local settings = {}
  1041.     settings.grid_cell_size         = registry.GRIDCELL_SIZE
  1042.     settings.grid_cell_count        = registry.GRIDCELL_COUNT
  1043.     settings.catalogue_slot_count   = registry.CATALOGUE_SLOTCOUNT
  1044.     settings.play_area_offset       = registry.PLAY_AREA_OFFSET
  1045.     settings.trenches               = registry.TRENCHES
  1046.     settings.game_field             = registry.GAME_FIELD
  1047.     settings.buildzone_offset       = registry.BUILDZONE_OFFSET
  1048.     settings.catalogue_slot_size    = registry.CATALOGUE_SLOTSIZE
  1049.     settings.catalogue_slot_offset  = registry.CATALOGUE_SLOT_OFFSET
  1050.    
  1051.    
  1052.    
  1053.    
  1054.     local filename = "last_settings.json"
  1055.     local filename_with_path = registry.RECORDS_FOLDER.."/"..filename
  1056.    
  1057.     if utils.file_exists(filename_with_path) then
  1058.         debugT("game has been run before - will compare last with current settings")
  1059.         -- read a table of the settigns used last time from the file
  1060.         local last_settings = json.decodeFromFile(filename_with_path)
  1061.         result.last_settings = last_settings -- return the last settigns as well so that catalogue slots can adapt
  1062.         --compare the two tables
  1063.         if settings.game_field.countX ~= last_settings.game_field.countX
  1064.             or settings.game_field.countZ ~= last_settings.game_field.countZ
  1065.             then
  1066.                 --delete the buildzones.json file
  1067.                 debugT("deleting buildzone list file as settings changed")
  1068.                 fs.delete(registry.BUILDZONES_LIST_FILE)
  1069.                 result.redo_play_area = true
  1070.             end
  1071.        
  1072.         if settings.grid_cell_size ~= last_settings.grid_cell_size then result.redo_everything = true end
  1073.        
  1074.         if settings.grid_cell_count ~= last_settings.grid_cell_count then result.redo_play_area = true end
  1075.        
  1076.         if settings.catalogue_slot_count.x ~= last_settings.catalogue_slot_count.x or
  1077.             settings.catalogue_slot_count.z ~= last_settings.catalogue_slot_count.z
  1078.             then result.redo_catalogue = true end
  1079.            
  1080.         if settings.play_area_offset.x ~= last_settings.play_area_offset.x or
  1081.             settings.play_area_offset.z ~= last_settings.play_area_offset.z
  1082.             then
  1083.                 result.redo_play_area = true
  1084.                 result.redo_catalogue = true
  1085.             end
  1086.        
  1087.         if settings.trenches.WIDTH ~= last_settings.trenches.WIDTH or
  1088.             settings.trenches.DEPTH ~= last_settings.trenches.DEPTH
  1089.             then result.redo_everything = true  end
  1090.        
  1091.         if settings.buildzone_offset ~= last_settings.buildzone_offset then result.redo_play_area = true end
  1092.        
  1093.         if settings.catalogue_slot_size.x ~= last_settings.catalogue_slot_size.x or
  1094.             settings.catalogue_slot_size.z ~= last_settings.catalogue_slot_size.z
  1095.             then result.redo_catalogue = true end
  1096.            
  1097.         if settings.catalogue_slot_offset ~= last_settings.catalogue_slot_offset then
  1098.             result.redo_play_area = true
  1099.             result.redo_catalogue = true
  1100.         end
  1101.     else       
  1102.         debugT("game has not been run before - will generate world")
  1103.         -- delete any buildzones list file that might be left there
  1104.         debugT("deleting buildzone list file as settings changed")
  1105.         fs.delete(registry.BUILDZONES_LIST_FILE)
  1106.         --end return 2+4+8 for full regeneration
  1107.         result.redo_everything = true
  1108.     end
  1109.     --last used settings file doesn't exist
  1110.     --create it
  1111.     debugT("saving last settings file")
  1112.     fs.makeDir(registry.RECORDS_FOLDER)
  1113.     local file = fs.open(filename_with_path,"w")
  1114.     file.write(json.encodePretty(settings))
  1115.     file.close()
  1116.     --
  1117.     return result
  1118. end
  1119.  
  1120. --- Creates a game object and initializes game management functions
  1121. -- This function is a bit large, and should be placed in its own module
  1122. -- at some point.
  1123. -- The game object creates and stores the complete Catalogue
  1124. -- The game object creates and stores a complete list of all Buildzones
  1125. -- The game object creates and stores a complete list of all Kews
  1126. -- The game object only tracks players who are NOT in a Kew
  1127. -- The game object knows where the spawn is
  1128. -- This function rebuilds the Catalogue and Buildzones in the gameworld
  1129. -- if any settings have changed.
  1130. -- This function adds scoreboards to your Minecraft world so that 20kb
  1131. -- operates correctly.
  1132. -- This function runs GameRule commands to set up your Minecraft world.
  1133. -- If DEBUG_MODE is on, then Kews are fixed to Play Phase with a large
  1134. -- time limit
  1135. -- This function kills all Villagers; it is the only way to be sure.
  1136. -- @return game The Game container object.
  1137. function setup()
  1138.     debugT("Starting Setup function.")
  1139.    
  1140.     local registryOK = registry.checkRegistryIntegrity()
  1141.     if not registryOK then
  1142.     --if not registry.FINE then
  1143.         debugT("setup failed")
  1144.         return false
  1145.     end
  1146.     --print ("actual SPAWNZONE_OFFSET is:", registry.SPAWNZONE_OFFSET)
  1147.    
  1148.     debugT("Starting items are: "..json.encode(registry.STARTING_ITEMS))
  1149.    
  1150.     local game = {}
  1151.     --game.elements = {} --moved to a local variable to avoid recursive containment in the "game" table
  1152.     --game.builds = {} --moved to a local variable to avoid recursive containment in the "game" table
  1153.     game.queues = {}
  1154.     --game.waitlist = {}
  1155.     --game.spawn = registry.SPAWN
  1156.     game.lastClock = os.clock()
  1157.     game.nowTime = os.clock()
  1158.    
  1159.     ---SETTINGS = registry.loadCustomSettings()
  1160.    
  1161.     debugT("Game object created")
  1162.    
  1163.     --SET UP THE GAME AREA
  1164.     debugT("setting up game area...")
  1165.     --do a file check to see if setting up the game area is needed
  1166.     debugT("checking for changed settings...")
  1167.     local rebuild = checkForGameAreaParametersChanges()
  1168.     debugT("need to recreate: "..json.encode(rebuild))
  1169.    
  1170.     --set up chunk loaders
  1171.     --commands.setblock(-71, 56, -511, "neotech:chunkLoader", 0, "replace", '{id:"neotech:chunkLoader", Diameter:1}')
  1172.     --get the chunk of the computer
  1173.  
  1174.     --the total size of game area
  1175.     --spawn zones
  1176.     --main spawn zone
  1177.     --check if spawn area needs rebuilding
  1178.     --if BitAND(rebuild,2)==2 then
  1179.     if rebuild.redo_everything or rebuild.redo_spawn_area then 
  1180.         debugT("building spawn areas...")
  1181.         --debugT("fillSmart from inside setup")
  1182.         --rebuild spawn area
  1183.         fillSmartOffsetXZ(
  1184.             registry.MAIN_SPAWN_AREA.x,
  1185.             registry.MAIN_SPAWN_AREA.y,
  1186.             registry.MAIN_SPAWN_AREA.z,
  1187.             registry.MAIN_SPAWN_AREA.w,
  1188.             -registry.TRENCHES.DEPTH,
  1189.             registry.MAIN_SPAWN_AREA.l,
  1190.             registry.TRENCHES.WIDTH,
  1191.             true,
  1192.             registry.BLOCKS.AIR
  1193.         )
  1194.         fillSmart(
  1195.             registry.MAIN_SPAWN_AREA.x,
  1196.             registry.MAIN_SPAWN_AREA.y,
  1197.             registry.MAIN_SPAWN_AREA.z,
  1198.             registry.MAIN_SPAWN_AREA.w,
  1199.             -registry.MAIN_SPAWN_AREA.y,
  1200.             registry.MAIN_SPAWN_AREA.l,
  1201.             registry.BLOCKS.DARK_GRID
  1202.         )
  1203.         --fill the grid
  1204.         fillGrid(
  1205.             registry.MAIN_SPAWN_AREA.x,
  1206.             registry.MAIN_SPAWN_AREA.y,
  1207.             registry.MAIN_SPAWN_AREA.z,
  1208.             registry.SPAWNZONE_SIZE,
  1209.             registry.MAIN_SPAWN_AREA.l,
  1210.             registry.BLOCKS.WHITE_GRID
  1211.         )
  1212.        
  1213.         --fill the glass border
  1214.         fillSmartRing(
  1215.             registry.MAIN_SPAWN_AREA.x,
  1216.             registry.MAIN_SPAWN_AREA.y+1,
  1217.             registry.MAIN_SPAWN_AREA.z,
  1218.             registry.MAIN_SPAWN_AREA.w,
  1219.             registry.MAIN_SPAWN_AREA.h,
  1220.             registry.MAIN_SPAWN_AREA.l,        
  1221.             registry.BLOCKS.SPAWNZONE_FENCE
  1222.         )  
  1223.                        
  1224.         local padx = registry.computer.x + math.floor(registry.SPAWNZONE_SIZE/2) + registry.PORTAL.OFFSET
  1225.         local pady = registry.computer.y - 1
  1226.         local padz = registry.computer.z - math.floor(registry.GAME_FIELD_MAX.countZ/2) * registry.PORTAL.OFFSET - math.floor((registry.GAME_FIELD_MAX.countZ/2) * registry.PORTAL.SIZE)
  1227.         for ix = 0, registry.GAME_FIELD_MAX.countZ - 1 do
  1228.             for iz=0, registry.GAME_FIELD_MAX.countZ - 1 do
  1229.                 local xpos = padx + ix * (registry.PORTAL.OFFSET + registry.PORTAL.SIZE)
  1230.                 local ypos = pady
  1231.                 local zpos = padz + iz * (registry.PORTAL.OFFSET + registry.PORTAL.SIZE)               
  1232.                 --print("making pads", ix, iz, xpos, ypos, zpos)
  1233.                 if registry.GAME_FIELD.countZ > iz and registry.GAME_FIELD.countX > ix then
  1234.                     --create the tp pads openings
  1235.                     --fillSmart( registry.BLOCKS.AIR.block, xpos, ypos, zpos, registry.PORTAL.SIZE, 1, registry.PORTAL.SIZE )
  1236.                     --create the tp pads
  1237.                     --fillSmart( registry.BLOCKS.DETECT.block, xpos, ypos-1, zpos, registry.PORTAL.SIZE, 1, registry.PORTAL.SIZE )     
  1238.                     --place the tp pad markers
  1239.                     --fillSmart( registry.BLOCKS.DETECT.block, xpos+math.floor(registry.PORTAL.SIZE/2), ypos, zpos+math.floor(registry.PORTAL.SIZE/2), 1, 1, 1 )
  1240.                 else
  1241.                     --mark the builzone pad as inactive
  1242.                     --debugT("fillSmart from mark buildzone inactive")
  1243.                     fillSmart( xpos, ypos, zpos, registry.PORTAL.SIZE, 1, registry.PORTAL.SIZE,registry.BLOCKS.WHITE_GRID )
  1244.                 end
  1245.             end
  1246.         end
  1247.     end
  1248.    
  1249.    
  1250.     --this section below is the actual creation of the catalogue slots in the world
  1251.     --check if catalogue area needs rebuilding
  1252.     --if BitAND(rebuild,8)==8 then 
  1253.     if rebuild.redo_everything or rebuild.redo_catalogue then  
  1254.         debugT("building catalogue slots...")
  1255.         --debugT("fillSmart from inside build catalogue slots")
  1256.         local x,y,z = registry.FIRST_ELEMENT.x, registry.FIRST_ELEMENT.y, registry.FIRST_ELEMENT.z
  1257.         fillSmartOffsetXZ(
  1258.             registry.CATALOG_AREA.x ,
  1259.             registry.CATALOG_AREA.y,
  1260.             registry.CATALOG_AREA.z,
  1261.             registry.CATALOG_AREA.dx,
  1262.             -registry.TRENCHES.DEPTH,
  1263.             registry.CATALOG_AREA.dz,
  1264.             registry.TRENCHES.WIDTH,
  1265.             true,
  1266.             registry.BLOCKS.AIR
  1267.         )
  1268.         --[[
  1269.         print("catalog area:",registry.CATALOG_AREA.x ,
  1270.             registry.CATALOG_AREA.y,
  1271.             registry.CATALOG_AREA.z,
  1272.             registry.CATALOG_AREA.dx,
  1273.             registry.CATALOG_AREA.dz)
  1274.         --]]
  1275.         fillSmart(
  1276.             registry.CATALOG_AREA.x ,
  1277.             registry.CATALOG_AREA.y,
  1278.             registry.CATALOG_AREA.z,
  1279.             registry.CATALOG_AREA.dx,
  1280.             -registry.CATALOG_AREA.y,
  1281.             registry.CATALOG_AREA.dz,
  1282.             registry.BLOCKS.DARK_GRID
  1283.         )
  1284.         fillGrid(
  1285.             registry.CATALOG_AREA.x ,
  1286.             registry.CATALOG_AREA.y,
  1287.             registry.CATALOG_AREA.z,
  1288.             registry.CATALOG_AREA.dx,
  1289.             registry.CATALOG_AREA.dz,
  1290.             registry.BLOCKS.WHITE_GRID
  1291.         )
  1292.         --print("element size",registry.ELEMENT.sizeX )
  1293.         for i=0,registry.CATALOGUE_SLOTCOUNT.z - 1 do
  1294.             for k=0,registry.CATALOGUE_SLOTCOUNT.x - 1 do
  1295.                 --local xpos = x - k*( 2*registry.ELEMENT.sizeX + registry.GRIDCELL_SIZE + 2 )
  1296.                 local xpos = x - k * ( registry.GRIDCELL_SIZE * ( 2*registry.CATALOGUE_SLOTSIZE.x + 2 + registry.CATALOGUE_SLOT_OFFSET))
  1297.                
  1298.                 local ypos = y - 1
  1299.                 local zpos = z + i*( registry.GRIDCELL_SIZE * ( registry.CATALOGUE_SLOTSIZE.z + 1 + registry.CATALOGUE_SLOT_OFFSET))
  1300.                
  1301.                 --fill white grid ring slot
  1302.                 --debugT("fillSmart from inside white grid ring")
  1303.                 fillSmartRing(
  1304.                     xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1-math.floor(registry.GRIDCELL_SIZE/2),
  1305.                     ypos,
  1306.                     zpos-1-math.floor(registry.GRIDCELL_SIZE/2),
  1307.                     2*(registry.CATALOGUE_SLOTSIZE.x+1)*registry.GRIDCELL_SIZE + 1,
  1308.                     1,
  1309.                     (registry.CATALOGUE_SLOTSIZE.z + 1)*registry.GRIDCELL_SIZE + 1,
  1310.                     registry.BLOCKS.WHITE_GRID
  1311.                 )
  1312.                 fillSmartRing(
  1313.                     xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1-math.floor(registry.GRIDCELL_SIZE/2),
  1314.                     ypos,
  1315.                     zpos-1-math.floor(registry.GRIDCELL_SIZE/2),
  1316.                     (registry.CATALOGUE_SLOTSIZE.x + 1)*registry.GRIDCELL_SIZE + 1,
  1317.                     1,
  1318.                     (registry.CATALOGUE_SLOTSIZE.z + 1)*registry.GRIDCELL_SIZE + 1,
  1319.                     registry.BLOCKS.WHITE_GRID
  1320.                 )
  1321.                 --fill white grid ring element
  1322.                 fillSmartRing(
  1323.                     xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1,
  1324.                     ypos,
  1325.                     zpos-1,
  1326.                     registry.ELEMENT.sizeX+2,
  1327.                     1,
  1328.                     registry.ELEMENT.sizeZ+2,
  1329.                     registry.BLOCKS.WHITE_GRID
  1330.                 )
  1331.                 --fill white grid key
  1332.                 fillSmart(xpos, ypos, zpos, registry.ELEMENT.sizeX, 1, registry.ELEMENT.sizeZ,registry.BLOCKS.WHITE_GRID)
  1333.                 --fill dark grid slot
  1334.                 fillGrid(
  1335.                     xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1-math.floor(registry.GRIDCELL_SIZE/2),
  1336.                     ypos,
  1337.                     zpos-1-math.floor(registry.GRIDCELL_SIZE/2),
  1338.                     2*(registry.CATALOGUE_SLOTSIZE.x+1)*registry.GRIDCELL_SIZE + 1,
  1339.                     (registry.CATALOGUE_SLOTSIZE.x + 1)*registry.GRIDCELL_SIZE + 1,
  1340.                     registry.BLOCKS.DARK_GRID
  1341.                 )
  1342.                 --fill plug grid key
  1343.                 fillGrid(xpos, ypos, zpos, registry.ELEMENT.sizeX, registry.ELEMENT.sizeZ,registry.BLOCKS.PLUG)
  1344.                 --fill plug grid element
  1345.                 fillGrid(
  1346.                     xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-1,
  1347.                     ypos,
  1348.                     zpos-1,
  1349.                     registry.ELEMENT.sizeX+2,
  1350.                     registry.ELEMENT.sizeZ+2,
  1351.                     registry.BLOCKS.PLUG
  1352.                 )
  1353.                 --fillSmart(registry.BLOCKS.VOCAB_REPLACE.block, xpos, ypos, zpos, registry.ELEMENT.sizeX, 1, registry.ELEMENT.sizeZ)
  1354.                 --fillSmart(registry.BLOCKS.VOCAB_DETECT.block, xpos - registry.ELEMENT.sizeX - 1, ypos, zpos, registry.ELEMENT.sizeX, 1, registry.ELEMENT.sizeZ)
  1355.                
  1356.                 -- move elements and their keys to the new slot locaitons          
  1357.                 if rebuild.last_settings then
  1358.                     local old_element = {
  1359.                         sizeX = rebuild.last_settings.catalogue_slot_size.x * rebuild.last_settings.grid_cell_size,
  1360.                         sizeY = registry.VOCAB_HEIGHT,
  1361.                         sizeZ = rebuild.last_settings.catalogue_slot_size.z * rebuild.last_settings.grid_cell_size
  1362.                     }
  1363.                     local old_first_element = {
  1364.                         x = registry.computer.x - rebuild.last_settings.play_area_offset.x * rebuild.last_settings.grid_cell_size -
  1365.                             old_element.sizeX - math.floor(rebuild.last_settings.grid_cell_size/2),
  1366.                         y = registry.computer.y,
  1367.                         z = utils.closestGridCoord(registry.computer.z, rebuild.last_settings.grid_cell_size, registry.computer.z +
  1368.                             registry.SPAWNZONE_SIZE/2) + rebuild.last_settings.play_area_offset.z * rebuild.last_settings.grid_cell_size +
  1369.                             math.floor(rebuild.last_settings.grid_cell_size/2) + 1
  1370.                     }
  1371.                     local old_key_xpos = old_first_element.x - k * ( rebuild.last_settings.grid_cell_size *
  1372.                         ( 2*rebuild.last_settings.catalogue_slot_size.x + 2 + rebuild.last_settings.catalogue_slot_offset))
  1373.                
  1374.                     local old_key_ypos = old_first_element.y
  1375.                
  1376.                     local old_key_zpos = old_first_element.z + i*( rebuild.last_settings.grid_cell_size *
  1377.                         ( rebuild.last_settings.catalogue_slot_size.z + 1 + rebuild.last_settings.catalogue_slot_offset))
  1378.                    
  1379.                     local old_element_xpos = old_key_xpos - rebuild.last_settings.grid_cell_size * ( rebuild.last_settings.catalogue_slot_size.x + 1 )
  1380.                     local old_element_ypos = old_key_ypos
  1381.                     local old_element_zpos = old_key_zpos
  1382.                    
  1383.                    
  1384.                     -- moves the key
  1385.                     debugT(
  1386.                         "Moving the key blocks from: "..(old_key_xpos)..", "..old_key_ypos..", "..(old_key_zpos)..
  1387.                         " with size: "..old_element.sizeX..", "..old_element.sizeY..", "..old_element.sizeZ..
  1388.                         " to: "..(xpos-(old_element.sizeX-registry.ELEMENT.sizeX)/2)..", "..(ypos+1)..", "..(zpos-(old_element.sizeZ-registry.ELEMENT.sizeZ)/2)
  1389.                     )
  1390.                     cloneSmart(
  1391.                         old_key_xpos, old_key_ypos, old_key_zpos,
  1392.                         old_element.sizeX, old_element.sizeY, old_element.sizeZ,
  1393.                         xpos-(old_element.sizeX-registry.ELEMENT.sizeX)/2, ypos+1, zpos-(old_element.sizeZ-registry.ELEMENT.sizeZ)/2,
  1394.                         registry.CLONE_MASK_MODE.REPLACE, registry.CLONE_MODE.MOVE
  1395.                     )
  1396.                     --moves the element
  1397.                     debugT(
  1398.                         "Moving the element blocks from: "..(old_element_xpos)..", "..old_element_ypos..", "..(old_element_zpos)..
  1399.                         " with size: "..old_element.sizeX..", "..old_element.sizeY..", "..old_element.sizeZ..
  1400.                         " to: "..(xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-(old_element.sizeX-registry.ELEMENT.sizeX)/2)..", "..(ypos+1)..", "..(zpos-(old_element.sizeZ-registry.ELEMENT.sizeZ)/2)
  1401.                     )
  1402.                     cloneSmart(
  1403.                         old_element_xpos, old_element_ypos, old_element_zpos,
  1404.                         old_element.sizeX, old_element.sizeY, old_element.sizeZ,
  1405.                         xpos-registry.GRIDCELL_SIZE*(registry.CATALOGUE_SLOTSIZE.x+1)-(old_element.sizeX-registry.ELEMENT.sizeX)/2, ypos+1, zpos-(old_element.sizeZ-registry.ELEMENT.sizeZ)/2,
  1406.                         registry.CLONE_MASK_MODE.REPLACE, registry.CLONE_MODE.MOVE
  1407.                     )
  1408.                     -- TODO for the support of 4-way roation later here we might need a clone command for the underground blocks
  1409.                     os.sleep(1) -- wait for the server to catch up
  1410.                 end
  1411.             end
  1412.         end
  1413.         --fillSmart(registry.BLOCKS.RING.block, registry.FIRST_ELEMENT.x, registry.FIRST_ELEMENT.y-1, registry.FIRST_ELEMENT.z, 1, 1, 1)
  1414.         ---
  1415.        
  1416.     end
  1417.    
  1418.     --if BitAND(rebuild,4)==4 then 
  1419.     if rebuild.redo_everything or rebuild.redo_play_area then  
  1420.         debugT("building play area...")
  1421.         --debugT("fillSmart from inside build play area")
  1422.         fillSmartOffsetXZ(
  1423.             registry.PLAY_AREAS.x ,
  1424.             registry.PLAY_AREAS.y,
  1425.             registry.PLAY_AREAS.z,
  1426.             registry.PLAY_AREAS.dx,
  1427.             -registry.TRENCHES.DEPTH,
  1428.             registry.PLAY_AREAS.dz,
  1429.             registry.TRENCHES.WIDTH,
  1430.             true,
  1431.             registry.BLOCKS.AIR
  1432.         )
  1433.         fillSmart(
  1434.             registry.PLAY_AREAS.x ,
  1435.             registry.PLAY_AREAS.y,
  1436.             registry.PLAY_AREAS.z,
  1437.             registry.PLAY_AREAS.dx,
  1438.             -registry.PLAY_AREAS.y,
  1439.             registry.PLAY_AREAS.dz,
  1440.             registry.BLOCKS.DARK_GRID
  1441.         )
  1442.         local x,y,z = registry.FIRST_ZONE.x, registry.FIRST_ZONE.y, registry.FIRST_ZONE.z
  1443.         for i=0,registry.GAME_FIELD.countZ - 1 do
  1444.             for k=0,registry.GAME_FIELD.countX - 1 do
  1445.                 local xpos = x + k*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE)
  1446.                 local ypos = y
  1447.                 local zpos = z + i*( registry.BUILDZONE_WIDTH + registry.BUILDZONE_OFFSET*registry.GRIDCELL_SIZE)
  1448.                 fillSmartRing(xpos,ypos,zpos,registry.BUILDZONE_WIDTH,1,registry.BUILDZONE_WIDTH,registry.BLOCKS.WHITE_GRID)
  1449.             end
  1450.         end
  1451.         fillGrid(
  1452.             registry.PLAY_AREAS.x ,
  1453.             registry.PLAY_AREAS.y,
  1454.             registry.PLAY_AREAS.z,
  1455.             registry.PLAY_AREAS.dx,
  1456.             registry.PLAY_AREAS.dz,
  1457.             registry.BLOCKS.WHITE_GRID
  1458.         )
  1459.     end
  1460.    
  1461.     --vocabzone creation
  1462.     debugT("initializing catalogue elements...")
  1463.     --the following is a set of abstract objects, not the actual creating of the catalgoue slots in the world
  1464.     --it should run always
  1465.     --game.elements = initCatalogueElements(
  1466.     catalogue_elements = initCatalogueElements(
  1467.         registry.CATALOGUE_SLOTCOUNT.x,
  1468.         registry.CATALOGUE_SLOTCOUNT.z,
  1469.         registry.ELEMENT.sizeX,
  1470.         registry.ELEMENT.sizeZ
  1471.     )
  1472.    
  1473.     debugT("Setting up catalogue elements")
  1474.     commands.exec("kill @e[type=ArmorStand]")
  1475.     --for i,vz in ipairs(game.elements) do
  1476.     for i,vz in ipairs(catalogue_elements) do  
  1477.         local detector, message1 = commands.testforblock(vz.keyCenterX,vz.keyCenterY,vz.keyCenterZ,registry.BLOCKS.DETECT.block) -- the variant is omited to allow variations of the detect block to be used as alternative detectors
  1478.         local blocker, message2 = commands.testforblock(vz.keyCenterX,vz.keyCenterY,vz.keyCenterZ,registry.BLOCKS.DETECT_DEAD.block,registry.BLOCKS.DETECT_DEAD.variant)
  1479.         --print("element",i,message1, message2)
  1480.         if not (detector or blocker) then
  1481.             commands.setblock(vz.keyCenterX,vz.keyCenterY,vz.keyCenterZ,registry.BLOCKS.DETECT_DEAD.block,registry.BLOCKS.DETECT_DEAD.variant)
  1482.         end
  1483.         --label the slot in the world with its number
  1484.         --slot_number
  1485.         commands.summon("ArmorStand",(vz.keyCenterX+vz.elementCenterX)/2,vz.keyCenterY,vz.keyCenterZ,'{CustomName:"slot_#'..i..'",Invisible:1b,CustomNameVisible:1b}')
  1486.         --slot_number = slot_number + 1
  1487.         --commands.setblock(vz.elementCenterX,vz.elementCenterY,vz.elementCenterZ,registry.BLOCKS.DARK_GRID.block)
  1488.         --commands.setblock(vz.keyX,vz.keyY,vz.keyZ,registry.BLOCKS.DARK_GRID.block)
  1489.         --commands.setblock(vz.elementX,vz.elementY,vz.elementZ,registry.BLOCKS.WHITE_GRID.block)              
  1490.     end
  1491.    
  1492.     --[[
  1493.    
  1494.     if true then
  1495.         return
  1496.     end
  1497.    
  1498.     ]]--
  1499.        
  1500.     --generate catalogue rewards
  1501.     --[[
  1502.     for i=1,#registry.VOCABS_DATA do
  1503.         if registry.VOCABS_DATA[i].rewardUrban then
  1504.             registry.REWARDS[i] = registry.houseBlock(registry.VOCABS_DATA[i].rewardCount)
  1505.         else
  1506.             registry.REWARDS[i] = registry.gardenBlock(registry.VOCABS_DATA[i].rewardCount)
  1507.         end
  1508.     end
  1509.     --]]
  1510.    
  1511.     debugT("Catalogue definitions successfully initialized!")
  1512.    
  1513.     --kill all villagers
  1514.     commands.exec("kill @e[type=Villager]")
  1515.     debugT("Villagers destroyed")
  1516.    
  1517.     --buildzone creation
  1518.     debugT("Making building zone objects.")
  1519.     --game.builds appears to store the games currently in progress
  1520.     --game.builds = initBuildzones(registry.NUMBER_OF_BUILDZONES,game.elements,registry.BUILDZONE_WIDTH)--,registry.BUILDZONE_FLOOR_HEIGHT)
  1521.     buildzones = initBuildzones(registry.NUMBER_OF_BUILDZONES,catalogue_elements,registry.BUILDZONE_WIDTH)--,registry.BUILDZONE_FLOOR_HEIGHT)
  1522.     --for i,build in ipairs(game.builds) do
  1523.     for i,build in ipairs(buildzones) do
  1524.         table.insert(game.queues,newQueue(build, registry.MAX_PLAYERS_PER_GAME, registry.PORTALS_LOCATIONS[i]))
  1525.    
  1526.     end
  1527.     debugT("starting the building of portals...")
  1528.     for i, kew in ipairs(game.queues) do
  1529.         debugT("building of portal:",i)
  1530.         drawPortal( kew.portal, kew.phase)
  1531.     end
  1532.     debugT("building of portals DONE!")
  1533.  
  1534.     ----
  1535.     debugT("Adding scoreboards.")
  1536.         --print(#registry.VOCABS_DATA)
  1537.     for i=1,#registry.VOCABS_DATA do
  1538.         commands.scoreboard("objectives","add","building_"..i,"dummy")
  1539.     end
  1540.     commands.scoreboard("objectives","add","highscores","dummy","Best Neighbourhoods")
  1541.     if registry.SHOW_HIGHSCORES then
  1542.         commands.scoreboard("objectives","setdisplay","sidebar","highscores")
  1543.     end
  1544.     commands.scoreboard("objectives","add","VillagerLife","dummy")
  1545.     commands.scoreboard("objectives","add","built","dummy", "Structures Built")
  1546.     commands.scoreboard("objectives","add","highest","dummy", "Personal Highest")
  1547.     commands.scoreboard("objectives","add","played","dummy","Games Played")
  1548.     commands.scoreboard("objectives","setdisplay","list","played")
  1549.    
  1550.     commands.title("@a","times",0,30,30) -- what does this do?
  1551.    
  1552.     ----
  1553.     debugT("setting the needed preferences of the minecraft world.")
  1554.     commands.gamerule("doDaylightCycle",false) --
  1555.     commands.gamerule("keepInventory",true)
  1556.     commands.gamerule("doTileDrops",true) --
  1557.     commands.gamerule("sendCommandFeedback", true)
  1558.     commands.gamerule("logAdminCommands",true) -- it looks like this needs to be on for the tp funtion used in getAllPos to return its message properly
  1559.     commands.gamerule("commandBlockOutput",false) --
  1560.     commands.time("set",6000) --
  1561.    
  1562.     ---
  1563.     math.randomseed( os.time() )
  1564.     debugT("Computer clock is: "..os.clock())
  1565.     debugT("20.000 BLOCKS is ready to run!")
  1566.    
  1567.     return game
  1568. end
  1569.  
  1570. function swapBlocks()
  1571.     for k, v in ipairs(registry.BLOCKS_TO_SWAP) do
  1572.         local result, message = commands.scoreboard("players","set","@e[type=Item]","bad_"..v.name,1,"{Item:{id:minecraft:"..v.block..",Damage:"..v.variant.."s}}")
  1573.         --debugT("swap block found success:"..tostring(result).." "..json.encode(message))
  1574.         result, message = commands.scoreboard("players","set","@e[type=Item]","bad_"..v.name,0,"{Item:{id:minecraft:"..v.block..",Damage:"..v.variant.."s,tag:{display:{Name:"..v.name.."}}}}")
  1575.         --debugT("swap block cleaned success:"..tostring(result).." "..json.encode(message))
  1576.         result, message = commands.entitydata("@e[type=Item,score_bad_"..v.name.."=1,score_bad_"..v.name.."_min=1]", v.minecraft_tag) -- registry.houseNBT ) --
  1577.         --debugT(v.minecraft_tag)
  1578.         --debugT("swap block swapped success:"..tostring(result).." "..json.encode(message))
  1579.     end
  1580. end
  1581.  
  1582. --- Runs a single step of the game loop
  1583. -- Runs the game object through each of these update steps in order.
  1584. -- See the comments on each of the steps.
  1585. -- @param game The game object as created in setup()
  1586. function update(game)
  1587.     --debugT("updating game state")
  1588.     local elapsed = updateClock(game)
  1589.     --update players
  1590.     --debugT("update: will checkPlayers")
  1591.     checkPlayers(game)
  1592.     --debugT("update: will doTimerUpdates")
  1593.     doTimerUpdates(game,elapsed)
  1594.     --debugT("update: will doPhaseUpdates")
  1595.     doPhaseUpdates(game)
  1596.     --debugT("update: will doPhaseEnds")
  1597.     doPhaseEnds(game)
  1598.     --debugT("update: will checkBoundaries")
  1599.     checkBoundaries(game)
  1600.     --debugT("update: will checkForHomecomers")
  1601.     checkForHomecomers(game)
  1602.     --debugT("update: will allocateWaiters")
  1603.     allocateWaiters(game)
  1604. end
  1605.  
  1606. --- Calculates elapsed time during a game tick
  1607. -- Updates the given game objects clock using the operating system time
  1608. -- @param game The game object as created in setup()
  1609. -- @return elapsed How much time has elapsed since time was updated
  1610. function updateClock(game)
  1611.     game.nowTime = os.clock()
  1612.     local elapsed = game.nowTime - game.lastClock
  1613.     game.lastClock = game.nowTime
  1614.     return elapsed
  1615. end
  1616.  
  1617. --- Updates all kews in the game object based on elapsed time
  1618. -- Since Kews do the timekeeping, let them know how much time as elapsed.
  1619. -- @param game The game object as created in setup()
  1620. -- @param elapsed Seconds as calculated by updateClock()
  1621. function doTimerUpdates(game,elapsed)
  1622.     for i,kew in ipairs(game.queues) do
  1623.         --print("updating timer for zone: ", i)
  1624.         --print("timer is : ", kew.timer)
  1625.         --print("phase is : ", kew.phase)
  1626.         kew.timer = kew.timer - elapsed
  1627.     end
  1628. end
  1629.  
  1630. --- Deal with players who should be in Buildzones
  1631. -- Checks all Kews (and therefore Buildzones). If the Kew is in Phase 2
  1632. -- (Play Phase), then check on all players. If those players are out
  1633. -- of bounds, move them back to the closest edge of the buildzone.
  1634. -- This also sends them a bi-lingual warning if there were moved.
  1635. -- @param game The game object as created in setup()
  1636. function checkBoundaries(game)
  1637.     --debugT("begin checking boundaries")
  1638.     for i,kew in ipairs(game.queues) do
  1639.         --debugT("checking boundaries for buildzone #"..kew.buildzone.locid)
  1640.         if kew.phase == registry.QUEUE_PHASE.PLAYING then
  1641.             --boundaries
  1642.             --debugT("buildzone #"..kew.buildzone.locid.." is in phase 2")
  1643.             local x_min = kew.buildzone.x-2
  1644.             local x_max = kew.buildzone.x+kew.buildzone.w+4
  1645.             local z_min = kew.buildzone.z-2
  1646.             local z_max = kew.buildzone.z+kew.buildzone.w+4
  1647.  
  1648.             --local toBeCorrected = {}
  1649.  
  1650.             for name,player in pairs(kew.playerlist) do
  1651.                 --debugT("checking boundaries for player "..player.name.." indexed as "..name)
  1652.                 if player.status == registry.PLAYER_STATUS.IN_GAME then
  1653.                     --debugT("player "..name.." is active")
  1654.                     --debugT("calling getAllPos for player "..player.name)
  1655.                     local listOfOne = getAllPos('m=2,name='..player.name)
  1656.                     --debugT("getAllPos for player "..player.name.." completed")
  1657.                     if listOfOne and listOfOne[1] then
  1658.                         --debugT("getAllPos for player "..player.name.." returned a value")
  1659.                         player.x = listOfOne[1].x
  1660.                         player.y = listOfOne[1].y
  1661.                         player.z = listOfOne[1].z
  1662.                         local changed = false
  1663.                         if player.x > x_max then
  1664.                             changed = true
  1665.                             player.x = x_max-4
  1666.                         end
  1667.                         if player.x < x_min then
  1668.                             changed = true
  1669.                             player.x = x_min+4
  1670.                         end
  1671.                         if player.z > z_max then
  1672.                             changed = true
  1673.                             player.z = z_max-4
  1674.                         end
  1675.                         if player.z < z_min then
  1676.                             changed = true
  1677.                             player.z = z_min+4
  1678.                         end
  1679.                         if changed then
  1680.                             teleportToPoint(player.x,kew.buildzone.y+2,player.z,{player},false,
  1681.                             "TELEPORTED BACK TO GAME: Please stay inside the building zone or use HOMECOMER to leave the game!",
  1682.                             "Zurück ins Spiel teleportiert: Bitte bleib innerhalb des Baufeldes oder nutze den HEIMKEHRER um das Spiel zu verlassen!")
  1683.                         end
  1684.                     end
  1685.                 end
  1686.                 --debugT("Completed: checking boundaries for player "..player.name.." indexed as "..name)
  1687.             end
  1688.         end
  1689.     end
  1690.     --debugT("end checking boundaries")
  1691. end
  1692.  
  1693.  
  1694. --- Check if a Buildzone is worth saving
  1695. -- Many plays of a buildzone will be junk. Here you can set the logic
  1696. -- which determines if a buildzone was valuable.
  1697. -- Currently always returns that the zone is valuable.
  1698. -- @param buildzone The buildzone to check.
  1699. -- @return True is the buildzone was junk
  1700. function checkIfBuildzoneIsCrap(buildzone)
  1701.     debugT("Buildzone was ok")
  1702.     return false
  1703. end
  1704.  
  1705.  
  1706. --- Everything that happens when the Play Phase finishes due to time limit.
  1707. -- Removes the ring which denotes a game in progress.
  1708. -- Removes Detector Blocks and then fills the floor in.
  1709. -- Checks if the buildzone was valuable and if so it will clean it.
  1710. -- Sets the zone played state based on value. A played zone will not be
  1711. -- overwritten by future buildzones.
  1712. -- Bilingual messages are sent to players to let them know what happened.
  1713. -- @param kew A kew object that contains a Buildzone
  1714. function cleanAfterGameOver(kew)
  1715.     local buildzone = kew.buildzone
  1716.     debugT("cleanAfterGameOver started for buildzone #".. buildzone.locid)
  1717.     commands.async.setblock(buildzone.x,buildzone.y,buildzone.z,registry.BLOCKS.VICTORY_MARKER.block)
  1718.     fillSmartRing(buildzone.x,buildzone.y,buildzone.z,buildzone.w,1,buildzone.w,registry.BLOCKS.AIR)
  1719.     --for each level remove playing blocks like detectors
  1720.   for h=1,256-buildzone.y do
  1721.         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.variant)
  1722.         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.variant)
  1723.         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.variant)
  1724.         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.variant)
  1725.     end
  1726.   --replaces air on the bottom level with flooring to show the area is completed
  1727.     commands.async.fill(buildzone.x,buildzone.y,buildzone.z,buildzone.x+buildzone.w,buildzone.y,buildzone.z+buildzone.w,registry.BLOCKS.CAMP_FLOOR.block,registry.BLOCKS.CAMP_FLOOR.variant,"replace",registry.BLOCKS.PLUG.block,registry.BLOCKS.PLUG.variant)
  1728.     commands.async.fill(buildzone.x,buildzone.y+1,buildzone.z,buildzone.x+buildzone.w,buildzone.y,buildzone.z+buildzone.w,registry.BLOCKS.PHVFLOOR.block,registry.BLOCKS.PHVFLOOR.variant,"replace","minecraft:air","0")
  1729.    
  1730.     ---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
  1731.    
  1732.     local wasCrap = checkIfBuildzoneIsCrap(buildzone)
  1733.     local gameovermessageEN
  1734.     local gameovermessageDE
  1735.     if wasCrap then
  1736.         --mark this buildzone for replacement
  1737.         --change the flag to played=false
  1738.             debugT("cleanAfterGameOver is crap ".. buildzone.locid)
  1739.         updateZonePlayedState(buildzone,false)
  1740.         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"
  1741.         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"
  1742.        
  1743.     else
  1744.         --change the flag to played=true
  1745.         debugT("cleanAfterGameOver otherwise ".. buildzone.locid)
  1746.         updateZonePlayedState(buildzone,true)
  1747.        
  1748.         gameovermessageEN = "Thank you for playing IBA_GAME! Play another game or look for your game result at: www.20000blocks.com"
  1749.         gameovermessageDE = "Vielen Dank, dass du IBA_GAME gespielt hast! Starte eine neue Runde oder schau dir deine Spielergebnisse an unter: www.20000blocks.com"
  1750.     end
  1751.    
  1752.     for name, player in pairs(kew.playerlist) do
  1753.         if registry.ANNOUNCE_ENGLISH then
  1754.             -- announce success in English
  1755.             commands.async.tellraw(player.name,'["",{"text":"'..gameovermessageEN..'","color":"white"}]')
  1756.         end
  1757.         if registry.ANNOUNCE_GERMAN then
  1758.             -- announce success in German
  1759.             commands.async.tellraw(player.name,'["",{"text":"'..gameovermessageDE..'","color":"gold"}]')
  1760.         end
  1761.     end
  1762.    
  1763. end
  1764.  
  1765. --- Changes a given locid to played.
  1766. -- Strange that the LOCS object is a global and not in the registry.
  1767. -- That is probably bad. This function also saves the given location to
  1768. -- file.
  1769. -- @param buildzone The buildzone that was just finished
  1770. -- @param newstate Boolean Has the location been played successfully?
  1771. function updateZonePlayedState(buildzone, newstate)
  1772.     debugT("updating buildzone's #"..buildzone.locid.." played stated to: "..tostring(newstate))
  1773.     --change the flag to played=newstate
  1774.     LOCS[buildzone.locid].played = newstate
  1775.     --and write the LOCS object to the json file
  1776.     writeGridToFile()
  1777. end
  1778.  
  1779. --- Process timekeeping and update Phases of Kews.
  1780. -- Run every game step. Iterate over all Kews and update their phase
  1781. -- based on the remaining time in kew.timer.
  1782. -- If the kew is on the Play Phase, then do the gameplay logic
  1783. -- stored in updatePlayedZone().
  1784. -- Update player timers (xp bar timer) and give players a large warning
  1785. -- title if the game is almost over.
  1786. -- @param game The game object as created by setup()
  1787. function doPhaseUpdates(game)
  1788.     for i,kew in ipairs(game.queues) do
  1789.        
  1790.         local minutes = string.format("%02d",math.floor(kew.timer/60))
  1791.         local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
  1792.         if kew.timer <= 0 then
  1793.             minutes = "00"
  1794.             seconds = "00"
  1795.         end
  1796.        
  1797.         if kew.phase == registry.QUEUE_PHASE.DORMANT then
  1798.             --waiting phase
  1799.             -- Never start the wait phase until someone joins
  1800.             if countActivePlayers(kew) == 0 then
  1801.                 kew.timer = kew.phases[kew.phase].length
  1802.             else
  1803.                 -- but if we have a player then start now
  1804.                 kew.timer = 0
  1805.             end
  1806.            
  1807.             --displayTitleToPlayers(kew.playerlist,"Game starting!")
  1808.             displayTimeToPlayers(kew.playerlist,minutes,seconds)
  1809.         elseif kew.phase == registry.QUEUE_PHASE.PLAYING then
  1810.             --playing phase
  1811.             --debugT("buildzone #"..)
  1812.             local victory = updatePlayedZone(kew) --currently victory updatePlayedZone returns always false
  1813.             displayTimeToPlayers(kew.playerlist,minutes,seconds)
  1814.             if victory then
  1815.                 kew.timer = -2
  1816.             end
  1817.            
  1818.             -- unless finish if all players quit
  1819.             if countActivePlayers(kew) == 0 then
  1820.                 kew.timer = -1
  1821.             end
  1822.         elseif kew.phase == registry.QUEUE_PHASE.GAMEOVER then
  1823.             --end phase
  1824.             displayTimeToPlayers(kew.playerlist,minutes,seconds)
  1825.         end
  1826.     end
  1827. end
  1828.  
  1829. --- Update the Minecraft Scoreboards based on what players built.
  1830. -- This runs after a buildzone is completed it currently rewards all
  1831. -- participants with more played score.
  1832. -- @param kew A Kew object which has just moved from Phase PLAYING to GAMEOVER.
  1833. function processHighscores(kew)
  1834.     local buildzone = kew.buildzone
  1835.     for name,player in pairs(kew.playerlist) do
  1836.         commands.async.scoreboard("players","add",player.name,"played",1)
  1837.     end
  1838. end
  1839.  
  1840. --- Export a Kews buildzone detail once it is complete
  1841. -- Requires a kew so it can access the playerlist.
  1842. -- @param kew The Kew object which contains players and a buildzone
  1843. -- @param saveOnline Boolean true: save the game also online to the database; false: save only in a file locally
  1844. local function exportKewData(kew, saveOnline)
  1845.     local buildzone = kew.buildzone
  1846.     local saved = {}
  1847.     saved.position =
  1848.         {
  1849.             x=buildzone.x,
  1850.             y=buildzone.y,
  1851.             z=buildzone.z
  1852.         }
  1853.    
  1854.     saved.players = {}
  1855.     for name, player in pairs(kew.playerlist) do
  1856.         table.insert(saved.players,player.name)
  1857.     end
  1858.     --saved.structures = buildzone.structures
  1859.     saved.buildings = buildzone.buildings
  1860.     --saved.totals = tracker.tallyTable(buildzone.buildings)
  1861.     --saved.highest = buildzone.highest
  1862.     saved.stats = {
  1863.         --cityVersion = registry.CITY_VERSION,
  1864.         --height = buildzone.highest,
  1865.         --densityIndex = math.floor(100*buildzone.filledSlots/49), -- the density index is made from built area (filledSlots) over the ground area (7x7 slots = 49)
  1866.         --greenIndex = math.floor(100*buildzone.greenSlots/49), --the green index is made from green area (greenSlots) over the ground area (7x7 slots = 49)
  1867.         --variety = tablelength(buildzone.variety),
  1868.         timeCompleted = math.floor(os.clock()),
  1869.         gameLength = registry.PHASE_LENGTH_GAME
  1870.     }
  1871.    
  1872.    
  1873.     fs.makeDir(registry.RECORDS_FOLDER)
  1874.    
  1875.     local file = fs.open(registry.RECORDS_FOLDER.."/"..kew.filename..".json","w")
  1876.     local filecontent = json.encodePretty(saved)
  1877.     debugT("saving the game at buildzone "..kew.buildzone.locid.." to local file...")
  1878.     file.write(filecontent)
  1879.     file.close()
  1880.     debugT("local file saved: "..registry.RECORDS_FOLDER.."/"..kew.filename..".json")
  1881.     if saveOnline then --for now this is disabled until we figure out how things look in the webGL viewer
  1882.        
  1883.         debugT("saving the game at buildzone "..kew.buildzone.locid.." online...")
  1884.         --writeToDatabase(kew.filename,filecontent,saved.position.x,saved.position.z)
  1885.         --debugT("saved")
  1886.     end
  1887. end
  1888.  
  1889. -- this function writes to the online database that we use to display models in the webGL viewer
  1890. local function writeToDatabase(name,data,x,z)
  1891.    
  1892.     -- the user agent needs to be renamed otherwise the dfeult one is Java and that is blocked by the .htaccess file on the website
  1893.     local headers = {
  1894.         [ "User-Agent" ] = "20.000 BLOCKS"
  1895.     }
  1896.    
  1897.     local link = http.post(
  1898.         "http://www.20000blocks.com/DatabaseAccess/UploadModel.php",
  1899.         "name="..textutils.urlEncode(name).."&"..
  1900.         "content="..textutils.urlEncode(data).."&"..
  1901.         "x="..x.."&"..
  1902.         "z="..z,
  1903.         headers
  1904.     )
  1905.     local linkURL = link.readAll()
  1906.     if linkURL then
  1907.         --message texts
  1908.         local msg_EN = 'The latest game result has been uploaded to the webviewer.\n'
  1909.         local msg_DE = 'Die neueste Runde wurde in den Webviewer geladen.\n'
  1910.         local linkText_EN = 'See it and share it!'
  1911.         local linkText_DE = 'Schau es und teile es!'
  1912.         local hoverText_EN = 'Click here to see and share the last game!'
  1913.         local hoverText_DE = 'Click here to see and share the last game!'
  1914.         --message text with the link
  1915.         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}]'
  1916.        
  1917.         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}]'
  1918.         -- announce success in English
  1919.         commands.async.tellraw("@a",linkmsg_EN)
  1920.         if registry.ANNOUNCE_GERMAN then
  1921.             --announce success in German
  1922.             commands.async.tellraw("@a",linkmsg_DE)
  1923.         end
  1924.     end
  1925. end
  1926.  
  1927. function 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)
  1928.     http.post(
  1929.         "http://www.20000blocks.com/DatabaseAccess/SwitchVersion.php",
  1930.         "id="..textutils.urlEncode(id).."&"..
  1931.         "relative="..textutils.urlEncode(relative)
  1932.     )
  1933. end
  1934.  
  1935. --- Update the blocks in a wait area
  1936. -- Takes three parameters which decide the base, top and middle blocks
  1937. -- of the portal. This is also used to "close" a portal to players
  1938. -- @param portal_location A x,y,z coord object. A kew.portal can be passed
  1939. -- @param queue_phase The phase in which the game queue of the buildzone corresponding to this portal is currently in
  1940. function drawPortal(portal_location,queue_phase) --baseblock,middleblock,topblock)
  1941.     debugT("drawing a portal at: "..portal_location.x..", "..portal_location.y..", "..portal_location.z)
  1942.     if queue_phase == registry.QUEUE_PHASE.DORMANT then
  1943.         --fill with air the ground level
  1944.         ---[[
  1945.         fillSmart(
  1946.             portal_location.x,
  1947.             portal_location.y,
  1948.             portal_location.z,
  1949.             registry.PORTAL.SIZE,
  1950.             1,
  1951.             registry.PORTAL.SIZE,
  1952.             registry.BLOCKS.AIR
  1953.         )
  1954.         --fill with detector blocks one level below ground
  1955.         fillSmart(
  1956.             portal_location.x,
  1957.             portal_location.y-1,
  1958.             portal_location.z,
  1959.             registry.PORTAL.SIZE,
  1960.             1,
  1961.             registry.PORTAL.SIZE,
  1962.             registry.BLOCKS.DETECT
  1963.         )
  1964.         --]]
  1965.     elseif queue_phase == registry.QUEUE_PHASE.PLAYING then
  1966.         --fill with air the ground level
  1967.         fillSmart(portal_location.x,portal_location.y,portal_location.z,registry.PORTAL.SIZE,1,registry.PORTAL.SIZE,registry.BLOCKS.AIR )
  1968.         --fill with detector blocks one level below ground
  1969.         fillSmart(portal_location.x,portal_location.y-1,portal_location.z,registry.PORTAL.SIZE,1,registry.PORTAL.SIZE,registry.BLOCKS.DETECT )
  1970.         --mark with a construnction block the middle point
  1971.         commands.async.setblock(portal_location.x+(registry.PORTAL.SIZE/2),portal_location.y,portal_location.z+(registry.PORTAL.SIZE/2),registry.BLOCKS.CONSTRUCTION.block,registry.BLOCKS.CONSTRUCTION.variant)
  1972.     elseif queue_phase == registry.QUEUE_PHASE.GAMEOVER then
  1973.         --fill with construction block the ground level
  1974.         fillSmart(portal_location.x,portal_location.y,portal_location.z,registry.PORTAL.SIZE,1,registry.PORTAL.SIZE,registry.BLOCKS.CONSTRUCTION )
  1975.     end
  1976.     --[[
  1977.     if baseblock then
  1978.         commands.async.fill(zone.x,zone.y,zone.z,zone.x+registry.PORTAL.SIZE-1,zone.y,zone.z+registry.PORTAL.SIZE-1,baseblock.block,baseblock.variant)
  1979.     end
  1980.  
  1981.     if topblock then
  1982.         commands.async.fill(zone.x,zone.y+1,zone.z,zone.x+registry.PORTAL.SIZE-1,zone.y+1,zone.z+registry.PORTAL.SIZE-1,topblock.block,topblock.variant)
  1983.     end
  1984.  
  1985.     if middleblock then
  1986.         commands.async.setblock(zone.x+(registry.PORTAL.SIZE/2),zone.y+1,zone.z+(registry.PORTAL.SIZE/2),middleblock.block,middleblock.variant)
  1987.     end
  1988.     --]]
  1989.  
  1990. end
  1991.  
  1992. --- Move from the Wait Phase to the Play Phase
  1993. -- Anything that needs to be done ONCE before the Play Phase starts
  1994. -- happens here.
  1995. -- The buildzone is moved to a clean area.
  1996. -- The players in the Kew are moved to the buildzone.
  1997. -- The buildzone is cleaned up (now that the chunks are loaded
  1998. -- The buildzone is prepares (detector blocks placed)
  1999. -- Players recieve starting items
  2000. -- A friendly message is shown for them to begin
  2001. -- Kew Phase and Timer are updated
  2002. -- @param kew The Kew to update
  2003. function endWaitPhase(kew)--, game)
  2004.     --moveBuildzone(kew.buildzone,game.builds)
  2005.     --teleportToZone(kew.buildzone,kew.playerlist,"Your game has started! BUILD A HOUSE!", "Das Spiel hat begonnen! BAUE EIN HAUS!")--teleport selected players
  2006.     debugT("ending the wait phase for buildzone "..kew.buildzone.locid)
  2007.     cleanBuildzone(kew.buildzone)
  2008.     prepareBuildzone(kew.buildzone)--prepare build zone
  2009.     --giveItems(kew.playerlist,registry.STARTING_ITEMS) --Starting items are given as players join now, not all at once
  2010.     displayTitleToPlayers(kew.playerlist,"BUILD!","Place your resources and stand on a detector block.")
  2011.     kew.victory = false
  2012.     --displayTime(kew.buildzone.selector,0,0)
  2013.     kew.phase = registry.QUEUE_PHASE.PLAYING
  2014.     kew.timer = kew.phases[kew.phase].length
  2015.     drawPortal(kew.portal,kew.phase)
  2016.     debugT("wait phase for buildzone "..kew.buildzone.locid.. " - ended")
  2017. end
  2018.  
  2019. --- Move from the Play Phase to the End Phase
  2020. -- Anything that needs to be done ONCE before the End Phase starts
  2021. -- happens here.
  2022. -- Player highscores are updated
  2023. -- The Kew and Buildzone data is saved to file
  2024. -- The buildzone is given a clean and checked for value
  2025. -- Kew Phase and Timer are updated
  2026. -- @param kew The Kew to update
  2027. function endPlayPhase(kew)
  2028.     debugT("ending the play phase for buildzone "..kew.buildzone.locid)
  2029.     processHighscores(kew)
  2030.     exportKewData(kew,true) -- saves the final state of the game and writes it to the online database
  2031.     cleanAfterGameOver(kew)
  2032.     kew.phase = registry.QUEUE_PHASE.GAMEOVER
  2033.     --displayTime(kew.buildzone.selector,0,0)
  2034.     kew.timer = kew.phases[kew.phase].length
  2035.     displayTitleToPlayers(kew.playerlist,"Times Up!","Use HOMECOMER to return to spawn")
  2036.     drawPortal(kew.portal,kew.phase)
  2037.     debugT("play phase for buildzone "..kew.buildzone.locid.. " - ended")
  2038. end
  2039.  
  2040. --- Move from the End Phase to the Wait Phase
  2041. -- Anything that needs to be done ONCE before the End Phase starts
  2042. -- happens here.
  2043. -- Players are removed from the Kews playerlist
  2044. -- Kew Phase and Timer are updated
  2045. -- @param kew The Kew to update
  2046. function endEndPhase(kew)
  2047.     debugT("ending the final phase for buildzone "..kew.buildzone.locid)
  2048.     removePlayersFromKew(kew)
  2049.     kew.phase = registry.QUEUE_PHASE.DORMANT
  2050.     --displayTime(kew.buildzone.selector,0,0)
  2051.     kew.timer = kew.phases[kew.phase].length
  2052.     drawPortal(kew.portal, kew.phase)
  2053.     debugT("final phase for buildzone "..kew.buildzone.locid.. " - ended")
  2054. end
  2055.  
  2056. --- Calculate end of Phase and change to next Phase
  2057. -- This code runs ONCE at the end of each phase and what actually
  2058. -- happens is specific to which phase the given kew is in.
  2059. -- Kew timers are filled and Kew Phases are updated here only.
  2060. -- @param game The game object as created in setup()
  2061. function doPhaseEnds(game)
  2062.     for i,kew in ipairs(game.queues) do
  2063.         if kew.timer <= 0 then
  2064.             if kew.phase == registry.QUEUE_PHASE.DORMANT then
  2065.                 --waiting phase ends goto play phase
  2066.                 endWaitPhase(kew) --, game)
  2067.             elseif kew.phase == registry.QUEUE_PHASE.PLAYING then
  2068.                 --playing phase ends goto end phase
  2069.                 endPlayPhase(kew)
  2070.             elseif kew.phase == registry.QUEUE_PHASE.GAMEOVER and countActivePlayers(kew) == 0 then
  2071.                 --end phase ends goto waiting phase
  2072.                 endEndPhase(kew)
  2073.             end
  2074.         end
  2075.     end
  2076. end
  2077.  
  2078.  
  2079. -- Replaces important blocks such as Detectors
  2080. -- Replaces everything that is needed to start the game. Does not
  2081. -- rebuild the floor, or clear anything away. based on the settings it
  2082. -- creates a full grid, or a partial grid, or no grid of Detectors
  2083. -- it also places the ring, although this is disabled for now
  2084. -- @param buildzone The buildzone to prepare
  2085. function prepareBuildzone(buildzone)
  2086.     debugT("Preparing buildzone "..buildzone.locid.." ...")
  2087.     local bz = buildzone
  2088.     local x,y,z,w = bz.x,bz.y,bz.z,bz.w
  2089.     --debugT("fillSmart from inside prepareBuildzone")
  2090.     --place the white grid accross the full buildzone as a base
  2091.     --commands.async.fill(x,y,z,x+w,y,z+w,registry.BLOCKS.CAMP_FLOOR.block)
  2092.     fillSmart(x,y,z,w,1,w,registry.BLOCKS.CAMP_FLOOR)
  2093.     --fillSmartRing(buildzone.x,buildzone.y-1,buildzone.z,buildzone.w,registry.BLOCKS.CONSTRUCTION.block) --this draws the construction stripe around the buildzone
  2094.     --create the grid of detectors surrounded by plus plugs
  2095.     if registry.DO_GRID then
  2096.         --fillGrid()
  2097.         local halfCell = math.floor(registry.GRIDCELL_SIZE/2)
  2098.         for x=0,registry.GRIDCELL_COUNT-1 do
  2099.             for z=0,registry.GRIDCELL_COUNT-1 do
  2100.                 local rand = math.random()*100
  2101.                 if rand > registry.GRID_HOLE_CHANCE then --and result then
  2102.                     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.variant,"replace","minecraft:air")
  2103.                     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)
  2104.                     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)
  2105.                 end
  2106.             end
  2107.         end
  2108.     end
  2109.     --mark the game in the LOCS array as not available anymore, and save the updated game grid to the grid file
  2110.     --change the flag to played=true
  2111.     --print("prepareBuildzone", buildzone.locid)
  2112.     updateZonePlayedState(buildzone,true)
  2113.     debugT("Buildzone "..buildzone.locid.." is prepared.")
  2114. end
  2115.  
  2116. -- Removes everything in a buildzone
  2117. -- Literally replaces every block inside the buildzone with air and
  2118. -- then removes all floating items.
  2119. -- @param buildzone A buildzone to clean
  2120. function cleanBuildzone(buildzone)
  2121.     debugT("Cleaning buildzone "..buildzone.locid.." ...")
  2122.     --for each level, remove all blocks
  2123.     debugT("fillSmart from inside cleanBuildzone")
  2124.     fillSmart(buildzone.x-1, buildzone.y, buildzone.z-1, buildzone.w+2, 256-buildzone.y, buildzone.w+2, registry.BLOCKS.AIR)
  2125.     --for h=buildzone.y,255 do
  2126.     --  commands.async.fill(buildzone.x,h,buildzone.z,buildzone.x+buildzone.w,h,buildzone.z+buildzone.w,"minecraft:air")
  2127.     --end
  2128.     --remove all floating items in the loaded part of the world
  2129.     commands.async.kill("@e[type=item]")
  2130.     debugT("Buildzone "..buildzone.locid.." is cleaned.")
  2131. end
  2132.  
  2133. --- Takes players out of a Kews playerlist
  2134. -- Gives all players a message telling them to return to spawn and
  2135. -- then removes them from the playerlist. This releases them from being
  2136. -- trapped in the buildzone boundary.
  2137. -- @param kew The Kew to clear players from
  2138. function removePlayersFromKew(kew)
  2139.     debugT("removing all players from the list for buildzone "..kew.buildzone.locid.." ...")
  2140.     for name, player in pairs(kew.playerlist) do
  2141.         if registry.ANNOUNCE_ENGLISH then
  2142.             -- announce success in English
  2143.             commands.async.tellraw(player.name,'["",{"text":"TIME OUT! GAME COMPLETE! Use your HOMECOMER to return to spawn.","color":"white"}]')
  2144.         end
  2145.         if registry.ANNOUNCE_GERMAN then
  2146.             -- announce success in German
  2147.             commands.async.tellraw(player.name,'["",{"text":"ENDE! SPIEL ABGESCHLOSSEN! Nutze den HEIMKEHRER um zum Anfang zurück zu kehren.","color":"gold"}]')
  2148.         end
  2149.     end
  2150.     kew.playerlist = {}
  2151.     debugT("Player list for buildzone "..kew.buildzone.locid.." is now empty") 
  2152. end
  2153.  
  2154. --- Resets a player to be harmless
  2155. -- Use this when you want to be sure a player cannot modify blocks
  2156. -- and that they have no wool to place. You can also send them a friendly
  2157. -- message about why you took their stuff!
  2158. -- @param playername String of the players name
  2159. -- @param message String A friendly message for the given player
  2160. function resetPlayer(playername,message)
  2161.     debugT("resetPlayer: reseting player '"..playername.."' to adventure mdoe with no wool and pickaxe")
  2162.     commands.tell(playername,message)
  2163.     commands.async.gamemode(2,playername)
  2164.     commands.async.clear(playername,"minecraft:wool")
  2165.     commands.async.clear(playername,"minecraft:stone_pickaxe")
  2166. end
  2167.  
  2168. --- Checks if given player is in a buildzone
  2169. -- Uses a playerdata object and the buildzone selector
  2170. -- @param player A playerdata object from newPlayerData()
  2171. -- @param buildzone A buildzone object to get the selector from
  2172. -- @return result True if the player is in the buildzone
  2173. function checkForPlayerInBuildzone(player,buildzone)
  2174.     local result,message = commands.testfor('@a[name='..player.name..','..buildzone.selector..']')
  2175.     return result
  2176. end
  2177.  
  2178. --- Checks if a given player is in a given waiting area
  2179. -- Builds a selector for the portal from the given portal
  2180. -- @param player A playerdata object from newPlayerData()
  2181. -- @param portal A portal from a Kew object
  2182. -- @return result True if the player is in the wait area
  2183. function checkForPlayerInPortal(player,portal) --currently not used anywhere
  2184.     local selector = "x="..portal.x..",y="..portal.y..",z="..portal.z..",dx="..registry.PORTAL.SIZE..",dy=1,dz="..registry.PORTAL.SIZE
  2185.     local result,message = commands.testfor('@a[name='..player.name..','..selector..']')
  2186.     return result
  2187. end
  2188.  
  2189. --- Checks if a given player is in a given area
  2190. -- Builds a selector for the area from the given area parameters
  2191. -- @param player A playerdata object from newPlayerData()
  2192. -- @param area Specified as a table with x,y,z,w,l,h fields
  2193. -- @return result True if the player is in the wait area
  2194. function checkForPlayerInArea(player,area) --currently not used anywhere
  2195.    
  2196.     local selector = "x="..area.x..",y="..area.y..",z="..area.z..",dx="..area.w..",dy="..area.h..",dz="..area.l
  2197.     --debugT("checking for player '"..player.name.."' in area: "..selector)
  2198.     local result,message = commands.testfor('@a[name='..player.name..','..selector..']')
  2199.     return result
  2200. end
  2201.  
  2202. --- Gets a list of all players in a given Portal
  2203. -- Builds a selector for the portal from the given portal
  2204. -- @param portal A portal from a Kew object
  2205. -- @return result A list of playerdata objects from GetAllPos()
  2206. function checkPortal(portal)
  2207.     local selector = "x="..portal.x..",y="..portal.y..",z="..portal.z..",dx="..registry.PORTAL.SIZE..",dy=1,dz="..registry.PORTAL.SIZE
  2208.     local result = getAllPos('m=2,'..selector)
  2209.     return result
  2210. end
  2211.  
  2212.  
  2213. --- Updates our information on all players we think are in the game
  2214. -- Checks the waitlist and all kews. Each player is checked if they are
  2215. -- still online and if they are playing in a buildzone.
  2216. -- @param game A game object as created by setup()
  2217. function checkPlayers(game)
  2218.     --get all players in adventure mode and sort them around
  2219.     local loggedIn = getAllPos('m=2')
  2220.     number_of_players_adventure = tablelength(loggedIn)
  2221.     --number_of_players_creative = tablelength(getAllPos('m=1')) --disabled for now until we figure how to deal with the glitches
  2222.     --check currently playing players
  2223.     --debugT("the loggedIn table before player dispatching is:"..json.encode(loggedIn))
  2224.     for l,kew in ipairs(game.queues) do
  2225.         for name,builder in pairs(kew.playerlist) do
  2226.             local isPlaying = checkForPlayerInBuildzone(builder,kew.buildzone)
  2227.             --remove players who are already in kews from the waitlist
  2228.             for j=#loggedIn,1,-1 do  --count backwards so removing an element is safe
  2229.                 if loggedIn[j].name == builder.name then
  2230.                     --debugT("found player: "..loggedIn[j].name.." in kew: "..kew.buildzone.locid)
  2231.                     table.remove(loggedIn,j)
  2232.                 end
  2233.                 --debugT("the loggedIn table after player found is:"..json.encode(loggedIn))
  2234.             end
  2235.             --if the game is in progress and the player is not found then remove them from the gamekew
  2236.             if not isPlaying and kew.phase == registry.QUEUE_PHASE.PLAYING then
  2237.                 kew.playerlist[builder.name].status = registry.PLAYER_STATUS.LEFT_OTHERWISE
  2238.             end
  2239.         end
  2240.     end
  2241.     --check if players are in the spawn area
  2242.     --debugT("the loggedIn table after player dispatching is:"..json.encode(loggedIn))
  2243.     for j=#loggedIn,1,-1 do
  2244.         local isInSpawnArea = checkForPlayerInArea(loggedIn[j], registry.MAIN_SPAWN_AREA)
  2245.         if isInSpawnArea then  --count backwards so removing an element is safe
  2246.             table.remove(loggedIn,j)
  2247.         end
  2248.     end
  2249.     --debugT("the loggedIn table after spawnzone filtering is:"..json.encode(loggedIn))
  2250.     --if there are still players in loggedIn then they must be force moved to spawn
  2251.     if tablelength(loggedIn) > 0 then
  2252.         debugT("teleporting free roaming players back to spawn area: "..playerListToString(loggedIn))
  2253.         teleportToPoint(registry.SPAWN.x,registry.SPAWN.y,registry.SPAWN.z,loggedIn,true,"You have been teleported to the spawn area. Use the portals to join a game", "(Translate to DE)You have been teleported to the spawn area. Use the portals to join a game")
  2254.     end
  2255. end
  2256.  
  2257.  
  2258.  
  2259. function addToGame(kew,waiter)
  2260.     -- check if player already exists in playerlist
  2261.     -- teleport them
  2262.     -- add to playerlist if not
  2263.     -- add starting items if not
  2264.     -- update player status if they exist
  2265.     -- if playerlist is full, fill in the portal
  2266.     local buildzone = kew.buildzone
  2267.     local textEN = "You should never see this text"
  2268.     local textDE = "You should never see this text (in German)"
  2269.     if (#kew.playerlist > 0 and kew.playerlist[waiter.name]) then
  2270.         -- player has been here before so just change status to 0 and tp them
  2271.         --print("player was here before")
  2272.         kew.playerlist[waiter.name].status = registry.PLAYER_STATUS.IN_GAME
  2273.         textEN = "Welcome back to the buildzone."
  2274.         textDE = "Welcome back to the buildzone (TRANSLATE)"
  2275.         debugT("Adding '"..waiter.name.."' as RETURNING player to buildzone #"..buildzone.locid)
  2276.     else
  2277.         --print("player was NOT here before")
  2278.         kew.playerlist[waiter.name] = waiter
  2279.         kew.playerlist[waiter.name].status = registry.PLAYER_STATUS.IN_GAME
  2280.         giveItems({waiter},registry.STARTING_ITEMS)
  2281.         textEN = "Welcome to the buildzone. Build your first structure."
  2282.         textDE = "Welcome to the buildzone. Build your first structure. (TRANSLATE)"
  2283.         debugT("Adding '"..waiter.name.."' as NEW player to buildzone #"..buildzone.locid)
  2284.     end
  2285.     --print("buildzone", buildzone)
  2286.     --print("waiter", waiter)  
  2287.     --print("textEN", textEN)
  2288.     --print("textDE", textDE)
  2289.     scatterIntoZone(buildzone, {waiter}, textEN, textDE)
  2290.     --teleportToPoint(buildzone.x+2+(buildzone.w/2),buildzone.y+5,buildzone.z+2+(buildzone.w/2),{waiter},false,textEN, textDE)
  2291. end
  2292.  
  2293. function inZoneChangeMode(zone,mode)
  2294.     --debugT("changing every in wait zone to adventure mode")
  2295.     local selector = "x="..zone.x..",y="..zone.y..",z="..zone.z..",dx="..registry.PORTAL.SIZE..",dy=1,dz="..registry.PORTAL.SIZE
  2296.     commands.async.gamemode(mode,"@a["..selector.."]")
  2297. end
  2298.  
  2299. -- Adds waiting players to Kew playerlists
  2300. -- checks which players are in which portals and adds them to games
  2301. -- based on that. If there are any creative mode players in the zone,
  2302. -- change them to adventure mode.
  2303. -- @param game the game object as created by setup()
  2304. function allocateWaiters(game)
  2305.     for i, kew in ipairs(game.queues) do
  2306.         --debugT("allocateWaiters: the queues for loop start")
  2307.         if (kew.phase == registry.QUEUE_PHASE.DORMANT or kew.phase == registry.QUEUE_PHASE.PLAYING) and countActivePlayers(kew) < kew.maxplayers then
  2308.             --debugT("allocateWaiters: the if statement start")
  2309.             inZoneChangeMode(kew.portal,2)
  2310.             local waiters = checkPortal(kew.portal)
  2311.             if #waiters > 0 then debugT("found player in launchpad") end
  2312.             for index,waiter in ipairs(waiters) do
  2313.                 --debugT("allocateWaiters: the waiters for loop start")
  2314.                 addToGame(kew,waiter)
  2315.                 --debugT("allocateWaiters: the waiters for loop end")
  2316.             end
  2317.             --debugT("allocateWaiters: the if statement end")
  2318.         end
  2319.         --debugT("allocateWaiters: the queues for loop end")
  2320.     end
  2321.     --debugT("allocateWaiters: completed")
  2322. end
  2323.  
  2324. --- Adds a new request to check a Detector Block safely
  2325. -- Makes sure that incoming check requests dont exist already
  2326. -- Players can still have multiple requests, but no two requests from
  2327. -- the same tile will exist. Requests are processed at a rate of one per
  2328. -- game step, so its important that we dont have duplicates as it slows
  2329. -- the game loop down a lot.
  2330. -- @param player A playerdata Object as created by newPlayerData().
  2331. -- @param buildzone A buildzone to which the request should be added.
  2332. function addToChecklist(player,buildzone)
  2333.     for _, detector in ipairs(buildzone.waitingForCheck) do
  2334.         if detector.x == player.x and detector.y == player.y and detector.z == player.z then
  2335.             return false
  2336.         end
  2337.     end
  2338.     table.insert(buildzone.waitingForCheck,player)
  2339.     return true
  2340. end
  2341.  
  2342. --- Cleans barriers from a buildzone
  2343. -- removes all barrier blocks from a buildzone which are used to
  2344. -- carve space in Elements.
  2345. -- TODO This should be updated to only clean an area
  2346. -- the size of an element specified with x,y,z.
  2347. -- @param buildzone A buildzone that should be cleaned
  2348. function cleanBarriers(buildzone)
  2349.     --debugT()
  2350.     for h=0,200 do
  2351.         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")
  2352.     end
  2353. end
  2354.  
  2355. --- Update a buildzone that is in the Play Phase
  2356. -- Detection and Game Logic is mostly kept here. Meat and Potatoes time.
  2357. -- Wow, actually most of this is disabled for now.
  2358. -- If there are waiting requests for checking a detector block, do
  2359. -- the first one in the list.
  2360. -- Check it against the catalogue we have stored in the buildzone
  2361. -- (not the complete catalogue). If it matches then clone in the new
  2362. -- Building, give Rewards and clean Barriers.
  2363. -- Currently always returns False for victory.
  2364. -- @param kew a Kew object which contains a Buildzone
  2365. -- @return victory Boolean, Did this placement cause a victory?
  2366. function updatePlayedZone(kew)
  2367.     local buildzone = kew.buildzone
  2368.     local victory = false
  2369.     local buildzoneSelector = buildzone.selector
  2370.     --get all players on a detector block, add them to the list of things to check
  2371.     local detectLocations = getAllOnBlockType(registry.BLOCKS['DETECT'].block,buildzoneSelector)
  2372.     --print(#detectLocations.." Players standing on detectors")
  2373.     for _, player in ipairs(detectLocations) do
  2374.         addToChecklist(player,buildzone)
  2375.     end
  2376.  
  2377.     --DEAL WITH THE DETECTOR AT THE TOP OF THE LIST IF THERE IS ONE
  2378.     if #buildzone.waitingForCheck > 0 then
  2379.         --DO PARTICLE EFFECTS IF A DETECTING BLOCK THAT IS DETECTING
  2380.         for i,loc in ipairs(buildzone.waitingForCheck) do
  2381.             searchParticle(loc.x,loc.y+1,loc.z)
  2382.         end
  2383.         local totalResult = false
  2384.         local checked = table.remove(buildzone.waitingForCheck,1)
  2385.         local x,y,z,name = checked.x,checked.y,checked.z,checked.name
  2386.         for i,element in pairs(buildzone.elements) do
  2387.             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")
  2388.             if result then
  2389.                 --clone in the correct vocab
  2390.                 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")
  2391.                 --debugT(clonemes[1])
  2392.                 --commands.async.give(name,element.reward)
  2393.                 giveItems({checked},registry.DEFAULT_REWARDS)
  2394.                 debugT("successful detect of element #"..i.." in buildzone #"..buildzone.locid.." at:"..x..", "..y..", "..z)
  2395.                 -- announce  success in English
  2396.                 --[[
  2397.                 local rewardType = 'nature'
  2398.                 local rewardTypeDE = 'grüne'
  2399.                 if element.rewardUrban then
  2400.                     rewardType = 'urban'
  2401.                     rewardTypeDE = 'urbane'
  2402.                 end
  2403.                 --]]
  2404.                 if registry.ANNOUNCE_ENGLISH then
  2405.                     --announce success in English
  2406.                     --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"}]')
  2407.                     commands.async.tellraw(name,'["",{"text":"You built an element!","color":"white"}]')
  2408.                 end
  2409.                 if registry.ANNOUNCE_GERMAN then
  2410.                     -- announce  success in German
  2411.                     --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"}]')
  2412.                     commands.async.tellraw(name,'["",{"text":"Du hast ein element gebaut!","color":"gold"}]')
  2413.                 end
  2414.                
  2415.                 --clear out barrier blocks
  2416.                 cleanBarriers(buildzone)
  2417.                
  2418.                 --ADD THE NEW STRUCTURE TO THE RECORDS
  2419.                 --table.insert(buildzone.structures,element.nameEN)
  2420.                 --record the place of the element as x, y, z and element id
  2421.                 local building = {id=element.id,xpos=x,ypos=y-1,zpos=z,name="element_"..element.id,time=os.clock(),player=name}
  2422.                 table.insert(buildzone.buildings, building)
  2423.                
  2424.                 --save the game incrementally
  2425.                 exportKewData(kew,false) -- saves the new state of the game locally to a file, doesn't write to the database yet
  2426.                
  2427.                 --[[ DISABLED UNTIL THE NEW GOAL SYSTEM IS IMPLEMENTED
  2428.                
  2429.                 buildzone.greenSlots = buildzone.greenSlots + element.greenSlots
  2430.                
  2431.                 buildzone.filledSlots = buildzone.filledSlots + element.slots
  2432.                 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
  2433.                 if newHeight > buildzone.highest then
  2434.                     buildzone.highest = newHeight
  2435.                 end
  2436.                
  2437.                 -- count variety               
  2438.                 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
  2439.                 --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
  2440.                 --]]
  2441.                 --[[
  2442.                 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
  2443.                 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
  2444.                 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
  2445.                 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
  2446.                 if varietyId ~= 17 and varietyId ~= 18 then --skip the two riser as they are not buildings
  2447.                 --]]
  2448.                 --[[
  2449.                 if buildzone.variety[varietyId] then
  2450.                     --print("increasing existing item")
  2451.                     buildzone.variety[varietyId] = buildzone.variety[varietyId] + 1
  2452.                 else
  2453.                     --print("adding new item")
  2454.                     buildzone.variety[varietyId] = 1
  2455.                 end
  2456.                 --end
  2457.                
  2458.            
  2459.                
  2460.                
  2461.                 --- CHECK FOR PERSONAL RECORDS
  2462.                 --- check if the new structure is the highest
  2463.                 --- CHANGE here to live detect the contribution of the new structure to the 4 goals and update them
  2464.                
  2465.                 local personalbest = tracker.getScore(name,"highest")
  2466.                 if personalbest.count < newHeight then
  2467.                     --commands.async.tell(name,"You just topped your personal record for highest structure!")
  2468.                     commands.async.scoreboard("players","add",name,"highest",1)
  2469.                     if registry.ANNOUNCE_ENGLISH then
  2470.                         -- announce success in English
  2471.                         commands.async.tellraw(name,'["",{"text":"You just topped your personal record for highest neighbourhood!","color":"green"}]')
  2472.                     end
  2473.                     if registry.ANNOUNCE_GERMAN then
  2474.                         -- announce success in German
  2475.                         commands.async.tellraw(name,'["",{"text":"Du hast soeben deinen persönlichen Rekord für die höchste Nachbarschaft gebrochen!","color":"gold"}]')
  2476.                     end
  2477.                 end
  2478.            
  2479.                 ---
  2480.                 ---
  2481.                 -- CHECK if placing the current structure would result in beating a server-wide record on the 4 goals
  2482.                 --calculate total slots - FOR GOAL "DENSEST NEIGHBOURHOOD"
  2483.                 local most = tracker.getScore("Densest_[points]","highscores")
  2484.                 local Kint = math.floor(100 * buildzone.filledSlots / 49) -- Kint is the density index made from built area (filledSlots) over ground area (7x7 slots = 49)
  2485.                 if Kint > most.count then
  2486.                     commands.async.scoreboard("players","set","Densest_[points]","highscores",Kint)
  2487.                     if registry.ANNOUNCE_ENGLISH then
  2488.                         -- announce success in English
  2489.                         commands.async.tellraw("@a",'["",{"text":"Great! '..name.. ' just topped the record for the DENSEST NEIGHBOURHOOD!","color":"green"}]')
  2490.                     end
  2491.                     if registry.ANNOUNCE_GERMAN then
  2492.                         -- announce success in German
  2493.                         commands.async.tellraw("@a",'["",{"text":"Sehr gut! '..name.. ' hat einen neuen Rekord für die DICHTESTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  2494.                     end                
  2495.                 end
  2496.                
  2497.                 -- FOR THE GOAL "MOST DIVERSE NEIGHBOURHOOD"
  2498.                 -- here we need to count how many varieties of buildings there are
  2499.                 --local structures = tracker.tallyTable(buildzone.structures) -- this counts the variety of buildings in a game
  2500.                 local mostDiverse = tracker.getScore("Most-Diverse_[out-of-26]","highscores")
  2501.                 local typeCount = tablelength(buildzone.variety)
  2502.                 --print("variety count is: "..typeCount)
  2503.                 if typeCount > mostDiverse.count then
  2504.                     commands.async.scoreboard("players","set","Most-Diverse_[out-of-26]","highscores", typeCount)
  2505.                     if registry.ANNOUNCE_ENGLISH then
  2506.                         -- announce success in English
  2507.                         commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' just topped the record for the MOST DIVERSE NEIGHBOURHOOD!","color":"green"}]')
  2508.                     end
  2509.                     if registry.ANNOUNCE_GERMAN then
  2510.                         -- announce success in German
  2511.                         commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' hat soeben einen neuen Rekord für die VIELSEITIGSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  2512.                     end
  2513.                 end
  2514.    
  2515.                 -- FOR THE GOAL "GREENEST NEIGHBOURHOOD"
  2516.                 -- here we need to count the number of green vocabs
  2517.                 local greenest = tracker.getScore("Greenest_[points]","highscores")
  2518.                 local Gint = math.floor(100*buildzone.greenSlots/49) --Gint is the green index, made from green area (greenSlots) over ground area (7x7 slots = 49)
  2519.                 if Gint > greenest.count then
  2520.                     commands.async.scoreboard("players","set","Greenest_[points]","highscores",Gint)
  2521.                     if registry.ANNOUNCE_ENGLISH then
  2522.                         -- announce success in English
  2523.                         commands.async.tellraw("@a",'["",{"text":"Awesome! '..name.. ' just topped the record for the GREENEST NEIGHBOURHOOD!","color":"green"}]')
  2524.                     end
  2525.                     if registry.ANNOUNCE_GERMAN then
  2526.                         -- announce success in German
  2527.                         commands.async.tellraw("@a",'["",{"text":"Klasse! '..name.. ' hat einen neuen Rekord für die GRÜNSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  2528.                     end
  2529.                 end
  2530.    
  2531.                 --calculate highest placement -- FOR THE GOAL "TALLEST NEIGHBOURHOOD"
  2532.                 local highest = tracker.getScore("Tallest_[meters]","highscores")
  2533.                 if buildzone.highest > highest.count then
  2534.                     commands.async.scoreboard("players","set","Tallest_[meters]","highscores",buildzone.highest)
  2535.                     if registry.ANNOUNCE_ENGLISH then
  2536.                         -- announce success in English
  2537.                         commands.async.tellraw("@a",'["",{"text":"Incredible! '..name..' just topped the record for TALLEST NEIGHBOURHOOD!","color":"green"}]')
  2538.                     end
  2539.                     if registry.ANNOUNCE_GERMAN then
  2540.                         -- announce success in German
  2541.                         commands.async.tellraw("@a",'["",{"text":"Unglaublich! '..name..' hat einen neuen Rekord für die HÖCHSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  2542.                     end
  2543.                 end
  2544.                
  2545.                
  2546.                 --increase the "how many structures did i build" score for the building player
  2547.                 commands.async.scoreboard("players","add",name,"built",1)
  2548.                 commands.async.scoreboard("players","add",name,"building_"..element.id,1)
  2549.                 --]]
  2550.                 totalResult = true
  2551.                 break
  2552.                
  2553.             end
  2554.         end
  2555.         if totalResult then
  2556.             --yey win, do a happy time
  2557.             successParticle(x,y,z)
  2558.            
  2559.         else
  2560.             --no vocab found so do a fail particle
  2561.             --announce in English
  2562.             commands.async.tellraw(name,'["",{"text":"The shape you have built does not match any shape in the catalogue, try a different one.","color":"red"}]')
  2563.             if registry.ANNOUNCE_GERMAN then
  2564.                 -- announce in German
  2565.                 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"}]')
  2566.             end
  2567.             failParticle(x,y-1,z)
  2568.             debugT("The key that player activated is not in the catalogue.")
  2569.         end
  2570.     end
  2571.     return victory
  2572. end
  2573.  
  2574. local symbols = {
  2575.     "(X) ",
  2576.     "(-) "
  2577.     }
  2578. local spin = 1
  2579.  
  2580. --- Display game information in the terminal
  2581. -- Slated for removal
  2582. function debugDisplayTerminal(game)
  2583.     --print("starting debug display")
  2584.     term.clear()
  2585.     term.setTextColor(colors.green)
  2586.     print("20.000 BLOCKS v."..VERSION_NUMBER.." - (HOLD CTRL+T TO QUIT) "..symbols[spin])
  2587.     --[[ disabled for now until we deal with the TP glitches
  2588.     if number_of_players_adventure and number_of_players_creative then
  2589.         print("TOTAL PLAYERS: "..(number_of_players_adventure + number_of_players_creative).." - ADVENTURE [ "..number_of_players_adventure.." ], CREATIVE [ "..number_of_players_creative.." ]")
  2590.     end
  2591.     --]]
  2592.     if number_of_players_adventure  then
  2593.         print("TOTAL ADVENTURE MODE PLAYERS: "..number_of_players_adventure)
  2594.     end
  2595.     term.setTextColor(colors.white)
  2596.     spin = spin +1
  2597.     if spin > #symbols then spin = 1 end
  2598.    
  2599.    
  2600.    
  2601.     local line = 2
  2602.     --print("running with "..registry.NUMBER_OF_BUILDZONES.." buildzones")
  2603.     --print("Player Status Key ( 0 = in game, 1 = quit with homecomer, 2 = left game )")
  2604.     for i,kew in ipairs(game.queues) do
  2605.         --monitor.setCursorPos(1,line)
  2606.         local minutes = string.format("%02d",math.floor(kew.timer/60))
  2607.         local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
  2608.         print("BUILDZONE "..i.." | PHASE: "..kew.phase.." | TIME: "..math.floor(kew.timer).." | PLAYERS: "..tablelength(kew.playerlist))
  2609.         print("-LIST: "..playerListToString(kew.playerlist))
  2610.         --print(json.encode(kew.playerlist))
  2611.     end
  2612.    
  2613.     --use the remaining terminal lines to show the log
  2614.     -- the terminal has 19 lines, 18 available for printing, last one stays clear at all times
  2615.     term.setTextColor(colors.red)
  2616.     print("===== LATEST LOG:")
  2617.     for i=13-(2*#game.queues), 0, -1 do
  2618.         if #debug_log > i then
  2619.             print(debug_log[#debug_log-i].message:sub (1,51))
  2620.         end
  2621.     end
  2622.     term.setTextColor(colors.white)
  2623.    
  2624. end
  2625.  
  2626.  
  2627. -- the main function
  2628. function MAIN()
  2629.    
  2630.  
  2631.    
  2632.     term.clear()
  2633.     term.setTextColor(colors.blue)
  2634.     debugT("Starting 20.000 BLOCKS")
  2635.     debugT("Version: "..VERSION_NUMBER.." - "..VERSION_NAME)
  2636.     debugT("Lua v.".._G._VERSION)
  2637.     term.setTextColor(colors.white)
  2638.    
  2639.     LOCS = buildGrid(registry.GAME_FIELD.countX, registry.GAME_FIELD.countZ)
  2640.    
  2641.     local game = setup(LOCS)
  2642.     if not game then
  2643.         return
  2644.     end
  2645.    
  2646.     --print("20.000 BLOCKS is running...")
  2647.     --local skip = false
  2648.     --if not skip then
  2649.     debugT("20.000 BLOCKS is running...")
  2650.    
  2651.     local sleeptime = 1 --how many seconds to wait before redoing the code in the loop
  2652.     local the_timer = os.startTimer(sleeptime)
  2653.     --local blockswapper_time = 0.05 --how many seconds to wait before redoing the blockswapping code
  2654.     --local the_blockswapper = os.startTimer(blockswapper_time)
  2655.     --
  2656.     while true do
  2657.         local event, arg, isHeld = os.pullEvent()
  2658.         print(event)
  2659.         --print(tostring(arg))
  2660.         --print(isHeld)
  2661.         if event == "timer" and arg == the_timer then
  2662.             --debugT("beginning of main game loop")
  2663.             if registry.DEBUG_MODE == false then
  2664.                 term.clear()
  2665.                 term.setTextColor(colors.green)
  2666.                 print("20.000 BLOCKS v."..VERSION_NUMBER.." - (hold CTRL+T to quit) "..symbols[spin])
  2667.                 term.setTextColor(colors.white)
  2668.                 spin = spin +1
  2669.                 if spin > #symbols then spin = 1 end
  2670.             else
  2671.                 --debugT("begin debug info display")
  2672.                 debugDisplayTerminal(game)
  2673.                 --debugT("end debug info display")         
  2674.             end
  2675.  
  2676.             --debugT("begin update(game)")
  2677.             --debugT(utils.to_string(game))
  2678.             update(game)
  2679.             --debugT("end update(game)")       
  2680.             --debugT(utils.to_string(game))    
  2681.             --make always nice weather
  2682.             --commands.async.weather("clear",10000)
  2683.  
  2684.             -- this needs to be quite high to avoid players experiencing glitches
  2685.             -- where they are returned back to their last location from few seconds ago
  2686.             -- if they move fast. this happens because we use the teleport command
  2687.             -- to get player locations by teleporting them to their current location
  2688.             --os.sleep(2)
  2689.             --
  2690.             the_timer = os.startTimer(sleeptime) --restart the timer
  2691.             --debugT("end of main game loop")
  2692.             --elseif arg == the_blockswapper then
  2693.             swapBlocks()
  2694.             --os.queueEvent("swap")
  2695.             --the_blockswapper = os.startTimer(blockswapper_time) --restart the timer
  2696.         end
  2697.     end
  2698.     --end
  2699. end
  2700.  
  2701. -- process command line parameters
  2702. local tArgs = { ... } -- get the command line arguments
  2703. if #tArgs == 1 then
  2704.     cleanbuildzone = tArgs[1]
  2705. elseif #tArgs > 1 then
  2706.     print("Usage: play <true(cleans buildzone)/false(default, doesnt clean)>")
  2707.     return
  2708. end
  2709. -- run the game
  2710. MAIN()
Add Comment
Please, Sign In to add comment