Advertisement
antonsavov

Untitled

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