FILES ----- spawner.config weather.config [NEW] behaviors\coordinator\npccombat.behavior behaviors\npc\combat.behavior behaviors\npc\finalreact.behavior behaviors\npc\react.behavior behaviors\npc\reactionchat.behavior biomes\distributions.config biomes\surface\forest.biome biomes\surface\garden.biome biomes\surface\ocean.biome biomes\surface\snow.biome biomes\surface\tundra.biome biomes\surface_detached\eyepatch.biome [NEW] dungeons\microdungeons\biomes\garden\archway.json [NEW] dungeons\microdungeons\biomes\garden\archway1.json dungeons\microdungeons\biomes\garden\gardenbridge2.json dungeons\microdungeons\biomes\garden\gardenhouseruin1.json dungeons\microdungeons\biomes\garden\gardenmicrodungeons.dungeon [NEW] dungeons\microdungeons\biomes\garden\grave1.json [NEW] dungeons\microdungeons\biomes\garden\grave2.json dungeons\microdungeons\biomes\garden\large1.json [NEW] dungeons\microdungeons\biomes\garden\littlecave1.json [NEW] dungeons\microdungeons\biomes\garden\mediumburriedruin.json dungeons\microdungeons\biomes\garden\mediumgardenflowers.json dungeons\microdungeons\biomes\garden\mediumgardenruin1.json dungeons\microdungeons\biomes\garden\mediumgardenruincamp.json dungeons\microdungeons\biomes\garden\mediumgardenruinplain.json dungeons\microdungeons\biomes\garden\mediumgardenruintall.json [NEW] dungeons\microdungeons\biomes\garden\smallcamp.json dungeons\microdungeons\biomes\garden\smallgardenflowers.json dungeons\microdungeons\biomes\garden\smalltower.json dungeons\microdungeons\biomes\garden\smalltower2.json [NEW] dungeons\microdungeons\biomes\garden\wall1.json [NEW] dungeons\microdungeons\biomes\garden\wall2.json dungeons\other\naturalcave\entrance1-objects.png dungeons\other\naturalcave\entrance2a-objects.png dungeons\other\naturalcave\entrance2a.png dungeons\other\naturalcave\entrance2b-objects.png dungeons\other\naturalcave\entrance2b.png dungeons\other\naturalcave\entrance2c-objects.png dungeons\other\naturalcave\entrance2c.png dungeons\other\naturalcave\entrance3-objects.png dungeons\other\naturalcave\entrance5-objects.png dungeons\other\naturalcave\entrance6-objects.png dungeons\other\naturalcave\naturalcave.dungeon monsters\bmonster.lua [NEW] monsters\critter\bunny\body.monsterpart [NEW] monsters\critter\bunny\body.png [NEW] monsters\critter\bunny\bunny.animation [NEW] monsters\critter\bunny\bunny.monstertype [NEW] monsters\critter\bunny\default.frames [NEW] monsters\critter\eyepodcritter\body.frames [NEW] monsters\critter\eyepodcritter\body.monsterpart [NEW] monsters\critter\eyepodcritter\body.png [NEW] monsters\critter\eyepodcritter\eyepodcritter.animation [NEW] monsters\critter\eyepodcritter\eyepodcritter.monstertype [NEW] monsters\critter\gullcritter\body.frames [NEW] monsters\critter\gullcritter\body.monsterpart [NEW] monsters\critter\gullcritter\body.png [NEW] monsters\critter\gullcritter\gullcritter.animation [NEW] monsters\critter\gullcritter\gullcritter.monstertype [NEW] monsters\critter\owlcritter\body.frames [NEW] monsters\critter\owlcritter\body.monsterpart [NEW] monsters\critter\owlcritter\body.png [NEW] monsters\critter\owlcritter\owlcritter.animation [NEW] monsters\critter\owlcritter\owlcritter.monstertype [NEW] monsters\critter\reasonablecritter\body.frames [NEW] monsters\critter\reasonablecritter\body.monsterpart [NEW] monsters\critter\reasonablecritter\body.png [NEW] monsters\critter\reasonablecritter\reasonablecritter.animation [NEW] monsters\critter\reasonablecritter\reasonablecritter.monstertype monsters\flying\largeflying\largeflying.monstertype monsters\ground\largebiped\largebiped.monstertype monsters\ground\largequadruped\largequadruped.monstertype monsters\ground\smallbiped\smallbiped.monstertype monsters\ground\smallquadruped\smallquadruped.monstertype npcs\bmain.lua npcs\default_reactions.config npcs\tutorial.npctype npcs\villager.npctype npcs\mission\florancelebrator.npctype npcs\mission\floranspectator.npctype npcs\story\nuru.npctype objects\colony\colonydeed\colonydeed.object [NEW] objects\generic\birdsnest\birdsnest.frames [NEW] objects\generic\birdsnest\birdsnest.object [NEW] objects\generic\birdsnest\birdsnest.png [NEW] objects\generic\birdsnest\icon.png objects\generic\travellersbeacon\travellersbeacon.object parallax\images\forestback\base\1.png parallax\images\forestback\base\2.png parallax\images\forestback\base\3.png parallax\images\forestback\base\4.png parallax\surface\forest.parallax scripts\behavior.lua scripts\actions\reaction.lua [NEW] scripts\behavior\bdata.lua [NEW] scripts\behavior\bgroup.lua [NEW] scripts\behavior\composite.lua [NEW] scripts\behavior\decorator.lua stagehands\coordinator.lua [NEW] stagehands\coordinator\npccombat.lua [NEW] stats\effects\npcreactions\bored.animation [NEW] stats\effects\npcreactions\bored.statuseffect [NEW] stats\effects\npcreactions\love.animation [NEW] stats\effects\npcreactions\love.statuseffect [NEW] stats\effects\npcreactions\nosebleed.animation [NEW] stats\effects\npcreactions\nosebleedleft.statuseffect [NEW] stats\effects\npcreactions\nosebleedright.statuseffect [NEW] stats\effects\npcreactions\particlereaction.lua [NEW] stats\effects\npcreactions\vomit.animation [NEW] stats\effects\npcreactions\vomitleft.statuseffect [NEW] stats\effects\npcreactions\vomitright.statuseffect tenants\merchant_apex.tenant tenants\merchant_avian.tenant tenants\merchant_floran.tenant tenants\merchant_glitch.tenant tenants\merchant_human.tenant tenants\merchant_hylotl.tenant tenants\villager_apex.tenant [NEW] tenants\villager_apex2.tenant tenants\villager_avian.tenant [NEW] tenants\villager_avian2.tenant tenants\villager_floran.tenant [NEW] tenants\villager_floran2.tenant tenants\villager_glitch.tenant [NEW] tenants\villager_glitch2.tenant tenants\villager_human.tenant [NEW] tenants\villager_human2.tenant tenants\villager_hylotl.tenant [NEW] tenants\villager_hylotl2.tenant treasure\common.treasurepools DIFFS ----- spawner.config 972c972,1029 < }, --- > }, > > "eyepodcritter" : { > "spawnParameters" : { > "area" : "surface", > "region" : "all", > "time" : "all" > }, > > "targetDensity" : 0.01, > "monsterType" : "eyepodcritter", > "monsterParameters" : { > "aggressive" : false > } > }, > > "gullcritter" : { > "spawnParameters" : { > "area" : "surface", > "region" : "exposed", > "time" : "day" > }, > > "targetDensity" : 0.15, > "monsterType" : "gullcritter", > "monsterParameters" : { > "aggressive" : false > } > }, > > "reasonablecritter" : { > "spawnParameters" : { > "area" : "surface", > "region" : "exposed", > "time" : "day" > }, > > "targetDensity" : 0.15, > "monsterType" : "reasonablecritter", > "monsterParameters" : { > "aggressive" : false > } > }, > > "owlcritter" : { > "spawnParameters" : { > "area" : "surface", > "region" : "exposed", > "time" : "all" > }, > > "targetDensity" : 0.02, > "monsterType" : "owlcritter", > "monsterParameters" : { > "aggressive" : false > } > }, > weather.config 1c1 < //**OPTIONS** --- > //**OPTIONS** 57,59c57,59 < [0.14, "rain"], < [0.14, "drizzle"], < [0.04, "snow" ] --- > [0.15, "rain"], > [0.15, "drizzle"], > [0.02, "snow" ] behaviors\npc\combat.behavior 24c24,26 < "parameters": {} --- > "parameters": { > "trackingRange": 50 > } 31,32d32 < "groupId": "combat", < "goalType": "entity", 33a34,36 > "goalType": "entity", > "groupId": "combat", > "maxMembers": 8, 35c38 < "maxMembers": 8 --- > "behavior": "/behaviors/coordinator/npccombat.behavior" 400,411c403 < "title": "entityPosition", < "type": "action", < "name": "entityPosition", < "parameters": { < "entity": "target" < }, < "output": { < "position": "movePosition" < } < }, < { < "title": "dynamic", --- > "title": "selector", 413c405 < "name": "dynamic", --- > "name": "selector", 417,419c409,411 < "title": "task", < "type": "decorator", < "name": "task", --- > "title": "groupResource", > "type": "action", > "name": "groupResource", 422,424c414 < "taskId": "closeleft", < "minMembers": 1, < "maxMembers": 1 --- > "name": "movePosition" 426,439c416,417 < "child": { < "title": "offsetPosition", < "type": "action", < "name": "offsetPosition", < "parameters": { < "offset": [ < -2, < 0 < ], < "position": "movePosition" < }, < "output": { < "position": "movePosition" < } --- > "output": { > "position": "movePosition" 443,445c421,423 < "title": "task", < "type": "decorator", < "name": "task", --- > "title": "sequence", > "type": "composite", > "name": "sequence", 447,450c425,428 < "groupId": "combat", < "taskId": "closeright", < "minMembers": 1, < "maxMembers": 1 --- > "type": "sliding", > "state": "off", > "fromEntity": "attackTarget", > "toEntity": "fleeTarget" 452,461c430,440 < "child": { < "title": "offsetPosition", < "type": "action", < "name": "offsetPosition", < "parameters": { < "offset": [ < 2, < 0 < ], < "position": "movePosition" --- > "children": [ > { > "title": "entityPosition", > "type": "action", > "name": "entityPosition", > "parameters": { > "entity": "target" > }, > "output": { > "position": "movePosition" > } 463,464c442,454 < "output": { < "position": "movePosition" --- > { > "title": "groundPosition", > "type": "action", > "name": "groundPosition", > "parameters": { > "avoidLiquid": true, > "maxHeight": 5, > "minHeight": -25, > "position": "movePosition" > }, > "output": { > "position": "movePosition" > } 466,518c456 < } < }, < { < "title": "task", < "type": "decorator", < "name": "task", < "parameters": { < "groupId": "combat", < "taskId": "farleft", < "minMembers": 1, < "maxMembers": 1 < }, < "child": { < "title": "offsetPosition", < "type": "action", < "name": "offsetPosition", < "parameters": { < "offset": [ < -4, < 0 < ], < "position": "movePosition" < }, < "output": { < "position": "movePosition" < } < } < }, < { < "title": "task", < "type": "decorator", < "name": "task", < "parameters": { < "groupId": "combat", < "taskId": "farright", < "minMembers": 1, < "maxMembers": 1 < }, < "child": { < "title": "offsetPosition", < "type": "action", < "name": "offsetPosition", < "parameters": { < "offset": [ < 4, < 0 < ], < "position": "movePosition" < }, < "output": { < "position": "movePosition" < } < } --- > ] 521,534d458 < }, < { < "title": "groundPosition", < "type": "action", < "name": "groundPosition", < "parameters": { < "avoidLiquid": true, < "maxHeight": 5, < "minHeight": -25, < "position": "movePosition" < }, < "output": { < "position": "movePosition" < } behaviors\npc\finalreact.behavior 2a3 > "description": "", 7c8,10 < "/npcs/bmain.lua" --- > "/npcs/bmain.lua", > "/scripts/actions/entities.lua", > "/scripts/actions/movement.lua" 102a106,183 > } > ] > }, > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": {}, > "children": [ > { > "title": "isReaction", > "type": "action", > "name": "isReaction", > "parameters": { > "reactionVar": "reaction", > "reactionName": "follow" > } > }, > { > "title": "parallel", > "type": "composite", > "name": "parallel", > "parameters": { > "fail": 1, > "success": -1 > }, > "children": [ > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": {}, > "children": [ > { > "title": "entityPosition", > "type": "action", > "name": "entityPosition", > "parameters": { > "entity": "reactTarget" > }, > "output": { > "position": "reactTarget" > } > }, > { > "title": "moveToPosition", > "type": "action", > "name": "moveToPosition", > "parameters": { > "avoidLiquid": true, > "groundPosition": true, > "maxGround": 5, > "minGround": -5, > "position": "reactTarget", > "run": false, > "failFast": false > }, > "output": { > "direction": "direction" > } > } > ] > }, > { > "title": "inverter", > "type": "decorator", > "name": "inverter", > "parameters": {}, > "child": { > "title": "timer", > "type": "action", > "name": "timer", > "parameters": { > "time": 60 > } > } > } > ] behaviors\npc\react.behavior 9c9,11 < "/scripts/actions/movement.lua" --- > "/scripts/actions/movement.lua", > "/scripts/actions/entities.lua", > "/scripts/actions/math.lua" 309c311 < "reactionName": "blush" --- > "reactionName": "neutral" 313c315 < "title": "addEphemeralEffect", --- > "title": "emote", 315c317 < "name": "addEphemeralEffect", --- > "name": "emote", 317c319 < "name": "blush" --- > "emote": "neutral" 334c336 < "reactionName": "neutral" --- > "reactionName": "laugh" 342c344 < "emote": "neutral" --- > "emote": "laugh" 359c361 < "reactionName": "laugh" --- > "reactionName": "annoyed" 367c369 < "emote": "laugh" --- > "emote": "annoyed" 384c386 < "reactionName": "annoyed" --- > "reactionName": "oh" 392c394 < "emote": "annoyed" --- > "emote": "oh" 409c411 < "reactionName": "oh" --- > "reactionName": "oooh" 417c419 < "emote": "oh" --- > "emote": "oooh" 434c436 < "reactionName": "oooh" --- > "reactionName": "wink" 442c444 < "emote": "oooh" --- > "emote": "wink" 459c461 < "reactionName": "wink" --- > "reactionName": "love" 467c469,590 < "emote": "wink" --- > "emote": "happy" > } > }, > { > "title": "addEphemeralEffect", > "type": "action", > "name": "addEphemeralEffect", > "parameters": { > "name": "love" > } > }, > { > "title": "timer", > "type": "action", > "name": "timer", > "parameters": { > "time": 1.5 > } > } > ] > }, > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": {}, > "children": [ > { > "title": "isReaction", > "type": "action", > "name": "isReaction", > "parameters": { > "reactionVar": "reaction", > "reactionName": "nosebleed" > } > }, > { > "title": "emote", > "type": "action", > "name": "emote", > "parameters": { > "emote": "happy" > } > }, > { > "title": "entityDirection", > "type": "action", > "name": "entityDirection", > "parameters": { > "entity": "self", > "target": "reactTarget" > }, > "output": { > "direction": "direction" > } > }, > { > "title": "selector", > "type": "composite", > "name": "selector", > "parameters": {}, > "children": [ > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": {}, > "children": [ > { > "title": "greaterThan", > "type": "action", > "name": "greaterThan", > "parameters": { > "first": "direction", > "second": 0 > } > }, > { > "title": "addEphemeralEffect", > "type": "action", > "name": "addEphemeralEffect", > "parameters": { > "name": "nosebleedright", > "duration": "1" > } > } > ] > }, > { > "title": "addEphemeralEffect", > "type": "action", > "name": "addEphemeralEffect", > "parameters": { > "name": "nosebleedleft", > "duration": "1" > } > } > ] > } > ] > }, > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": {}, > "children": [ > { > "title": "isReaction", > "type": "action", > "name": "isReaction", > "parameters": { > "reactionVar": "reaction", > "reactionName": "vomit" > } > }, > { > "title": "emote", > "type": "action", > "name": "emote", > "parameters": { > "emote": "oooh" 468a592,647 > }, > { > "title": "entityDirection", > "type": "action", > "name": "entityDirection", > "parameters": { > "entity": "self", > "target": "reactTarget" > }, > "output": { > "direction": "direction", > "vector": "" > } > }, > { > "title": "selector", > "type": "composite", > "name": "selector", > "parameters": {}, > "children": [ > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": {}, > "children": [ > { > "title": "greaterThan", > "type": "action", > "name": "greaterThan", > "parameters": { > "first": "direction", > "second": 0 > } > }, > { > "title": "addEphemeralEffect", > "type": "action", > "name": "addEphemeralEffect", > "parameters": { > "name": "vomitright", > "duration": "1" > } > } > ] > }, > { > "title": "addEphemeralEffect", > "type": "action", > "name": "addEphemeralEffect", > "parameters": { > "name": "vomitleft", > "duration": "1" > } > } > ] behaviors\npc\reactionchat.behavior 154,159c154,191 < "title": "timer", < "type": "action", < "name": "timer", < "parameters": { < "time": 4 < } --- > "title": "selector", > "type": "composite", > "name": "selector", > "parameters": {}, > "children": [ > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": {}, > "children": [ > { > "title": "isFinalReaction", > "type": "action", > "name": "isFinalReaction", > "parameters": { > "influence": "influence" > } > }, > { > "title": "timer", > "type": "action", > "name": "timer", > "parameters": { > "time": 1.5 > } > } > ] > }, > { > "title": "timer", > "type": "action", > "name": "timer", > "parameters": { > "time": 4 > } > } > ] biomes\distributions.config 367a368,373 > "mainBiomeMicrodungeon" : { > "type" : "random", > > "blockProbability" : 0.03 > }, > biomes\surface\forest.biome 8c8 < "extraSpawns" : [ "greentip", "blueback", "birdcritter", "squirrelcritter", "snail", "mousecritter" ], --- > "extraSpawns" : [ "greentip", "blueback", "birdcritter", "squirrelcritter", "snail", "mousecritter", "owlcritter" ], 15c15 < "extraSpawns" : [ "blueback", "redwing", "birdcritter", "squirrelcritter", "snail", "mousecritter" ], --- > "extraSpawns" : [ "blueback", "redwing", "birdcritter", "squirrelcritter", "snail", "mousecritter", "owlcritter" ], 31,44d30 < { < // light lavenderish + red night < "mainColor" : [255, 255, 255], < < "morningColors" : [ [255, 151, 153], [255, 196, 197] ], < "dayColors" : [ [233, 179, 255], [245, 221, 225] ], < "eveningColors" : [ [195, 151, 255], [233, 217, 255] ], < "nightColors" : [ [50, 0, 0, 80], [50, 0, 0, 160] ], < < "morningLightColor" : [176, 81, 83], < "dayLightColor" : [182, 137, 200], < "eveningLightColor" : [150, 115, 199], < "nightLightColor" : [56, 17, 17] < }, 46c32 < // light reddish + overcast night --- > // sunny earth days, red/orange sunrise and purple/red sunset 49,61c35,38 < "morningColors" : [ [255, 224, 129], [252, 230, 164] ], < "dayColors" : [ [255, 152, 107], [255, 183, 152] ], < "eveningColors" : [ [254, 121, 69], [254, 165, 129] ], < "nightColors" : [ [40, 17, 17, 80], [40, 17, 17, 160] ], < < "morningLightColor" : [202, 177, 100], < "dayLightColor" : [202, 138, 100], < "eveningLightColor" : [202, 100, 100], < "nightLightColor" : [40, 17, 17] < }, < { < // light muted blueish < "mainColor" : [255, 255, 255], --- > "morningColors" : [ [242, 120, 0], [255, 230, 176] ], > "dayColors" : [ [115, 224, 255], [255, 255, 255] ], > "eveningColors" : [ [125, 17, 158], [210, 52, 50] ], > "nightColors" : [ [24, 38, 53, 80], [58, 42, 70, 160] ], 63,71c40,43 < "morningColors" : [ [203, 167, 56], [203, 108, 56] ], < "dayColors" : [ [179, 223, 251], [190, 190, 210] ], < "eveningColors" : [ [201, 169, 59], [195, 47, 44] ], < "nightColors" : [ [17, 19, 56, 80], [17, 19, 56, 160] ], < < "morningLightColor" : [158, 121, 42], < "dayLightColor" : [190, 190, 210], < "eveningLightColor" : [124, 50, 38], < "nightLightColor" : [17, 19, 56] --- > "morningLightColor" : [140, 71, 0], > "dayLightColor" : [200, 200, 200], > "eveningLightColor" : [160, 120, 180], > "nightLightColor" : [40, 20, 60] 74c46 < // slight overcast --- > // sunny green day, darkgreen/yellow sunrise and purple/blue sunset 77,80c49,52 < "morningColors" : [ [140, 140, 180], [120, 120, 180] ], < "dayColors" : [ [190, 190, 210], [170, 170, 210] ], < "eveningColors" : [ [160, 120, 180], [140, 100, 180] ], < "nightColors" : [ [26, 26, 31, 80], [26, 26, 31, 160] ], --- > "morningColors" : [ [68, 164, 84], [243, 201, 115] ], > "dayColors" : [ [115, 255, 204], [255, 255, 255] ], > "eveningColors" : [ [43, 17, 118], [244, 161, 231] ], > "nightColors" : [ [24, 38, 53, 80], [58, 42, 70, 160] ], 82,83c54,55 < "morningLightColor" : [140, 140, 180], < "dayLightColor" : [190, 190, 210], --- > "morningLightColor" : [20, 91, 100], > "dayLightColor" : [200, 200, 200], 85c57 < "nightLightColor" : [26, 26, 31] --- > "nightLightColor" : [40, 20, 60] 88c60 < // light aqua with yellow sunrise --- > // sunny lilac day, blue/orange sunrise and blue/green sunset 91,103c63,66 < "morningColors" : [ [227, 209, 123], [244, 196, 66] ], < "dayColors" : [ [197, 236, 246], [133, 185, 235] ], < "eveningColors" : [ [246, 220, 186], [246, 177, 88] ], < "nightColors" : [ [26, 26, 31, 60], [26, 26, 31, 180] ], < < "morningLightColor" : [192, 174, 126], < "dayLightColor" : [190, 202, 204], < "eveningLightColor" : [192, 125, 80], < "nightLightColor" : [26, 26, 31] < }, < { < // light aqua with pinkish sunrise/sunset < "mainColor" : [255, 255, 255], --- > "morningColors" : [ [0, 24, 55], [255, 140, 49] ], > "dayColors" : [ [176, 115, 255], [255, 255, 255] ], > "eveningColors" : [ [100, 86, 173], [0, 222, 73] ], > "nightColors" : [ [24, 38, 53, 80], [58, 42, 70, 160] ], 105,113c68,71 < "morningColors" : [ [219, 119, 184], [246, 153, 177] ], < "dayColors" : [ [197, 236, 246], [133, 185, 235] ], < "eveningColors" : [ [189, 143, 172], [255, 194, 192] ], < "nightColors" : [ [29, 26, 31, 60], [29, 26, 31, 180] ], < < "morningLightColor" : [200, 158, 169], < "dayLightColor" : [190, 202, 204], < "eveningLightColor" : [163, 134, 134], < "nightLightColor" : [29, 26, 31] --- > "morningLightColor" : [140, 71, 0], > "dayLightColor" : [200, 200, 200], > "eveningLightColor" : [160, 120, 180], > "nightLightColor" : [40, 20, 60] 116c74 < // pinkish all around --- > // sunny pink day, pink/peach sunrise and blue/pink sunset 119,127c77,85 < "morningColors" : [ [255, 167, 152], [255, 163, 208] ], < "dayColors" : [ [228, 152, 169], [243, 205, 193] ], < "eveningColors" : [ [221, 186, 235], [247, 73, 121] ], < "nightColors" : [ [28, 14, 14, 60], [28, 14, 14, 180] ], < < "morningLightColor" : [195, 156, 149], < "dayLightColor" : [197, 184, 182], < "eveningLightColor" : [197, 98, 126], < "nightLightColor" : [28, 14, 14] --- > "morningColors" : [ [197, 48, 174], [253, 161, 96] ], > "dayColors" : [ [255, 116, 122], [255, 255, 255] ], > "eveningColors" : [ [88, 42, 91], [175, 20, 50] ], > "nightColors" : [ [24, 38, 53, 80], [58, 42, 70, 160] ], > > "morningLightColor" : [140, 71, 0], > "dayLightColor" : [200, 200, 200], > "eveningLightColor" : [180, 120, 120], > "nightLightColor" : [40, 20, 60] 130c88 < // cool mint --- > // sunny orange day, orange/yellow sunrise and green/orange sunset 133,141c91,99 < "morningColors" : [ [129, 230, 204], [164, 230, 210] ], < "dayColors" : [ [107, 230, 132], [152, 230, 163] ], < "eveningColors" : [ [69, 230, 101], [129, 230, 145] ], < "nightColors" : [ [17, 17, 40, 60], [17, 17, 40, 180] ], < < "morningLightColor" : [100, 240, 202], < "dayLightColor" : [100, 240, 202], < "eveningLightColor" : [100, 240, 202], < "nightLightColor" : [17, 17, 40] --- > "morningColors" : [ [174, 89, 47], [255, 197, 54] ], > "dayColors" : [ [255, 186, 116], [255, 255, 255] ], > "eveningColors" : [ [3, 90, 92], [250, 138, 77] ], > "nightColors" : [ [24, 38, 53, 80], [58, 42, 70, 160] ], > > "morningLightColor" : [140, 71, 0], > "dayLightColor" : [200, 200, 200], > "eveningLightColor" : [180, 120, 120], > "nightLightColor" : [40, 20, 60] biomes\surface\garden.biome 32c32 < // slight overcast --- > // sunny earth days, red/orange sunrise and purple/red sunset 133c133 < "priority" : 3, --- > "priority" : 1, 135c135 < "distribution" : "/biomes/distributions.config:scatteredLarge", --- > "distribution" : "/biomes/distributions.config:mainBiomeMicrodungeon", 152,160d151 < }, < { < "mode" : "floor", < "priority" : 3.0, < "variants" : 1, < "distribution" : "/biomes/distributions.config:tiyDistTerrainfeatures", < < "type" : "microdungeon", < "microdungeons" : [ "terrainfeatures" ] biomes\surface\ocean.biome 8c8 < "extraSpawns" : [ "tidefly", "seahornet" ], --- > "extraSpawns" : [ "tidefly", "seahornet", "gullcritter" ], 15c15 < "extraSpawns" : [ "tidefly", "wavebird" ], --- > "extraSpawns" : [ "tidefly", "wavebird", "gullcritter" ], biomes\surface\snow.biome 8c8 < "extraSpawns" : [ "frostfly", "icetip", "bunnycommon" ], --- > "extraSpawns" : [ "frostfly", "icetip", "bunnycommon", "reasonablecritter" ], 15c15 < "extraSpawns" : [ "frostfly", "frostfleck", "bunnycommon" ], --- > "extraSpawns" : [ "frostfly", "frostfleck", "bunnycommon", "reasonablecritter" ], biomes\surface\tundra.biome 10c10 < "extraSpawns" : [ "aurorabee", "driftbell", "bunny" ], --- > "extraSpawns" : [ "aurorabee", "driftbell", "bunny", "reasonablecritter" ], 17c17 < "extraSpawns" : [ "aurorabee", "shardwing", "bunny" ], --- > "extraSpawns" : [ "aurorabee", "shardwing", "bunny", "reasonablecritter" ], biomes\surface_detached\eyepatch.biome 8c8 < "extraSpawns" : [ "eyefriend" ], --- > "extraSpawns" : [ "eyefriend", "eyepodcritter" ], 15c15 < "extraSpawns" : [ ], --- > "extraSpawns" : [ "eyefriend", "eyepodcritter" ], dungeons\microdungeons\biomes\garden\gardenbridge2.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\gardenhouseruin1.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\gardenmicrodungeons.dungeon 7c7 < "anchor" : [ "mediumgardenflowers", "mediumgardenruin1", "mediumgardenruincamp", "mediumgardenruinplain", "mediumgardenruintall", "smallgardenflowers", "gardenbridge1", "gardenbridge2", "gardenhouseruin1" ], --- > "anchor" : [ "gardenbridge1", "gardenbridge2", "gardenhouseruin1", "grave1", "grave2", "littlecave1", "mediumburriedruin", "mediumgardenflowers", "mediumgardenruin1", "mediumgardenruincamp", "mediumgardenruinplain", "mediumgardenruintall", "smallgardenflowers" , "smalltower", "smalltower2" ], 15a16,64 > "name" : "gardenbridge1", > "rules" : [ > [ "maxSpawnCount", [1] ] > ], > "def" : [ "tmx", "gardenbridge1.json" ] > }, > { > "name" : "gardenbridge2", > "rules" : [ > [ "maxSpawnCount", [1] ] > ], > "def" : [ "tmx", "gardenbridge2.json" ] > }, > { > "name" : "gardenhouseruin1", > "rules" : [ > [ "maxSpawnCount", [1] ] > ], > "def" : [ "tmx", "gardenhouseruin1.json" ] > }, > { > "name" : "grave1", > "rules" : [ > [ "maxSpawnCount", [1] ] > ], > "def" : [ "tmx", "grave1.json" ] > }, > { > "name" : "grave2", > "rules" : [ > [ "maxSpawnCount", [1] ] > ], > "def" : [ "tmx", "grave2.json" ] > }, > { > "name" : "littlecave1", > "rules" : [ > [ "maxSpawnCount", [1] ] > ], > "def" : [ "tmx", "littlecave1.json" ] > }, > { > "name" : "mediumburriedruin", > "rules" : [ > [ "maxSpawnCount", [1] ] > ], > "def" : [ "tmx", "mediumburriedruin.json" ] > }, > { 48c97 < "def" : [ "tmx", "mediumgardenruinplain.json" ] --- > "def" : [ "tmx", "mediumgardenruintall.json" ] 55c104 < "def" : [ "tmx", "mediumgardenruinplain.json" ] --- > "def" : [ "tmx", "smallgardenflowers.json" ] 58c107 < "name" : "gardenbridge1", --- > "name" : "smalltower", 62c111 < "def" : [ "tmx", "gardenbridge1.json" ] --- > "def" : [ "tmx", "smalltower.json" ] 65c114 < "name" : "gardenbridge2", --- > "name" : "smalltower2", 69,76c118 < "def" : [ "tmx", "gardenbridge2.json" ] < }, < { < "name" : "gardenhouseruin1", < "rules" : [ < [ "maxSpawnCount", [1] ] < ], < "def" : [ "tmx", "gardenhouseruin1.json" ] --- > "def" : [ "tmx", "smalltower2.json" ] dungeons\microdungeons\biomes\garden\large1.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\mediumgardenflowers.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\mediumgardenruin1.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\mediumgardenruincamp.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\mediumgardenruinplain.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\mediumgardenruintall.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\smallgardenflowers.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\smalltower.json [TMX file differences are left out for huge size.] dungeons\microdungeons\biomes\garden\smalltower2.json [TMX file differences are left out for huge size.] dungeons\other\naturalcave\naturalcave.dungeon 513a514,519 > > { > "value" : [80, 149, 91, 255], > "comment" : "travellersbeacon", > "brush" : [ [ "clear" ], [ "object", "travellersbeacon", { "direction" : "left" } ] ] > }, monsters\bmonster.lua 22c22 < self.behavior = BTree:new(entity.behavior()) --- > self.behavior = BTree:new(entity.configParameter("behavior")) monsters\flying\largeflying\largeflying.monstertype 152,171c152 < "acidicSpitAttack", < "acidSprayAttack", < "barbSprayAttack", < "bloodVomitAttack", < "bubbleBlastAttack", < "darkPlasmaAttack", < "explosivePhlegmAttack", < "fireballAttack", < "fireSwirlAttack", < "flameBurstAttack", < "flySwarmAttack", < "gasBelchAttack", < "iceBlastAttack", < "iceShotAttack", < "rockShotAttack", < "shockBallAttack", < "shockingBoltAttack", < "sonicScreamAttack", < "sonicWaveAttack", < "twistingPulseAttack" --- > "shockingWaveAttack", "staticDischargeAttack", "bubbleBlastAttack", "waterGunAttack", "burninghaloAttack", "gasBelchAttack", "rainbowVomitAttack", "shockingBoltAttack", "plasmaTorpedoAttack", "eyeballSprayAttack", "bloodVomitAttack", "acidicSpitAttack", "fireballAttack", "icerockShotAttack", "doubleBarbSprayAttack", "miniDragonBreathAttack", "acidSprayAttack", "beamBurstAttack", "plasmaSweepAttack", "eyeballShotAttack", "glitterAttack", "darkGravityBallAttack", "fireSwirlAttack", "rockRollAttack", "iceBlastAttack", "snotBubbleAttack", "leafyGustAttack", "mudBallAttack", "lightBallAttack", "shardSprayAttack", "blueFlameAttack", "smokeRingAttack", "putridWaveAttack", "boneRainAttack", "orbOfZotsAttack", "snotShotAttack", "fishBreathAttack", "explosivePhlegmAttack", "cellBlastAttack" monsters\ground\largebiped\largebiped.monstertype 119,120c119,120 < "walkSpeed" : 2.5, < "runSpeed" : 6.5 --- > "walkSpeed" : 3.0, > "runSpeed" : 11.0 monsters\ground\largequadruped\largequadruped.monstertype 157c157 < "runSpeed" : 8.0 --- > "runSpeed" : 12.0 monsters\ground\smallbiped\smallbiped.monstertype 100,101c100,101 < "walkSpeed" : 2.5, < "runSpeed" : 6.5 --- > "walkSpeed" : 1, > "runSpeed" : 9 monsters\ground\smallquadruped\smallquadruped.monstertype 110,111c110,111 < "walkSpeed" : 2.5, < "runSpeed" : 6.5 --- > "walkSpeed" : 2.0, > "runSpeed" : 10.0 npcs\bmain.lua 17c17 < self.behavior = BTree:new(entity.behavior()) --- > self.behavior = BTree:new(entity.configParameter("behavior")) npcs\default_reactions.config 28c28,29 < [2.0, "blush"], --- > [1.0, "love"], > [1.0, "nosebleed"], 30a32,62 > "love" : [ > [2.0, "love"], > [1.0, "nosebleed"], > [1.0, "wink"] > ], > "nosebleed" : [ > [1.0, "wink"], > [1.0, "nosebleed"], > [1.0, "love"], > [1.0, "vomit"] > ], > "vomit" : [ > [4.0, "vomit"], > [1.0, "cry"], > [1.0, "gohome"], > [1.0, "flee"] > ], > "gohome" : [ > [3.0, "quit"], > [1.0, "follow"] > ], > "flee" : [ > [3.0, "quit"], > [3.0, "follow"], > [1.0, "cry"], > [1.0, "smile"] > ], > "follow" : [ > [1.0, "gohome"], > [1.0, "flee"] > ], 40d71 < [1.0, "blush"], 46a78,80 > [1.0, "love"], > [1.0, "nosebleed"], > [1.0, "vomit"], 51c85,86 < [1.0, "gohome"] --- > [1.0, "gohome"], > [1.0, "follow"] 57c92 < "finalReactions" : ["quit", "flee", "gohome"] --- > "finalReactions" : ["quit", "flee", "gohome", "follow"] npcs\tutorial.npctype 14,15d13 < "behavior" : "/behaviors/npc/tutorial.behavior", < 16a15,16 > "behavior" : "/behaviors/npc/tutorial.behavior", > 115c115 < "You should have a flashlight on you for when it gets dark. Hungry beasts come out to hunt at night!", --- > "You should have a flashlight on you for when it gets dark. Hungry beasts come out to hunt!", 125c125 < "Can you imagine what it must have been like to live only on one planet?", --- > "Can you imagine what it must have been like to only be able to live on one planet?", 562c562 < "baseValue" : 40 --- > "baseValue" : 80 565c565 < "baseValue" : 5.0 --- > "baseValue" : 15.0 npcs\villager.npctype 14,15d13 < "behavior" : "/behaviors/npc/villager.behavior", < 16a15,17 > "behavior" : "/behaviors/npc/villager.behavior", > "personality" : "normal", > npcs\mission\florancelebrator.npctype 15d14 < "behavior" : "/behaviors/npc/floranspectator.behavior", 17a17,18 > "behavior" : "/behaviors/npc/floranspectator.behavior", > npcs\mission\floranspectator.npctype 15,16d14 < "behavior" : "/behaviors/npc/floranspectator.behavior", < 17a16,17 > "behavior" : "/behaviors/npc/floranspectator.behavior", > npcs\story\nuru.npctype 25,26d24 < "behavior" : "/behaviors/sequences/floranmission/nuruboss.behavior", < 27a26,27 > "behavior" : "/behaviors/sequences/floranmission/nuruboss.behavior", > objects\colony\colonydeed\colonydeed.object 40c40 < "debug" : false, --- > "debug" : true, objects\generic\travellersbeacon\travellersbeacon.object 22,23c22,23 < "imageLayers" : [ { "image" : "travellersbeacon.png:." } ], < "imagePosition" : [-8, 0], --- > "imageLayers" : [ { "image" : "travellersbeacon.png:.", "fullbright" : true }, { "image" : "travellersbeaconlit.png:." } ], > "imagePosition" : [-16, -16], parallax\surface\forest.parallax 57c57 < "fadePercent" : 0.15 --- > "fadePercent" : 0.35 59a60,61 > // Day Clouds > 63c65 < "offset" : [0, 120], --- > "offset" : [0, 240], 65,67c67,71 < "minSpeed" : 5000, < "maxSpeed" : 10000, < "fadePercent" : 0.15 --- > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" 69d72 < 73c76 < "offset" : [0, 140], --- > "offset" : [0, 280], 75,77c78,82 < "minSpeed" : 2000, < "maxSpeed" : 5000, < "fadePercent" : 0.06 --- > "minSpeed" : 500, > "maxSpeed" : 2500, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" 79d83 < 83c87 < "offset" : [0, 150], --- > "offset" : [0, 300], 85,87c89,93 < "minSpeed" : 5000, < "maxSpeed" : 10000, < "fadePercent" : 0.04 --- > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" 89d94 < 93c98 < "offset" : [0, 60], --- > "offset" : [0, 120], 95,97c100,104 < "minSpeed" : 5000, < "maxSpeed" : 10000, < "fadePercent" : 0.15 --- > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" 99d105 < 103c109 < "offset" : [0, 80], --- > "offset" : [0, 160], 105c111,122 < "minSpeed" : 2000, --- > "minSpeed" : 500, > "maxSpeed" : 2500, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" > }, > { > "kind" : "clouds1", > "baseCount" : 2, > "offset" : [0, 200], > "parallax" : 6, > "minSpeed" : 1000, 107c124,148 < "fadePercent" : 0.06 --- > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" > }, > { > "kind" : "clouds3", > "baseCount" : 2, > "offset" : [0, 2], > "parallax" : 9, > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" > }, > { > "kind" : "clouds2", > "baseCount" : 2, > "offset" : [0, 40], > "parallax" : 14, > "minSpeed" : 500, > "maxSpeed" : 2500, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" 109d149 < 113c153 < "offset" : [0, 100], --- > "offset" : [0, 80], 115,117c155,159 < "minSpeed" : 5000, < "maxSpeed" : 10000, < "fadePercent" : 0.04 --- > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : true, > "timeOfDayCorrelation" : "dayCloudVisible" 119a162,163 > // Night Clouds > 123c167 < "offset" : [0, 1], --- > "offset" : [0, 240], 125,127c169,173 < "minSpeed" : 5000, < "maxSpeed" : 10000, < "fadePercent" : 0.15 --- > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" 129d174 < 133c178 < "offset" : [0, 20], --- > "offset" : [0, 280], 135c180,191 < "minSpeed" : 2000, --- > "minSpeed" : 500, > "maxSpeed" : 2500, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" > }, > { > "kind" : "clouds1", > "baseCount" : 2, > "offset" : [0, 300], > "parallax" : 6, > "minSpeed" : 1000, 137c193,217 < "fadePercent" : 0.06 --- > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" > }, > { > "kind" : "clouds3", > "baseCount" : 2, > "offset" : [0, 120], > "parallax" : 9, > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" > }, > { > "kind" : "clouds2", > "baseCount" : 2, > "offset" : [0, 160], > "parallax" : 14, > "minSpeed" : 500, > "maxSpeed" : 2500, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" 139d218 < 142a222,243 > "offset" : [0, 200], > "parallax" : 6, > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" > }, > { > "kind" : "clouds3", > "baseCount" : 2, > "offset" : [0, 2], > "parallax" : 9, > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" > }, > { > "kind" : "clouds2", > "baseCount" : 2, 143a245,255 > "parallax" : 14, > "minSpeed" : 500, > "maxSpeed" : 2500, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" > }, > { > "kind" : "clouds1", > "baseCount" : 2, > "offset" : [0, 80], 145,147c257,261 < "minSpeed" : 5000, < "maxSpeed" : 10000, < "fadePercent" : 0.04 --- > "minSpeed" : 1000, > "maxSpeed" : 5000, > "fadePercent" : 0.0, > "unlit" : false, > "timeOfDayCorrelation" : "nightCloudVisible" scripts\behavior.lua 0a1,3 > require "/scripts/behavior/bgroup.lua" > require "/scripts/behavior/bdata.lua" > 2c5 < local extend = function(base) --- > function extend(base) 17c20 < function BTree:new(behavior) --- > function BTree:new(path) 21c24 < newTree.behavior = behavior --- > local behavior = root.behaviorModule(path) 26c29 < self:loadScripts(behavior.scripts) --- > self.loadScripts(behavior.scripts) 39,40c42,43 < function BTree:loadScripts(scripts) < for _,script in ipairs(scripts) do --- > function BTree.loadScripts(scripts) > for _,script in pairs(scripts) do 59a63,68 > function BTree:interrupt() > if self.root then > self.root:interrupt() > end > end > 76a86,89 > function BTNode:interrupt() > return false > end > 80c93 < local composites = {} --- > composites = {} 129,434c142 < -- Sequence node < -- Runs each child in order until one child fails < BTSequence = BTComposite.new() < composites["sequence"] = BTSequence < < function BTSequence.new(children) < local newNode = { < children = children or {}, < } < setmetatable(newNode, extend(BTSequence)) < return newNode < end < < function BTSequence.fromJson(node, parameters) < local children = {} < for _,child in pairs(node.children) do < table.insert(children, nodeFromJson(child, parameters)) < end < return BTSequence.new(children) < end < < function BTSequence:run(dt) < if self.current == nil then self.current = 1 end < < while self.current <= #self.children do < local result = self:runChild(self.current, dt) < < if result == true then < self.current = self.current + 1 < elseif result == false then < return false < else < return "running" < end < end < return true < end < < function BTSequence:reset() < if self.current and self.children[self.current] then < self.children[self.current]:reset() < end < self.current = nil < end < < -- Cleanup node < -- Runs each child in order until one child fails < -- On fail or interruption it still runs each child once < BTCleanup = BTComposite.new() < composites["cleanup"] = BTCleanup < < function BTCleanup.new(children) < local newNode = { < children = children or {}, < current = 1 < } < setmetatable(newNode, extend(BTCleanup)) < return newNode < end < < function BTCleanup.fromJson(node, parameters) < local children = {} < for _,child in pairs(node.children) do < table.insert(children, nodeFromJson(child, parameters)) < end < return BTCleanup.new(children) < end < < function BTCleanup:run(dt) < while self.current <= #self.children do < local result = self:runChild(self.current, dt) < < if result == true then < self.current = self.current + 1 < elseif result == false then < self:cleanup(dt) < return false < else < return "running" < end < end < return true < end < < function BTCleanup:cleanup(dt) < self.current = self.current + 1 < while self.current <= #self.children do < self:runChild(self.current, dt) < self.current = self.current + 1 < end < end < < function BTCleanup:interrupt() < self:cleanup(script.updateDt()) < end < < function BTCleanup:reset() < if self.current and self.children[self.current] then < self.children[self.current]:reset() < end < self.current = 1 < end < < -- Selector node < -- Runs each child until one succeeds < BTSelector = BTComposite.new() < composites["selector"] = BTSelector < < function BTSelector.new(children) < local newNode = { < children = children or {}, < state = {} -- reset on every success or fail < } < setmetatable(newNode, extend(BTSelector)) < return newNode < end < < function BTSelector.fromJson(node, parameters) < local children = {} < for _,child in pairs(node.children) do < table.insert(children, nodeFromJson(child, parameters)) < end < return BTSelector.new(children) < end < < function BTSelector:run(dt) < if self.current == nil then self.current = 1 end < < while self.current <= #self.children do < local result = self:runChild(self.current, dt) < < if result == false then < self.current = self.current + 1 < elseif result == true then < return true < else < return "running" < end < end < return false < end < < function BTSelector:reset() < if self.current and self.children[self.current] then < self.children[self.current]:reset() < end < self.current = nil < end < < -- Dynamic node < -- Dynamic selector that keeps running failed nodes while running the current node < BTDynamic = BTComposite.new() < composites["dynamic"] = BTDynamic < < function BTDynamic.new(children) < local newNode = { < children = children or {}, < state = {} -- reset on every success or fail < } < setmetatable(newNode, extend(BTDynamic)) < return newNode < end < < function BTDynamic.fromJson(node, parameters) < local children = {} < for _,child in pairs(node.children) do < table.insert(children, nodeFromJson(child, parameters)) < end < return BTDynamic.new(children) < end < < function BTDynamic:run(dt) < if self.current == nil then self.current = 1 end < < local result < for i,child in ipairs(self.children) do < if i <= self.current then < result = self:runChild(i, dt) < < if result == false then < if i == self.current then < self.current = self.current + 1 < end < else < if i < self.current and result == "running" then < --Interrupt and reset the current node < self.children[self.current]:interrupt() < self.children[self.current]:reset() < end < < self.current = i < < if result == true then < return true < end < end < else < break < end < end < return result < end < < function BTDynamic:reset() < if self.current and self.children[self.current] then < self.children[self.current]:reset() < end < self.current = nil < end < < -- Parallel node < -- Runs all the children until success/fail conditions are met < BTParallel = BTComposite.new() < composites["parallel"] = BTParallel < < function BTParallel.new(parameters, children) < local newNode = { < children = children or {}, < success = parameters.success or -1, < fail = parameters.fail or -1, < running = {} < } < setmetatable(newNode, extend(BTParallel)) < return newNode < end < < function BTParallel.fromJson(node, parameters) < local children = {} < for _,child in pairs(node.children) do < table.insert(children, nodeFromJson(child, parameters)) < end < local newNode = BTParallel.new(node.parameters, children) < return newNode < end < < function BTParallel:run(dt) < local succeeded = 0 < local failed = 0 < < for i,_ in ipairs(self.children) do < local result = self:runChild(i, dt) < < if result == "running" then < self.running[i] = true < else < self.running[i] = false < end < < if result == true then < succeeded = succeeded + 1 < elseif result == false then < failed = failed + 1 < end < < if succeeded == #self.children or (self.success ~= -1 and succeeded >= self.success) then < return true < elseif failed == #self.children or (self.fail ~= -1 and failed >= self.fail) then < return false < end < < end < < return "running" < end < < function BTParallel:interruptRunning() < for i,running in pairs(self.running) do < if running then < self.children[i]:interrupt() < end < end < end < < function BTParallel:reset() < self:interruptRunning() < self.running = {} < for _,child in pairs(self.children) do < child:reset() < end < end < < -- Random node < -- Runs one random child < BTRandomize = BTComposite.new() < composites["randomize"] = BTRandomize < < function BTRandomize.new(children) < local newNode = { < children = children or {}, < } < setmetatable(newNode, extend(BTRandomize)) < return newNode < end < < function BTRandomize.fromJson(node, parameters) < local children = {} < for _,child in pairs(node.children) do < table.insert(children, nodeFromJson(child, parameters)) < end < return BTRandomize.new(children) < end < < function BTRandomize:run(dt) < if self.current == nil then self.current = math.random(1, #self.children) end < < local result = self:runChild(self.current, dt) --- > require "/scripts/behavior/composite.lua" 436,444d143 < return result < end < < function BTRandomize:reset() < if self.current and self.children[self.current] then < self.children[self.current]:reset() < end < self.current = nil < end 449c148 < local decorators = {} --- > decorators = {} 486,786c185 < -- Inverter < -- Return false if the child is true, return true if the child is false < BTInverter = BTDecorator.new() < decorators["inverter"] = BTInverter < < function BTInverter.new(child) < local newNode = {} < setmetatable(newNode, extend(BTInverter)) < newNode:setChild(child) < return newNode < end < < function BTInverter.fromJson(node, parameters) < return BTInverter.new(nodeFromJson(node.child, parameters)) < end < < function BTInverter:run(dt) < local result = self:runChild(dt) < if result == true then < return false < elseif result == false then < return true < else < return "running" < end < end < < -- Succeeder < -- Always returns running or success < BTSucceeder = BTDecorator.new() < decorators["succeeder"] = BTSucceeder < < function BTSucceeder.new(child) < local newNode = {} < setmetatable(newNode, extend(BTSucceeder)) < newNode:setChild(child) < return newNode < end < < function BTSucceeder.fromJson(node, parameters) < return BTSucceeder.new(nodeFromJson(node.child, parameters)) < end < < function BTSucceeder:run(dt) < local result = self:runChild(dt) < if result == true or result == false then < return true < else < return "running" < end < end < < -- Failer < -- Always returns failure < BTFailer = BTDecorator.new() < decorators["failer"] = BTFailer < < function BTFailer.new(child) < local newNode = {} < setmetatable(newNode, extend(BTFailer)) < newNode:setChild(child) < return newNode < end < < function BTFailer.fromJson(node, parameters) < return BTFailer.new(nodeFromJson(node.child, parameters)) < end < < function BTFailer:run(dt) < local result = self:runChild(dt) < if result == true or result == false then < return false < else < return "running" < end < end < < -- Limiter < -- Globally limit the amount of executions < BTLimiter = BTDecorator.new() < decorators["limiter"] = BTLimiter < limiters = {} < < function BTLimiter.new(child, limit) < local newNode = { < limit = limit or 1, < runs = 0 < } < setmetatable(newNode, extend(BTLimiter)) < newNode:setChild(child) < return newNode < end < < function BTLimiter.fromJson(node, parameters) < local parameters = node.parameters or {} < return BTLimiter.new(nodeFromJson(node.child, parameters), parameters.limit) < end < < function BTLimiter:run(dt) < limiters[self] = limiters[self] or 0 < if limiters[self] >= self.limit then return false end < local result = self:runChild(dt) < if result == true then < limiters[self] = limiters[self] + 1 < return true < else < return result < end < end < < -- Cooldown < -- After an action succeeds wait a specified amount of time before running it again < BTCooldown = BTDecorator.new() < decorators["cooldown"] = BTCooldown < < function BTCooldown.new(cooldown, onFail, child) < if onFail == nil then onFail = false end < local newNode = { < cooldown = cooldown, < onFail = onFail, < time = 0 < } < setmetatable(newNode, extend(BTCooldown)) < newNode:setChild(child) < return newNode < end < < function BTCooldown.fromJson(node, parameters) < local args = node.parameters or {} < return BTCooldown.new(args.cooldown, args.onFail, nodeFromJson(node.child, parameters)) < end < < function BTCooldown:run(dt) < if world.time() < self.time then < return false < end < < local result = self:runChild(dt) < if result == true or (onFail and result == false) then < self.time = world.time() + self.cooldown < end < return result < end < < -- Repeater < -- Loop n times < BTRepeater = BTDecorator.new() < decorators["repeater"] = BTRepeater < < function BTRepeater.new(maxLoops, untilSuccess, child) < local newNode = { < maxLoops = maxLoops, < untilSuccess = untilSuccess, < loops = 0 < } < setmetatable(newNode, extend(BTRepeater)) < newNode:setChild(child) < return newNode < end < < function BTRepeater.fromJson(node, parameters) < local args = node.parameters or {} < args = parseArgs(args, { < maxLoops = -1, < untilSuccess = false < }) < return BTRepeater.new(args.maxLoops, args.untilSuccess, nodeFromJson(node.child, parameters)) < end < < function BTRepeater:run(dt) < while (self.loops < self.maxLoops or self.maxLoops == -1) and (not self.untilSuccess or self.result ~= true) do < self.result = self:runChild(dt) < if self.result == true or self.result == false then < self.loops = self.loops + 1 < else < break < end < end < return self.result < end < < function BTRepeater:reset() < self.result = nil < self.loops = 0 < self.child:reset() < end < < -- Group < -- Share a goal with nearby entities with the same goal < -- Coordinates entities < BTGroup = BTDecorator.new() < decorators["group"] = BTGroup < < function BTGroup.new(args, child) < local newNode = { < init = false, < position = args.position, < group = { < groupId = args.groupId, < goalType = args.goalType, < goal = args.goal, < minMembers = args.minMembers, < maxMembers = args.maxMembers, < behavior = args.behavior < } < } < setmetatable(newNode, extend(BTGroup)) < newNode:setChild(child) < return newNode < end < < function BTGroup.fromJson(node, parameters) < local args = node.parameters or {} < args = parseArgs(args, { < }) < return BTGroup.new(args, nodeFromJson(node.child, parameters)) < end < < function BTGroup:run(dt) < if not self.init then < self:parseGoal() < self.init = true < end < < local position = BData:getPosition(self.position) < local groupResult = BGroup:joinGroup(self.group, position) < < --Someone else returned success to the shared goal < if groupResult == "success" then < BGroup:leaveGroup(self.group.groupId) < return true < end < < if groupResult == true then < local childResult = self:runChild(dt) < if childResult == false or childResult == true then < BGroup:leaveGroup(self.group.groupId) < if childResult == true then < BGroup:setGroupSuccess(self.group.groupId) < end < end < return childResult < else < self.init = false < return false < end < end < < function BTGroup:parseGoal() < if self.group.goalType == "entity" then < self.group.goal = BData:getEntity(self.group.goal) < elseif self.group.goalType == "position" then < self.group.goal = BData:getPosition(self.group.goal) < elseif self.group.goalType == "list" then < self.group.goal = BData:getList(self.group.goal) < end < end < < function BTGroup:reset(dt) < self.init = false < self.child:reset() < end < < -- Task < -- Limit entities in a group to a task < -- Coordinates entities within a group < BTTask = BTDecorator.new() < decorators["task"] = BTTask < < function BTTask.new(args, child) < local newNode = { < groupId = args.groupId, < task = { < taskId = args.taskId, < minMembers = args.minMembers, < maxMembers = args.maxMembers < } < } < setmetatable(newNode, extend(BTTask)) < newNode:setChild(child) < return newNode < end < < function BTTask.fromJson(node, parameters) < local args = node.parameters or {} < args = parseArgs(args, { < }) < return BTTask.new(args, nodeFromJson(node.child, parameters)) < end < < function BTTask:run(dt) < if BGroup:joinTask(self.groupId, self.task) then < return self:runChild(dt) < else < return false < end < end < < function BTTask:reset(dt) < self.child:reset() < end --- > require "/scripts/behavior/decorator.lua" 836c235 < -- JSON PARSING --- > -- MODULE NODES 837a237 > BTModule = BTNode.new() 839,913c239,245 < function nodeFromJson(node, parameters) < if node.type == "action" then < return BTAction.fromJson(node, parameters) < elseif node.type == "composite" then < return BTComposite.fromJson(node, parameters) < elseif node.type == "decorator" then < return BTDecorator.fromJson(node, parameters) < elseif node.type == "module" then < local module = root.behaviorModule(node.path, parameters) < BTree:loadScripts(module.scripts) < return nodeFromJson(module.root, module.parameters) < else < world.logInfo("Invalid node type %s", node.type) < end < end < < ----------------------------------------------------------- < -- DATABASE < ----------------------------------------------------------- < < BData = { < board = {} < } < < function BData:set(type, key, value) < self.board[type] = self.board[type] or {} < if key == nil then return false end < self.board[type][key] = value < end < < function BData:get(type, key) < self.board[type] = self.board[type] or {} < return self.board[type][key] < end < < function BData:setNumber(key, number) < self:set("number", key, number) < end < < function BData:getNumber(key) < if type(key) == "number" then < return key < else < return self:get("number", key) < end < end < < function BData:setEntity(key, entityId) < self:set("entity", key, entityId) < end < < function BData:getEntity(key) < if type(key) == "number" then < return key < elseif key == "self" then < return entity.id() < else < return self:get("entity", key) < end < end < < function BData:setVec2(key, vector) < self:set("vec2", key, vector) < end < < function BData:getVec2(key) < if type(key) == "table" then < return {BData:getNumber(key[1]), BData:getNumber(key[2])} < else < return self:get("vec2", key) < end < end < < function BData:setPosition(key, position) < self:set("position", key, position) --- > function BTModule.new(module) > local newNode = { > parameters = module.parameters or {}, > path = module.path > } > setmetatable(newNode, extend(BTModule)) > return newNode 916,923c248,252 < function BData:getPosition(key) < if type(key) == "table" then < return key < elseif key == "self" then < return mcontroller.position() < else < return self:get("position", key) < end --- > function BTModule.fromJson(node, parameters) > return BTModule.new({ > path = node.path, > parameters = node.parameters > }) 926,930c255,260 < function BData.listType(args) < for k,v in pairs(args) do < if k ~= "list" and k ~= "dt" then < return k,v < end --- > function BTModule:run(dt) > if not self.node then > local tree = root.behaviorModule(self.path) > local parameters = parseArgs(self.parameters, tree.parameters) > BTree.loadScripts(tree.scripts) > self.node = nodeFromJson(tree.root, parameters) 932d261 < end 934,964c263,265 < function BData:getList(listKey) < self.lists = self.lists or {} < if type(listKey) == "table" then < return listKey < else < return self.lists[listKey] < end < end < < function BData:setList(listKey, list) < self.lists = self.lists or {} < if listKey == nil then return false end < self.lists[listKey] = list < return true < end < < < function BData:pushList(listKey, value) < self.lists = self.lists or {} < self.lists[listKey] = self.lists[listKey] or {} < table.insert(self.lists[listKey], 1, value) < return true < end < < function BData:popList(listKey) < self.lists = self.lists or {} < self.lists[listKey] = self.lists[listKey] or {} < if self.lists[listKey][1] then < local value = self.lists[listKey][1] < table.remove(self.lists[listKey], 1) < return value --- > local result = self.node:run(dt) > if result == true or result == false then > self.node:reset() 965a267 > return result 968,972c270,272 < function BData:peekList(listKey) < self.lists = self.lists or {} < self.lists[listKey] = self.lists[listKey] or {} < if self.lists[listKey][1] then < return self.lists[listKey][1] --- > function BTModule:reset() > if self.node then > self.node:reset() 976,986c276,278 < function BData:clearList(listKey) < self.lists = self.lists or {} < self.lists[listKey] = {} < return true < end < < function BData:inList(listKey, value) < self.lists = self.lists or {} < self.lists[listKey] = self.lists[listKey] or {} < for _,v in ipairs(self.lists[listKey]) do < if v == value then return true end --- > function BTModule:interrupt() > if self.node then > self.node:interrupt() 988d279 < return false 992c283 < -- BEHAVIOR GROUPS --- > -- JSON PARSING 995,1063c286,289 < BGroup = { < groups = {}, < joinedGroups = {}, < tasks = {}, < joinedTasks = {} < } < < function BGroup.findGroupPosition(goalType, goal) < if goalType == "entity" then < return world.entityPosition(goal) < elseif goalType == "position" then < return goal < elseif goalType == "list" then < world.logInfo("Cannot get position for goal type \"list\"") < end < end < < function BGroup:joinGroup(group, position) < if self.groups[group.groupId] then < if world.entityExists(self.groups[group.groupId]) then < return self:requestJoinGroup(self.groups[group.groupId], group.groupId, group.goalType, group.goal) < else < self.groups[group.groupId] = nil < end < end < position = position or BGroup.findGroupPosition(group.goalType, group.goal) < < --Query existing coordinators < local stagehands = world.entityQuery(position, 10, {includedTypes = {"stagehand"}}) < for k,stagehandId in ipairs(stagehands) do < if world.stagehandType(stagehandId) == "coordinator" then < local result = self:requestJoinGroup(stagehandId, group.groupId, group.goalType, group.goal) < if result == true then < self.groups[group.groupId] = stagehandId < end < if result then return result end < end < end < < --Spawn a coordinator < local stagehandId = world.spawnStagehand(position, "coordinator", {scriptConfig = group, behavior = group.behavior}) < return self:requestJoinGroup(stagehandId, group.groupId, group.goalType, group.goal) < end < < function BGroup:requestJoinGroup(entityId, groupId, goalType, goal) < self.joinedGroups = self.joinedGroups or {} < local result = world.callScriptedEntity(entityId, "onRequestJoin", entity.id(), goalType, goal) < if result then < self.joinedGroups[groupId] = entityId < if result == true then < self.groups[groupId] = entityId < end < end < return result < end < < function BGroup:leaveGroup(groupId) < local coordinator = self:groupCoordinator(groupId) < if coordinator then < --world.logInfo("%s left group %s", entity.id(), groupId) < world.callScriptedEntity(coordinator, "onLeaveGroup", entity.id()) < end < end < < function BGroup:updateGroups() < --Leave any tasks not joined this update < for taskId,task in pairs(self.tasks) do < if not self.joinedTasks[taskId] then < self:leaveTask(task.groupId, task.taskId) --- > function nodeFromJson(node, parameters) > if node.parameters then > for k,v in pairs(node.parameters) do > node.parameters[k] = replaceTag(v, parameters) 1066,1067d291 < self.tasks = self.joinedTasks < self.joinedTasks = {} 1069,1073c293,302 < --Leave any groups not joined this update < for groupId,entityId in pairs(self.groups) do < if self.joinedGroups[groupId] == nil or self.joinedGroups[groupId] ~= entityId then < BGroup:leaveGroup(groupId) < end --- > if node.type == "action" then > return BTAction.fromJson(node, parameters) > elseif node.type == "composite" then > return BTComposite.fromJson(node, parameters) > elseif node.type == "decorator" then > return BTDecorator.fromJson(node, parameters) > elseif node.type == "module" then > return BTModule.fromJson(node, parameters) > else > world.logInfo("Invalid node type %s", node.type) 1075,1076d303 < self.groups = self.joinedGroups < self.joinedGroups = {} 1079,1085c306,315 < function BGroup:joinTask(groupId, task) < self.joinedTasks = self.joinedTasks or {} < local coordinator = self:groupCoordinator(groupId) < if coordinator then < local result = world.callScriptedEntity(coordinator, "onRequestTask", entity.id(), task) < if result then < self.joinedTasks[groupId.."."..task.taskId] = {groupId = groupId, taskId = task.taskId} --- > function replaceTag(value, parameters) > if type(value) == "string" then > local tagString = value:match("^<.+>$") > if tagString ~= nil then > tagString = tagString:sub(2, -2) > if parameters[tagString] then > return parameters[tagString] > else > world.logInfo("Could not find parameter for tag '%s'", tagString) > end 1087,1109d316 < return result < end < end < < function BGroup:leaveTask(groupId, taskId) < local coordinator = self:groupCoordinator(groupId) < if coordinator then < return world.callScriptedEntity(coordinator, "onLeaveTask", entity.id(), taskId) < end < end < < function BGroup:setGroupSuccess(groupId, taskId) < local coordinator = self:groupCoordinator(groupId) < if coordinator then < return world.callScriptedEntity(coordinator, "setSuccess", entity.id()) < end < end < < function BGroup:groupCoordinator(groupId) < if self.groups[groupId] and world.entityExists(self.groups[groupId]) then < return self.groups[groupId] < else < return false 1110a318 > return value 1153,1281d360 < -- param name < function setFlag(args, output) < args = parseArgs(args, {}) < BData:set("bool", args.name, true) < return true < end < < -- param name < function unsetFlag(args, output) < args = parseArgs(args, {}) < BData:set("bool", args.name, false) < return true < end < < -- param name < function hasFlag(args, output) < args = parseArgs(args, {}) < return BData:get("bool", args.name) == true < end < < function clearAllFlags(args) < BData.board.bool = {} < end < < --Lists < < -- param list < -- param entity < -- param number < -- param position < -- param vector < function listPush(args, output) < args = parseArgs(args, { < list = nil < }) < local getType,index = BData.listType(args) < local value = BData:get(getType, index) < if value == nil then return false end < return BData:pushList(args.list, value) < end < < -- param list < -- output entity < -- output number < -- output position < -- output vector < function listPop(args, output) < args = parseArgs(args, { < list = nil < }) < local value = BData:popList(args.list) < if value == nil then return false end < < local setType,index = BData.listType(output) < if setType then < BData:set(setType, index, value) < end < return true < end < < -- param list < -- output entity < -- output number < -- output position < -- output vector < function listGet(args, output) < args = parseArgs(args, { < list = nil < }) < local value = BData:peekList(args.list) < if value == nil then return false end < < local setType,index = BData.listType(output) < if setType then < BData:set(setType, index, value) < end < return true < end < < -- param list < -- param entity < -- param number < -- param position < -- param vector < function listContains(args) < args = parseArgs(args, { < list = nil < }) < local getType,index = BData.listType(args) < local value = BData:get(getType, index) < return BData:inList(args.list, value) < end < < -- param list < function listClear(args) < args = parseArgs(args, { < list = nil < }) < return BData:clearList(args.list) < end < < -- param entity < -- output entity < function setEntity(args, output) < args = parseArgs(args, { < entity = "self", < }) < < local entityId = BData:getEntity(args.entity) < if entityId == nil then return false end < < BData:setEntity(output.entity, entityId) < return true < end < < -- param entity < -- output entity < function setNumber(args, output) < args = parseArgs(args, { < number = 0 < }) < < local number = BData:getNumber(args.number) < if number == nil then return false end < < BData:setNumber(output.number, BData:getNumber(args.number)) < return true < end < 1293c372 < local setType, name = BData.listType(output) --- > local setType, name = BData.findType(output) 1312c391 < local setType, name = BData.listType(output) --- > local setType, name = BData.findType(output) 1317a397,431 > > -- args groupId > -- args name > -- args default > -- output [type] > function groupResource(args, output) > args = parseArgs(args, { > groupId = nil, > name = nil > }) > if args.groupId == nil or args.name == nil then return false end > > local setType,outputName = BData.findType(output) > local value = BGroup:getResource(args.groupId, args.name) > if setType == nil or value == nil then return false end > > BData:set(setType, outputName, value) > return true > end > > function runFunction(args, output) > args = parseArgs(args, { > func = nil, > script = nil > }) > if args.func == nil or args.script == nil then return false end > > require(args.script) > if _ENV[args.func] ~= nil and type(_ENV[args.func]) == "function" then > _ENV[args.func](args.dt) > return true > end > > return false > end \ No newline at end of file scripts\actions\reaction.lua 55a56 > --world.logInfo(entity.id().." reacting with "..reaction) 90c91,92 < reaction = "" --- > reaction = "", > influence = "" 92a95 > local influence = BData:get("influence", args.influence) 94c97 < if final == reaction then --- > if final == reaction or final == influence then stagehands\coordinator.lua 7a8,10 > self.groupResources = ResourceSet:new() > self.memberResources = {} > 8a12,17 > self.group.onJoin = function(entityId) > self.memberResources[entityId] = ResourceSet:new() > end > self.group.onLeave = function(entityId) > self.memberResources[entityId] = nil > end 12,15c21,22 < local behavior = entity.behavior() < if behavior.root ~= nil then < self.btree = BTree:new(behavior) < self.btree:loadScripts() --- > if entity.configParameter("behavior") then > self.btree = BTree:new(entity.configParameter("behavior")) 19d25 < self.resources = {} 22c28,32 < function update(dt) --- > function update(dt) > if self.btree and self.btree:run(dt) ~= "running" then > self.btree:reset() > end > 35,38d44 < if self.btree and self.btree:run(dt) ~= "running" then < self.btree:reset() < end < 42a49,53 > > self.groupResources:update() > for _,memberSet in pairs(self.memberResources) do > memberSet:update() > end 75a87,95 > function onGetResource(entityId, resource) > local memberResource = self.memberResources[entityId]:get(resource) > if memberResource ~= nil then > return memberResource > else > return self.groupResources:get(resource) > end > end > 89c109 < if not listContains(self.goal, value) then --- > if not inList(self.goal, value) then 99c119 < --GROUPS --- > -- GROUPS 154a175 > if self.onJoin then self.onJoin(entityId) end 168a190 > if self.onLeave then self.onLeave(memberId) end 173c195 < function listContains(list, value) --- > function inList(list, value) 177a200,225 > end > > -- RESOURCES > > ResourceSet = {} > > function ResourceSet:new() > local newSet = { > resources = {}, > newResources = {} > } > setmetatable(newSet, extend(self)) > return newSet > end > > function ResourceSet:set(k,v) > self.newResources[k] = v > end > > function ResourceSet:get(k) > return self.newResources[k] or self.resources[k] > end > > function ResourceSet:update() > self.resources = self.newResources > self.newResources = {} tenants\merchant_apex.tenant 3c3 < "priority": 2, --- > "priority": 3, tenants\merchant_avian.tenant 3c3 < "priority": 2, --- > "priority": 3, tenants\merchant_floran.tenant 3c3 < "priority": 2, --- > "priority": 3, tenants\merchant_glitch.tenant 3c3 < "priority": 2, --- > "priority": 3, tenants\merchant_human.tenant 3c3 < "priority": 2, --- > "priority": 3, tenants\merchant_hylotl.tenant 3c3 < "priority": 2, --- > "priority": 3, tenants\villager_apex.tenant 3c3 < "priority": 1, --- > "priority": 2, tenants\villager_avian.tenant 3c3 < "priority": 1, --- > "priority": 2, tenants\villager_floran.tenant 3c3 < "priority": 1, --- > "priority": 2, tenants\villager_glitch.tenant 3c3 < "priority": 1, --- > "priority": 2, tenants\villager_human.tenant 3c3 < "priority": 1, --- > "priority": 2, tenants\villager_hylotl.tenant 3c3 < "priority": 1, --- > "priority": 2, treasure\common.treasurepools 92a93,104 > "birdsnest" : [ > [0, { > "poolRounds" : [ > [0.2, 0], > [0.8, 1] > ], > "pool" : [ > {"weight" : 0.9, "item" : "egg"} > ] > }] > ], >