Advertisement
antonsavov

Untitled

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