Advertisement
antonsavov

Untitled

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