Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local VERSION = '1.0.0 - Public Release'
- os.loadAPI('tracker')
- os.loadAPI('json')
- print("Starting 20.000 Blocks")
- DEBUG_MODE = false
- local monitor = peripheral.wrap("right")
- local ox,oy,oz = commands.getBlockPosition()
- 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
- SPAWN_VILLAGER = false
- DO_GRID = true
- GRID_HOLE_CHANCE = 0
- NUMBER_OF_BUILDZONES = 6
- NUMBER_OF_VOCAB = 10
- GAME_LENGTH = 600
- VOCAB_WIDTH = 27
- VOCAB_HEIGHT = 19
- 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
- BUILDZONE_FLOOR_HEIGHT = -1
- HOMECOMER_TYPE = "Pig"
- HOMECOMER_VALUE = 90 --90 is for pig
- SPAWN = {
- x=12110,
- y=57,
- z=-1777,
- a1=90,
- a2=0
- }
- FIRSTZONE= {
- x=11685,
- y=57,
- z=-1869
- }
- WAITZONE = {
- x=12093,
- y=56,
- z=-1779,
- w=5,
- l=5
- }
- --this is the block at ~-4 ~ ~-4 from the corner of the shape zone
- --i.e., (the one with the grammar shape in it) of the vocab that is closest to zero
- FIRSTVOCAB= {
- x=0,
- y=57,
- z=5
- }
- VICTORY_HEIGHT = 30
- VICTORY_TOTAL = 50
- VICTORY_SPECIFIC = {name='garden',count=101}
- WOOL_PER_EMERALD = 64
- BLOCKS = {
- CAMP_FLOOR = {block='minecraft:sandstone',data=0},
- CONSTRUCTION = {block='minecraft:diamond_ore',data=0},
- RING = {block='minecraft:diamond_ore',data=0},
- DETECT = {block='minecraft:red_sandstone',data=0},
- DETECT_DEAD = {block='minecraft:obsidian',data=0},
- VOCAB_DETECT = {block="minecraft:quartz_block",data=0},
- VOCAB_REPLACE = {block="minecraft:coal_block",data=0},
- VICTORY_MARKER = {block="minecraft:emerald_block",data=0},
- PLUG = {block="minecraft:lapis_ore",data=0},
- PHVFLOOR = {block="minecraft:stone_slab",data=3},
- BUILDING_HOUSE = {block="minecraft:wool",data=0},
- BUILDING_GARDEN = {block="minecraft:wool",data=13},
- BUILDING_WATER = {block="minecraft:wool",data=1},
- _matWhiteSmooth ={block="mincreaft:stained_hardened_clay",data=0},
- _matWhiteSmooth2 = {block="minecraft:brick_block",data=0},
- _matYellowSmooth = {block="minecraft:stained_hardened_clay",data=4},
- _matPinkSmooth = {block="minecraft:stained_hardened_clay",data=6},
- _matBlueSmooth = {block="minecraft:stained_hardened_clay",data=9},
- _matPurpleSmooth = {block="minecraft:stained_hardened_clay",data=10},
- _matWhiteTextured = {block="minecraft:planks",data=4},
- _matYellowTextured = {block="minecraft:planks",data=1},
- _matPinkTextured = {block="minecraft:planks",data=0},
- _matBlueTextured = {block="minecraft:planks",data=2},
- _matPurpleTextured = {block="minecraft:planks",data=5},
- }
- --contains a list of all posible Buildzones (build a bit later)
- LOCS = {}
- if DEBUG_MODE then
- GAME_LENGTH = 12000
- NUMBER_OF_BUILDZONES = 1
- end
- -- see if the file exists
- function file_exists(file)
- local f = fs.open(file, "rb")
- if f then f:close() end
- return f ~= nil
- end
- --creates a grid of absolute references (0,0) (1,0)
- function buildGrid(w,h)
- local grid = readGridFromFile()
- if grid then
- -- grid was read from teh file successfully
- else
- --generate file from scratch
- grid = {}
- for z=0,h-1 do
- for x=0,w-1 do
- table.insert(grid,{x=x,z=z,played=false})
- end
- end
- end
- return grid
- end
- function readGridFromFile()
- local result = nil
- fs.makeDir("/records")
- local filename = "/records/_buildzones-list.yaml"
- if file_exists(filename) then
- ---read from file
- result = json.decodeFromFile(filename)
- end
- return result
- end
- function writeGridToFile()
- fs.makeDir("/records")
- local filename = "/records/_buildzones-list.yaml"
- local file = fs.open(filename,"w")
- file.write(json.encodePretty(LOCS))
- file.close()
- end
- --sets where and how big the PHV area is
- --second number is along the long edge of PHV starting at the spawn side
- --first number is along the short edge of PHV starting from the park side
- if DEBUG_MODE then
- FIRSTZONE= {
- x=5,
- y=57,
- z=-7
- }
- LOCS = buildGrid(1,3)
- else
- LOCS = buildGrid(11,27)
- end
- --call these to return a proper minecraft item string including adventure mode properties
- function houseBlock(quant)
- 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..'"]}'
- return text
- end
- function gardenBlock(quant)
- 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..'"]}'
- return text
- end
- PICKAXE_USES = 40
- pickaxe = 'stone_pickaxe 1 '..131-PICKAXE_USES..' {CanDestroy:["'..BLOCKS.BUILDING_HOUSE.block..'"],display:{Name:"Resource Remover",Lore:[Use the pickaxe to remove up to '..PICKAXE_USES..' resource blocks]}}'
- STARTING_ITEMS = {
- houseBlock(30), gardenBlock(30),pickaxe
- }
- DEFAULT_NAME = 'BUILDING'
- --[[
- VOCAB_NAMES = {
- 'freestand-house',
- 'freestand-house',
- 'freestand-house',
- 'freestand-house',
- 'dbl-ext-house',
- 'dbl-ext-house',
- 'dbl-ext-house',
- 'dbl-ext-house',
- 'bridge-house',
- 'bridge-house',
- 'bridge-garden',
- 'bridge-garden',
- 'ext-house',
- 'ext-house',
- 'ext-house',
- 'ext-house',
- 'riser-1',
- 'riser-2',
- 'city-garden',
- 'city-plaza',
- 'dbl-ext-garden',
- 'dbl-ext-garden',
- 'dbl-ext-garden',
- 'dbl-ext-garden',
- 'ext-garden',
- 'ext-garden',
- 'ext-garden',
- 'ext-garden',
- 'corner-garden',
- 'corner-garden',
- 'corner-garden',
- 'corner-garden',
- 'corner-house',
- 'corner-house',
- 'corner-house',
- 'corner-house',
- 'freestand-garden',
- 'freestand-garden',
- 'freestand-garden',
- 'freestand-garden'
- }
- --]]
- ----------------------------------------------------------------------------------------------------------------
- -- the data structure below represents the catalogue of vocabularies as built in minecraft
- -- id - is unique for each vocab, starting from 1 going to 40 currently
- -- column and row - represent the "physical" location of the vocab model in the catalogue in the minecraft world
- -- nameEN and name DE - are names for english and german. for now english names must not have spaces, use dashes (-) instead
- -- typeEN and typeDE - are the type names, also in english and german such as tech&science spaces
- -- height - is how many blocks is this structure tall
- -- 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
- -- 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
- -- greenSlots - is how many slots are green and is used for easier calculation of the GREENEST GOAL
- VOCABS_DATA = {
- -- urban houses
- {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},
- {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},
- {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},
- {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},
- -- urban businesses
- {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},
- {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},
- {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},
- {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},
- -- urban tech&science spaces
- {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},
- {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},
- -- green tech&science spaces
- {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},
- {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},
- -- urban house extensions
- {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},
- {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},
- {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},
- {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},
- --risers
- {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},
- {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},
- --plazas
- {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},
- {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},
- --green businesses
- {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},
- {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},
- {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},
- {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},
- ---green private garden extensions
- {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},
- {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},
- {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},
- {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},
- ---green gathering spaces
- {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},
- {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},
- {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},
- {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},
- ----urban gathering spaces
- {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},
- {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},
- {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},
- {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},
- ---green-roof houses
- {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},
- {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},
- {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},
- {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},
- }
- DEFAULT_REWARD = houseBlock(4)
- REWARDS = {}
- --constructor for player object so that data structure is consistant
- function newPlayerData(name,x,y,z)
- local p = {
- name = name,
- x=x,
- y=y,
- z=z
- }
- return p
- end
- --return a list of all players in the game world as player objects
- local function getAllPos(selector)
- local result, message = commands.tp("@a["..selector.."]","~ ~ ~")
- local names = {}
- if result == true then
- for i,result in ipairs(message) do
- local wordpattern = "[^, ]+"
- local numberpattern = "[%-% ]%d+[%.]%d+"
- local words,numbers = {},{}
- for word in string.gmatch(result, wordpattern) do
- table.insert(words,word)
- end
- for number in string.gmatch(result, numberpattern) do table.insert(numbers,number) end
- local coords = {
- x = math.floor(numbers[1]),
- y = math.floor(numbers[2]),
- z = math.floor(numbers[3])
- }
- local name = words[2]
- table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
- --print("Player Found - getAllPos")
- end
- end
- return names
- end
- --sort table by random
- local function shuffleTable( t )
- local rand = math.random
- assert( t, "shuffleTable() expected a table, got nil" )
- local iterations = #t
- local j
- for i = iterations, 2, -1 do
- j = rand(i)
- t[i], t[j] = t[j], t[i]
- end
- end
- --returns a list of player objects containing all players who are standing on the given block, and who also are in the given selection
- local function getAllOnBlockType(block,selector)
- local result, message = commands.exec("execute @a["..selector.."] ~ ~ ~ detect ~ ~-1 ~ "..block.." -1 tp @p[r=1] ~ ~ ~")
- local names = {}
- if result == true then
- for i,result in ipairs(message) do
- local wordpattern = "[^, ]+"
- local numberpattern = "[%-% ]%d+[%.]%d+"
- local words,numbers = {},{}
- for word in string.gmatch(result, wordpattern) do table.insert(words,word) end
- for number in string.gmatch(result, numberpattern) do table.insert(numbers,number) end
- if numbers[1] and numbers[2] and numbers[3] then
- local coords = {
- x = math.floor(numbers[1]),
- y = math.floor(numbers[2]),
- z = math.floor(numbers[3])
- }
- local name = words[2]
- table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
- print("Found a player - getOnBlock")
- else
- print("Error: Coordinate Numbers were missing")
- end
- end
- end
- return names
- end
- --gives a player a HOMECOMER egg with their name on it. Removes all spawn eggs first
- local function giveHomecomer(name)
- commands.clear(name,'spawn_egg')
- 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]}}')
- end
- --returns a list of HOMECOMER entities and their names
- local function getHomecomers()
- local result, message = commands.exec("execute @e[type="..HOMECOMER_TYPE.."] ~ ~ ~ tp @e[r=1] ~ ~ ~")
- local names = {}
- if result == true then
- for i,result in ipairs(message) do
- local wordpattern = "[^, ]+"
- local numberpattern = "[%-% ]%d+[%.]%d+"
- local words,numbers = {},{}
- for word in string.gmatch(result, wordpattern) do table.insert(words,word) print(word) end
- for number in string.gmatch(result, numberpattern) do table.insert(numbers,number) end
- if numbers[1] and numbers[2] and numbers[3] then
- local coords = {
- x = math.floor(numbers[1]),
- y = math.floor(numbers[2]),
- z = math.floor(numbers[3])
- }
- local name = words[4]
- table.insert(names,newPlayerData(name,coords.x,coords.y,coords.z))
- print("Found a player - getOnBlock "..name)
- else
- print("Error: Coordinate Numbers were missing")
- end
- end
- end
- return names
- end
- local function removePlayerFromKew(game,playername)
- for _,kew in pairs(game.queues) do
- for index, player in ipairs(kew.playerlist) do
- if player.name == playername then
- table.remove(kew.playerlist,index)
- end
- end
- if #kew.playerlist == 0 and kew.phase == 2 then
- --game can be ended as no players are left
- kew.timer = 0
- end
- end
- end
- local function movePlayerToSpawn(playername)
- respawnPlayer(playername)
- commands.async.tp(playername,SPAWN.x,SPAWN.y,SPAWN.z,SPAWN.a1,SPAWN.a2)
- commands.async.tellraw(playername,'["",{"text":"You used your HOMECOMER and TELEPORTED BACK TO SPAWN","color":"white"}]')
- commands.async.tellraw(playername,'["",{"text":"Du hast den HEIMKEHRER benutzt um dich zurück zum Anfang zu teleportieren.","color":"gold"}]')
- end
- --takes a list of homecomers and deals with all those players, moving them back to spawn and removing them from game
- --also gives them a new homecomer
- local function dealWithHomecomers(game, homecomers)
- for _,homecomer in pairs(homecomers) do
- --remove player from current game if in game
- removePlayerFromKew(game,homecomer.name)
- --teleport them back to spawn
- movePlayerToSpawn(homecomer.name)
- --give a new homecomer
- giveHomecomer(homecomer.name)
- --particle effects
- --teleport message
- end
- --kill all homecomers
- if #homecomers>0 then
- commands.tp("@e[type="..HOMECOMER_TYPE.."]",100000,200,100000)
- commands.kill("@e[type="..HOMECOMER_TYPE.."]")
- os.sleep(#homecomers*0.2)
- end
- end
- --creates a villager with special items
- local function spawnVillager(x,y,z)
- 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"]}}} ]}}')
- end
- --displays a time as experience points to a selection of players
- local function displayTime(selector,minutes,seconds)
- --commands.title("@a["..selector.."]","subtitle",'{text:"Time left: '..minutes..":"..seconds..'",color:red,bold:false,underlined:false,italic:false,strikethrough:false,obfuscated:false}')
- commands.async.xp("-1000000L","@a["..selector.."]")
- local secondstot = (minutes * 60) + seconds
- commands.async.xp(tostring(secondstot).."L","@a["..selector.."]")
- end
- --displays a title to a selection of players
- local function displayTitle(selector,text)
- commands.async.title("@a["..selector.."]","title",'{text:"'..text..'"}')
- end
- --simply runs displayTitle on a list of players
- local function displayTitleToGroup(playerlist,text)
- for i,player in ipairs(playerlist) do
- displayTitle("name="..player.name,text)
- end
- end
- --simply runs displayTime on a list of players
- local function displayTimeToGroup(playerlist,minutes,seconds)
- for i,player in ipairs(playerlist) do
- displayTime("name="..player.name,minutes,seconds)
- end
- end
- --teleports a list of players to an exact place and sends them a message about it
- local function teleportToPoint(x,y,z,playerlist,clear,textEN, textDE)
- for i,player in ipairs(playerlist) do
- player.x = x
- player.y = y
- player.z = z
- commands.async.gamemode(2,player.name)
- if clear then
- commands.async.clear(player.name,"wool")
- commands.async.clear(player.name,"stone_pickaxe")
- end
- commands.tp("@a[name="..player.name.."]",x,y,z)
- commands.async.tellraw(player.name,'["",{"text":"'..textEN..'","color":"white"}]')
- commands.async.tellraw(player.name,'["",{"text":"'..textDE..'","color":"gold"}]')
- end
- end
- --teleports a list of players to a given buildzone
- local function teleportToZone(buildzone,playerlist,textEN, textDE)
- teleportToPoint(buildzone.x+2+(buildzone.w/2),buildzone.y+5,buildzone.z+2+(buildzone.w/2),playerlist,true,textEN, textDE)
- end
- --gives the same list of items to a list of players
- local function giveItems(playerlist,itemlist)
- local given = 0
- for i,player in ipairs(playerlist) do
- --commands.async.clear(player.name)
- for j,item in ipairs(itemlist) do
- commands.async.give("@a[name="..player.name.."]",item)
- given = given +1
- end
- giveHomecomer(player.name)
- end
- return given
- end
- --a multi builder which uses the vocab constructor to create sets of vocab
- local function makeVocabZones(quant,w)
- local x,y,z = FIRSTVOCAB.x, FIRSTVOCAB.y, FIRSTVOCAB.z
- local result = {}
- local id = 1
- for i=0,quant-1 do
- for k=0,3 do
- local zpos = i-4
- local ypos = k
- --print("vocab at X")
- --print(x-(2*w)-6)
- --print("and Z")
- --print(z+((w+1)*zpos))
- local nextVocab = newVocabZone(
- x-(2*w)-6,y+(ypos*(VOCAB_HEIGHT+3)),
- z+((w+1)*zpos),
- w,
- id,
- REWARDS[id] or DEFAULT_REWARD,
- VOCABS_DATA[id].nameEN or DEFAULT_NAME,
- VOCABS_DATA[id].nameDE or DEFAULT_NAME,
- VOCABS_DATA[id].typeEN,
- VOCABS_DATA[id].typeDE,
- VOCABS_DATA[id].height,
- VOCABS_DATA[id].slots,
- VOCABS_DATA[id].green,
- VOCABS_DATA[id].greenSlots,
- VOCABS_DATA[id].rewardUrban,
- VOCABS_DATA[id].rewardCount
- )
- table.insert(result,nextVocab)
- id = id +1
- end
- end
- return result
- end
- --finds the next free location(or buildzone) for a new game in a given area.
- --giving force as True will mean it overrides the first location no matter what
- local function findNextLoc(width,zones,force)
- local x,y,z,locid = 0,0,0,1
- for i,loc in ipairs(LOCS) do
- locid = i
- 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
- print("testing for available zone at: "..x..", "..y..", "..z)
- print("which is at grid cell at: "..loc.x..", "..loc.z)
- --local result,message = commands.testforblock(x,y+BUILDZONE_FLOOR_HEIGHT,z,"minecraft:air") -- this was used for the testing based on the minecraft model
- local result = true
- if loc.played then
- result = false
- print("zone has been played")
- end
- --print("testing done")
- --force the first zone to be selected unless it is taken in the "zones" parameter
- if force then result = true end
- --checks if the zone is already in the list of unavailable zones passed as parameter
- local zonefree = true
- for i,zone in ipairs(zones) do
- if zone.x == x and zone.z == z then
- zonefree = false
- end
- end
- --print("next position free is ",loc.x*width,oy,loc.z*width)
- --if result then print("true") else print("false") end
- if result and zonefree then
- --print("using loc: ",loc.x,loc.z)
- return x,y,z,locid --returns the coordinates of the new zone, plus its id in the LOCS table
- end
- end
- return nil,nil,nil, nil --returns empty if no zone is available
- end
- --relocates a buildzone to a new coordinate safely
- --avoids overlapping with other buildzones
- function moveBuildzone(buildzone,zones)
- local x,y,z,locid = findNextLoc(buildzone.w,zones)
- if x and y and z and locid then
- print("moved buildzone from "..buildzone.x..","..buildzone.z.." to "..x..","..y)
- local w = buildzone.w
- buildzone.x,buildzone.y,buildzone.z = x,y+BUILDZONE_FLOOR_HEIGHT,z
- buildzone.locid = locid --reassign the location id corresponding to the LOCS item for the grid cell of the moved zone
- buildzone.selector = "x="..x..",y="..tostring(y-1)..",z="..z..",dx="..w..",dy=256,dz="..w
- buildzone.structures = {} --a list of all vocabularies which have been contructed
- else
- print("buildzone at "..buildzone.x..","..buildzone.z.." stayed where it is")
- end
- end
- --multi builder to create sets of buildzones using the buildzone constructor
- local function makeBuildzones(quant,vocab,width,height)
- local result = {}
- for i=1,quant do
- --print("locating available slot")
- local x,y,z,locid = findNextLoc(width,result)
- if x and y and z and locid then
- --print("made new buildzone at",x,y,z)
- table.insert(result,newBuildZone(x,y+height,z,width,vocab,locid))
- else
- --print("failed to make new buildzone")
- end
- end
- local remaining = NUMBER_OF_BUILDZONES - #result
- --print("doing this remaining thing")
- for i=1, remaining do
- local x,y,z,locid = findNextLoc(width,result,true)
- if x and y and z and locid then
- --print("forced new buildzone at",x,y,z)
- table.insert(result,newBuildZone(x,y+height,z,width,vocab, locid))
- else
- print("failed to force new buildzone")
- end
- end
- return result
- end
- --vocab constructor. Enforces some data structure
- function newVocabZone(x,y,z,w,id, reward,nameEN, nameDE, typeEN, typeDE, height, slots,green,greenSlots, rewardUrban, rewardCount)
- local nvz = {}
- nvz.x ,nvz.y ,nvz.z ,nvz.w = x,y,z,w
- nvz.cx = nvz.x - nvz.w - 2
- nvz.cy = nvz.y
- nvz.cz = nvz.z
- nvz.nameEN = nameEN
- nvz.reward = reward
- --- new stuff
- nvz.id = id
- nvz.nameDE = nameDE
- nvz.typeEN = typeEN
- nvz.typeDE = typeDE
- nvz.height = height
- nvz.slots = slots
- nvz.green = green
- nvz.greenSlots = greenSlots
- nvz.rewardUrban = rewardUrban
- nvz.rewardCount = rewardCount
- return nvz
- end
- --buildzone constructor. Enforces some data structure
- function newBuildZone(x,y,z,w,vocabZones,locid)
- local nbz = {}
- nbz.x ,nbz.y ,nbz.z ,nbz.w = x,y,z,w
- nbz.selector = "x="..x..",y="..(y-5)..",z="..z..",dx="..w..",dy=256,dz="..w
- nbz.structures = {} --a list of all vocabularies names which have been contructed
- nbz.buildings = {} --a list of all vocabularies with full data (x,y,z,id,name) which have been contructed
- nbz.filledSlots = 0 --to count how many slots have been filled with buildings. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
- nbz.greenSlots = 0 --to count how many of the slots are green. the matrix is 7x7x20 slots. one slot is 9x9x9 blocks big
- 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
- nbz.waitingForCheck = {}
- nbz.highest = 0
- nbz.vocab = vocabZones
- nbz.locid = locid
- return nbz
- end
- --kew constructor. Enforces some data structure
- function newQueue(buildzone,maxplayers)
- local q = {}
- q.timer = 1
- q.phase = 1
- q.victory = false
- q.phases = {
- {
- name = "Selecting Players",
- length = 25,
- displaylength = 15
- },
- {
- name = "Game In Progress",
- length = GAME_LENGTH,
- displaylength = 70
- },
- {
- name = "Round Complete",
- length = 35,
- displaylength = 5
- }
- }
- q.playerlist = {}
- q.maxplayers = maxplayers
- q.buildzone = buildzone
- return q
- end
- --creates a ring of blocks using coordinates
- function fillRing(x,y,z,w,block)
- commands.fill(x,y,z,x+w,y,z,block)
- commands.fill(x+w,y,z,x+w,y,z+w,block)
- commands.fill(x,y,z+w,x+w,y,z+w,block)
- commands.fill(x,y,z+w,x,y,z,block)
- end
- function setup()
- print("debug: starting setup function.")
- local game = {}
- game.vocab = {}
- game.builds = {}
- game.queues = {}
- game.waitlist = {}
- game.spawn = SPAWN
- game.lastClock = os.clock()
- game.nowTime = os.clock()
- --generate vocab rewards
- for i=1,#VOCABS_DATA do
- if VOCABS_DATA[i].rewardUrban then
- REWARDS[i] = houseBlock(VOCABS_DATA[i].rewardCount)
- else
- REWARDS[i] = gardenBlock(VOCABS_DATA[i].rewardCount)
- end
- end
- --kill all villagers
- commands.exec("kill @e[type=Villager]")
- --buildzone and vocabzone creation
- print("debug-setup: making vocab zones.")
- game.vocab = makeVocabZones(NUMBER_OF_VOCAB,VOCAB_WIDTH)
- print("debug-setup: making building zones.")
- game.builds = makeBuildzones(NUMBER_OF_BUILDZONES,game.vocab,BUILDZONE_WIDTH,BUILDZONE_FLOOR_HEIGHT)
- for i,build in ipairs(game.builds) do
- table.insert(game.queues,newQueue(build,4))
- end
- print("debug-setup: testing for properly setup vocabs.")
- for i,vz in ipairs(game.vocab) do
- local x,y,z,w = vz.x,vz.y,vz.z,vz.w
- local cx,cy,cz = vz.cx,vz.cy,vz.cz
- local detector, message1 = commands.testforblock(x+(math.floor(w/2)),y,z+(math.floor(w/2)),BLOCKS.DETECT.block)
- local blocker, message2 = commands.testforblock(x+(math.floor(w/2)),y,z+(math.floor(w/2)),BLOCKS.DETECT_DEAD.block)
- if not (detector or blocker) then
- for nx=0,2 do
- for nz=0,2 do
- commands.setblock(x+(nx*9)+4,y-1,z+(nz*9)+4,BLOCKS.VOCAB_REPLACE.block)
- commands.setblock(cx+(nx*9)+4,cy-1,cz+(nz*9)+4,BLOCKS.VOCAB_DETECT.block)
- end
- end
- commands.setblock(x+(math.floor(w/2)),y,z+(math.floor(w/2)),BLOCKS.DETECT_DEAD.block)
- end
- end
- print("debug-setup: adding scoreboards.")
- --[[
- for i, name in ipairs(VOCAB_NAMES) do
- commands.scoreboard("objectives","add",name,"dummy")
- end
- --]]
- print(#VOCABS_DATA)
- for i=1,#VOCABS_DATA do
- commands.scoreboard("objectives","add","building_"..i,"dummy")
- end
- --commands.gamerule("doDaylightCycle",false) -- this is included in the spawn controller script
- commands.gamerule("keepInventory",true)
- --commands.gamerule("doTileDrops",false) -- this is included in the spawn controller script
- --commands.gamerule("logAdminCommands",false) -- this is included in the spawn controller script
- --commands.gamerule("commandBlockOutput",false) -- this is included in the spawn controller script
- --commands.time("set",6000) -- this is included in the spawn controller script
- commands.scoreboard("objectives","add","highscores","dummy","Best Neighbourhoods")
- commands.scoreboard("objectives","add","VillagerLife","dummy")
- commands.scoreboard("objectives","add","built","dummy", "Structures Built")
- commands.scoreboard("objectives","add","highest","dummy", "Personal Highest")
- commands.scoreboard("objectives","add","played","dummy","Games Played")
- commands.title("@a","times",0,30,30) -- what does this do?
- math.randomseed( os.time() )
- commands.scoreboard("objectives","setdisplay","sidebar","highscores")
- commands.scoreboard("objectives","setdisplay","list","played")
- print("time is: "..os.time())
- print( "time is: "..textutils.formatTime( os.time(), false ) )
- print("day is: "..os.day())
- print("computer clock is: "..os.clock())
- if DEBUG_MODE then
- for i,build in ipairs(game.builds) do
- build.phase = 2
- build.timer = 500
- end
- end
- print("Computer Co-ordinates ",ox,oy,oz)
- print("20.000 Blocks Active!")
- return game
- end
- function checkForHomecomers(game)
- --execute on all homecomers
- local homecomers = getHomecomers()
- dealWithHomecomers(game,homecomers)
- end
- --main game loop
- --runs the game object through each of these update steps in order
- function update(game)
- local elapsed = updateClock(game)
- --update players
- checkPlayers(game)
- doTimerUpdates(game,elapsed)
- doPhaseUpdates(game)
- doPhaseEnds(game)
- checkBoundaries(game)
- checkForHomecomers(game)
- if #game.waitlist > 0 then allocateWaiters(game) end
- end
- --calculates elapsed time during a game tick
- function updateClock(game)
- game.nowTime = os.clock()
- local elapsed = game.nowTime - game.lastClock
- game.lastClock = game.nowTime
- return elapsed
- end
- --updates all kews in the game object based on elapsed time
- function doTimerUpdates(game,elapsed)
- for i,kew in ipairs(game.queues) do
- kew.timer = kew.timer - elapsed
- end
- end
- --check players are inside their buildzone and move them back if not
- function checkBoundaries(game)
- for i,kew in ipairs(game.queues) do
- if kew.phase ==2 then
- --boundaries
- local x_min = kew.buildzone.x
- local x_max = kew.buildzone.x+kew.buildzone.w
- local z_min = kew.buildzone.z
- local z_max = kew.buildzone.z+kew.buildzone.w
- local toBeCorrected = {}
- for j,player in ipairs(kew.playerlist) do
- local listOfOne = getAllPos('m=2,name='..player.name)
- if listOfOne and listOfOne[1] then
- player.x = listOfOne[1].x
- player.y = listOfOne[1].y
- player.z = listOfOne[1].z
- local changed = false
- if player.x > x_max then
- changed = true
- player.x = x_max-2
- end
- if player.x < x_min then
- changed = true
- player.x = x_min+2
- end
- if player.z > z_max then
- changed = true
- player.z = z_max-2
- end
- if player.z < z_min then
- changed = true
- player.z = z_min+2
- end
- 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
- end
- end
- end
- end
- end
- --here you can set the logic which determines if a buildzone was valuable.
- --Return true if it is crap and should be replaced
- function checkIfBuildzoneIsCrap(buildzone)
- if #buildzone.structures < 5 then
- print("Buildzone was crap")
- return true
- end
- print("Buildzone was ok")
- return false
- end
- --Everything that happens after a buildzone was completed
- --due to time limit.
- function cleanAfterVictory(buildzone)
- commands.async.setblock(buildzone.x,buildzone.y,buildzone.z,BLOCKS.VICTORY_MARKER.block)
- fillRing(buildzone.x,buildzone.y,buildzone.z,buildzone.w,"minecraft:air",0,"replace",BLOCKS.CONSTRUCTION.block,BLOCKS.CONSTRUCTION.data)
- for h=0,256-buildzone.y do
- 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)
- 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)
- 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)
- 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)
- end
- 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)
- 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")
- local wasCrap = checkIfBuildzoneIsCrap(buildzone)
- if wasCrap then
- --mark this buildzone for replacement
- commands.async.setblock(buildzone.x,buildzone.y,buildzone.z,"minecraft:air")
- else
- --need to find the LOCS item corresponding to this buildzone
- --change the flag to played=true
- LOCS[buildzone.locid].played = true
- --and write the LOCS object to the json file
- writeGridToFile()
- end
- end
- --these happen every tick and require the game object
- --updates are performed on each Queue (kew) and within each
- --of those on each buildzone.
- function doPhaseUpdates(game)
- for i,kew in ipairs(game.queues) do
- local minutes = string.format("%02d",math.floor(kew.timer/60))
- local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
- if kew.timer <= 0 then
- minutes = "00"
- seconds = "00"
- end
- if kew.phase == 1 then
- --waiting phase
- if #kew.playerlist == kew.maxplayers and kew.timer > 5 then kew.timer = 5 end
- if not DEBUG_MODE and #kew.playerlist == 0 then kew.timer = kew.phases[1].length end
- displayTitleToGroup(kew.playerlist,"Game starting!")
- displayTimeToGroup(kew.playerlist,minutes,seconds)
- --show countdown
- elseif kew.phase == 2 then
- --playing phase
- if #kew.playerlist == 0 then timer = 0 end -- finish if all players quit
- -- do vocab logic
- local victory = updatePlayedZone(kew.buildzone) --currently victory updatePlayedZone returns always false
- --
- displayTimeToGroup(kew.playerlist,minutes,seconds)
- elseif kew.phase == 3 then
- --end phase
- displayTitleToGroup(kew.playerlist,"Use HOMECOMER to return")
- --displayTimeToGroup(kew.playerlist,minutes,seconds)
- end
- end
- end
- --this runs after a buildzone is completed
- --it should tally structure types and set scoreboard highscores
- --it also rewards all participants with more played score
- function processHighscores(kew)
- local buildzone = kew.buildzone
- --add score to players who finished this game
- for _,player in ipairs(kew.playerlist) do
- commands.async.scoreboard("players","add",player.name,"played",1)
- end
- end
- --function to export a buildzone detail once it is complete
- --requires a kew so it can access the playerlist
- local function exportKewData(kew)
- local buildzone = kew.buildzone
- local saved = {}
- saved.position =
- {
- x=buildzone.x,
- y=buildzone.y,
- z=buildzone.z
- }
- local timestamp = math.floor(os.clock())
- --saved.timeCompleted = timestamp
- saved.players = {}
- for _, player in ipairs(kew.playerlist) do
- table.insert(saved.players,player.name)
- end
- --saved.structures = buildzone.structures
- saved.buildings = buildzone.buildings
- saved.totals = tracker.tallyTable(buildzone.structures)
- --saved.highest = buildzone.highest
- saved.stats = {
- cityVersion = CITY_VERSION,
- height = buildzone.highest,
- densityIndex = math.floor(100*buildzone.filledSlots/49), -- the density index is made from built area (filledSlots) over the ground area (7x7 slots = 49)
- greenIndex = math.floor(100*buildzone.greenSlots/49), --the green index is made from green area (greenSlots) over the ground area (7x7 slots = 49)
- variety = tablelength(buildzone.variety),
- timeCompleted = timestamp,
- gameLength = GAME_LENGTH
- }
- fs.makeDir("/records")
- local file = fs.open("/records/"..timestamp.."at"..buildzone.x.."_"..buildzone.z..".yaml","w")
- file.write(json.encodePretty(saved))
- file.close()
- end
- --this code runs ONCE at the end of each phase
- --what actually happens is specific to which phase the
- --particular kew is in.
- function doPhaseEnds(game)
- for i,kew in ipairs(game.queues) do
- if kew.timer <= 0 then
- if kew.phase == 1 then
- --waiting phase ends goto play phase
- moveBuildzone(kew.buildzone,game.builds)
- teleportToZone(kew.buildzone,kew.playerlist,"Your game has started! BUILD A HOUSE!", "Das Spiel hat begonnen! BAUE EIN HAUS!")--teleport selected players
- cleanBuildzone(kew.buildzone)
- prepareBuildzone(kew.buildzone)--prepare build zone
- giveItems(kew.playerlist,STARTING_ITEMS) --give starting items
- displayTitle(kew.buildzone.selector,"BUILD!")
- kew.victory = false
- --displayTime(kew.buildzone.selector,0,0)
- kew.phase = 2
- kew.timer = kew.phases[2].length
- elseif kew.phase == 2 then
- --playing phase ends goto end phase
- processHighscores(kew)
- exportKewData(kew)
- cleanAfterVictory(kew.buildzone)
- kew.phase = 3
- --displayTime(kew.buildzone.selector,0,0)
- kew.timer = kew.phases[3].length
- elseif kew.phase == 3 then
- --end phase ends goto waiting phase
- removePlayersFromKew(game,kew)
- kew.phase = 1
- --displayTime(kew.buildzone.selector,0,0)
- kew.timer = kew.phases[1].length
- end
- end
- end
- end
- --Replaces everything that is needed to start the game. Does not rebuild the floor, or clear anything away.
- --based on the settings it creates a full grid, or a partial grid, or no grid
- --it also places the ring, although this is disabled for now
- function prepareBuildzone(buildzone)
- local bz = buildzone
- local x,y,z,w = bz.x,bz.y,bz.z,bz.w
- 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
- fillRing(buildzone.x,buildzone.y,buildzone.z,buildzone.w,BLOCKS.CONSTRUCTION.block) --this draws the construction stripe around the buildzone
- --create the grid of detectors surrounded by plus plugs
- if DO_GRID then
- for x=0,6 do
- for z=0,6 do
- local rand = math.random()*100
- --local result, text = commands.testforblock(bz.x+(x*9)+4,bz.y-1,bz.z+(z*9)+4,BLOCKS.CAMP_FLOOR.block)
- if rand > GRID_HOLE_CHANCE then --and result then
- commands.async.setblock(bz.x+(x*9)+4,bz.y,bz.z+(z*9)+4,BLOCKS.DETECT.block,BLOCKS.DETECT.data,"replace","minecraft:air")
- 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)
- 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)
- --commands.async.setblock(bz.x+(x*9)+4,bz.y-1,bz.z+(z*9)+4,BLOCKS.CAMP_FLOOR.block)
- end
- end
- end
- end
- commands.async.setblock(buildzone.x,buildzone.y,buildzone.z,BLOCKS.CONSTRUCTION.block)
- end
- --deletes everything inside the buildzone
- function cleanBuildzone(buildzone)
- print("Cleaning buildzone")
- for h=0,VICTORY_HEIGHT+20 do
- commands.async.fill(buildzone.x,buildzone.y+h,buildzone.z,buildzone.x+buildzone.w,buildzone.y+h,buildzone.z+buildzone.w,"minecraft:air")
- end
- end
- --[[
- --moves all players assigned to the queue into the waiting area for the provided game.
- --It also changes them to Adventure mode and clears their inventory
- function respawnPlayers(game,kew)
- 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
- for i,player in ipairs(kew.playerlist) do
- --table.insert(game.waitlist,player)
- respawnPlayer(player,"")
- end
- kew.playerlist = {}
- end
- --]]
- function removePlayersFromKew(game,kew)
- for _, player in ipairs(kew.playerlist) do
- --commands.tell(player.name,"Your game is over. Use your Heimkehrer to return to spawn")
- -- announce success in English
- commands.async.tellraw(player.name,'["",{"text":"TIME OUT! GAME COMPLETE! Use your HOMECOMER to return to spawn.","color":"white"}]')
- -- announce success in German
- commands.async.tellraw(player.name,'["",{"text":"ENDE! SPIEL ABGESCHLOSSEN! Nutze den HEIMKEHRER um zum Anfang zurück zu kehren.","color":"gold"}]')
- end
- kew.playerlist = {}
- end
- function respawnPlayer(playername,message)
- commands.tell(playername,message)
- commands.async.gamemode(2,playername)
- commands.async.clear(playername,"minecraft:wool")
- commands.async.clear(playername,"minecraft:stone_pickaxe")
- end
- function checkForPlayerInBuildzone(player,buildzone)
- local result,message = commands.testfor('@a[name='..player.name..','..buildzone.selector..']')
- return result
- end
- function checkForPlayerInWaitzone(player)
- local selector = "x="..WAITZONE.x..",y="..WAITZONE.y..",z="..WAITZONE.z..",dx="..WAITZONE.w..",dy=256,dz="..WAITZONE.l
- local result,message = commands.testfor('@a[name='..player.name..','..selector..']')
- return result
- end
- function checkPlayers(game)
- local selector = "x="..WAITZONE.x..",y="..WAITZONE.y..",z="..WAITZONE.z..",dx="..WAITZONE.w..",dy=256,dz="..WAITZONE.l
- local loggedIn = getAllPos('m=2,'..selector)
- --refresh waitlist
- game.waitlist = loggedIn
- --check currently playing players
- for l,kew in ipairs(game.queues) do
- for i,builder in ipairs(kew.playerlist) do
- local isPlaying = checkForPlayerInBuildzone(builder,kew.buildzone)
- --remove players who are already in kews from the waitlist
- for j, player in ipairs(loggedIn) do
- if player.name == builder.name then
- table.remove(loggedIn,j)
- end
- end
- --if the game is in progress and the player is not found then remove them from the gamekew
- if not isPlaying and kew.phase == 2 then
- --table.remove(kew.playerlist,i)
- --print("Removed "..builder.name.." from game in progress")
- end
- end
- end
- end
- --adds players who wait in the orange room to slots in waiting buildzones
- function allocateWaiters(game)
- --find free slots
- local freeslots = {}
- for i, kew in ipairs(game.queues) do
- if kew.phase == 1 and #kew.playerlist < kew.maxplayers then
- local slots = kew.maxplayers - #kew.playerlist
- for j=1,slots do
- table.insert(freeslots,kew)
- end
- end
- end
- --RE-ENABLE SECOND SHUFFLETABLE IF YOU WANT RANDOM PLAYER MATCHUPS
- shuffleTable(game.waitlist)
- --shuffleTable(freeslots)
- while #freeslots > 0 and #game.waitlist > 0 do
- local player = table.remove(game.waitlist,1)
- local freeslot = table.remove(freeslots,1).playerlist
- table.insert(freeslot,player)
- end
- end
- --PARTICLE FUNCTIONS
- --particles shown to player while their shape is being checked for match
- function searchParticle(x,y,z)
- commands.async.particle("fireworksSpark",x,y,z,0.01,3,0.01,0.01,100)
- end
- -- particles shown to player on successful vocab match
- function successParticle(x,y,z)
- commands.async.particle("happyVillager",x,y,z,2,2,2,1,1000)
- commands.async.playsound("random.levelup","@a",x,y,z,1,1.2)
- end
- --- particles shown to player on failed vocab match
- function failParticle(x,y,z)
- commands.async.particle("reddust",x,y,z,0.1,0.1,1.5,1,200)
- commands.async.particle("reddust",x,y,z,1.5,0.1,0.1,1,200)
- commands.async.playsound("random.bowhit","@a",x,y,z,1,0.8)
- end
- --makes sure that incoming check requests dont exist already
- function addToChecklist(player,buildzone)
- for _, detector in ipairs(buildzone.waitingForCheck) do
- if detector.x == player.x and detector.y == player.y and detector.z == player.z then
- return false
- end
- end
- table.insert(buildzone.waitingForCheck,player)
- return true
- end
- --removes all barrier blocks from a buildzone which are used to carve space in vocabs
- function cleanBarriers(buildzone)
- for h=0,200 do
- 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")
- end
- end
- --The main chunk of code which deals with stepping on detector blocks and reading the vocab
- function updatePlayedZone(buildzone)
- local victory = false
- local buildzoneSelector = buildzone.selector
- --get all players on diamond, add them to the list of things to check
- local detectLocations = getAllOnBlockType(BLOCKS.DETECT.block,buildzoneSelector)
- for _, player in ipairs(detectLocations) do
- addToChecklist(player,buildzone)
- end
- --DEAL WITH THE DETECTOR AT THE TOP OF THE LIST IF THERE IS ONE
- if #buildzone.waitingForCheck > 0 then
- --DO PARTICLE EFFECTS IF A DETECTING BLOCK THAT IS DETECTING
- for i,loc in ipairs(buildzone.waitingForCheck) do
- searchParticle(loc.x,loc.y+1,loc.z)
- end
- local totalResult = false
- local checked = table.remove(buildzone.waitingForCheck,1)
- local x,y,z,name = checked.x,checked.y,checked.z,checked.name
- for i,vocab in pairs(buildzone.vocab) do
- 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")
- if result then
- --clone in the correct vocab
- 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")
- if DEBUG_MODE then
- print(clonemes[1])
- end
- commands.async.give(name,vocab.reward)
- -- announce vocab success in English
- local rewardType = 'nature'
- local rewardTypeDE = 'grüne'
- if vocab.rewardUrban then
- rewardType = 'urban'
- rewardTypeDE = 'urbane'
- end
- --print(vocab.typeEN)
- --print(vocab.nameEN)
- --print(vocab.height)
- --print(vocab.slots)
- --print(vocab.greenSlots)
- --print(vocab.rewardCount)
- --print(rewardType)
- 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"}]')
- -- announce vocab success in German
- 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"}]')
- --clear out barrier blocks
- cleanBarriers(buildzone)
- --ADD THE NEW STRUCTURE TO THE RECORDS
- table.insert(buildzone.structures,vocab.nameEN) ---CHANGE HERE to make it record the place of the vocab too x, y, z and vocab id
- local building = {id=vocab.id,xpos=x,ypos=y,zpos=z,name=vocab.nameEN,time=os.clock(),player=name}
- table.insert(buildzone.buildings, building)
- --if vocab.green then
- buildzone.greenSlots = buildzone.greenSlots + vocab.greenSlots
- --end
- buildzone.filledSlots = buildzone.filledSlots + vocab.slots
- 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
- if newHeight > buildzone.highest then
- buildzone.highest = newHeight
- end
- -- count variety
- print("adding variety: "..vocab.id)
- 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
- --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
- 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
- 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
- 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
- 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
- if varietyId ~= 17 and varietyId ~= 18 then --skip the two riser as they ar enot buildings
- if buildzone.variety[varietyId] then
- print("increasing existing item")
- buildzone.variety[varietyId] = buildzone.variety[varietyId] + 1
- else
- print("adding new item")
- buildzone.variety[varietyId] = 1
- end
- end
- --- CHECK FOR PERSONAL RECORDS
- --- check if the new structure is the highest
- --- CHANGE here to live detect the contribution of the new structure to the 4 goals and update them
- local personalbest = tracker.getScore(name,"highest")
- if personalbest.count < newHeight then
- --commands.async.tell(name,"You just topped your personal record for highest structure!")
- commands.async.scoreboard("players","add",name,"highest",1)
- -- announce success in English
- commands.async.tellraw(name,'["",{"text":"You just topped your personal record for highest neighbourhood!","color":"white"}]')
- -- announce success in German
- commands.async.tellraw(name,'["",{"text":"Du hast soeben deinen persönlichen Rekord für die höchste Nachbarschaft gebrochen!","color":"gold"}]')
- end
- ---
- ---
- -- CHECK if placing the current structure would result in beating a server-wide record on the 4 goals
- --calculate total slots - FOR GOAL "DENSEST NEIGHBOURHOOD"
- local most = tracker.getScore("Densest_[points]","highscores")
- local Kint = math.floor(100 * buildzone.filledSlots / 49) -- Kint is the density index made from built area (filledSlots) over ground area (7x7 slots = 49)
- if Kint > most.count then
- commands.async.scoreboard("players","set","Densest_[points]","highscores",Kint)
- -- announce success in English
- commands.async.tellraw("@a",'["",{"text":"Great! '..name.. ' just topped the record for the DENSEST NEIGHBOURHOOD!","color":"white"}]')
- -- announce success in German
- commands.async.tellraw("@a",'["",{"text":"Sehr gut! '..name.. ' hat einen neuen Rekord für die DICHTESTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
- --commands.async.say("@a","The record for the Densest Neighbourhood has been topped!")
- end
- -- FOR THE GOAL "MOST DIVERSE NEIGHBOURHOOD"
- -- here we need to count how many varieties of buildings there are
- --local structures = tracker.tallyTable(buildzone.structures) -- this counts the variety of buildings in a game
- local mostDiverse = tracker.getScore("Most-Diverse_[out-of-26]","highscores")
- local typeCount = tablelength(buildzone.variety)
- print("variety count is: "..typeCount)
- if typeCount > mostDiverse.count then
- commands.async.scoreboard("players","set","Most-Diverse_[out-of-26]","highscores", typeCount)
- -- announce success in English
- commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' just topped the record for the MOST DIVERSE NEIGHBOURHOOD!","color":"white"}]')
- -- announce success in German
- commands.async.tellraw("@a",'["",{"text":"Wow! '..name.. ' hat soeben einen neuen Rekord für die VIELSEITIGSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
- --commands.async.say("@a","The record for the Most Diverse Neighbourhood has been topped!")
- end
- -- FOR THE GOAL "GREENEST NEIGHBOURHOOD"
- -- here we need to count the number of green vocabs
- local greenest = tracker.getScore("Greenest_[points]","highscores")
- local Gint = math.floor(100*buildzone.greenSlots/49) --Gint is the green index, made from green area (greenSlots) over ground area (7x7 slots = 49)
- if Gint > greenest.count then
- commands.async.scoreboard("players","set","Greenest_[points]","highscores",Gint)
- -- announce success in English
- commands.async.tellraw("@a",'["",{"text":"Awesome! '..name.. ' just topped the record for the GREENEST NEIGHBOURHOOD!","color":"white"}]')
- -- announce success in German
- commands.async.tellraw("@a",'["",{"text":"Klasse! '..name.. ' hat einen neuen Rekord für die GRÜNSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
- ---commands.async.say("@a","The record for the Densest Neighbourhood has been topped!")
- end
- --calculate highest placement -- FOR THE GOAL "TALLEST NEIGHBOURHOOD"
- local highest = tracker.getScore("Tallest_[meters]","highscores")
- if buildzone.highest > highest.count then
- commands.async.scoreboard("players","set","Tallest_[meters]","highscores",buildzone.highest)
- -- announce success in English
- commands.async.tellraw("@a",'["",{"text":"Incredible! '..name..' just topped the record for TALLEST NEIGHBOURHOOD!","color":"white"}]')
- -- announce success in German
- commands.async.tellraw("@a",'["",{"text":"Unglaublich! '..name..' hat einen neuen Rekord für die HÖCHSTE NACHBARSCHAFT aufgestellt!","color":"gold"}]')
- --commands.async.say("@a","The record for the Tallest Negihbourhood has been topped!")
- end
- --increase the "how many structures did i build" score for the building player
- commands.async.scoreboard("players","add",name,"built",1)
- commands.async.scoreboard("players","add",name,"building_"..vocab.id,1)
- totalResult = true
- break
- end
- end
- if totalResult then
- --yey win, do a happy time
- successParticle(x,y,z)
- else
- --no vocab found so do a fail particle
- --announce in English
- commands.async.tellraw(name,'["",{"text":"The shape you have built does not match any shape in the catalogue, try a different one.","color":"red"}]')
- -- announce in German
- 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"}]')
- failParticle(x,y-1,z)
- end
- end
- return victory
- end
- -- returns how many items are in a table/list
- function tablelength(T)
- local count = 0
- for _ in pairs(T) do count = count + 1 end
- return count
- end
- --Display game information on the monitor
- function debugDisplay(game)
- monitor.clear()
- if blink then
- monitor.setCursorPos(1,1)
- monitor.setTextColor(colors.red)
- monitor.write("Running")
- monitor.setTextColor(colors.white)
- redstone.setOutput("top",true)
- blink = false
- else
- redstone.setOutput("top",false)
- blink = true
- end
- local line = 2
- for i,kew in ipairs(game.queues) do
- monitor.setCursorPos(1,line)
- local minutes = string.format("%02d",math.floor(kew.timer/60))
- local seconds = string.format("%02d",math.floor(kew.timer - (minutes*60)))
- monitor.write("Buildzone "..i.." | Phase: "..kew.phase.." | Time: "..minutes..":"..seconds)
- monitor.setCursorPos(1,line+1)
- for i,player in ipairs(kew.playerlist) do
- monitor.write(player.name.." ")
- end
- line = line +2
- end
- monitor.setCursorPos(1,10)
- for i,player in ipairs(game.waitlist) do
- monitor.write(player.name.." ")
- end
- end
- --BEGIN RUNTIME CODE
- local blink = true
- local game = setup()
- while true do
- update(game)
- if monitor then debugDisplay(game) end
- commands.async.weather("clear",10000)
- local resetbutton = redstone.getInput("left")
- if resetbutton then
- print("reset!")
- for i,kew in ipairs(game.queues) do
- if kew.phase == 2 then
- kew.timer = 5
- end
- end
- end
- sleep(2)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement