Advertisement
antonsavov

Untitled

May 16th, 2017
202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 63.96 KB | None | 0 0
  1. local VERSION = '1.0.2 - models are now exported to the DB upon saving'
  2. os.loadAPI('tracker')
  3. os.loadAPI('json')
  4.  
  5. print("Starting 20.000 Blocks")
  6.  
  7. DEBUG_MODE = false
  8. local monitor = peripheral.wrap("right")
  9. local ox,oy,oz = commands.getBlockPosition()
  10.  
  11. CITY_VERSION = 1 -- this denotes which iteration of the map is current. When the map is full, i.e. all buildzones have been played we replace it with an empty one and increase the city vesrion with 1
  12. SPAWN_VILLAGER = false
  13. DO_GRID = true --this refers to the grid of detector blocks placed on the ground at the start of each new game
  14. GRIDCELL_SIZE = 9 -- the width of one grid cell in minecraft blocks. MUST BE ODD NUMBER
  15. GRIDCELL_COUNT = 7 -- the number of gridcells or slots across X and Z in one game. for IBA_GAME it is 7x7
  16. PLUG_LENGTH = 3 -- the number of minecraft blocks which the crosses arround each detector block that are made out of plug blocks will expand to
  17. GRID_HOLE_CHANCE = 0
  18. NUMBER_OF_BUILDZONES = 6
  19. NUMBER_OF_VOCAB = 10
  20. PHASE_LENGTH_GAME = 600 --seconds a game lasts
  21. PHASE_LENGTH_WAIT = 15 --seconds to wait for players to stand in the yeloow box before starting a game
  22. PHASE_LENGTH_OVER = 15 --seconds to wait after a game is completing befor setting the buildzone to the next phase
  23. VOCAB_WIDTH = 27
  24. VOCAB_HEIGHT = 19
  25. BUILDZONE_WIDTH = 62 -- the actual zone width is 63 blocks, but for some reason due to how minecraft handles relative coordinates this has to be 62
  26. BUILDZONE_FLOOR_HEIGHT = -1
  27. HOMECOMER_TYPE = "Pig"
  28. HOMECOMER_VALUE = 90 --90 is for pig
  29. MAX_PLAYERS_PER_GAME = 4
  30. MIN_BUILDINGS = 5 -- the minimum number of buildings a buildzone must have in order to be saved and no discarded at the end of a game
  31.  
  32. SPAWN = {
  33. x=12110,
  34. y=57,
  35. z=-1777,
  36. a1=90,
  37. a2=0
  38. }
  39. FIRSTZONE= {
  40. x=11685,
  41. y=57,
  42. z=-1869
  43. }
  44. WAITZONE = {
  45. x=12093,
  46. y=56,
  47. z=-1779,
  48. w=5,
  49. l=5
  50. }
  51. --this is the block at ~-4 ~ ~-4 from the corner of the shape zone
  52. --i.e., (the one with the grammar shape in it) of the vocab that is closest to zero
  53. FIRSTVOCAB= {
  54. x=0,
  55. y=57,
  56. z=5
  57. }
  58. --VICTORY_HEIGHT = 30
  59. --VICTORY_TOTAL = 50
  60. --VICTORY_SPECIFIC = {name='garden',count=101}
  61.  
  62.  
  63. WOOL_PER_EMERALD = 64
  64.  
  65.  
  66. BLOCKS = {
  67. CAMP_FLOOR = {block='minecraft:sandstone',data=0},
  68. CONSTRUCTION = {block='minecraft:diamond_ore',data=0},
  69. RING = {block='minecraft:diamond_ore',data=0},
  70. DETECT = {block='minecraft:red_sandstone',data=0},
  71. DETECT_DEAD = {block='minecraft:obsidian',data=0},
  72. VOCAB_DETECT = {block="minecraft:quartz_block",data=0},
  73. VOCAB_REPLACE = {block="minecraft:coal_block",data=0},
  74. VICTORY_MARKER = {block="minecraft:emerald_block",data=0},
  75. PLUG = {block="minecraft:lapis_ore",data=0},
  76. PHVFLOOR = {block="minecraft:stone_slab",data=3},
  77. BUILDING_HOUSE = {block="minecraft:wool",data=0},
  78. BUILDING_GARDEN = {block="minecraft:wool",data=13},
  79. BUILDING_WATER = {block="minecraft:wool",data=1},
  80. _matWhiteSmooth ={block="mincreaft:stained_hardened_clay",data=0},
  81. _matWhiteSmooth2 = {block="minecraft:brick_block",data=0},
  82. _matYellowSmooth = {block="minecraft:stained_hardened_clay",data=4},
  83. _matPinkSmooth = {block="minecraft:stained_hardened_clay",data=6},
  84. _matBlueSmooth = {block="minecraft:stained_hardened_clay",data=9},
  85. _matPurpleSmooth = {block="minecraft:stained_hardened_clay",data=10},
  86. _matWhiteTextured = {block="minecraft:planks",data=4},
  87. _matYellowTextured = {block="minecraft:planks",data=1},
  88. _matPinkTextured = {block="minecraft:planks",data=0},
  89. _matBlueTextured = {block="minecraft:planks",data=2},
  90. _matPurpleTextured = {block="minecraft:planks",data=5},
  91. }
  92.  
  93. --contains a list of all posible Buildzones (build a bit later)
  94. LOCS = {}
  95.  
  96. if DEBUG_MODE then
  97. PHASE_LENGTH_GAME = 12000
  98. NUMBER_OF_BUILDZONES = 1
  99. end
  100.  
  101. -- see if the file exists
  102. function file_exists(file)
  103. local f = fs.open(file, "rb")
  104. if f then f:close() end
  105. return f ~= nil
  106. end
  107.  
  108. --creates a grid of absolute references (0,0) (1,0)
  109. function buildGrid(w,h)
  110. local grid = readGridFromFile()
  111. if grid then
  112. -- grid was read from the file successfully
  113. else
  114. --generate file from scratch
  115. grid = {}
  116. for z=0,h-1 do
  117. for x=0,w-1 do
  118. table.insert(grid,{x=x,z=z,played=false})
  119. end
  120. end
  121. end
  122. return grid
  123. end
  124.  
  125. function readGridFromFile()
  126. local result = nil
  127. fs.makeDir("/records")
  128. if DEBUG_MODE then
  129. local filename = "/records/_buildzones-list-debug-area.yaml"
  130. else
  131. local filename = "/records/_buildzones-list.yaml"
  132. end if
  133. if file_exists(filename) then
  134. ---read from file
  135. result = json.decodeFromFile(filename)
  136. end
  137. return result
  138. end
  139.  
  140. function writeGridToFile()
  141. fs.makeDir("/records")
  142. --local filename = "/records/_buildzones-list.yaml"
  143. if DEBUG_MODE then
  144. local filename = "/records/_buildzones-list-debug-area.yaml"
  145. else
  146. local filename = "/records/_buildzones-list.yaml"
  147. end if
  148. local file = fs.open(filename,"w")
  149. file.write(json.encodePretty(LOCS))
  150. file.close()
  151. end
  152.  
  153. --sets where and how big the PHV area is
  154. --second number is along the long edge of PHV starting at the spawn side
  155. --first number is along the short edge of PHV starting from the park side
  156. if DEBUG_MODE then
  157. FIRSTZONE= {
  158. x=5,
  159. y=57,
  160. z=-7
  161. }
  162.  
  163. LOCS = buildGrid(1,3)
  164. else
  165. LOCS = buildGrid(11,27)
  166. end
  167.  
  168. --call these to return a proper minecraft item string including adventure mode properties
  169. function houseBlock(quant)
  170. text = BLOCKS.BUILDING_HOUSE.block..' '..quant..' '..BLOCKS.BUILDING_HOUSE.data..' {display:{Name:"Urban Resource",Lore:[Place this against a Detector to build denser, more urban buildings]},CanPlaceOn:["'..BLOCKS.BUILDING_HOUSE.block..'","'..BLOCKS.PLUG.block..'","'..BLOCKS.DETECT.block..'"]}'
  171. return text
  172. end
  173.  
  174.  
  175. function gardenBlock(quant)
  176. text = BLOCKS.BUILDING_GARDEN.block..' '..quant..' '..BLOCKS.BUILDING_GARDEN.data..' {display:{Name:"Nature Resource",Lore:[Place this against a Detector to build greener, more open buildings]},CanPlaceOn:["'..BLOCKS.BUILDING_HOUSE.block..'","'..BLOCKS.PLUG.block..'","'..BLOCKS.DETECT.block..'"]}'
  177. return text
  178. end
  179.  
  180. PICKAXE_USES = 40
  181. pickaxe = 'stone_pickaxe 1 '..131-PICKAXE_USES..' {CanDestroy:["'..BLOCKS.BUILDING_HOUSE.block..'"],display:{Name:"Resource Remover",Lore:[Use the pickaxe to remove up to '..PICKAXE_USES..' resource blocks]}}'
  182.  
  183.  
  184.  
  185. STARTING_ITEMS = {
  186. houseBlock(30), gardenBlock(30),pickaxe
  187. }
  188.  
  189.  
  190. DEFAULT_NAME = 'BUILDING'
  191. --[[
  192. VOCAB_NAMES = {
  193. 'freestand-house',
  194. 'freestand-house',
  195. 'freestand-house',
  196. 'freestand-house',
  197. 'dbl-ext-house',
  198. 'dbl-ext-house',
  199. 'dbl-ext-house',
  200. 'dbl-ext-house',
  201. 'bridge-house',
  202. 'bridge-house',
  203. 'bridge-garden',
  204. 'bridge-garden',
  205. 'ext-house',
  206. 'ext-house',
  207. 'ext-house',
  208. 'ext-house',
  209. 'riser-1',
  210. 'riser-2',
  211. 'city-garden',
  212. 'city-plaza',
  213. 'dbl-ext-garden',
  214. 'dbl-ext-garden',
  215. 'dbl-ext-garden',
  216. 'dbl-ext-garden',
  217. 'ext-garden',
  218. 'ext-garden',
  219. 'ext-garden',
  220. 'ext-garden',
  221. 'corner-garden',
  222. 'corner-garden',
  223. 'corner-garden',
  224. 'corner-garden',
  225. 'corner-house',
  226. 'corner-house',
  227. 'corner-house',
  228. 'corner-house',
  229. 'freestand-garden',
  230. 'freestand-garden',
  231. 'freestand-garden',
  232. 'freestand-garden'
  233. }
  234. --]]
  235.  
  236.  
  237. ----------------------------------------------------------------------------------------------------------------
  238. -- the data structure below represents the catalogue of vocabularies as built in minecraft
  239. -- id - is unique for each vocab, starting from 1 going to 40 currently
  240. -- column and row - represent the "physical" location of the vocab model in the catalogue in the minecraft world
  241. -- nameEN and name DE - are names for english and german. for now english names must not have spaces, use dashes (-) instead
  242. -- typeEN and typeDE - are the type names, also in english and german such as tech&science spaces
  243. -- height - is how many blocks is this structure tall
  244. -- slots - is how many potential detector stones is this structure occupying as a building, ex. 2 for houses, 3 for corner extenstions, 0 for plazas
  245. -- green - is true or false and is used for easier calculation of the GREENEST GOAL - we dont use this field now and can be removed
  246. -- greenSlots - is how many slots are green and is used for easier calculation of the GREENEST GOAL
  247. VOCABS_DATA = {
  248. -- urban houses
  249. {id=1, column=1, row=1,nameEN="SINGLE-FAMILY-HOUSE",nameDE="EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=false, greenSlots=0, rewardUrban=false, rewardCount=4},
  250. {id=2, column=1, row=2,nameEN="SINGLE-FAMILY-HOUSE",nameDE="EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=false, greenSlots=0, rewardUrban=false, rewardCount=4},
  251. {id=3, column=1, row=3,nameEN="SINGLE-FAMILY-HOUSE",nameDE="EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=false, greenSlots=0, rewardUrban=false, rewardCount=4},
  252. {id=4, column=1, row=4,nameEN="SINGLE-FAMILY-HOUSE",nameDE="EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=false, greenSlots=0, rewardUrban=false, rewardCount=4},
  253. -- urban businesses
  254. {id=5, column=2, row=1,nameEN="GYM",nameDE="FITNESSSTUDIO", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=false, greenSlots=0, rewardUrban=false, rewardCount=8},
  255. {id=6, column=2, row=2,nameEN="OFFICE-BUILDING",nameDE="BÜROGEBÄUDE", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=false, greenSlots=0, rewardUrban=false, rewardCount=8},
  256. {id=7, column=2, row=3,nameEN="HOTEL",nameDE="HOTEL", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=false, greenSlots=0, rewardUrban=false, rewardCount=8},
  257. {id=8, column=2, row=4 ,nameEN="BANK",nameDE="BANK", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=false, greenSlots=0, rewardUrban=false, rewardCount=8},
  258. -- urban tech&science spaces
  259. {id=9, column=3, row=1,nameEN="LIBRARY",nameDE="BIBLIOTHEK", typeEN="TECH & SCIENCE SPACES",typeDE="WISSENSCHAFTSGEBÄUDE",height=16, slots=1, green=false, greenSlots=0, rewardUrban=false, rewardCount=10},
  260. {id=10, column=3, row=2,nameEN="FABLAB",nameDE="INNOVATIONSZENTRUM", typeEN="TECH & SCIENCE SPACES",typeDE="WISSENSCHAFTSGEBÄUDE",height=16, slots=1, green=false, greenSlots=0, rewardUrban=false, rewardCount=10},
  261. -- green tech&science spaces
  262. {id=11, column=3, row=3,nameEN="AQUAPONIC-GREENHOUSE",nameDE="AQUAPONIK-GEWÄCHSHAUS", typeEN="TECH & SCIENCE SPACES",typeDE="WISSENSCHAFTSGEBÄUDE",height=16, slots=1, green=true, greenSlots=1, rewardUrban=true, rewardCount=10},
  263. {id=12, column=3, row=4,nameEN="SCIENCE-BRIDGE",nameDE="WISSENSCHAFTSBRÜCKE", typeEN="TECH & SCIENCE SPACES",typeDE="WISSENSCHAFTSGEBÄUDE",height=16, slots=1, green=true, greenSlots=1, rewardUrban=true, rewardCount=10},
  264. -- urban house extensions
  265. {id=13, column=4, row=1,nameEN="HOUSE-EXTENSION",nameDE="HAUSERWEITERUNG", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=10, slots=1, green=false, greenSlots=0, rewardUrban=false, rewardCount=6},
  266. {id=14, column=4, row=2,nameEN="HOUSE-EXTENSION",nameDE="HAUSERWEITERUNG", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=10, slots=1, green=false, greenSlots=0, rewardUrban=false, rewardCount=6},
  267. {id=15, column=4, row=3,nameEN="HOUSE-EXTENSION",nameDE="HAUSERWEITERUNG", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=10, slots=1, green=false, greenSlots=0, rewardUrban=false, rewardCount=6},
  268. {id=16, column=4, row=4,nameEN="HOUSE-EXTENSION",nameDE="HAUSERWEITERUNG", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=10, slots=1, green=false, greenSlots=0, rewardUrban=false, rewardCount=6},
  269. --risers
  270. {id=17, column=5, row=1,nameEN="DOUBLE-FLOOR-RISER",nameDE="VERSCHIEBUNG-ZWEI-HOCH", typeEN="RISERS",typeDE="VERTIKALE VERSCHIEBUNGEN",height=0, slots=0, green=false, greenSlots=0, rewardUrban=true, rewardCount=8},
  271. {id=18, column=5, row=2,nameEN="SINGLE-FLOOR-RISER",nameDE="VERSCHIEBUNG-EINEN-HOCH", typeEN="RISERS",typeDE="VERTIKALE VERSCHIEBUNGEN",height=0, slots=0, green=false, greenSlots=0, rewardUrban=true, rewardCount=6},
  272. --plazas
  273. {id=19, column=5, row=3,nameEN="CITY-PLAZA",nameDE="STÄDTISCHER PLATZ", typeEN="PLAZAS",typeDE="PLÄTZE",height=0, slots=0, green=false, greenSlots=0, rewardUrban=false, rewardCount=2},
  274. {id=20, column=5, row=4,nameEN="PARK-PLAZA",nameDE="GRÜNER PLATZ", typeEN="PLAZAS",typeDE="PLÄTZE",height=0, slots=0, green=true, greenSlots=1, rewardUrban=true, rewardCount=2},
  275. --green businesses
  276. {id=21, column=6, row=1,nameEN="GREEN-GYM",nameDE="GRÜNES FITNESSSTUDIO", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=true, greenSlots=5, rewardUrban=true, rewardCount=8},
  277. {id=22, column=6, row=2,nameEN="GREEN-OFFICE-BUILDING",nameDE="GRÜNES BÜROGEBÄUDE", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=true, greenSlots=5, rewardUrban=true, rewardCount=8},
  278. {id=23, column=6, row=3,nameEN="GREEN-HOTEL",nameDE="GRÜNES HOTEL", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=true, greenSlots=5, rewardUrban=true, rewardCount=8},
  279. {id=24, column=6, row=4,nameEN="GREEN-BANK",nameDE="GRÜNES BANK", typeEN="BUSINESSES",typeDE="GESCHÄFTE",height=20, slots=5, green=true, greenSlots=5, rewardUrban=true, rewardCount=8},
  280. ---green private garden extensions
  281. {id=25, column=7, row=1,nameEN="HOUSE-GARDEN",nameDE="PRIVATGARTEN", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=0, slots=0, green=true, greenSlots=1, rewardUrban=true, rewardCount=6},
  282. {id=26, column=7, row=2,nameEN="HOUSE-GARDEN",nameDE="PRIVATGARTEN", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=0, slots=0, green=true, greenSlots=1, rewardUrban=true, rewardCount=6},
  283. {id=27, column=7, row=3,nameEN="HOUSE-GARDEN",nameDE="PRIVATGARTEN", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=0, slots=0, green=true, greenSlots=1, rewardUrban=true, rewardCount=6},
  284. {id=28, column=7, row=4,nameEN="HOUSE-GARDEN",nameDE="PRIVATGARTEN", typeEN="EXTENSIONS",typeDE="ERWEITERUNGEN",height=0, slots=0, green=true, greenSlots=1, rewardUrban=true, rewardCount=6},
  285. ---green gathering spaces
  286. {id=29, column=8, row=1,nameEN="OPEN-AIR-CINEMA",nameDE="FREILUFTKINO", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=true, greenSlots=3, rewardUrban=true, rewardCount=9},
  287. {id=30, column=8, row=2,nameEN="OPEN-AIR-SWIMMING-POOL",nameDE="FREIBAD", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=true, greenSlots=3, rewardUrban=true, rewardCount=9},
  288. {id=31, column=8, row=3,nameEN="GREEN-CAFE",nameDE="GRÜNES CAFÉ", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=true, greenSlots=3, rewardUrban=true, rewardCount=9},
  289. {id=32, column=8, row=4,nameEN="PALM-TREE-HOUSE",nameDE="PALMENGARTEN", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=true, greenSlots=3, rewardUrban=true, rewardCount=9},
  290. ----urban gathering spaces
  291. {id=33, column=9, row=1,nameEN="CINEMA",nameDE="KINO", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=false, greenSlots=0, rewardUrban=false, rewardCount=9},
  292. {id=34, column=9, row=2,nameEN="CONFERENCE-HALL",nameDE="KONFERENZHALLE", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=false, greenSlots=0, rewardUrban=false, rewardCount=9},
  293. {id=35, column=9, row=3,nameEN="CAFÉ",nameDE="CAFÉ", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=false, greenSlots=0, rewardUrban=false, rewardCount=9},
  294. {id=36, column=9, row=4,nameEN="ART-GALLERY",nameDE="KUNSTGALERIE", typeEN="GATHERING SPACES",typeDE="TREFFPUNKTE",height=8, slots=3, green=false, greenSlots=0, rewardUrban=false, rewardCount=9},
  295. ---green-roof houses
  296. {id=37, column=10, row=1,nameEN="GREEN-ROOF-HOUSE",nameDE="GRÜNES EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=true, greenSlots=2, rewardUrban=true, rewardCount=4},
  297. {id=38, column=10, row=2,nameEN="GREEN-ROOF-HOUSE",nameDE="GRÜNES EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=true, greenSlots=2, rewardUrban=true, rewardCount=4},
  298. {id=39, column=10, row=3,nameEN="GREEN-ROOF-HOUSE",nameDE="GRÜNES EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=true, greenSlots=2, rewardUrban=true, rewardCount=4},
  299. {id=40, column=10, row=4,nameEN="GREEN-ROOF-HOUSE",nameDE="GRÜNES EINFAMILIENHAUS", typeEN="HOUSES",typeDE="HÄUSER",height=10, slots=2, green=true, greenSlots=2, rewardUrban=true, rewardCount=4},
  300. }
  301.  
  302.  
  303. DEFAULT_REWARD = houseBlock(4)
  304.  
  305. REWARDS = {}
  306.  
  307.  
  308. --constructor for player object so that data structure is consistant
  309. function newPlayerData(name,x,y,z)
  310. local p = {
  311. name = name,
  312. x=x,
  313. y=y,
  314. z=z
  315. }
  316. return p
  317. end
  318.  
  319. --return a list of all players in the game world as player objects
  320. local function getAllPos(selector)
  321. local result, message = commands.tp("@a["..selector.."]","~ ~ ~")
  322. local names = {}
  323. if result == true then
  324. for i,result in ipairs(message) do
  325. local wordpattern = "[^, ]+"
  326. local numberpattern = "[%-% ]%d+[%.]%d+"
  327. local words,numbers = {},{}
  328.  
  329. for word in string.gmatch(result, wordpattern) do
  330. table.insert(words,word)
  331. end
  332.  
  333. for number in string.gmatch(result, numberpattern) do table.insert(numbers,number) end
  334.  
  335. local coords = {
  336. x = math.floor(numbers[1]),
  337. y = math.floor(numbers[2]),
  338. z = math.floor(numbers[3])
  339. }
  340. local name = words[2]
  341. table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
  342. --print("Player Found - getAllPos")
  343. end
  344. end
  345. return names
  346. end
  347.  
  348. --sort table by random
  349. local function shuffleTable( t )
  350. local rand = math.random
  351. assert( t, "shuffleTable() expected a table, got nil" )
  352. local iterations = #t
  353. local j
  354.  
  355. for i = iterations, 2, -1 do
  356. j = rand(i)
  357. t[i], t[j] = t[j], t[i]
  358. end
  359. end
  360.  
  361. --returns a list of player objects containing all players who are standing on the given block, and who also are in the given selection
  362. local function getAllOnBlockType(block,selector)
  363. local result, message = commands.exec("execute @a["..selector.."] ~ ~ ~ detect ~ ~-1 ~ "..block.." -1 tp @p[r=1] ~ ~ ~")
  364. local names = {}
  365. if result == true then
  366. for i,result in ipairs(message) do
  367. local wordpattern = "[^, ]+"
  368. local numberpattern = "[%-% ]%d+[%.]%d+"
  369. local words,numbers = {},{}
  370.  
  371. for word in string.gmatch(result, wordpattern) do table.insert(words,word) end
  372. for number in string.gmatch(result, numberpattern) do table.insert(numbers,number) end
  373.  
  374. if numbers[1] and numbers[2] and numbers[3] then
  375. local coords = {
  376. x = math.floor(numbers[1]),
  377. y = math.floor(numbers[2]),
  378. z = math.floor(numbers[3])
  379. }
  380. local name = words[2]
  381. table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
  382. print("Found a player - getOnBlock")
  383. else
  384. print("Error: Coordinate Numbers were missing")
  385. end
  386. end
  387. end
  388. return names
  389. end
  390.  
  391. --gives a player a HOMECOMER egg with their name on it. Removes all spawn eggs first
  392. local function giveHomecomer(name)
  393. commands.clear(name,'spawn_egg')
  394.  
  395. commands.give(name,'spawn_egg 1 '..HOMECOMER_VALUE..' {CanPlaceOn:["'..BLOCKS.PHVFLOOR.block..'","'..BLOCKS.CAMP_FLOOR.block..'","'..BLOCKS._matWhiteSmooth.block..'","'..BLOCKS._matWhiteSmooth2.block..'","'..BLOCKS._matYellowSmooth.block..'","'..BLOCKS._matPinkSmooth.block..'","'..BLOCKS._matBlueSmooth.block..'","'..BLOCKS._matPurpleSmooth.block..'","'..BLOCKS._matWhiteTextured.block..'","'..BLOCKS._matYellowTextured.block..'","'..BLOCKS._matPinkTextured.block..'","'..BLOCKS._matBlueTextured.block..'","'..BLOCKS._matPurpleTextured.block..'"],display:{Name:"HOMECOMER - '..name..'",Lore:[Use this on the floor to return to spawn]}}')
  396. end
  397.  
  398. --returns a list of HOMECOMER entities and their names
  399. local function getHomecomers()
  400. local result, message = commands.exec("execute @e[type="..HOMECOMER_TYPE.."] ~ ~ ~ tp @e[r=1] ~ ~ ~")
  401. local names = {}
  402. if result == true then
  403. for i,result in ipairs(message) do
  404. local wordpattern = "[^, ]+"
  405. local numberpattern = "[%-% ]%d+[%.]%d+"
  406. local words,numbers = {},{}
  407.  
  408. for word in string.gmatch(result, wordpattern) do table.insert(words,word) print(word) end
  409. for number in string.gmatch(result, numberpattern) do table.insert(numbers,number) end
  410.  
  411. if numbers[1] and numbers[2] and numbers[3] then
  412. local coords = {
  413. x = math.floor(numbers[1]),
  414. y = math.floor(numbers[2]),
  415. z = math.floor(numbers[3])
  416. }
  417. local name = words[4]
  418. table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
  419. print("Found a player - getOnBlock "..name)
  420. else
  421. print("Error: Coordinate Numbers were missing")
  422. end
  423. end
  424. end
  425. return names
  426. end
  427.  
  428. local function removePlayerFromKew(game,playername)
  429. for _,kew in pairs(game.queues) do
  430. for index, player in ipairs(kew.playerlist) do
  431. if player.name == playername then
  432. table.remove(kew.playerlist,index)
  433. end
  434. end
  435. if #kew.playerlist == 0 and kew.phase == 2 then
  436. --game can be ended as no players are left
  437. kew.timer = 0
  438. end
  439. end
  440. end
  441.  
  442. local function movePlayerToSpawn(playername)
  443. respawnPlayer(playername)
  444. commands.async.tp(playername,SPAWN.x,SPAWN.y,SPAWN.z,SPAWN.a1,SPAWN.a2)
  445. commands.async.tellraw(playername,'["",{"text":"You used your HOMECOMER and TELEPORTED BACK TO SPAWN","color":"white"}]')
  446. commands.async.tellraw(playername,'["",{"text":"Du hast den HEIMKEHRER benutzt um dich zurück zum Anfang zu teleportieren.","color":"gold"}]')
  447. end
  448.  
  449. --takes a list of homecomers and deals with all those players, moving them back to spawn and removing them from game
  450. --also gives them a new homecomer
  451. local function dealWithHomecomers(game, homecomers)
  452. for _,homecomer in pairs(homecomers) do
  453. --remove player from current game if in game
  454. removePlayerFromKew(game,homecomer.name)
  455. --teleport them back to spawn
  456. movePlayerToSpawn(homecomer.name)
  457. --give a new homecomer
  458. giveHomecomer(homecomer.name)
  459. --particle effects
  460. --teleport message
  461. end
  462. --kill all homecomers
  463. if #homecomers>0 then
  464. commands.tp("@e[type="..HOMECOMER_TYPE.."]",100000,200,100000)
  465. commands.kill("@e[type="..HOMECOMER_TYPE.."]")
  466. os.sleep(#homecomers*0.2)
  467. end
  468. end
  469.  
  470.  
  471.  
  472.  
  473. --creates a villager with special items
  474. local function spawnVillager(x,y,z)
  475. 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:'..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-PICKAXE_USES..',tag:{CanDestroy:["minecraft:wool"]}}} ]}}')
  476. end
  477.  
  478.  
  479. --displays a time as experience points to a selection of players
  480. local function displayTime(selector,minutes,seconds)
  481. --commands.title("@a["..selector.."]","subtitle",'{text:"Time left: '..minutes..":"..seconds..'",color:red,bold:false,underlined:false,italic:false,strikethrough:false,obfuscated:false}')
  482. commands.async.xp("-1000000L","@a["..selector.."]")
  483. local secondstot = (minutes * 60) + seconds
  484. commands.async.xp(tostring(secondstot).."L","@a["..selector.."]")
  485. end
  486.  
  487. --displays a title to a selection of players
  488. local function displayTitle(selector,text)
  489. commands.async.title("@a["..selector.."]","title",'{text:"'..text..'"}')
  490. end
  491.  
  492. --simply runs displayTitle on a list of players
  493. local function displayTitleToGroup(playerlist,text)
  494. for i,player in ipairs(playerlist) do
  495. displayTitle("name="..player.name,text)
  496. end
  497. end
  498.  
  499. --simply runs displayTime on a list of players
  500. local function displayTimeToGroup(playerlist,minutes,seconds)
  501. for i,player in ipairs(playerlist) do
  502. displayTime("name="..player.name,minutes,seconds)
  503. end
  504. end
  505.  
  506. --teleports a list of players to an exact place and sends them a message about it
  507. local function teleportToPoint(x,y,z,playerlist,clear,textEN, textDE)
  508. for i,player in ipairs(playerlist) do
  509. player.x = x
  510. player.y = y
  511. player.z = z
  512. commands.async.gamemode(2,player.name)
  513. if clear then
  514. commands.async.clear(player.name,"wool")
  515. commands.async.clear(player.name,"stone_pickaxe")
  516. end
  517. commands.tp("@a[name="..player.name.."]",x,y,z)
  518. commands.async.tellraw(player.name,'["",{"text":"'..textEN..'","color":"white"}]')
  519. commands.async.tellraw(player.name,'["",{"text":"'..textDE..'","color":"gold"}]')
  520. end
  521. end
  522.  
  523. --teleports a list of players to a given buildzone
  524. local function teleportToZone(buildzone,playerlist,textEN, textDE)
  525. teleportToPoint(buildzone.x+2+(buildzone.w/2),buildzone.y+5,buildzone.z+2+(buildzone.w/2),playerlist,true,textEN, textDE)
  526.  
  527. end
  528.  
  529. --gives the same list of items to a list of players
  530. local function giveItems(playerlist,itemlist)
  531. local given = 0
  532. for i,player in ipairs(playerlist) do
  533. --commands.async.clear(player.name)
  534. for j,item in ipairs(itemlist) do
  535. commands.async.give("@a[name="..player.name.."]",item)
  536. given = given +1
  537. end
  538. giveHomecomer(player.name)
  539. end
  540. return given
  541. end
  542.  
  543. --a multi builder which uses the vocab constructor to create sets of vocab
  544. local function makeVocabZones(quant,w)
  545. local x,y,z = FIRSTVOCAB.x, FIRSTVOCAB.y, FIRSTVOCAB.z
  546. local result = {}
  547. local id = 1
  548. for i=0,quant-1 do
  549. for k=0,3 do
  550. local zpos = i-4
  551. local ypos = k
  552. --print("vocab at X")
  553. --print(x-(2*w)-6)
  554. --print("and Z")
  555. --print(z+((w+1)*zpos))
  556. local nextVocab = newVocabZone(
  557. x-(2*w)-6,y+(ypos*(VOCAB_HEIGHT+3)),
  558. z+((w+1)*zpos),
  559. w,
  560. id,
  561. REWARDS[id] or DEFAULT_REWARD,
  562. VOCABS_DATA[id].nameEN or DEFAULT_NAME,
  563. VOCABS_DATA[id].nameDE or DEFAULT_NAME,
  564. VOCABS_DATA[id].typeEN,
  565. VOCABS_DATA[id].typeDE,
  566. VOCABS_DATA[id].height,
  567. VOCABS_DATA[id].slots,
  568. VOCABS_DATA[id].green,
  569. VOCABS_DATA[id].greenSlots,
  570. VOCABS_DATA[id].rewardUrban,
  571. VOCABS_DATA[id].rewardCount
  572. )
  573. table.insert(result,nextVocab)
  574. id = id +1
  575. end
  576. end
  577. return result
  578. end
  579.  
  580. --finds the next free location(or buildzone) for a new game in a given area.
  581. --giving force as True will mean it overrides the first location no matter what
  582. local function findNextLoc(width,zones,force)
  583. local x,y,z,locid = 0,0,0,1
  584. for i,loc in ipairs(LOCS) do
  585. locid = i
  586. x,y,z = FIRSTZONE.x+(loc.x*(width+1)),FIRSTZONE.y,FIRSTZONE.z+(-loc.z*(width+1)) -- these are the coordinates of this LOC in the minecraft world
  587. --print("testing for available zone at: "..x..", "..y..", "..z)
  588. --print("which is at grid cell at: "..loc.x..", "..loc.z)
  589. --local result,message = commands.testforblock(x,y+BUILDZONE_FLOOR_HEIGHT,z,"minecraft:air") -- this was used for the testing based on the minecraft model
  590. local result = true
  591. if loc.played then
  592. result = false
  593. print("zone has been played")
  594. end
  595. --print("testing done")
  596. --force the first zone to be selected unless it is taken in the "zones" parameter
  597. if force then result = true end
  598. --checks if the zone is already in the list of unavailable zones passed as parameter
  599. local zonefree = true
  600. for i,zone in ipairs(zones) do
  601. if zone.x == x and zone.z == z then
  602. zonefree = false
  603. end
  604. end
  605. --print("next position free is ",loc.x*width,oy,loc.z*width)
  606. --if result then print("true") else print("false") end
  607. if result and zonefree then
  608. --print("using loc: ",loc.x,loc.z)
  609. return x,y,z,locid --returns the coordinates of the new zone, plus its id in the LOCS table
  610. end
  611. end
  612. return nil,nil,nil, nil --returns empty if no zone is available
  613.  
  614. end
  615.  
  616. --relocates a buildzone to a new coordinate safely
  617. --avoids overlapping with other buildzones
  618. function moveBuildzone(buildzone,zones)
  619. local x,y,z,locid = findNextLoc(buildzone.w,zones)
  620. if x and y and z and locid then
  621. print("moved buildzone from "..buildzone.x..","..buildzone.z.." to "..x..","..y)
  622. local w = buildzone.w
  623. buildzone.x,buildzone.y,buildzone.z = x,y+BUILDZONE_FLOOR_HEIGHT,z
  624. buildzone.locid = locid --reassign the location id corresponding to the LOCS item for the grid cell of the moved zone
  625. buildzone.selector = "x="..x..",y="..tostring(y-1)..",z="..z..",dx="..w..",dy=256,dz="..w
  626. buildzone.structures = {} --a list of all vocabularies which have been contructed
  627. else
  628. print("buildzone at "..buildzone.x..","..buildzone.z.." stayed where it is")
  629. end
  630. end
  631.  
  632. --multi builder to create sets of buildzones using the buildzone constructor
  633. local function makeBuildzones(quant,vocab,width,floorHeight)
  634. local result = {}
  635. for i=1,quant do
  636. --print("locating available slot")
  637. local x,y,z,locid = findNextLoc(width,result)
  638. if x and y and z and locid then
  639. --print("made new buildzone at",x,y,z)
  640. table.insert(result,newBuildZone(x,y+floorHeight,z,width,vocab,locid))
  641. else
  642. --print("failed to make new buildzone")
  643. end
  644. end
  645.  
  646. local remaining = NUMBER_OF_BUILDZONES - #result
  647. --print("doing this remaining thing")
  648. for i=1, remaining do
  649. local x,y,z,locid = findNextLoc(width,result,true)
  650. if x and y and z and locid then
  651. --print("forced new buildzone at",x,y,z)
  652. table.insert(result,newBuildZone(x,y+floorHeight,z,width,vocab, locid))
  653. else
  654. print("failed to force new buildzone")
  655. end
  656. end
  657.  
  658.  
  659. return result
  660. end
  661.  
  662. --vocab constructor. Enforces some data structure
  663. function newVocabZone(x,y,z,w,id, reward,nameEN, nameDE, typeEN, typeDE, height, slots,green,greenSlots, rewardUrban, rewardCount)
  664. local nvz = {}
  665. nvz.x ,nvz.y ,nvz.z ,nvz.w = x,y,z,w
  666.  
  667. nvz.cx = nvz.x - nvz.w - 2
  668. nvz.cy = nvz.y
  669. nvz.cz = nvz.z
  670. nvz.nameEN = nameEN
  671. nvz.reward = reward
  672. --- new stuff
  673. nvz.id = id
  674. nvz.nameDE = nameDE
  675. nvz.typeEN = typeEN
  676. nvz.typeDE = typeDE
  677. nvz.height = height
  678. nvz.slots = slots
  679. nvz.green = green
  680. nvz.greenSlots = greenSlots
  681. nvz.rewardUrban = rewardUrban
  682. nvz.rewardCount = rewardCount
  683.  
  684. return nvz
  685.  
  686. end
  687.  
  688. --buildzone constructor. Enforces some data structure
  689. function newBuildZone(x,y,z,w,vocabZones,locid)
  690. local nbz = {}
  691. nbz.x ,nbz.y ,nbz.z ,nbz.w = x,y,z,w
  692. nbz.selector = "x="..x..",y="..(y-5)..",z="..z..",dx="..w..",dy=256,dz="..w
  693. nbz.structures = {} --a list of all vocabularies names which have been contructed
  694. nbz.buildings = {} --a list of all vocabularies with full data (x,y,z,id,name) which have been contructed
  695. nbz.filledSlots = 0 --to count how many slots have been filled with buildings. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
  696. nbz.greenSlots = 0 --to count how many of the slots are green. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
  697. 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
  698. nbz.waitingForCheck = {}
  699. nbz.highest = 0
  700. nbz.vocab = vocabZones
  701. nbz.locid = locid
  702.  
  703. return nbz
  704. end
  705.  
  706. --kew constructor. Enforces some data structure
  707. function newQueue(buildzone,maxplayers)
  708. local q = {}
  709. q.timer = 1
  710. q.phase = 1
  711.  
  712. q.victory = false
  713. q.phases = {
  714. {
  715. name = "Selecting Players",
  716. length = PHASE_LENGTH_WAIT,
  717. displaylength = 15 --this field is not used
  718. },
  719. {
  720. name = "Game In Progress",
  721. length = PHASE_LENGTH_GAME,
  722. displaylength = 70 --this field is not used
  723. },
  724. {
  725. name = "Round Complete",
  726. length = PHASE_LENGTH_OVER,
  727. displaylength = 5 --this field is not used
  728. }
  729. }
  730. q.playerlist = {}
  731. q.maxplayers = maxplayers
  732. q.buildzone = buildzone
  733.  
  734. return q
  735. end
  736.  
  737.  
  738. --creates a ring of blocks using coordinates
  739. function fillRing(x,y,z,w,block)
  740. commands.fill(x,y,z,x+w,y,z,block)
  741. commands.fill(x+w,y,z,x+w,y,z+w,block)
  742. commands.fill(x,y,z+w,x+w,y,z+w,block)
  743. commands.fill(x,y,z+w,x,y,z,block)
  744. end
  745.  
  746. function setup()
  747. print("debug: starting setup function.")
  748. local game = {}
  749. game.vocab = {}
  750. game.builds = {}
  751. game.queues = {}
  752. game.waitlist = {}
  753. game.spawn = SPAWN
  754. game.lastClock = os.clock()
  755. game.nowTime = os.clock()
  756.  
  757. --generate vocab rewards
  758. for i=1,#VOCABS_DATA do
  759. if VOCABS_DATA[i].rewardUrban then
  760. REWARDS[i] = houseBlock(VOCABS_DATA[i].rewardCount)
  761. else
  762. REWARDS[i] = gardenBlock(VOCABS_DATA[i].rewardCount)
  763. end
  764. end
  765.  
  766. --kill all villagers
  767. commands.exec("kill @e[type=Villager]")
  768.  
  769. --buildzone and vocabzone creation
  770. print("debug-setup: making vocab zones.")
  771. game.vocab = makeVocabZones(NUMBER_OF_VOCAB,VOCAB_WIDTH)
  772. print("debug-setup: making building zones.")
  773. --game.builds appears to store the games currently in progress
  774. game.builds = makeBuildzones(NUMBER_OF_BUILDZONES,game.vocab,BUILDZONE_WIDTH,BUILDZONE_FLOOR_HEIGHT)
  775.  
  776. for i,build in ipairs(game.builds) do
  777. table.insert(game.queues,newQueue(build, MAX_PLAYERS_PER_GAME))
  778. end
  779. print("debug-setup: testing for properly setup vocabs.")
  780. for i,vz in ipairs(game.vocab) do
  781. local x,y,z,w = vz.x,vz.y,vz.z,vz.w
  782. local cx,cy,cz = vz.cx,vz.cy,vz.cz
  783.  
  784. local detector, message1 = commands.testforblock(x+(math.floor(w/2)),y,z+(math.floor(w/2)),BLOCKS.DETECT.block)
  785. local blocker, message2 = commands.testforblock(x+(math.floor(w/2)),y,z+(math.floor(w/2)),BLOCKS.DETECT_DEAD.block)
  786. if not (detector or blocker) then
  787. for nx=0,2 do
  788. for nz=0,2 do
  789. commands.setblock(x+(nx*9)+4,y-1,z+(nz*9)+4,BLOCKS.VOCAB_REPLACE.block)
  790. commands.setblock(cx+(nx*9)+4,cy-1,cz+(nz*9)+4,BLOCKS.VOCAB_DETECT.block)
  791. end
  792. end
  793. commands.setblock(x+(math.floor(w/2)),y,z+(math.floor(w/2)),BLOCKS.DETECT_DEAD.block)
  794.  
  795. end
  796.  
  797. end
  798.  
  799. print("debug-setup: adding scoreboards.")
  800.  
  801. --print(#VOCABS_DATA)
  802. for i=1,#VOCABS_DATA do
  803. commands.scoreboard("objectives","add","building_"..i,"dummy")
  804. end
  805.  
  806. --commands.gamerule("doDaylightCycle",false) -- this is included in the spawn controller script
  807. commands.gamerule("keepInventory",true)
  808. --commands.gamerule("doTileDrops",false) -- this is included in the spawn controller script
  809. --commands.gamerule("logAdminCommands",false) -- this is included in the spawn controller script
  810. --commands.gamerule("commandBlockOutput",false) -- this is included in the spawn controller script
  811. --commands.time("set",6000) -- this is included in the spawn controller script
  812. commands.scoreboard("objectives","add","highscores","dummy","Best Neighbourhoods")
  813. commands.scoreboard("objectives","add","VillagerLife","dummy")
  814. commands.scoreboard("objectives","add","built","dummy", "Structures Built")
  815. commands.scoreboard("objectives","add","highest","dummy", "Personal Highest")
  816. commands.scoreboard("objectives","add","played","dummy","Games Played")
  817.  
  818. commands.title("@a","times",0,30,30) -- what does this do?
  819.  
  820. math.randomseed( os.time() )
  821. commands.scoreboard("objectives","setdisplay","sidebar","highscores")
  822. commands.scoreboard("objectives","setdisplay","list","played")
  823.  
  824. --print("time is: "..os.time())
  825. --print( "time is: "..textutils.formatTime( os.time(), false ) )
  826. --print("day is: "..os.day())
  827. print("computer clock is: "..os.clock())
  828.  
  829. if DEBUG_MODE then
  830. for i,build in ipairs(game.builds) do
  831. build.phase = 2
  832. build.timer = 500
  833. end
  834. end
  835.  
  836. print("Computer Co-ordinates ",ox,oy,oz)
  837. print("20.000 Blocks Active!")
  838.  
  839. return game
  840. end
  841.  
  842. function checkForHomecomers(game)
  843. --execute on all homecomers
  844. local homecomers = getHomecomers()
  845. dealWithHomecomers(game,homecomers)
  846. end
  847.  
  848. --main game loop
  849. --runs the game object through each of these update steps in order
  850. function update(game)
  851. local elapsed = updateClock(game)
  852. --update players
  853. checkPlayers(game)
  854. doTimerUpdates(game,elapsed)
  855. doPhaseUpdates(game)
  856. doPhaseEnds(game)
  857. checkBoundaries(game)
  858. checkForHomecomers(game)
  859. if #game.waitlist > 0 then allocateWaiters(game) end
  860. end
  861.  
  862. --calculates elapsed time during a game tick
  863. function updateClock(game)
  864. game.nowTime = os.clock()
  865. local elapsed = game.nowTime - game.lastClock
  866. game.lastClock = game.nowTime
  867. return elapsed
  868. end
  869.  
  870. --updates all kews in the game object based on elapsed time
  871. function doTimerUpdates(game,elapsed)
  872. for i,kew in ipairs(game.queues) do
  873. kew.timer = kew.timer - elapsed
  874. end
  875. end
  876.  
  877. --check players are inside their buildzone and move them back if not
  878. function checkBoundaries(game)
  879. for i,kew in ipairs(game.queues) do
  880. if kew.phase ==2 then
  881. --boundaries
  882. local x_min = kew.buildzone.x
  883. local x_max = kew.buildzone.x+kew.buildzone.w
  884. local z_min = kew.buildzone.z
  885. local z_max = kew.buildzone.z+kew.buildzone.w
  886.  
  887. local toBeCorrected = {}
  888.  
  889. for j,player in ipairs(kew.playerlist) do
  890. local listOfOne = getAllPos('m=2,name='..player.name)
  891. if listOfOne and listOfOne[1] then
  892. player.x = listOfOne[1].x
  893. player.y = listOfOne[1].y
  894. player.z = listOfOne[1].z
  895. local changed = false
  896. if player.x > x_max then
  897. changed = true
  898. player.x = x_max-2
  899. end
  900. if player.x < x_min then
  901. changed = true
  902. player.x = x_min+2
  903. end
  904. if player.z > z_max then
  905. changed = true
  906. player.z = z_max-2
  907. end
  908. if player.z < z_min then
  909. changed = true
  910. player.z = z_min+2
  911. end
  912. if changed then teleportToPoint(player.x,kew.buildzone.y,player.z,{player},false,"TELEPORTED BACK TO GAME: Please stay inside the building zone or use HOMECOMER to leave the game!", "Zurück ins Spiel teleportiert: Bitte bleib innerhalb des Baufeldes oder nutze den HEIMKEHRER um das Spiel zu verlassen!") end
  913. end
  914. end
  915. end
  916. end
  917. end
  918.  
  919.  
  920. --here you can set the logic which determines if a buildzone was valuable.
  921. --Return true if it is crap and should be replaced
  922. function checkIfBuildzoneIsCrap(buildzone)
  923. if #buildzone.structures < MIN_BUILDINGS then
  924. print("Buildzone was crap")
  925. return true
  926. end
  927. print("Buildzone was ok")
  928. return false
  929. end
  930.  
  931.  
  932. --Everything that happens after a buildzone was completed
  933. --due to time limit.
  934. function cleanAfterGameOver(kew)
  935. local buildzone = kew.buildzone
  936. commands.async.setblock(buildzone.x,buildzone.y,buildzone.z,BLOCKS.VICTORY_MARKER.block)
  937. fillRing(buildzone.x,buildzone.y,buildzone.z,buildzone.w,"minecraft:air",0,"replace",BLOCKS.CONSTRUCTION.block,BLOCKS.CONSTRUCTION.data)
  938. for h=0,256-buildzone.y do
  939. 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",BLOCKS.DETECT.block,BLOCKS.DETECT.data)
  940. 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",BLOCKS.PLUG.block,BLOCKS.PLUG.data)
  941. 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",BLOCKS.BUILDING_GARDEN.block,BLOCKS.BUILDING_GARDEN.data)
  942. 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",BLOCKS.BUILDING_HOUSE.block,BLOCKS.BUILDING_HOUSE.data)
  943. end
  944. commands.async.fill(buildzone.x,buildzone.y-1,buildzone.z,buildzone.x+buildzone.w,buildzone.y-1,buildzone.z+buildzone.w,BLOCKS.CAMP_FLOOR.block,BLOCKS.CAMP_FLOOR.data,"replace",BLOCKS.PLUG.block,BLOCKS.PLUG.data)
  945. commands.async.fill(buildzone.x,buildzone.y,buildzone.z,buildzone.x+buildzone.w,buildzone.y,buildzone.z+buildzone.w,BLOCKS.PHVFLOOR.block,BLOCKS.PHVFLOOR.data,"replace","minecraft:air","0")
  946.  
  947. ---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
  948.  
  949. local wasCrap = checkIfBuildzoneIsCrap(buildzone)
  950. local gameovermessageEN
  951. local gameovermessageDE
  952. if wasCrap then
  953. --mark this buildzone for replacement
  954. --change the flag to played=false
  955. updateZonePlayedState(buildzone,false)
  956. gameovermessageEN = "Thank you for playing IBA_GAME! This game will be discarded because you built less than "..MIN_BUILDINGS.." buildings. Play another game or check what others have built at: www.20000blocks.com"
  957. gameovermessageDE = "Vielen Dank, dass du IBA_GAME gespielt hast! Diese Runde wird verworfen, da weniger als "..MIN_BUILDINGS.." Gebäude gebaut wurden. Starte eine neue Runde oder schau dir die Spielergebnisse anderer Spieler an unter: www.2000blocks.com"
  958.  
  959. else
  960. --change the flag to played=true
  961. updateZonePlayedState(buildzone,true)
  962.  
  963. gameovermessageEN = "Thank you for playing IBA_GAME! Play another game or look for your game result at: www.20000blocks.com"
  964. gameovermessageDE = "Vielen Dank, dass du IBA_GAME gespielt hast! Starte eine neue Runde oder schau dir deine Spielergebnisse an unter: www.20000blocks.com"
  965. end
  966.  
  967. for _, player in ipairs(kew.playerlist) do
  968. -- announce success in English
  969. commands.async.tellraw(player.name,'["",{"text":"'..gameovermessageEN..'","color":"white"}]')
  970. -- announce success in German
  971. commands.async.tellraw(player.name,'["",{"text":"'..gameovermessageDE..'","color":"gold"}]')
  972. end
  973.  
  974. end
  975.  
  976. function updateZonePlayedState(buildzone, newstate)
  977. --change the flag to played=newstate
  978. LOCS[buildzone.locid].played = newstate
  979. --and write the LOCS object to the json file
  980. writeGridToFile()
  981. end
  982.  
  983. --these happen every tick and require the game object
  984. --updates are performed on each Queue (kew) and within each
  985. --of those on each buildzone.
  986. function doPhaseUpdates(game)
  987. for i,kew in ipairs(game.queues) do
  988.  
  989. local minutes = string.format("%02d",math.floor(kew.timer/60))
  990. local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
  991. if kew.timer <= 0 then
  992. minutes = "00"
  993. seconds = "00"
  994. end
  995.  
  996. if kew.phase == 1 then
  997. --waiting phase
  998. if #kew.playerlist == kew.maxplayers and kew.timer > 5 then kew.timer = 5 end
  999. if not DEBUG_MODE and #kew.playerlist == 0 then kew.timer = kew.phases[1].length end
  1000.  
  1001. displayTitleToGroup(kew.playerlist,"Game starting!")
  1002. displayTimeToGroup(kew.playerlist,minutes,seconds)
  1003. --show countdown
  1004. elseif kew.phase == 2 then
  1005. --playing phase
  1006. if #kew.playerlist == 0 then timer = 0 end -- finish if all players quit
  1007. -- do vocab logic
  1008. local victory = updatePlayedZone(kew.buildzone) --currently victory updatePlayedZone returns always false
  1009. --
  1010. displayTimeToGroup(kew.playerlist,minutes,seconds)
  1011.  
  1012. elseif kew.phase == 3 then
  1013. --end phase
  1014. displayTitleToGroup(kew.playerlist,"Use HOMECOMER to return")
  1015. --displayTimeToGroup(kew.playerlist,minutes,seconds)
  1016.  
  1017.  
  1018. end
  1019. end
  1020. end
  1021.  
  1022. --this runs after a buildzone is completed
  1023. --it should tally structure types and set scoreboard highscores
  1024. --it also rewards all participants with more played score
  1025. function processHighscores(kew)
  1026. local buildzone = kew.buildzone
  1027.  
  1028.  
  1029.  
  1030. --add score to players who finished this game
  1031. for _,player in ipairs(kew.playerlist) do
  1032. commands.async.scoreboard("players","add",player.name,"played",1)
  1033. end
  1034. end
  1035.  
  1036. --function to export a buildzone detail once it is complete
  1037. --requires a kew so it can access the playerlist
  1038. local function exportKewData(kew)
  1039. local buildzone = kew.buildzone
  1040. local saved = {}
  1041. saved.position =
  1042. {
  1043. x=buildzone.x,
  1044. y=buildzone.y,
  1045. z=buildzone.z
  1046. }
  1047. local timestamp = math.floor(os.clock())
  1048. --saved.timeCompleted = timestamp
  1049. saved.players = {}
  1050. for _, player in ipairs(kew.playerlist) do
  1051. table.insert(saved.players,player.name)
  1052. end
  1053. --saved.structures = buildzone.structures
  1054. saved.buildings = buildzone.buildings
  1055. saved.totals = tracker.tallyTable(buildzone.structures)
  1056. --saved.highest = buildzone.highest
  1057. saved.stats = {
  1058. cityVersion = CITY_VERSION,
  1059. height = buildzone.highest,
  1060. densityIndex = math.floor(100*buildzone.filledSlots/49), -- the density index is made from built area (filledSlots) over the ground area (7x7 slots = 49)
  1061. greenIndex = math.floor(100*buildzone.greenSlots/49), --the green index is made from green area (greenSlots) over the ground area (7x7 slots = 49)
  1062. variety = tablelength(buildzone.variety),
  1063. timeCompleted = timestamp,
  1064. gameLength = PHASE_LENGTH_GAME
  1065. }
  1066.  
  1067. fs.makeDir("/records")
  1068.  
  1069. filename = timestamp.."at"..buildzone.x.."_"..buildzone.z
  1070. local file = fs.open("/records/"..filename..".yaml","w")
  1071.  
  1072. filecontent = json.encodePretty(saved)
  1073. file.write(filecontent)
  1074.  
  1075.  
  1076. local test = http.get("http://www.20000blocks.com/DatabaseAccess/GetVersion.php")
  1077. if test then
  1078. print("test is valid:"..test)
  1079. else
  1080. print("test is nil")
  1081. end
  1082.  
  1083.  
  1084. local link = http.post(
  1085. "http://www.20000blocks.com/DatabaseAccess/UploadModel.php",
  1086. "name="..textutils.urlEncode(filename).."&"..
  1087. "content="..textutils.urlEncode(filecontent).."&"..
  1088. "x="..buildzone.x.."&"..
  1089. "z="..buildzone.z
  1090. )
  1091.  
  1092.  
  1093. if 0 == 1 then --this currently doesnt work because the link variable is all the time nil
  1094.  
  1095. print(link.getResponseCode())
  1096. if link.readAll() then
  1097. local linkmsgEN = 'The latest game result has been uploaded to the webviewer and can be seen at:'..link.readAll()
  1098. local linkmsgDE = 'Die neueste Runde wurde in den Webviewer geladen und kann hier angeschaut werden:'..link.readAll()
  1099. -- announce success in English
  1100. commands.async.tellraw("@a",'["",{"text":"'..linkmsgEN..'","color":"white"}]')
  1101. --announce success in German
  1102. commands.async.tellraw("@a",'["",{"text":"'..linkmsgDE..'","color":"gold"}]')
  1103. end
  1104. end
  1105.  
  1106. file.close()
  1107. end
  1108.  
  1109. 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)
  1110. http.post(
  1111. "http://www.20000blocks.com/DatabaseAccess/SwitchVersion.php",
  1112. "id="..textutils.urlEncode(id).."&"..
  1113. "relative="..textutils.urlEncode(relative)
  1114. )
  1115. end
  1116.  
  1117. --this code runs ONCE at the end of each phase
  1118. --what actually happens is specific to which phase the
  1119. --particular kew is in.
  1120. function doPhaseEnds(game)
  1121. for i,kew in ipairs(game.queues) do
  1122. if kew.timer <= 0 then
  1123. if kew.phase == 1 then
  1124. --waiting phase ends goto play phase
  1125.  
  1126. moveBuildzone(kew.buildzone,game.builds) --what does this do?
  1127. teleportToZone(kew.buildzone,kew.playerlist,"Your game has started! BUILD A HOUSE!", "Das Spiel hat begonnen! BAUE EIN HAUS!")--teleport selected players
  1128. cleanBuildzone(kew.buildzone)
  1129. prepareBuildzone(kew.buildzone)--prepare build zone
  1130. giveItems(kew.playerlist,STARTING_ITEMS) --give starting items
  1131. displayTitle(kew.buildzone.selector,"BUILD!")
  1132. kew.victory = false
  1133. --displayTime(kew.buildzone.selector,0,0)
  1134. kew.phase = 2
  1135. kew.timer = kew.phases[kew.phase].length
  1136. elseif kew.phase == 2 then
  1137. --playing phase ends goto end phase
  1138. processHighscores(kew)
  1139. exportKewData(kew)
  1140. cleanAfterGameOver(kew)
  1141. kew.phase = 3
  1142. --displayTime(kew.buildzone.selector,0,0)
  1143. kew.timer = kew.phases[kew.phase].length
  1144. elseif kew.phase == 3 then
  1145. --end phase ends goto waiting phase
  1146. removePlayersFromKew(game,kew)
  1147. kew.phase = 1
  1148. --displayTime(kew.buildzone.selector,0,0)
  1149. kew.timer = kew.phases[kew.phase].length
  1150. end
  1151. end
  1152. end
  1153. end
  1154.  
  1155.  
  1156. --Replaces everything that is needed to start the game. Does not rebuild the floor, or clear anything away.
  1157. --based on the settings it creates a full grid, or a partial grid, or no grid
  1158. --it also places the ring, although this is disabled for now
  1159. function prepareBuildzone(buildzone)
  1160. local bz = buildzone
  1161. local x,y,z,w = bz.x,bz.y,bz.z,bz.w
  1162.  
  1163. commands.async.fill(x,y-1,z,x+w,y-1,z+w,BLOCKS.CAMP_FLOOR.block) --place the white grid accross the full buildzone as a base
  1164.  
  1165. fillRing(buildzone.x,buildzone.y-1,buildzone.z,buildzone.w,BLOCKS.CONSTRUCTION.block) --this draws the construction stripe around the buildzone
  1166. --create the grid of detectors surrounded by plus plugs
  1167. if DO_GRID then
  1168. for x=0,GRIDCELL_COUNT-1 do
  1169. for z=0,GRIDCELL_COUNT-1 do
  1170. local rand = math.random()*100
  1171. --local result, text = commands.testforblock(bz.x+(x*9)+4,bz.y-1,bz.z+(z*9)+4,BLOCKS.CAMP_FLOOR.block)
  1172. if rand > GRID_HOLE_CHANCE then --and result then
  1173. local halfCell = math.floor(GRIDCELL_SIZE/2)
  1174. commands.async.setblock(bz.x+(x*GRIDCELL_SIZE)+halfCell,bz.y,bz.z+(z*GRIDCELL_SIZE)+halfCell,BLOCKS.DETECT.block,BLOCKS.DETECT.data,"replace","minecraft:air")
  1175. commands.async.fill(bz.x+(x*GRIDCELL_SIZE)+halfCell-PLUG_LENGTH, bz.y-1,bz.z+(z*GRIDCELL_SIZE)+halfCell,bz.x+(x*GRIDCELL_SIZE)+halfCell+PLUG_LENGTH,bz.y-1,bz.z+(z*GRIDCELL_SIZE)+halfCell,BLOCKS.PLUG.block)
  1176. commands.async.fill(bz.x+(x*GRIDCELL_SIZE)+halfCell,bz.y-1,bz.z+(z*GRIDCELL_SIZE)+halfCell-PLUG_LENGTH,bz.x+(x*GRIDCELL_SIZE)+halfCell,bz.y-1,bz.z+(z*GRIDCELL_SIZE)+halfCell+PLUG_LENGTH,BLOCKS.PLUG.block)
  1177. end
  1178. end
  1179. end
  1180. end
  1181. --mark the game in the LOCS array as not available anymore, and save the updated game grid to the grid file
  1182. --change the flag to played=true
  1183. updateZonePlayedState(buildzone,true)
  1184. end
  1185.  
  1186. --deletes everything inside the buildzone
  1187. function cleanBuildzone(buildzone)
  1188. print("Cleaning buildzone")
  1189. for h=buildzone.y,255 do
  1190. commands.async.fill(buildzone.x,h,buildzone.z,buildzone.x+buildzone.w,h,buildzone.z+buildzone.w,"minecraft:air")
  1191. end
  1192. end
  1193.  
  1194. function removePlayersFromKew(game,kew)
  1195. for _, player in ipairs(kew.playerlist) do
  1196. --commands.tell(player.name,"Your game is over. Use your Heimkehrer to return to spawn")
  1197. -- announce success in English
  1198. commands.async.tellraw(player.name,'["",{"text":"TIME OUT! GAME COMPLETE! Use your HOMECOMER to return to spawn.","color":"white"}]')
  1199. -- announce success in German
  1200. commands.async.tellraw(player.name,'["",{"text":"ENDE! SPIEL ABGESCHLOSSEN! Nutze den HEIMKEHRER um zum Anfang zurück zu kehren.","color":"gold"}]')
  1201. end
  1202. kew.playerlist = {}
  1203. end
  1204.  
  1205. function respawnPlayer(playername,message)
  1206. commands.tell(playername,message)
  1207. commands.async.gamemode(2,playername)
  1208. commands.async.clear(playername,"minecraft:wool")
  1209. commands.async.clear(playername,"minecraft:stone_pickaxe")
  1210. end
  1211.  
  1212. function checkForPlayerInBuildzone(player,buildzone)
  1213. local result,message = commands.testfor('@a[name='..player.name..','..buildzone.selector..']')
  1214. return result
  1215. end
  1216.  
  1217. function checkForPlayerInWaitzone(player)
  1218. local selector = "x="..WAITZONE.x..",y="..WAITZONE.y..",z="..WAITZONE.z..",dx="..WAITZONE.w..",dy=256,dz="..WAITZONE.l
  1219. local result,message = commands.testfor('@a[name='..player.name..','..selector..']')
  1220. return result
  1221. end
  1222.  
  1223. function checkPlayers(game)
  1224. local selector = "x="..WAITZONE.x..",y="..WAITZONE.y..",z="..WAITZONE.z..",dx="..WAITZONE.w..",dy=256,dz="..WAITZONE.l
  1225. local loggedIn = getAllPos('m=2,'..selector)
  1226. --refresh waitlist
  1227. game.waitlist = loggedIn
  1228. --check currently playing players
  1229. for l,kew in ipairs(game.queues) do
  1230. for i,builder in ipairs(kew.playerlist) do
  1231. local isPlaying = checkForPlayerInBuildzone(builder,kew.buildzone)
  1232. --remove players who are already in kews from the waitlist
  1233. for j, player in ipairs(loggedIn) do
  1234. if player.name == builder.name then
  1235. table.remove(loggedIn,j)
  1236. end
  1237. end
  1238. --if the game is in progress and the player is not found then remove them from the gamekew
  1239. if not isPlaying and kew.phase == 2 then
  1240. --table.remove(kew.playerlist,i)
  1241. --print("Removed "..builder.name.." from game in progress")
  1242. end
  1243. end
  1244. end
  1245. end
  1246.  
  1247. --adds players who wait in the orange room to slots in waiting buildzones
  1248. function allocateWaiters(game)
  1249. --find free slots
  1250. local freeslots = {}
  1251. for i, kew in ipairs(game.queues) do
  1252. if kew.phase == 1 and #kew.playerlist < kew.maxplayers then
  1253. local slots = kew.maxplayers - #kew.playerlist
  1254. for j=1,slots do
  1255. table.insert(freeslots,kew)
  1256. end
  1257. end
  1258. end
  1259.  
  1260. --RE-ENABLE SECOND SHUFFLETABLE IF YOU WANT RANDOM PLAYER MATCHUPS
  1261. shuffleTable(game.waitlist)
  1262. --shuffleTable(freeslots)
  1263.  
  1264. while #freeslots > 0 and #game.waitlist > 0 do
  1265. local player = table.remove(game.waitlist,1)
  1266. local freeslot = table.remove(freeslots,1).playerlist
  1267. table.insert(freeslot,player)
  1268. end
  1269. end
  1270.  
  1271. --PARTICLE FUNCTIONS
  1272. --particles shown to player while their shape is being checked for match
  1273. function searchParticle(x,y,z)
  1274. commands.async.particle("fireworksSpark",x,y,z,0.01,3,0.01,0.01,100)
  1275. end
  1276. -- particles shown to player on successful vocab match
  1277. function successParticle(x,y,z)
  1278. commands.async.particle("happyVillager",x,y,z,2,2,2,1,1000)
  1279. commands.async.playsound("random.levelup","@a",x,y,z,1,1.2)
  1280. end
  1281. --- particles shown to player on failed vocab match
  1282. function failParticle(x,y,z)
  1283. commands.async.particle("reddust",x,y,z,0.1,0.1,1.5,1,200)
  1284. commands.async.particle("reddust",x,y,z,1.5,0.1,0.1,1,200)
  1285. commands.async.playsound("random.bowhit","@a",x,y,z,1,0.8)
  1286. end
  1287.  
  1288. --makes sure that incoming check requests dont exist already
  1289. function addToChecklist(player,buildzone)
  1290. for _, detector in ipairs(buildzone.waitingForCheck) do
  1291. if detector.x == player.x and detector.y == player.y and detector.z == player.z then
  1292. return false
  1293. end
  1294. end
  1295. table.insert(buildzone.waitingForCheck,player)
  1296. return true
  1297. end
  1298.  
  1299. --removes all barrier blocks from a buildzone which are used to carve space in vocabs
  1300. function cleanBarriers(buildzone)
  1301. for h=0,200 do
  1302. 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")
  1303. end
  1304. end
  1305.  
  1306. --The main chunk of code which deals with stepping on detector blocks and reading the vocab
  1307. function updatePlayedZone(buildzone)
  1308. local victory = false
  1309. local buildzoneSelector = buildzone.selector
  1310. --get all players on a detector block, add them to the list of things to check
  1311. local detectLocations = getAllOnBlockType(BLOCKS.DETECT.block,buildzoneSelector)
  1312. for _, player in ipairs(detectLocations) do
  1313. addToChecklist(player,buildzone)
  1314. end
  1315.  
  1316. --DEAL WITH THE DETECTOR AT THE TOP OF THE LIST IF THERE IS ONE
  1317. if #buildzone.waitingForCheck > 0 then
  1318. --DO PARTICLE EFFECTS IF A DETECTING BLOCK THAT IS DETECTING
  1319. for i,loc in ipairs(buildzone.waitingForCheck) do
  1320. searchParticle(loc.x,loc.y+1,loc.z)
  1321. end
  1322. local totalResult = false
  1323. local checked = table.remove(buildzone.waitingForCheck,1)
  1324. local x,y,z,name = checked.x,checked.y,checked.z,checked.name
  1325. for i,vocab in pairs(buildzone.vocab) do
  1326. local result,message = commands.testforblocks( vocab.x, vocab.y, vocab.z, vocab.x+vocab.w, vocab.y+VOCAB_HEIGHT, vocab.z+vocab.w, x-math.floor(vocab.w/2), y-1, z-math.floor(vocab.w/2),"masked")
  1327. if result then
  1328. --clone in the correct vocab
  1329. local cloneres,clonemes = commands.clone( vocab.cx, vocab.cy, vocab.cz, vocab.cx+vocab.w, vocab.cy+VOCAB_HEIGHT, vocab.cz+vocab.w, x-math.floor(vocab.w/2), y-1, z-math.floor(vocab.w/2),"masked")
  1330. if DEBUG_MODE then
  1331. print(clonemes[1])
  1332. end
  1333. commands.async.give(name,vocab.reward)
  1334. -- announce vocab success in English
  1335. local rewardType = 'nature'
  1336. local rewardTypeDE = 'grüne'
  1337. if vocab.rewardUrban then
  1338. rewardType = 'urban'
  1339. rewardTypeDE = 'urbane'
  1340. end
  1341. --print(vocab.typeEN)
  1342. --print(vocab.nameEN)
  1343. --print(vocab.height)
  1344. --print(vocab.slots)
  1345. --print(vocab.greenSlots)
  1346. --print(vocab.rewardCount)
  1347. --print(rewardType)
  1348. commands.async.tellraw(name,'["",{"text":"You built a '..vocab.nameEN.. ' ('..vocab.typeEN..'), which is '..vocab.height..'m tall and gives '..vocab.slots..' density pts, '..vocab.greenSlots..' green pts and '..vocab.rewardCount..'x '..rewardType..' resource!","color":"white"}]')
  1349. -- announce vocab success in German
  1350. commands.async.tellraw(name,'["",{"text":"Du hast ein '..vocab.typeDE..' | '..vocab.nameDE.. ' gebaut, das '..vocab.height..' Meter hoch ist und dir '..vocab.slots..' Punkte für die Dichte einbringt, jedoch '..vocab.greenSlots..' Punkte für Grünflächen und '..vocab.rewardCount..' '..rewardTypeDE..' Ressourcen!","color":"gold"}]')
  1351. --clear out barrier blocks
  1352. cleanBarriers(buildzone)
  1353.  
  1354. --ADD THE NEW STRUCTURE TO THE RECORDS
  1355. table.insert(buildzone.structures,vocab.nameEN)
  1356. --record the place of the vocab as x, y, z and vocab id
  1357. local building = {id=vocab.id,xpos=x,ypos=y,zpos=z,name=vocab.nameEN,time=os.clock(),player=name}
  1358. table.insert(buildzone.buildings, building)
  1359. --if vocab.green then
  1360. buildzone.greenSlots = buildzone.greenSlots + vocab.greenSlots
  1361. --end
  1362. buildzone.filledSlots = buildzone.filledSlots + vocab.slots
  1363. local newHeight = y + vocab.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
  1364. if newHeight > buildzone.highest then
  1365. buildzone.highest = newHeight
  1366. end
  1367. -- count variety
  1368. --print("adding variety: "..vocab.id)
  1369. local varietyId = vocab.id -- we use a variety id instead of the vocab id because vocab id 1,2,3,4 for example are all houses so it is the same variety
  1370. --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
  1371. 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
  1372. 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
  1373. 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
  1374. 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
  1375. if varietyId ~= 17 and varietyId ~= 18 then --skip the two riser as they ar enot buildings
  1376. if buildzone.variety[varietyId] then
  1377. --print("increasing existing item")
  1378. buildzone.variety[varietyId] = buildzone.variety[varietyId] + 1
  1379. else
  1380. --print("adding new item")
  1381. buildzone.variety[varietyId] = 1
  1382. end
  1383. end
  1384.  
  1385. --- CHECK FOR PERSONAL RECORDS
  1386. --- check if the new structure is the highest
  1387. --- CHANGE here to live detect the contribution of the new structure to the 4 goals and update them
  1388.  
  1389. local personalbest = tracker.getScore(name,"highest")
  1390. if personalbest.count < newHeight then
  1391. --commands.async.tell(name,"You just topped your personal record for highest structure!")
  1392. commands.async.scoreboard("players","add",name,"highest",1)
  1393. -- announce success in English
  1394. commands.async.tellraw(name,'["",{"text":"You just topped your personal record for highest neighbourhood!","color":"green"}]')
  1395. -- announce success in German
  1396. commands.async.tellraw(name,'["",{"text":"Du hast soeben deinen persönlichen Rekord für die höchste Nachbarschaft gebrochen!","color":"gold"}]')
  1397. end
  1398.  
  1399. ---
  1400. ---
  1401. -- CHECK if placing the current structure would result in beating a server-wide record on the 4 goals
  1402. --calculate total slots - FOR GOAL "DENSEST NEIGHBOURHOOD"
  1403. local most = tracker.getScore("Densest_[points]","highscores")
  1404. local Kint = math.floor(100 * buildzone.filledSlots / 49) -- Kint is the density index made from built area (filledSlots) over ground area (7x7 slots = 49)
  1405. if Kint > most.count then
  1406. commands.async.scoreboard("players","set","Densest_[points]","highscores",Kint)
  1407. -- announce success in English
  1408. commands.async.tellraw("@a",'["",{"text":"Great! '..name.. ' just topped the record for the DENSEST NEIGHBOURHOOD!","color":"green"}]')
  1409. -- announce success in German
  1410. commands.async.tellraw("@a",'["",{"text":"Sehr gut! '..name.. ' hat einen neuen Rekord für die DICHTESTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  1411. --commands.async.say("@a","The record for the Densest Neighbourhood has been topped!")
  1412. end
  1413.  
  1414. -- FOR THE GOAL "MOST DIVERSE NEIGHBOURHOOD"
  1415. -- here we need to count how many varieties of buildings there are
  1416. --local structures = tracker.tallyTable(buildzone.structures) -- this counts the variety of buildings in a game
  1417. local mostDiverse = tracker.getScore("Most-Diverse_[out-of-26]","highscores")
  1418. local typeCount = tablelength(buildzone.variety)
  1419. --print("variety count is: "..typeCount)
  1420. if typeCount > mostDiverse.count then
  1421. commands.async.scoreboard("players","set","Most-Diverse_[out-of-26]","highscores", typeCount)
  1422. -- announce success in English
  1423. commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' just topped the record for the MOST DIVERSE NEIGHBOURHOOD!","color":"green"}]')
  1424. -- announce success in German
  1425. commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' hat soeben einen neuen Rekord für die VIELSEITIGSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  1426. --commands.async.say("@a","The record for the Most Diverse Neighbourhood has been topped!")
  1427. end
  1428.  
  1429. -- FOR THE GOAL "GREENEST NEIGHBOURHOOD"
  1430. -- here we need to count the number of green vocabs
  1431. local greenest = tracker.getScore("Greenest_[points]","highscores")
  1432. local Gint = math.floor(100*buildzone.greenSlots/49) --Gint is the green index, made from green area (greenSlots) over ground area (7x7 slots = 49)
  1433. if Gint > greenest.count then
  1434. commands.async.scoreboard("players","set","Greenest_[points]","highscores",Gint)
  1435. -- announce success in English
  1436. commands.async.tellraw("@a",'["",{"text":"Awesome! '..name.. ' just topped the record for the GREENEST NEIGHBOURHOOD!","color":"green"}]')
  1437. -- announce success in German
  1438. commands.async.tellraw("@a",'["",{"text":"Klasse! '..name.. ' hat einen neuen Rekord für die GRÜNSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  1439. ---commands.async.say("@a","The record for the Densest Neighbourhood has been topped!")
  1440. end
  1441.  
  1442. --calculate highest placement -- FOR THE GOAL "TALLEST NEIGHBOURHOOD"
  1443. local highest = tracker.getScore("Tallest_[meters]","highscores")
  1444. if buildzone.highest > highest.count then
  1445. commands.async.scoreboard("players","set","Tallest_[meters]","highscores",buildzone.highest)
  1446. -- announce success in English
  1447. commands.async.tellraw("@a",'["",{"text":"Incredible! '..name..' just topped the record for TALLEST NEIGHBOURHOOD!","color":"green"}]')
  1448. -- announce success in German
  1449. commands.async.tellraw("@a",'["",{"text":"Unglaublich! '..name..' hat einen neuen Rekord für die HÖCHSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
  1450. --commands.async.say("@a","The record for the Tallest Negihbourhood has been topped!")
  1451. end
  1452.  
  1453.  
  1454. --increase the "how many structures did i build" score for the building player
  1455. commands.async.scoreboard("players","add",name,"built",1)
  1456. commands.async.scoreboard("players","add",name,"building_"..vocab.id,1)
  1457.  
  1458. totalResult = true
  1459. break
  1460.  
  1461. end
  1462. end
  1463. if totalResult then
  1464. --yey win, do a happy time
  1465. successParticle(x,y,z)
  1466. else
  1467. --no vocab found so do a fail particle
  1468. --announce in English
  1469. commands.async.tellraw(name,'["",{"text":"The shape you have built does not match any shape in the catalogue, try a different one.","color":"red"}]')
  1470. -- announce in German
  1471. 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"}]')
  1472. failParticle(x,y-1,z)
  1473. end
  1474. end
  1475. return victory
  1476. end
  1477.  
  1478. -- returns how many items are in a table/list
  1479. function tablelength(T)
  1480. local count = 0
  1481. for _ in pairs(T) do count = count + 1 end
  1482. return count
  1483. end
  1484.  
  1485. --Display game information on the monitor
  1486. function debugDisplay(game)
  1487. monitor.clear()
  1488. if blink then
  1489. monitor.setCursorPos(1,1)
  1490. monitor.setTextColor(colors.red)
  1491. monitor.write("Running")
  1492. monitor.setTextColor(colors.white)
  1493. redstone.setOutput("top",true)
  1494. blink = false
  1495. else
  1496. redstone.setOutput("top",false)
  1497. blink = true
  1498. end
  1499. local line = 2
  1500.  
  1501. for i,kew in ipairs(game.queues) do
  1502. monitor.setCursorPos(1,line)
  1503. local minutes = string.format("%02d",math.floor(kew.timer/60))
  1504. local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
  1505. monitor.write("Buildzone "..i.." | Phase: "..kew.phase.." | Time: "..minutes..":"..seconds)
  1506. monitor.setCursorPos(1,line+1)
  1507. for i,player in ipairs(kew.playerlist) do
  1508. monitor.write(player.name.." ")
  1509. end
  1510. line = line +2
  1511. end
  1512.  
  1513. monitor.setCursorPos(1,10)
  1514. for i,player in ipairs(game.waitlist) do
  1515. monitor.write(player.name.." ")
  1516. end
  1517. end
  1518.  
  1519. --BEGIN RUNTIME CODE
  1520. local blink = true
  1521. local game = setup()
  1522. while true do
  1523. update(game)
  1524. if monitor then debugDisplay(game) end
  1525. commands.async.weather("clear",10000)
  1526.  
  1527. local resetbutton = redstone.getInput("left")
  1528. if resetbutton then
  1529. print("reset!")
  1530. for i,kew in ipairs(game.queues) do
  1531. if kew.phase == 2 then
  1532. kew.timer = 5
  1533. end
  1534. end
  1535. end
  1536. sleep(2)
  1537. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement