diff --git a/README.rst b/README.rst index 1319707..a119c71 100644 --- a/README.rst +++ b/README.rst @@ -56,19 +56,12 @@ view the ``examples/froge directory`` for a generated pymodd project @script(triggers=[Trigger.EVERY_SECOND]) class EverySecond(): def _build(self): - self.actions = [ - if_else((NumberOfUnitsOfUnitType(UnitTypes.FROG) < 5), [ - create_unit_for_player_at_position_with_rotation(UnitTypes.FROG, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0), - ], [ - if_else((NumberOfUnitsOfUnitType(UnitTypes.FROG_BOSS) == 0), [ - if_else((Variables.BOSS_TIMER <= 0), [ - create_unit_for_player_at_position_with_rotation(UnitTypes.FROG_BOSS, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0), - update_ui_target_for_player_for_miliseconds(UiTarget.CENTER, 'BOSS SPAWNED', Undefined(), 5000), - set_variable(Variables.BOSS_TIMER, 200), - ], [ - ]), - decrease_variable_by_number(Variables.BOSS_TIMER, 1), - ], [ - ]), - ]), - ] \ No newline at end of file + if NumberOfUnitsOfUnitType(UnitTypes.FROG) < 5: + create_unit_for_player_at_position_with_rotation(UnitTypes.FROG, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0) + else: + if NumberOfUnitsOfUnitType(UnitTypes.FROG_BOSS) == 0: + if Variables.BOSS_TIMER <= 0: + create_unit_for_player_at_position_with_rotation(UnitTypes.FROG_BOSS, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0) + update_ui_target_for_player_for_miliseconds(UiTarget.CENTER, 'BOSS SPAWNED', Undefined(), 5000) + decrease_variable_by_number(Variables.BOSS_TIMER, 1) + diff --git a/examples/froge/entity_scripts.py b/examples/froge/entity_scripts.py index c3cbbb5..cf5987c 100644 --- a/examples/froge/entity_scripts.py +++ b/examples/froge/entity_scripts.py @@ -17,18 +17,12 @@ def _build(self): @script(triggers=[]) class UseItem(): def _build(self): - self.actions = [ - use_item_continuously_until_stopped(ItemCurrentlyHeldByUnit(ThisEntity())), - - ] + use_item_continuously_until_stopped(ItemCurrentlyHeldByUnit(ThisEntity())) @script(triggers=[]) class StopUsingItem(): def _build(self): - self.actions = [ - stop_using_item(ItemCurrentlyHeldByUnit(ThisEntity())), - - ] + stop_using_item(ItemCurrentlyHeldByUnit(ThisEntity())) class Frog(EntityScripts): @@ -42,9 +36,6 @@ def _build(self): @script(triggers=[]) class NewScript(): def _build(self): - self.actions = [ - comment('wdwadawd'), - - ] + comment('wdwadawd') diff --git a/examples/froge/game_variables.py b/examples/froge/game_variables.py index 3b9b2e6..783f0b4 100644 --- a/examples/froge/game_variables.py +++ b/examples/froge/game_variables.py @@ -1,81 +1,59 @@ -from pymodd.functions import UnitType, PlayerType, ItemType, Variable, EntityVariable, AnimationType, AttributeType, State, Shop, Music - - -class UnitTypes: - FROG_BOSS = UnitType("TyaKyQzgKc") - POOPER = UnitType("fighter") - FROG = UnitType("oTDQ3jlcMa") - - -class PlayerTypes: - AI = PlayerType("eA9ZwoweVz") - PLAYER = PlayerType("humanPlayer") +from pymodd.variable_types import ItemType, ProjectileType, UnitType, PlayerType, Variable, Variable, Variable, EntityVariable, PlayerVariable, Variable, Shop, Dialogue, Music, Sound, State, AnimationType, AttributeType, DataType class ItemTypes: - BOSS_FROG_TONGUE = ItemType("AqrGZUYBdS") - FROG_TONGUE = ItemType("BBCDO38dr7") - KNIFE = ItemType("bMDJQyFACm") - FROG_SWORD = ItemType("tmAlzggQX4") + BOSS_FROG_TONGUE = ItemType('AqrGZUYBdS', name='Boss Frog Tongue') + FROG_TONGUE = ItemType('BBCDO38dr7', name='Frog Tongue') + KNIFE = ItemType('bMDJQyFACm', name='Knife') + FROG_SWORD = ItemType('tmAlzggQX4', name='Frog Sword') class ProjectileTypes: pass -class Regions: - pass - - -class Variables: - AI = Variable("AI", variable_type='player') - BOSS_TIMER = Variable("bossTimer", variable_type='number') - DWADAWD = Variable("dwadawd", variable_type='unitGroup') - TEMP_UNIT = Variable("tempUnit", variable_type='unit') - TIMER = Variable("timer", variable_type='number') +class UnitTypes: + FROG_BOSS = UnitType('TyaKyQzgKc', name='Frog Boss') + POOPER = UnitType('fighter', name='Pooper') + FROG = UnitType('oTDQ3jlcMa', name='Frog') -class EntityVariables: - SENSOR_RADIUS = EntityVariable("sensorRadius", variable_type='number') - TARGET_UNIT = EntityVariable("targetUnit", variable_type='unit') +class PlayerTypes: + AI = PlayerType('eA9ZwoweVz', name='ai') + PLAYER = PlayerType('humanPlayer', name='Player') -class PlayerVariables: - pass +class ItemTypeGroups: + RANDOMGROUP = Variable('randomgroup', DataType.ITEM_TYPE_GROUP) -class AnimationTypes: - TONGUE_OUT = AnimationType("B1cWOYKvNL") - DEFAULT = AnimationType("default") - DROPPED = AnimationType("dropped") - USE = AnimationType("use") +class UnitTypeGroups: + UNITTYPEGROUP = Variable('unittypegroup', DataType.UNIT_TYPE_GROUP) -class AttributeTypes: - MOVE = AttributeType("G3adwzJecn") - HEALTH = AttributeType("health") - SPEED = AttributeType("speed") - FROG_KILLS = AttributeType("yjdyHZbWpA") +class Variables: + AI = Variable('AI', DataType.PLAYER) + BOSS_TIMER = Variable('bossTimer', DataType.NUMBER) + DWADAWD = Variable('dwadawd', DataType.UNIT_GROUP) + TEMP_UNIT = Variable('tempUnit', DataType.UNIT) + TIMER = Variable('timer', DataType.NUMBER) -class ItemTypeGroups: - RANDOMGROUP = Variable("randomgroup", variable_type='itemTypeGroup') +class EntityVariables: + SENSOR_RADIUS = EntityVariable('sensorRadius', DataType.NUMBER) + TARGET_UNIT = EntityVariable('targetUnit', DataType.UNIT) -class UnitTypeGroups: - UNITTYPEGROUP = Variable("unittypegroup", variable_type='unitTypeGroup') +class PlayerVariables: + TARGET_UNIT = PlayerVariable('targetUnit', DataType.UNIT) -class States: - DEFAULT = State("default") - DROPPED = State("dropped") - TONGUE_OUT = State("r60qiEIvyt") - SELECTED = State("selected") - UNSELECTED = State("unselected") +class Regions: + pass class Shops: - FROGE_SHOP = Shop("OJbEQyc7is") + FROGE_SHOP = Shop('OJbEQyc7is', name='Froge Shop') class Dialogues: @@ -83,10 +61,32 @@ class Dialogues: class Musics: - D = Music("iJ8RoRfyeu") + D = Music('iJ8RoRfyeu', name='d') class Sounds: pass +class States: + DEFAULT = State('default', name='default') + DROPPED = State('dropped', name='dropped') + TONGUE_OUT = State('r60qiEIvyt', name='tongue out') + SELECTED = State('selected', name='selected') + UNSELECTED = State('unselected', name='unselected') + + +class AnimationTypes: + TONGUE_OUT = AnimationType('B1cWOYKvNL', name='tongue out') + DEFAULT = AnimationType('default', name='default') + DROPPED = AnimationType('dropped', name='dropped') + USE = AnimationType('use', name='use') + + +class AttributeTypes: + MOVE = AttributeType('G3adwzJecn', name='move') + HEALTH = AttributeType('health', name='health ') + SPEED = AttributeType('speed', name='speed') + FROG_KILLS = AttributeType('yjdyHZbWpA', name='frog kills') + + diff --git a/examples/froge/scripts.py b/examples/froge/scripts.py index 4bbdea7..5a450a9 100644 --- a/examples/froge/scripts.py +++ b/examples/froge/scripts.py @@ -8,141 +8,79 @@ @script(triggers=[Trigger.GAME_START]) class Initialize(): def _build(self): - self.actions = [ - assign_player_to_player_type(Variables.AI, PlayerTypes.AI), - - ] + assign_player_to_player_type(Variables.AI, PlayerTypes.AI) @script(triggers=[Trigger.PLAYER_JOINS_GAME]) class PlayerJoins(): def _build(self): - self.actions = [ - create_unit_for_player_at_position_with_rotation(UnitTypes.POOPER, LastTriggeringPlayer(), RandomPositionInRegion(EntireMapRegion()), 0), - make_camera_of_player_track_unit(LastTriggeringPlayer(), LastCreatedUnit()), - assign_player_to_player_type(LastTriggeringPlayer(), PlayerTypes.PLAYER), - - ] + create_unit_for_player_at_position_with_rotation(UnitTypes.POOPER, LastTriggeringPlayer(), RandomPositionInRegion(EntireMapRegion()), 0) + make_camera_of_player_track_unit(LastTriggeringPlayer(), LastCreatedUnit()) + assign_player_to_player_type(LastTriggeringPlayer(), PlayerTypes.PLAYER) @script(triggers=[Trigger.PLAYER_LEAVES_GAME]) class PlayerLeaves(): def _build(self): - self.actions = [ - for_all_units_in(AllUnitsOwnedByPlayer(LastTriggeringPlayer()), [ - destroy_entity(SelectedUnit()), - - ], comment='when a player leaves, destroy all units owned by that player'), - - ] + for unit in AllUnitsOwnedByPlayer(LastTriggeringPlayer()): + destroy_entity(unit) @script(triggers=[Trigger.EVERY_SECOND]) class EverySecond(): def _build(self): - self.actions = [ - if_else((NumberOfUnitsOfUnitType(UnitTypes.FROG) < 5), [ - create_unit_for_player_at_position_with_rotation(UnitTypes.FROG, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0), - - ], [ - if_else((NumberOfUnitsOfUnitType(UnitTypes.FROG_BOSS) == 0), [ - if_else((Variables.BOSS_TIMER <= 0), [ - create_unit_for_player_at_position_with_rotation(UnitTypes.FROG_BOSS, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0), - update_ui_target_for_player_for_miliseconds(UiTarget.CENTER, 'BOSS SPAWNED', Undefined(), 5000), - set_variable(Variables.BOSS_TIMER, 200), - - ], [ - - ]), - decrease_variable_by_number(Variables.BOSS_TIMER, 1), - - ], [ - - ]), - - ]), - - ] + if NumberOfUnitsOfUnitType(UnitTypes.FROG) < 5: + create_unit_for_player_at_position_with_rotation(UnitTypes.FROG, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0) + else: + if NumberOfUnitsOfUnitType(UnitTypes.FROG_BOSS) == 0: + if Variables.BOSS_TIMER <= 0: + create_unit_for_player_at_position_with_rotation(UnitTypes.FROG_BOSS, Variables.AI, RandomPositionInRegion(EntireMapRegion()), 0) + update_ui_target_for_player_for_miliseconds(UiTarget.CENTER, 'BOSS SPAWNED', Undefined(), 5000) + decrease_variable_by_number(Variables.BOSS_TIMER, 1) @script(triggers=[Trigger.UNIT_ATTRIBUTE_BECOMES_ZERO]) class WhenAUnitsAttributeBecomes0OrLess(): def _build(self): - self.actions = [ - if_else((AttributeTypeOfAttribute(LastTriggeringAttribute()) == AttributeTypes.HEALTH), [ - if_else((PlayerTypeOfPlayer(OwnerOfEntity(LastTriggeringUnit())) == PlayerTypes.PLAYER), [ - set_entity_attribute(AttributeTypes.HEALTH, LastTriggeringUnit(), AttributeMaxOfEntity(AttributeTypes.HEALTH, LastTriggeringUnit())), - set_entity_variable(EntityVariables.TARGET_UNIT, LastTriggeringUnit(), Undefined()), - move_entity_to_position(LastTriggeringUnit(), CenterOfRegion(EntireMapRegion())), - - ], [ - if_else((UnitTypeOfUnit(LastTriggeringUnit()) == UnitTypes.FROG_BOSS), [ - set_player_attribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit()), PlayerAttribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit())) + 7), - - ], [ - set_player_attribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit()), PlayerAttribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit())) + 1), - - ]), - destroy_entity(LastTriggeringUnit()), - - ]), - - ], [ - if_else((AttributeTypeOfAttribute(LastTriggeringAttribute()) == AttributeTypes.MOVE), [ - set_entity_variable(EntityVariables.TARGET_UNIT, LastTriggeringUnit(), Undefined()), - for_all_entities_in(AllEntitiesInRegion(DynamicRegion(XCoordinateOfPosition(PositionOfEntity(LastTriggeringUnit())) - (ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()) / 2), YCoordinateOfPosition(PositionOfEntity(LastTriggeringUnit())) - (ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()) / 2), ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()), ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()))), [ - if_else((PlayerTypeOfPlayer(OwnerOfEntity(SelectedEntity())) == PlayerTypes.PLAYER), [ - if_else(((ValueOfEntityVariable(EntityVariables.TARGET_UNIT, LastTriggeringUnit()) == Undefined()) | (DistanceBetweenPositions(PositionOfEntity(SelectedEntity()), PositionOfEntity(LastTriggeringUnit())) > DistanceBetweenPositions(PositionOfEntity(ValueOfEntityVariable(EntityVariables.TARGET_UNIT, LastTriggeringUnit())), PositionOfEntity(LastTriggeringUnit())))), [ - create_floating_text_at_position_with_color('Froge sense', PositionOfEntity(LastTriggeringUnit()), '#327117', disabled=True), - set_entity_variable(EntityVariables.TARGET_UNIT, LastTriggeringUnit(), SelectedEntity()), - - ], [ - - ]), - - ], [ - - ]), - - ]), - if_else((ValueOfEntityVariable(EntityVariables.TARGET_UNIT, LastTriggeringUnit()) != Undefined()), [ - rotate_entity_instantly_to_face_position(LastTriggeringUnit(), PositionOfEntity(ValueOfEntityVariable(EntityVariables.TARGET_UNIT, LastTriggeringUnit()))), - if_else((UnitTypeOfUnit(LastTriggeringUnit()) == UnitTypes.FROG_BOSS), [ - apply_force_on_entity_at_angle(RandomNumberBetween(3000, 6000), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())), - - ], [ - apply_force_on_entity_at_angle(RandomNumberBetween(300, 600), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())), - - ]), - use_item_continuously_until_stopped(ItemCurrentlyHeldByUnit(LastTriggeringUnit())), - - ], [ - rotate_entity_instantly_to_face_position(LastTriggeringUnit(), RandomPositionInRegion(EntityBounds(LastTriggeringUnit()))), - if_else((UnitTypeOfUnit(LastTriggeringUnit()) == UnitTypes.FROG_BOSS), [ - apply_force_on_entity_at_angle(RandomNumberBetween(1500, 3500), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())), - - ], [ - apply_force_on_entity_at_angle(RandomNumberBetween(150, 400), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())), - - ]), - stop_using_item(ItemCurrentlyHeldByUnit(LastTriggeringUnit())), - - ]), - set_entity_attribute(AttributeTypes.MOVE, LastTriggeringUnit(), RandomNumberBetween(35, 100)), - - ], [ - - ]), - - ]), - - ] + if AttributeTypeOfAttribute(LastTriggeringAttribute()) == AttributeTypes.HEALTH: + if PlayerTypeOfPlayer(OwnerOfEntity(LastTriggeringUnit())) == PlayerTypes.PLAYER: + set_entity_attribute(AttributeTypes.HEALTH, LastTriggeringUnit(), AttributeMaxOfEntity(AttributeTypes.HEALTH, LastTriggeringUnit())) + set_entity_variable(PlayerVariables.TARGET_UNIT, LastTriggeringUnit(), Undefined()) + move_entity_to_position(LastTriggeringUnit(), CenterOfRegion(EntireMapRegion())) + else: + if UnitTypeOfUnit(LastTriggeringUnit()) == UnitTypes.FROG_BOSS: + set_variable(Variables.BOSS_TIMER, 200) + set_player_attribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit()), ValueOfPlayerAttribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit())) + 7) + else: + set_player_attribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit()), ValueOfPlayerAttribute(AttributeTypes.FROG_KILLS, OwnerOfEntity(LastAttackingUnit())) + 1) + destroy_entity(LastTriggeringUnit()) + else: + if AttributeTypeOfAttribute(LastTriggeringAttribute()) == AttributeTypes.MOVE: + set_entity_variable(PlayerVariables.TARGET_UNIT, LastTriggeringUnit(), Undefined()) + for entity in AllEntitiesInRegion(DynamicRegion(XCoordinateOfPosition(PositionOfEntity(LastTriggeringUnit())) - (ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()) / 2), YCoordinateOfPosition(PositionOfEntity(LastTriggeringUnit())) - (ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()) / 2), ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()), ValueOfEntityVariable(EntityVariables.SENSOR_RADIUS, LastTriggeringUnit()))): + if PlayerTypeOfPlayer(OwnerOfEntity(entity)) == PlayerTypes.PLAYER: + if ValueOfEntityVariable(PlayerVariables.TARGET_UNIT, LastTriggeringUnit()) == Undefined() or DistanceBetweenPositions(PositionOfEntity(entity), PositionOfEntity(LastTriggeringUnit())) > DistanceBetweenPositions(PositionOfEntity(ValueOfEntityVariable(PlayerVariables.TARGET_UNIT, LastTriggeringUnit())), PositionOfEntity(LastTriggeringUnit())): + create_floating_text_at_position_with_color('Froge sense', PositionOfEntity(LastTriggeringUnit()), '#327117', disabled=True) + set_entity_variable(PlayerVariables.TARGET_UNIT, LastTriggeringUnit(), entity) + if ValueOfEntityVariable(PlayerVariables.TARGET_UNIT, LastTriggeringUnit()) != Undefined(): + rotate_entity_instantly_to_face_position(LastTriggeringUnit(), PositionOfEntity(ValueOfEntityVariable(PlayerVariables.TARGET_UNIT, LastTriggeringUnit()))) + if UnitTypeOfUnit(LastTriggeringUnit()) == UnitTypes.FROG_BOSS: + apply_force_on_entity_at_angle(RandomNumberBetween(3000, 6000), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())) + else: + apply_force_on_entity_at_angle(RandomNumberBetween(300, 600), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())) + use_item_continuously_until_stopped(ItemCurrentlyHeldByUnit(LastTriggeringUnit())) + else: + rotate_entity_instantly_to_face_position(LastTriggeringUnit(), RandomPositionInRegion(EntityBounds(LastTriggeringUnit()))) + if UnitTypeOfUnit(LastTriggeringUnit()) == UnitTypes.FROG_BOSS: + apply_force_on_entity_at_angle(RandomNumberBetween(1500, 3500), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())) + else: + apply_force_on_entity_at_angle(RandomNumberBetween(150, 400), LastTriggeringUnit(), UnitsFacingAngle(LastTriggeringUnit())) + stop_using_item(ItemCurrentlyHeldByUnit(LastTriggeringUnit())) + set_entity_attribute(AttributeTypes.MOVE, LastTriggeringUnit(), RandomNumberBetween(35, 100)) @script(triggers=[]) class OpenShop(): def _build(self): - self.actions = [ - open_shop_for_player(Shops.FROGE_SHOP, OwnerOfEntity(LastCastingUnit())), - - ] \ No newline at end of file + open_shop_for_player(Shops.FROGE_SHOP, OwnerOfEntity(LastCastingUnit())) + diff --git a/examples/froge/utils/game.json b/examples/froge/utils/game.json index 2cc5917..50452f9 100644 --- a/examples/froge/utils/game.json +++ b/examples/froge/utils/game.json @@ -1 +1 @@ -{"__v":229,"_id":"63816c35103812aeda0c69b8","access":"private","allowDuplicateIPS":false,"allowGuestMode":false,"allowLateJoining":false,"allowVerifiedUserToChat":false,"androidLink":null,"autoSave":true,"backupOn":1678936212479,"banChat":[],"banIps":[],"banUsers":[],"canHostPrivateServers":false,"clientPhysicsEngine":"planck","clientSidePredictionEnabled":true,"cover":"https://cache.modd.io/asset/spriteImage/1589327274851_cover_blank.png","coverUpdated":false,"createdAt":"2022-11-26T01:30:29.896Z","dailyCoinTransferLimit":0,"data":{"abilities":{},"animationTypes":{"B1cWOYKvNL":{"frames":[2,1],"framesPerSecond":1,"loopCount":"","name":"tongue out"},"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"},"dropped":{"frames":[1],"framesPerSecond":0,"loopCount":"","name":"dropped"},"use":{"frames":[1,2,3,1],"framesPerSecond":20,"loopCount":1,"name":"use"}},"attributeTypes":{"G3adwzJecn":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":false,"isVisible":false,"max":100,"min":0,"name":"move","regenerateSpeed":-3,"showAsHUD":true,"showWhen":"","value":100},"health":{"color":"#ffff0f","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":100,"min":0,"name":"health ","regenerateSpeed":0,"showAsHUD":true,"value":100},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":5},"yjdyHZbWpA":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":true,"max":100000,"min":0,"name":"frog kills","regenerateSpeed":0,"showAsHUD":true,"showWhen":"","value":0}},"bodyTypes":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":10,"bullet":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":28,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":8,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":30,"z-index":{"depth":3,"layer":3}},"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":25,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":64,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":"18.6","itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":0,"y":15},"width":12,"z-index":{"depth":4,"layer":3}},"unselected":{"allowSleep":true,"angularDamping":1,"bullet":false,"carriedBy":["fighter"],"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"density":1,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"friction":0,"height":20,"holdPosition":{"rotation":0,"x":0,"y":33},"isFlying":false,"isTangible":false,"itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":1,"name":"unselected","restitution":1,"rotationSpeed":3,"spriteScale":1,"type":"none","typeWhenDrop":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":20},"width":8,"z-index":{"depth":3,"layer":3}}},"buffTypes":{"ammoSize":{"chance":0.1,"maxBonus":0.3,"minBonus":0,"unit":"percentage"},"ammoTotal":{"chance":0.2,"maxBonus":0.3,"minBonus":0,"unit":"percentage"},"bulletForce":{"chance":0.07,"maxBonus":1,"minBonus":0.1,"unit":"percentage"},"canPenetrate":{"chance":0.05,"unit":"boolean"},"canPushDebris":{"chance":0.05,"unit":"boolean"},"distanceEnd":{"chance":0.3,"maxBonus":500,"minBonus":100,"unit":"percentage"},"fireRate":{"chance":0.15,"maxBonus":-0.3,"minBonus":0,"unit":"percentage"},"height":{"chance":0.2,"maxBonus":0.3,"minBonus":0.05,"unit":"percentage"},"immunity":{"chance":0.1,"maxBonus":0.2,"minBonus":0.05,"unit":"percentage"},"maxStamina":{"chance":0.1,"maxBonus":120,"minBonus":20,"unit":"integer"},"movementSpeed":{"chance":0.02,"maxBonus":5,"minBonus":1,"unit":"integer"},"recoilForce":{"chance":0.04,"maxBonus":8,"minBonus":0,"unit":"integer"},"reloadRate":{"chance":0.1,"maxBonus":-0.3,"minBonus":0,"unit":"percentage"},"slowChance":{"chance":0.05,"maxBonus":0.1,"minBonus":0.02,"unit":"percentage"},"stunChance":{"chance":0.05,"maxBonus":0.1,"minBonus":0.02,"unit":"percentage"}},"entityTypeVariables":{"sensorRadius":{"dataType":"number","default":300},"targetUnit":{"dataType":"unit"}},"factions":{"6BTQoFGUFP":{"attributes":{"4P4pWD5ExV":{"color":"yellow","isVisible":true,"max":"100","min":0,"name":"Stamina","regenerateSpeed":0.3,"showAsHUD":true,"value":"100"}},"name":"asdf","relationships":{}},"PgVCU0WgYj":{"name":"fda","relationships":{}}},"images":[{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512752415166_fire_shotgun.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755562800_fire_empty.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755594697_fire_minigun.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755610131_fire_pistol.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755622475_fire_rifle.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755644317_man_cough.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755666761_man_scream1.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755675893_man_scream2.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512756015200_reload.mp3"}],"itemTypes":{"AqrGZUYBdS":{"animations":{"B1cWOYKvNL":{"frames":[2,1],"framesPerSecond":1,"loopCount":"","name":"tongue out"},"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"},"dropped":{"frames":[1],"framesPerSecond":0,"loopCount":"","name":"dropped"},"use":{"frames":[1,2,3,1],"framesPerSecond":20,"loopCount":1,"name":"use"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":25,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":64,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":"55.8","itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":0,"y":45},"width":36,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":2,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1662085262439_tongue.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":false},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":20}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":40},"delayBeforeUse":0,"description":null,"destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"B1cWOYKvNL","projectileType":"","runScript":"","sound":{},"tween":"none"}},"fireRate":2000,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Boss Frog Tongue","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"r60qiEIvyt":{"animation":"B1cWOYKvNL","body":"selected","name":"tongue out","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}},"BBCDO38dr7":{"animations":{"B1cWOYKvNL":{"frames":[2,1],"framesPerSecond":1,"loopCount":"","name":"tongue out"},"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"},"dropped":{"frames":[1],"framesPerSecond":0,"loopCount":"","name":"dropped"},"use":{"frames":[1,2,3,1],"framesPerSecond":20,"loopCount":1,"name":"use"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":25,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":64,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":"18.6","itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":0,"y":15},"width":12,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":2,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1662085262439_tongue.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":false},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":20}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":100},"delayBeforeUse":0,"description":null,"destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"B1cWOYKvNL","projectileType":"","runScript":"","sound":{},"tween":"none"}},"fireRate":1500,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Frog Tongue","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"r60qiEIvyt":{"animation":"B1cWOYKvNL","body":"selected","name":"tongue out","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}},"bMDJQyFACm":{"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":8,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":15,"y":34},"width":8,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588259290955_Small Machete Knife.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":false},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":10}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":60},"delayBeforeUse":0,"description":null,"destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"use","projectileType":"","runScript":"","sound":{},"tween":"swingCW"}},"fireRate":500,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Knife","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}},"tmAlzggQX4":{"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":8,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":15,"y":34},"width":8,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1662090448324_frog-sword.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":true},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":40}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":60},"delayBeforeUse":0,"description":"Made from fresh frog","destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"use","projectileType":"","runScript":"","sound":{},"tween":"poke"}},"fireRate":500,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Frog Sword","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}}},"map":{"height":32,"infinite":false,"layers":[{"data":[28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],"height":32,"name":"floor","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0},{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"height":32,"name":"floor2","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0},{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,155,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,156,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"height":32,"name":"walls","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0},{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"height":32,"name":"trees","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0}],"nextobjectid":1,"orientation":"orthogonal","originalTileHeight":64,"originalTileWidth":64,"renderorder":"right-down","tiledversion":"1.1.5","tileheight":64,"tilesets":[{"columns":20,"firstgid":1,"image":"https://cache.modd.io/asset/spriteImage/1569798717927_forest-tilesheet.png","imageheight":1088,"imagewidth":1280,"margin":0,"name":"forest-tilesheet","spacing":0,"tilecount":340,"tileheight":64,"tilewidth":64}],"tilewidth":64,"type":"map","version":1,"width":32},"music":{"iJ8RoRfyeu":{"file":"https://cache.modd.io/asset/sound/1666740498538_breath.mp3","name":"d","volume":25}},"particleTypes":{},"particles":{"7pA9mm1MLG":{"color":"#f4ff00","deathOpacityBase":1,"lifeBase":30,"mountPosition":{"x":0,"y":0},"name":"spark","quantityBase":5,"quantityTimespan":30,"velocityVector":{"baseVector":{"x":0,"y":0},"maxVector":{"x":1,"y":1},"minVector":{"x":-1,"y":-1}}},"87BiLybZhy":{"color":"#636363","deathOpacityBase":1,"lifeBase":50,"mountPosition":{"x":0,"y":0},"name":"bullet","quantityBase":1,"quantityTimespan":30,"velocityVector":{"baseVector":{"x":0,"y":0},"maxVector":{"x":1,"y":1},"minVector":{"x":-1,"y":-1}}}},"playerTypeVariables":{},"playerTypes":{"eA9ZwoweVz":{"attributes":{},"color":"white","name":"ai","relationships":{"humanPlayer":"hostile"},"showNameLabel":false},"humanPlayer":{"attributes":{"yjdyHZbWpA":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":true,"max":100000,"min":0,"name":"frogeKills","regenerateSpeed":0,"showAsHUD":true,"showWhen":"","value":0}},"color":"#ffffff","name":"Player","relationships":{"humanPlayer":"friendly"},"showNameLabel":true,"variables":{}}},"projectileTypes":{},"scripts":{"5BUXtByxVf":{"actions":[{"player":{"entity":{"function":"getLastCastingUnit","vars":[]},"function":"getOwner","vars":[]},"shop":"OJbEQyc7is","type":"openShopForPlayer","vars":[]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"5BUXtByxVf","name":"open shop","order":5,"parent":null,"triggers":[]},"CE0PBg1VWG":{"actions":[{"conditions":[{"operandType":"attributeType","operator":"=="},{"entity":{"function":"getTriggeringAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getAttributeTypeOfAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"health"],"else":[{"conditions":[{"operandType":"attributeType","operator":"=="},{"entity":{"function":"getTriggeringAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getAttributeTypeOfAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"G3adwzJecn"],"else":[],"then":[{"entity":{"function":"getTriggeringUnit"},"type":"setEntityVariable","value":{"function":"undefinedValue"},"variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"null","key":"targetUnit","text":"targetUnit"}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"actions":[{"conditions":[{"operandType":"playerType","operator":"=="},{"function":"playerTypeOfPlayer","player":{"entity":{"function":"getSelectedEntity","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"humanPlayer"],"else":[],"then":[{"conditions":[{"operandType":"or","operator":"OR"},[{"operandType":"unit","operator":"=="},{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"null","key":"targetUnit","text":"targetUnit"}}},{"function":"undefinedValue"}],[{"operandType":"number","operator":">"},{"function":"distanceBetweenPositions","positionA":{"entity":{"function":"getSelectedEntity"},"function":"getEntityPosition"},"positionB":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}},{"function":"distanceBetweenPositions","positionA":{"entity":{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"null","key":"targetUnit","text":"targetUnit"}}},"function":"getEntityPosition"},"positionB":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}}]],"else":[],"then":[{"color":"#327117","disabled":true,"position":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getEntityPosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"text":"Froge sense","type":"createFloatingText","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},{"entity":{"function":"getTriggeringUnit"},"type":"setEntityVariable","value":{"function":"getSelectedEntity"},"variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"null","key":"targetUnit","text":"targetUnit"}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}],"entityGroup":{"function":"entitiesInRegion","region":{"function":"dynamicRegion","height":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"null","key":"sensorRadius","text":"sensorRadius"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}],"width":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"null","key":"sensorRadius","text":"sensorRadius"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"x":{"function":"calculate","items":[{"operator":"-"},{"function":"getPositionX","position":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}},{"function":"calculate","items":[{"operator":"/"},{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"null","key":"sensorRadius","text":"sensorRadius"}}},2]}],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"y":{"function":"calculate","items":[{"operator":"-"},{"function":"getPositionY","position":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}},{"function":"calculate","items":[{"operator":"/"},{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"null","key":"sensorRadius","text":"sensorRadius"}}},2]}],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"type":"forAllEntities","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},{"conditions":[{"operandType":"unit","operator":"!="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"null","key":"targetUnit","text":"targetUnit"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"function":"undefinedValue","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"else":[{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"position":{"function":"getRandomPositionInRegion","region":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"entityBounds","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"rotateEntityToFacePosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"conditions":[{"operandType":"unitType","operator":"=="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getUnitTypeOfUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"TyaKyQzgKc"],"else":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":400,"min":150,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":3500,"min":1500,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getItemCurrentlyHeldByUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"hasFixedCSP":null,"type":"stopUsingItem","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"position":{"entity":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"null","key":"targetUnit","text":"targetUnit"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getEntityPosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"rotateEntityToFacePosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"conditions":[{"operandType":"unitType","operator":"=="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getUnitTypeOfUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"TyaKyQzgKc"],"else":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":600,"min":300,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":6000,"min":3000,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getItemCurrentlyHeldByUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"hasFixedCSP":null,"type":"startUsingItem","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"attribute":"G3adwzJecn","entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setEntityAttribute","value":{"function":"getRandomNumberBetween","max":100,"min":35,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"conditions":[{"operandType":"playerType","operator":"=="},{"function":"playerTypeOfPlayer","player":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"humanPlayer"],"else":[{"conditions":[{"operandType":"unitType","operator":"=="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getUnitTypeOfUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"TyaKyQzgKc"],"else":[{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setPlayerAttribute","value":{"function":"calculate","items":[{"operator":"+"},{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit"},"function":"getOwner"},"function":"getPlayerAttribute"},1],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"type":"setVariable","value":200,"variableName":"bossTimer","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setPlayerAttribute","value":{"function":"calculate","items":[{"operator":"+"},{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit"},"function":"getOwner"},"function":"getPlayerAttribute"},7],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"destroyEntity","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"attribute":"health","entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setEntityAttribute","value":{"attribute":"health","entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"entityAttributeMax","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"function":"getTriggeringUnit"},"type":"setEntityVariable","value":{"function":"undefinedValue"},"variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"null","key":"targetUnit","text":"targetUnit"}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"position":{"function":"centerOfRegion","region":{"function":"getEntireMapRegion","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"moveEntity","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"CE0PBg1VWG","name":"when a units attribute becomes 0 or less","order":4,"parent":null,"triggers":[{"type":"unitAttributeBecomesZero"}]},"P8MwXcSxq7":{"actions":[{"conditions":[{"operandType":"number","operator":"<"},{"function":"getNumberOfUnitsOfUnitType","unitType":"oTDQ3jlcMa","vars":[]},5],"else":[{"conditions":[{"operandType":"number","operator":"=="},{"function":"getNumberOfUnitsOfUnitType","unitType":"TyaKyQzgKc","vars":[]},0],"else":[],"then":[{"conditions":[{"operandType":"number","operator":"<="},{"function":"getVariable","variableName":"bossTimer","vars":[]},0],"else":[],"then":[{"angle":0,"entity":{"function":"getVariable","variableName":"AI","vars":[]},"position":{"function":"getRandomPositionInRegion","region":{"function":"getEntireMapRegion","vars":[]},"vars":[]},"type":"createUnitAtPosition","unitType":"TyaKyQzgKc","vars":[]},{"player":{"function":"undefinedValue","vars":[]},"target":"center-lg","time":5000,"type":"updateUiTextForTimeForPlayer","value":"BOSS SPAWNED","vars":[]}],"type":"condition","vars":[]},{"number":1,"type":"decreaseVariableByNumber","variable":{"function":"getVariable","variableName":"bossTimer","vars":[]},"vars":[]}],"type":"condition","vars":[]}],"then":[{"angle":0,"entity":{"function":"getVariable","variableName":"AI","vars":[]},"position":{"function":"getRandomPositionInRegion","region":{"function":"getEntireMapRegion","vars":[]},"vars":[]},"type":"createUnitAtPosition","unitType":"oTDQ3jlcMa","vars":[]}],"type":"condition","vars":[]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"P8MwXcSxq7","name":"every second","order":3,"parent":null,"triggers":[{"type":"secondTick"}]},"initialize":{"actions":[{"entity":{"function":"getVariable","variableName":"AI","vars":[]},"playerType":"eA9ZwoweVz","type":"assignPlayerType","vars":[]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"initialize","name":"initialize","order":-1,"parent":null,"triggers":[{"type":"gameStart"}]},"playerJoinsGame":{"actions":[{"angle":0,"entity":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"position":{"function":"getRandomPositionInRegion","region":{"function":"getEntireMapRegion","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"type":"createUnitAtPosition","unitType":"fighter","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},{"player":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"type":"playerCameraTrackUnit","unit":{"function":"getLastCreatedUnit","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},{"entity":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"playerType":"humanPlayer","type":"assignPlayerType","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"playerJoinsGame","name":"player joins","order":1,"parent":null,"triggers":[{"type":"playerJoinsGame"}]},"playerLeavesGame":{"actions":[{"actions":[{"entity":{"function":"selectedUnit","vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]},"type":"destroyEntity","vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]}],"comment":"when a player leaves, destroy all units owned by that player","type":"forAllUnits","unitGroup":{"function":"allUnitsOwnedByPlayer","player":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"playerLeavesGame","name":"player leaves","order":2,"parent":null,"triggers":[{"type":"playerLeavesGame"}]}},"settings":{"allowDuplicateIPs":true,"camera":{"trackingDelay":3,"zoom":{"default":600,"type":"static"}},"constants":{"currency":"Food"},"displayScoreboard":true,"gravity":{"x":0,"y":0},"images":{"cover":"https://cache.modd.io/1501275562940_two houses cover.png","logo":"https://cache.modd.io/asset/spriteImage/1593103756304_modd_logo.png"},"inventory":{"isEnabled":false},"menuHTML":"
\n\t
\n\t\t{{ loginForm }}\n\t
\n\n\t\n\n\t{{#if isUserLoggedIn }}\n {{ friendsPanel }}\n {{/if}}\n
\n\n
\n\t
\n\t\t

\n\t\t

\n\t\t\n\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t{{ coinShop }}\n\t\t\t\t
\n\t\t\t
\n\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t{{ playForm }}\t\t\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t{{ skinShop }}\n\t\t\t\t
\n\t\t\t
\n\t\t\t\n\t\t
\n\t
\n
","menudiv":"KILL THE FROGSWJG","prettifyingScoreboard":true,"scoreAttributeId":"points","scoreBoard":"n5JEoENeGg","shop":{"isEnabled":false}},"shops":{"OJbEQyc7is":{"dismissible":true,"itemTypes":{"bMDJQyFACm":{"hideIfRequirementNotMet":false,"hideIfUnaffordable":false,"isPurchasable":true,"price":{"coins":0,"playerAttributes":{},"requiredItemTypes":[]},"quantity":"","replaceItemInTargetSlot":false,"requirement":{"playerAttributes":{},"requiredItemTypes":[]}},"tmAlzggQX4":{"hideIfRequirementNotMet":false,"hideIfUnaffordable":false,"isPurchasable":true,"price":{"coins":0,"playerAttributes":{"yjdyHZbWpA":15},"requiredItemTypes":{}},"quantity":"","replaceItemInTargetSlot":false,"requirement":{"playerAttributes":{},"requiredItemTypes":[]}}},"name":"Froge Shop","unitTypes":{}}},"sound":{},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}},"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"r60qiEIvyt":{"animation":"","body":"selected","name":"tongue out","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"tilesets":[{"image":"https://cache.modd.io/two_houses-0.18/tilesheet.png","name":"tilesheet_complete"},{"image":"https://cache.modd.io/two_houses-0.18/2x1.png","name":"2x1"},{"image":"https://cache.modd.io/two_houses-0.18/2x3.png","name":"2x3"},{"image":"https://cache.modd.io/two_houses-0.18/3x1.png","name":"3x1"},{"image":"https://cache.modd.io/two_houses-0.18/3x4.png","name":"3x4"},{"image":"https://cache.modd.io/two_houses-0.18/spritesheet/shop.png","name":"shop"}],"unitTypes":{"TyaKyQzgKc":{"abilitiesJ8Gtv5HQ8JREnjD":{"a":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"b":{"keyDown":"shop","keyUp":"","mobilePosition":{"x":419,"y":32}},"button1":{"keyDown":"startUsingItem","keyUp":"stopUsingItem","mobilePosition":{"x":326,"y":132}},"d":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"down":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"e":{"keyDown":"pickUp","keyUp":"","mobilePosition":{"x":366,"y":85}},"f":{"keyDown":"pickUp","keyUp":""},"g":{"keyDown":"drop","keyUp":"","mobilePosition":{"x":365,"y":33}},"left":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}},"right":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"s":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"up":{"keyDown":"moveUp","keyUp":"stopMovingUp"},"w":{"keyDown":"moveUp","keyUp":"stopMovingUp"}},"ai":{"attackResponse":"fight","enabled":false,"idleBehaviour":"stay","letGoDistance":"","maxAttackRange":10,"maxTravelDistance":500,"pathFindingMethod":"simple","sensorRadius":150,"sensorResponse":"none"},"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{"G3adwzJecn":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":false,"isVisible":[],"max":100,"min":0,"name":"move","regenerateSpeed":-15,"showAsHUD":true,"showWhen":"","value":100},"health":{"color":"#327117","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":["centerBar","unitBarFriendly","unitBarNeutral","unitBarHostile"],"max":1000,"min":0,"name":"health ","regenerateSpeed":0,"showAsHUD":true,"showWhen":"valueChanges","value":1000},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":0}},"backpackSize":12,"baseSpeed":53,"bodies":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":10,"bullet":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":89,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":8,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":90,"z-index":{"depth":3,"layer":3}}},"body":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":true,"item":true,"items":true,"projectiles":true,"unit":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":3,"friction":0.01,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":40,"isFlying":false,"linearDamping":5,"name":"Human-body","rotationSpeed":2,"spriteScale":1,"type":"dynamic","width":40,"z-index":{"depth":3,"layer":3}},"canBePurchasedBy":[],"canBuyItem":true,"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588431285926_Frog.png"},"confinedWithinMapBoundaries":true,"controls":{"abilities":{"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}}},"absoluteRotation":false,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"movementControlScheme":"wasd","movementMethod":"velocity","movementType":"wasd","permittedInventorySlots":[]},"defaultItem":[],"defaultItems":[{"key":"AqrGZUYBdS","name":"Boss Frog Tongue","value":"Boss Frog Tongue"}],"effects":{"attacked":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"idle":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"move":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""}},"handle":"human","inventoryImage":"","inventorySize":5,"isPurchasable":false,"name":"Frog Boss","particles":{},"price":{},"skin":"https://s3-us-west-1.amazonaws.com/modd/halloween-0.18/spritesheet/man.png","sound":{"KK9JlU1UQy":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517554516253_man_cough.mp3","name":"Cough"},"fEhDyJ8knx":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517556903046_man_scream1.mp3","name":"Scream"}},"spawnPosition":{"x":1500,"y":2200},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}}},"variables":{"sensorRadius":{"dataType":"number","default":400,"defaultKey":"sensorRadius","key":"sensorRadius"},"targetUnit":{"dataType":"unit"}}},"fighter":{"abilities":{"a":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"button1":{"keyDown":"use","keyUp":"stopUse"},"d":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"e":{"keyDown":"pickUp","keyUp":""},"g":{"keyDown":"drop","keyUp":""},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}},"s":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"w":{"keyDown":"moveUp","keyUp":"stopMovingUp"}},"ai":{"attackResponse":"none","enabled":false,"idleBehaviour":"stay","letGoDistance":"","maxAttackRange":400,"maxTravelDistance":"","pathFindingMethod":"simple","sensorRadius":0,"sensorResponse":"none"},"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{"health":{"color":"#90654a","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":["centerBar"],"max":100,"min":0,"name":"health ","regenerateSpeed":"0.2","showAsHUD":true,"value":100},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":7}},"backpackSize":12,"baseSpeed":53,"bodies":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":1,"bullet":false,"bulletDestroyedOnCollisionWithWall/unit":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":53,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":52,"z-index":{"depth":3,"layer":3}}},"body":{"allowSleep":true,"angularDamping":1,"bulletDestroyedOnCollisionWithWall/unit":false,"collidesWith":{"debris":true,"item":true,"items":true,"projectiles":true,"unit":true,"units":true,"walls":true},"fixedRotation":false,"fixtures":[{"density":3,"friction":0.01,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":40,"isFlying":false,"linearDamping":5,"name":"Human-body","rotationSpeed":2,"spriteScale":1,"type":"dynamic","width":40,"z-index":{"depth":3,"layer":3}},"canBePurchasedBy":[],"canBuyItem":true,"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588274010931_Funny Man Poo.png"},"confinedWithinMapBoundaries":true,"controls":{"abilities":{"b":{"keyDown":{"cost":{},"scriptName":"5BUXtByxVf"},"keyUp":{"cost":{},"scriptName":""}},"button1":{"keyDown":{"cost":{},"isEntityScript":true,"scriptName":"umIqJLd7De"},"keyUp":{"cost":{},"isEntityScript":true,"scriptName":"OJ9Po4VSQg"}},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}}},"absoluteRotation":false,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"movementControlScheme":"wasd","movementMethod":"velocity","movementType":"wasd","permittedInventorySlots":[]},"defaultItem":[{"key":"gun","name":"Gun","value":"Gun"},{"key":"crowbar","name":"Crowbar","value":"Crowbar"}],"defaultItems":[{"key":"bMDJQyFACm","name":"knife","value":"knife"}],"effects":{"attacked":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":"recoil"},"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"blood","runScript":"","sound":{}},"idle":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"move":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""}},"equipmentAllowed":5,"handle":"human","inventoryImage":"","inventorySize":5,"isPurchasable":false,"isUnTargetable":false,"name":"Pooper","particles":{},"price":{},"scripts":{"OJ9Po4VSQg":{"actions":[{"entity":{"entity":{"function":"thisEntity"},"function":"getItemCurrentlyHeldByUnit"},"hasFixedCSP":null,"type":"stopUsingItem"}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"OJ9Po4VSQg","name":"stop using item","order":1,"parent":null,"triggers":[]},"umIqJLd7De":{"actions":[{"entity":{"entity":{"function":"thisEntity"},"function":"getItemCurrentlyHeldByUnit"},"hasFixedCSP":null,"type":"startUsingItem"}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"umIqJLd7De","name":"use item","order":0,"parent":null,"triggers":[]}},"skin":"https://s3-us-west-1.amazonaws.com/modd/halloween-0.18/spritesheet/man.png","sound":{"KK9JlU1UQy":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517554516253_man_cough.mp3","name":"Cough"},"fEhDyJ8knx":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517556903046_man_scream1.mp3","name":"Scream"}},"spawnPosition":{"x":1500,"y":2200},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}}},"variables":{}},"oTDQ3jlcMa":{"abilitiesJ8Gtv5HQ8JREnjD":{"a":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"b":{"keyDown":"shop","keyUp":"","mobilePosition":{"x":419,"y":32}},"button1":{"keyDown":"startUsingItem","keyUp":"stopUsingItem","mobilePosition":{"x":326,"y":132}},"d":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"down":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"e":{"keyDown":"pickUp","keyUp":"","mobilePosition":{"x":366,"y":85}},"f":{"keyDown":"pickUp","keyUp":""},"g":{"keyDown":"drop","keyUp":"","mobilePosition":{"x":365,"y":33}},"left":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}},"right":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"s":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"up":{"keyDown":"moveUp","keyUp":"stopMovingUp"},"w":{"keyDown":"moveUp","keyUp":"stopMovingUp"}},"ai":{"attackResponse":"fight","enabled":false,"idleBehaviour":"stay","letGoDistance":"","maxAttackRange":10,"maxTravelDistance":500,"pathFindingMethod":"simple","sensorRadius":150,"sensorResponse":"none"},"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{"G3adwzJecn":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":false,"isVisible":[],"max":100,"min":0,"name":"move","regenerateSpeed":-15,"showAsHUD":true,"showWhen":"","value":100},"health":{"color":"#327117","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":["centerBar","unitBarFriendly","unitBarNeutral","unitBarHostile"],"max":100,"min":0,"name":"health ","regenerateSpeed":0,"showAsHUD":true,"showWhen":"valueChanges","value":100},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":0}},"backpackSize":12,"baseSpeed":53,"bodies":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":10,"bullet":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":28,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":8,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":30,"z-index":{"depth":3,"layer":3}}},"body":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":true,"item":true,"items":true,"projectiles":true,"unit":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":3,"friction":0.01,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":40,"isFlying":false,"linearDamping":5,"name":"Human-body","rotationSpeed":2,"spriteScale":1,"type":"dynamic","width":40,"z-index":{"depth":3,"layer":3}},"canBePurchasedBy":[],"canBuyItem":true,"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588431285926_Frog.png"},"confinedWithinMapBoundaries":true,"controls":{"abilities":{"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}}},"absoluteRotation":false,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"movementControlScheme":"wasd","movementMethod":"velocity","movementType":"wasd","permittedInventorySlots":[]},"defaultItem":[],"defaultItems":[{"key":"BBCDO38dr7","name":"Frog Tongue","value":"Frog Tongue"}],"effects":{"attacked":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"idle":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"move":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""}},"handle":"human","inventoryImage":"","inventorySize":5,"isPurchasable":false,"name":"Frog","particles":{},"price":{},"scripts":{"XUAEBhSryo":{"actions":[{"comment":"wdwadawd","type":"comment"}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"XUAEBhSryo","name":"new script","order":0,"parent":null,"triggers":[]}},"skin":"https://s3-us-west-1.amazonaws.com/modd/halloween-0.18/spritesheet/man.png","sound":{"KK9JlU1UQy":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517554516253_man_cough.mp3","name":"Cough"},"fEhDyJ8knx":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517556903046_man_scream1.mp3","name":"Scream"}},"spawnPosition":{"x":1500,"y":2200},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}}},"variables":{"sensorRadius":{"dataType":"number","default":400,"defaultKey":"sensorRadius","key":"sensorRadius"},"targetUnit":{"dataType":"unit"}}}},"variables":{"AI":{"dataType":"player","default":"computer1"},"bossTimer":{"dataType":"number","default":0},"dwadawd":{"dataType":"unitGroup"},"randomgroup":{"dataType":"itemTypeGroup","default":{"BBCDO38dr7":{"probability":20,"quantity":1},"bMDJQyFACm":{"probability":20,"quantity":1},"tmAlzggQX4":{"probability":20,"quantity":1}}},"tempUnit":{"dataType":"unit"},"timer":{"dataType":"number","default":0},"unittypegroup":{"dataType":"unitTypeGroup","default":{"TyaKyQzgKc":{"probability":20,"quantity":1},"fighter":{"probability":20,"quantity":1},"oTDQ3jlcMa":{"probability":20,"quantity":1}}}}},"defaultMaxPlayers":32,"discordInviteLink":null,"dontResize":false,"enableMiniMap":false,"enablePersistedData":false,"enableVideoChat":false,"extrapolation":true,"facebookLink":null,"featuredOrderNo":-1,"frameRate":15,"gamePlayInstructions":"","gameSlug":"p2H8kqy9c","heightBasedZIndex":false,"hidden":false,"highScores":[],"invitedUsers":[],"iosLink":null,"isDeleted":false,"isFeatured":false,"isGuestPlayerAllowed":true,"isLobbyEnabled":false,"isMod":true,"isModdable":false,"lastPlayedAt":"2023-03-08T23:50:55.198Z","lifeSpanHours":5,"link":null,"lobbyUnitKey":"","mapBackgroundColor":"#000000","maxLobbySize":4,"minLobbySize":2,"mobileReady":false,"moreIoGames":false,"owner":"5dc7aca54006dc3c67a150c8","parentGameId":"634e14bfb4b75e6d3e7730ee","patchNotes":null,"physicsEngine":"planck","playCount":1,"preferredRegion":"us","privateServerIdleTimeout":0.1,"reasonForTakingDown":"","redirect":"off","releases":[{"_id":"63816c35103812aeda0c69b9","isStable":false,"release":"63816c35103812aeda0c69b6","version":0.01}],"revenueSharing":false,"sandboxMode":"advanced","solanaWalletLoginEnabled":false,"tier":"1","title":"Froge","totalPlayCount":15,"twitterLink":null,"updatedAt":"2023-03-16T03:09:51.493Z","version":0.01,"youtubeLink":null} \ No newline at end of file +{"__v":851,"_id":"6311661c535ef4072260feb2","access":"private","allowDuplicateIPS":false,"allowGuestMode":false,"allowLateJoining":false,"allowVerifiedUserToChat":false,"androidLink":null,"autoSave":true,"backupOn":1677200135429,"banChat":[],"banIps":[],"banUsers":[],"canHostPrivateServers":false,"clientPhysicsEngine":"planck","clientSidePredictionEnabled":false,"cover":"https://cache.modd.io/asset/spriteImage/1662091460423_1588259290955_Small_Machete_Knife.png","createdAt":"2022-09-02T02:10:36.829Z","dailyCoinTransferLimit":0,"data":{"abilities":{},"animationTypes":{"B1cWOYKvNL":{"frames":[2,1],"framesPerSecond":1,"loopCount":"","name":"tongue out"},"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"},"dropped":{"frames":[1],"framesPerSecond":0,"loopCount":"","name":"dropped"},"use":{"frames":[1,2,3,1],"framesPerSecond":20,"loopCount":1,"name":"use"}},"attributeTypes":{"G3adwzJecn":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":false,"isVisible":false,"max":100,"min":0,"name":"move","regenerateSpeed":-3,"showAsHUD":true,"showWhen":"","value":100},"health":{"color":"#ffff0f","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":100,"min":0,"name":"health ","regenerateSpeed":0,"showAsHUD":true,"value":100},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":5},"yjdyHZbWpA":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":true,"max":100000,"min":0,"name":"frog kills","regenerateSpeed":0,"showAsHUD":true,"showWhen":"","value":0}},"bodyTypes":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":10,"bullet":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":28,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":8,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":30,"z-index":{"depth":3,"layer":3}},"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":25,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":64,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":"18.6","itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":0,"y":15},"width":12,"z-index":{"depth":4,"layer":3}},"unselected":{"allowSleep":true,"angularDamping":1,"bullet":false,"carriedBy":["fighter"],"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"density":1,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"friction":0,"height":20,"holdPosition":{"rotation":0,"x":0,"y":33},"isFlying":false,"isTangible":false,"itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":1,"name":"unselected","restitution":1,"rotationSpeed":3,"spriteScale":1,"type":"none","typeWhenDrop":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":20},"width":8,"z-index":{"depth":3,"layer":3}}},"buffTypes":{"ammoSize":{"chance":0.1,"maxBonus":0.3,"minBonus":0,"unit":"percentage"},"ammoTotal":{"chance":0.2,"maxBonus":0.3,"minBonus":0,"unit":"percentage"},"bulletForce":{"chance":0.07,"maxBonus":1,"minBonus":0.1,"unit":"percentage"},"canPenetrate":{"chance":0.05,"unit":"boolean"},"canPushDebris":{"chance":0.05,"unit":"boolean"},"distanceEnd":{"chance":0.3,"maxBonus":500,"minBonus":100,"unit":"percentage"},"fireRate":{"chance":0.15,"maxBonus":-0.3,"minBonus":0,"unit":"percentage"},"height":{"chance":0.2,"maxBonus":0.3,"minBonus":0.05,"unit":"percentage"},"immunity":{"chance":0.1,"maxBonus":0.2,"minBonus":0.05,"unit":"percentage"},"maxStamina":{"chance":0.1,"maxBonus":120,"minBonus":20,"unit":"integer"},"movementSpeed":{"chance":0.02,"maxBonus":5,"minBonus":1,"unit":"integer"},"recoilForce":{"chance":0.04,"maxBonus":8,"minBonus":0,"unit":"integer"},"reloadRate":{"chance":0.1,"maxBonus":-0.3,"minBonus":0,"unit":"percentage"},"slowChance":{"chance":0.05,"maxBonus":0.1,"minBonus":0.02,"unit":"percentage"},"stunChance":{"chance":0.05,"maxBonus":0.1,"minBonus":0.02,"unit":"percentage"}},"entityTypeVariables":{"sensorRadius":{"dataType":"number","default":300},"targetUnit":{"dataType":"unit"}},"factions":{"6BTQoFGUFP":{"attributes":{"4P4pWD5ExV":{"color":"yellow","isVisible":true,"max":"100","min":0,"name":"Stamina","regenerateSpeed":0.3,"showAsHUD":true,"value":"100"}},"name":"asdf","relationships":{}},"PgVCU0WgYj":{"name":"fda","relationships":{}}},"images":[{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512752415166_fire_shotgun.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755562800_fire_empty.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755594697_fire_minigun.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755610131_fire_pistol.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755622475_fire_rifle.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755644317_man_cough.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755666761_man_scream1.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512755675893_man_scream2.mp3"},{"key":"sound","url":"https://modd.s3.amazonaws.com/sprites/1512756015200_reload.mp3"}],"itemTypes":{"AqrGZUYBdS":{"animations":{"B1cWOYKvNL":{"frames":[2,1],"framesPerSecond":1,"loopCount":"","name":"tongue out"},"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"},"dropped":{"frames":[1],"framesPerSecond":0,"loopCount":"","name":"dropped"},"use":{"frames":[1,2,3,1],"framesPerSecond":20,"loopCount":1,"name":"use"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":25,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":64,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":"55.8","itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":0,"y":45},"width":36,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":2,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1662085262439_tongue.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":false},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":20}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":40},"delayBeforeUse":0,"description":null,"destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"B1cWOYKvNL","projectileType":"","runScript":"","sound":{},"tween":"none"}},"fireRate":2000,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Boss Frog Tongue","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"r60qiEIvyt":{"animation":"B1cWOYKvNL","body":"selected","name":"tongue out","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}},"BBCDO38dr7":{"animations":{"B1cWOYKvNL":{"frames":[2,1],"framesPerSecond":1,"loopCount":"","name":"tongue out"},"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"},"dropped":{"frames":[1],"framesPerSecond":0,"loopCount":"","name":"dropped"},"use":{"frames":[1,2,3,1],"framesPerSecond":20,"loopCount":1,"name":"use"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":25,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":64,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":"18.6","itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":0,"y":15},"width":12,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":2,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1662085262439_tongue.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":false},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":20}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":100},"delayBeforeUse":0,"description":null,"destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"B1cWOYKvNL","projectileType":"","runScript":"","sound":{},"tween":"none"}},"fireRate":1500,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Frog Tongue","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"r60qiEIvyt":{"animation":"B1cWOYKvNL","body":"selected","name":"tongue out","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}},"bMDJQyFACm":{"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":8,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":15,"y":34},"width":8,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588259290955_Small Machete Knife.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":false},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":10}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":60},"delayBeforeUse":0,"description":null,"destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"use","projectileType":"","runScript":"","sound":{},"tween":"swingCW"}},"fireRate":500,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Knife","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}},"tmAlzggQX4":{"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{},"bodies":{"dropped":{"allowSleep":true,"angularDamping":1,"bullet":false,"collidesWith":{"debris":false,"items":false,"projectiles":false,"units":false,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":58},"jointType":"weldJoint","linearDamping":1,"name":"dropped","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"x":0,"y":48},"width":8,"z-index":{"depth":2,"layer":1}},"selected":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":false,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0.01,"isSensor":false,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":27,"itemAnchor":{"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"selected","rotationSpeed":3,"spriteScale":1,"type":"spriteOnly","unitAnchor":{"x":15,"y":34},"width":8,"z-index":{"depth":4,"layer":3}}},"bonus":{"consume":{"playerAttribute":{},"unitAttribute":{}},"passive":{"isDisabledInBackpack":false,"playerAttribute":{},"unitAttribute":{}}},"buffTypes":[],"bulletDestroyedOnCollisionWithWall/unitDistance":1300,"bulletDestroyedOnCollisionWithWall/unitForce":14,"bulletDestroyedOnCollisionWithWall/unitStartPosition":{"rotation":0,"x":0,"y":0},"bulletDestroyedOnCollisionWithWall/unitType":"raycast","bulletStartPosition":{"rotation":0,"x":0,"y":0},"canBePurchasedBy":[],"canBeUsedBy":[],"carriedBy":[],"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1662090448324_frog-sword.png"},"controls":{"backpackAllowed":true,"canMerge":true,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"permittedInventorySlots":[],"undroppable":true},"cost":{"quantity":0},"damage":{"unitAttributes":{"health":40}},"damageDelay":0,"damageHitBox":{"height":30,"offsetX":0,"offsetY":50,"width":60},"delayBeforeUse":0,"description":"Made from fresh frog","destroyTimer":30000,"effects":{"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"empty":{"animation":"","sound":{}},"reload":{"animation":"","sound":{}},"use":{"animation":"use","projectileType":"","runScript":"","sound":{},"tween":"poke"}},"fireRate":500,"frames":{},"handle":"","hideIfUnaffordable":false,"hits":[],"inventoryImage":null,"isGun":false,"isPurchasable":true,"isStackable":false,"isUsedOnPickup":false,"knockbackForce":0,"maxQuantity":null,"name":"Frog Sword","particles":{},"penetration":false,"projectileType":"","quantity":null,"recoilForce":0,"reloadRate":2800,"removeWhenEmpty":false,"sound":{},"states":{"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"type":"weapon","variables":{}}},"map":{"height":32,"infinite":false,"layers":[{"data":[28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],"height":32,"name":"floor","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0},{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"height":32,"name":"floor2","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0},{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,155,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,156,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"height":32,"name":"walls","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0},{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"height":32,"name":"trees","opacity":1,"type":"tilelayer","visible":true,"width":32,"x":0,"y":0}],"nextobjectid":1,"orientation":"orthogonal","originalTileHeight":64,"originalTileWidth":64,"renderorder":"right-down","tiledversion":"1.1.5","tileheight":64,"tilesets":[{"columns":20,"firstgid":1,"image":"https://cache.modd.io/asset/spriteImage/1569798717927_forest-tilesheet.png","imageheight":1088,"imagewidth":1280,"margin":0,"name":"forest-tilesheet","spacing":0,"tilecount":340,"tileheight":64,"tilewidth":64}],"tilewidth":64,"type":"map","version":1,"width":32},"music":{"iJ8RoRfyeu":{"file":"https://cache.modd.io/asset/sound/1666740498538_breath.mp3","name":"d","volume":25}},"particleTypes":{},"particles":{"7pA9mm1MLG":{"color":"#f4ff00","deathOpacityBase":1,"lifeBase":30,"mountPosition":{"x":0,"y":0},"name":"spark","quantityBase":5,"quantityTimespan":30,"velocityVector":{"baseVector":{"x":0,"y":0},"maxVector":{"x":1,"y":1},"minVector":{"x":-1,"y":-1}}},"87BiLybZhy":{"color":"#636363","deathOpacityBase":1,"lifeBase":50,"mountPosition":{"x":0,"y":0},"name":"bullet","quantityBase":1,"quantityTimespan":30,"velocityVector":{"baseVector":{"x":0,"y":0},"maxVector":{"x":1,"y":1},"minVector":{"x":-1,"y":-1}}}},"playerTypeVariables":{"targetUnit":{"dataType":"unit"}},"playerTypes":{"eA9ZwoweVz":{"attributes":{},"color":"white","name":"ai","relationships":{"humanPlayer":"hostile"},"showNameLabel":false},"humanPlayer":{"attributes":{"yjdyHZbWpA":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":true,"max":100000,"min":0,"name":"frogeKills","regenerateSpeed":0,"showAsHUD":true,"showWhen":"","value":0}},"color":"#ffffff","name":"Player","relationships":{"humanPlayer":"friendly"},"showNameLabel":true,"variables":{"targetUnit":{"dataType":"unit"}}}},"projectileTypes":{},"scripts":{"5BUXtByxVf":{"actions":[{"player":{"entity":{"function":"getLastCastingUnit","vars":[]},"function":"getOwner","vars":[]},"shop":"OJbEQyc7is","type":"openShopForPlayer","vars":[]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"5BUXtByxVf","name":"open shop","order":6,"parent":null,"triggers":[]},"CE0PBg1VWG":{"actions":[{"conditions":[{"operandType":"attributeType","operator":"=="},{"entity":{"function":"getTriggeringAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getAttributeTypeOfAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"health"],"else":[{"conditions":[{"operandType":"attributeType","operator":"=="},{"entity":{"function":"getTriggeringAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getAttributeTypeOfAttribute","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"G3adwzJecn"],"else":[],"then":[{"entity":{"function":"getTriggeringUnit"},"type":"setEntityVariable","value":{"function":"undefinedValue"},"variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"oTDQ3jlcMa","key":"targetUnit","text":"targetUnit"}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"actions":[{"conditions":[{"operandType":"playerType","operator":"=="},{"function":"playerTypeOfPlayer","player":{"entity":{"function":"getSelectedEntity","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"humanPlayer"],"else":[],"then":[{"conditions":[{"operandType":"or","operator":"OR"},[{"operandType":"unit","operator":"=="},{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"oTDQ3jlcMa","key":"targetUnit","text":"targetUnit"}}},{"function":"undefinedValue"}],[{"operandType":"number","operator":">"},{"function":"distanceBetweenPositions","positionA":{"entity":{"function":"getSelectedEntity"},"function":"getEntityPosition"},"positionB":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}},{"function":"distanceBetweenPositions","positionA":{"entity":{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"oTDQ3jlcMa","key":"targetUnit","text":"targetUnit"}}},"function":"getEntityPosition"},"positionB":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}}]],"else":[],"then":[{"color":"#327117","disabled":true,"position":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getEntityPosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"text":"Froge sense","type":"createFloatingText","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},{"entity":{"function":"getTriggeringUnit"},"type":"setEntityVariable","value":{"function":"getSelectedEntity"},"variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"oTDQ3jlcMa","key":"targetUnit","text":"targetUnit"}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}],"entityGroup":{"function":"entitiesInRegion","region":{"function":"dynamicRegion","height":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"oTDQ3jlcMa","key":"sensorRadius","text":"sensorRadius"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}],"width":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"oTDQ3jlcMa","key":"sensorRadius","text":"sensorRadius"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"x":{"function":"calculate","items":[{"operator":"-"},{"function":"getPositionX","position":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}},{"function":"calculate","items":[{"operator":"/"},{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"oTDQ3jlcMa","key":"sensorRadius","text":"sensorRadius"}}},2]}],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"y":{"function":"calculate","items":[{"operator":"-"},{"function":"getPositionY","position":{"entity":{"function":"getTriggeringUnit"},"function":"getEntityPosition"}},{"function":"calculate","items":[{"operator":"/"},{"entity":{"function":"getTriggeringUnit"},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"number","entity":"oTDQ3jlcMa","key":"sensorRadius","text":"sensorRadius"}}},2]}],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},"type":"forAllEntities","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"},{"id":"selectedEntity","source":"forAllEntities"},{"id":"getSelectedEntity","source":"forAllEntities"}]},{"conditions":[{"operandType":"unitType","operator":"!="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"oTDQ3jlcMa","key":"targetUnit","text":"targetUnit"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"function":"undefinedValue","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"else":[{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"position":{"function":"getRandomPositionInRegion","region":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"entityBounds","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"rotateEntityToFacePosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"conditions":[{"operandType":"unitType","operator":"=="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getUnitTypeOfUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"TyaKyQzgKc"],"else":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":400,"min":150,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":3500,"min":1500,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getItemCurrentlyHeldByUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"hasFixedCSP":null,"type":"stopUsingItem","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"position":{"entity":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getValueOfEntityVariable","variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"oTDQ3jlcMa","key":"targetUnit","text":"targetUnit"},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getEntityPosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"rotateEntityToFacePosition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"conditions":[{"operandType":"unitType","operator":"=="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getUnitTypeOfUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"TyaKyQzgKc"],"else":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":600,"min":300,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"angle":{"function":"unitsFacingAngle","unit":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"force":{"function":"getRandomNumberBetween","max":6000,"min":3000,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"applyForceOnEntityAngle","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getItemCurrentlyHeldByUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"hasFixedCSP":null,"type":"startUsingItem","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"attribute":"G3adwzJecn","entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setEntityAttribute","value":{"function":"getRandomNumberBetween","max":100,"min":35,"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"conditions":[{"operandType":"playerType","operator":"=="},{"function":"playerTypeOfPlayer","player":{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"humanPlayer"],"else":[{"conditions":[{"operandType":"unitType","operator":"=="},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getUnitTypeOfUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"TyaKyQzgKc"],"else":[{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setPlayerAttribute","value":{"function":"calculate","items":[{"operator":"+"},{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit"},"function":"getOwner"},"function":"getPlayerAttribute"},1],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"type":"setVariable","value":200,"variableName":"bossTimer","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"getOwner","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setPlayerAttribute","value":{"function":"calculate","items":[{"operator":"+"},{"attribute":"yjdyHZbWpA","entity":{"entity":{"function":"getLastAttackingUnit"},"function":"getOwner"},"function":"getPlayerAttribute"},7],"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"destroyEntity","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"then":[{"attribute":"health","entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"setEntityAttribute","value":{"attribute":"health","entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"function":"entityAttributeMax","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"function":"getTriggeringUnit"},"type":"setEntityVariable","value":{"function":"undefinedValue"},"variable":{"function":"getEntityVariable","variable":{"dataType":"unit","entity":"oTDQ3jlcMa","key":"targetUnit","text":"targetUnit"}},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},{"entity":{"function":"getTriggeringUnit","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"position":{"function":"centerOfRegion","region":{"function":"getEntireMapRegion","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]},"type":"moveEntity","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"type":"condition","vars":[{"id":"getTriggeringUnit","source":"trigger"},{"id":"getTriggeringAttribute","source":"trigger"}]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"CE0PBg1VWG","name":"when a unit's attribute becomes 0 or less","order":4,"parent":null,"triggers":[{"type":"unitAttributeBecomesZero"}]},"P8MwXcSxq7":{"actions":[{"conditions":[{"operandType":"number","operator":"<"},{"function":"getNumberOfUnitsOfUnitType","unitType":"oTDQ3jlcMa","vars":[]},5],"else":[{"conditions":[{"operandType":"number","operator":"=="},{"function":"getNumberOfUnitsOfUnitType","unitType":"TyaKyQzgKc","vars":[]},0],"else":[],"then":[{"conditions":[{"operandType":"number","operator":"<="},{"function":"getVariable","variableName":"bossTimer","vars":[]},0],"else":[],"then":[{"angle":0,"entity":{"function":"getVariable","variableName":"AI","vars":[]},"position":{"function":"getRandomPositionInRegion","region":{"function":"getEntireMapRegion","vars":[]},"vars":[]},"type":"createUnitAtPosition","unitType":"TyaKyQzgKc","vars":[]},{"player":{"function":"undefinedValue","vars":[]},"target":"center-lg","time":5000,"type":"updateUiTextForTimeForPlayer","value":"BOSS SPAWNED","vars":[]}],"type":"condition","vars":[]},{"number":1,"type":"decreaseVariableByNumber","variable":"bossTimer","vars":[]}],"type":"condition","vars":[]}],"then":[{"angle":0,"entity":{"function":"getVariable","variableName":"AI","vars":[]},"position":{"function":"getRandomPositionInRegion","region":{"function":"getEntireMapRegion","vars":[]},"vars":[]},"type":"createUnitAtPosition","unitType":"oTDQ3jlcMa","vars":[]}],"type":"condition","vars":[]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"P8MwXcSxq7","name":"every second","order":3,"parent":null,"triggers":[{"type":"secondTick"}]},"initialize":{"actions":[{"entity":{"function":"getVariable","variableName":"AI","vars":[]},"playerType":"eA9ZwoweVz","type":"assignPlayerType","vars":[]}],"isProtected":true,"key":"initialize","name":"initialize","order":-1,"parent":null,"triggers":[{"type":"gameStart"}]},"playerJoinsGame":{"actions":[{"angle":0,"entity":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"position":{"function":"getRandomPositionInRegion","region":{"function":"getEntireMapRegion","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"type":"createUnitAtPosition","unitType":"fighter","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},{"fighter":{"function":"getTriggeringPlayer"},"player":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"type":"playerCameraTrackUnit","unit":{"function":"getLastCreatedUnit","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},{"entity":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]},"playerType":"humanPlayer","type":"assignPlayerType","vars":[{"id":"getTriggeringPlayer","source":"trigger"}]}],"conditions":[],"key":"playerJoinsGame","name":"player joins","order":1,"parent":null,"triggers":[{"type":"playerJoinsGame"}]},"playerLeavesGame":{"actions":[{"actions":[{"entity":{"function":"selectedUnit","vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]},"type":"destroyEntity","vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]}],"comment":"when a player leaves, destroy all units owned by that player","type":"forAllUnits","unitGroup":{"fighter":{"function":"getTriggeringPlayer"},"function":"allUnitsOwnedByPlayer","player":{"function":"getTriggeringPlayer","vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]},"vars":[{"id":"getTriggeringPlayer","source":"trigger"},{"id":"selectedUnit","source":"forAllUnits"},{"id":"getSelectedUnit","source":"forAllUnits"}]}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"playerLeavesGame","name":"player leaves","order":2,"parent":null,"triggers":[{"type":"playerLeavesGame"}]}},"settings":{"allowDuplicateIPs":true,"camera":{"trackingDelay":3,"zoom":{"default":600,"type":"static"}},"constants":{"currency":"Food"},"displayScoreboard":true,"gravity":{"x":0,"y":0},"images":{"cover":"https://cache.modd.io/1501275562940_two houses cover.png","logo":"https://cache.modd.io/asset/spriteImage/1593103756304_modd_logo.png"},"inventory":{"isEnabled":false},"menuHTML":"
\n\t
\n\t\t{{ loginForm }}\n\t
\n\n\t\n\n\t{{#if isUserLoggedIn }}\n {{ friendsPanel }}\n {{/if}}\n
\n\n
\n\t
\n\t\t

\n\t\t

\n\t\t\n\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t{{ coinShop }}\n\t\t\t\t
\n\t\t\t
\n\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t{{ playForm }}\t\t\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t{{ skinShop }}\n\t\t\t\t
\n\t\t\t
\n\t\t\t\n\t\t
\n\t
\n
","menudiv":"KILL THE FROGSWJG","prettifyingScoreboard":true,"scoreAttributeId":"points","scoreBoard":"n5JEoENeGg","shop":{"isEnabled":false}},"shops":{"OJbEQyc7is":{"dismissible":true,"itemTypes":{"bMDJQyFACm":{"hideIfRequirementNotMet":false,"hideIfUnaffordable":false,"isPurchasable":true,"price":{"coins":0,"playerAttributes":{},"requiredItemTypes":[]},"quantity":"","replaceItemInTargetSlot":false,"requirement":{"playerAttributes":{},"requiredItemTypes":[]}},"tmAlzggQX4":{"hideIfRequirementNotMet":false,"hideIfUnaffordable":false,"isPurchasable":true,"price":{"coins":0,"playerAttributes":{"yjdyHZbWpA":15},"requiredItemTypes":{}},"quantity":"","replaceItemInTargetSlot":false,"requirement":{"playerAttributes":{},"requiredItemTypes":[]}}},"name":"Froge Shop","unitTypes":{}}},"sound":{},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}},"dropped":{"animation":"dropped","body":"dropped","name":"dropped","particles":{},"sound":{}},"r60qiEIvyt":{"animation":"","body":"selected","name":"tongue out","particles":{},"sound":{}},"selected":{"animation":"default","body":"selected","name":"selected","particles":{},"sound":{}},"unselected":{"animation":"none","body":"none","name":"unselected","particles":{},"sound":{}}},"tilesets":[{"image":"https://cache.modd.io/two_houses-0.18/tilesheet.png","name":"tilesheet_complete"},{"image":"https://cache.modd.io/two_houses-0.18/2x1.png","name":"2x1"},{"image":"https://cache.modd.io/two_houses-0.18/2x3.png","name":"2x3"},{"image":"https://cache.modd.io/two_houses-0.18/3x1.png","name":"3x1"},{"image":"https://cache.modd.io/two_houses-0.18/3x4.png","name":"3x4"},{"image":"https://cache.modd.io/two_houses-0.18/spritesheet/shop.png","name":"shop"}],"unitTypes":{"TyaKyQzgKc":{"abilitiesJ8Gtv5HQ8JREnjD":{"a":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"b":{"keyDown":"shop","keyUp":"","mobilePosition":{"x":419,"y":32}},"button1":{"keyDown":"startUsingItem","keyUp":"stopUsingItem","mobilePosition":{"x":326,"y":132}},"d":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"down":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"e":{"keyDown":"pickUp","keyUp":"","mobilePosition":{"x":366,"y":85}},"f":{"keyDown":"pickUp","keyUp":""},"g":{"keyDown":"drop","keyUp":"","mobilePosition":{"x":365,"y":33}},"left":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}},"right":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"s":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"up":{"keyDown":"moveUp","keyUp":"stopMovingUp"},"w":{"keyDown":"moveUp","keyUp":"stopMovingUp"}},"ai":{"attackResponse":"fight","enabled":false,"idleBehaviour":"stay","letGoDistance":"","maxAttackRange":10,"maxTravelDistance":500,"pathFindingMethod":"simple","sensorRadius":150,"sensorResponse":"none"},"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{"G3adwzJecn":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":false,"isVisible":[],"max":100,"min":0,"name":"move","regenerateSpeed":-15,"showAsHUD":true,"showWhen":"","value":100},"health":{"color":"#327117","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":["centerBar","unitBarFriendly","unitBarNeutral","unitBarHostile"],"max":1000,"min":0,"name":"health ","regenerateSpeed":0,"showAsHUD":true,"showWhen":"valueChanges","value":1000},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":0}},"backpackSize":12,"baseSpeed":53,"bodies":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":10,"bullet":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":89,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":8,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":90,"z-index":{"depth":3,"layer":3}}},"body":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":true,"item":true,"items":true,"projectiles":true,"unit":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":3,"friction":0.01,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":40,"isFlying":false,"linearDamping":5,"name":"Human-body","rotationSpeed":2,"spriteScale":1,"type":"dynamic","width":40,"z-index":{"depth":3,"layer":3}},"canBePurchasedBy":[],"canBuyItem":true,"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588431285926_Frog.png"},"confinedWithinMapBoundaries":true,"controls":{"abilities":{"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}}},"absoluteRotation":false,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"movementControlScheme":"wasd","movementMethod":"velocity","movementType":"wasd","permittedInventorySlots":[]},"defaultItem":[],"defaultItems":[{"key":"AqrGZUYBdS","name":"Boss Frog Tongue","value":"Boss Frog Tongue"}],"effects":{"attacked":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"idle":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"move":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""}},"handle":"human","inventoryImage":"","inventorySize":5,"isPurchasable":false,"name":"Frog Boss","particles":{},"price":{},"skin":"https://s3-us-west-1.amazonaws.com/modd/halloween-0.18/spritesheet/man.png","sound":{"KK9JlU1UQy":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517554516253_man_cough.mp3","name":"Cough"},"fEhDyJ8knx":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517556903046_man_scream1.mp3","name":"Scream"}},"spawnPosition":{"x":1500,"y":2200},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}}},"variables":{"sensorRadius":{"dataType":"number","default":400,"defaultKey":"sensorRadius","key":"sensorRadius"},"targetUnit":{"dataType":"unit"}}},"fighter":{"abilities":{"a":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"button1":{"keyDown":"use","keyUp":"stopUse"},"d":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"e":{"keyDown":"pickUp","keyUp":""},"g":{"keyDown":"drop","keyUp":""},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}},"s":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"w":{"keyDown":"moveUp","keyUp":"stopMovingUp"}},"ai":{"attackResponse":"none","enabled":false,"idleBehaviour":"stay","letGoDistance":"","maxAttackRange":400,"maxTravelDistance":"","pathFindingMethod":"simple","sensorRadius":0,"sensorResponse":"none"},"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{"health":{"color":"#90654a","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":["centerBar"],"max":100,"min":0,"name":"health ","regenerateSpeed":"0.2","showAsHUD":true,"value":100},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":7}},"backpackSize":12,"baseSpeed":53,"bodies":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":1,"bullet":false,"bulletDestroyedOnCollisionWithWall/unit":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":53,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":5,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":52,"z-index":{"depth":3,"layer":3}}},"body":{"allowSleep":true,"angularDamping":1,"bulletDestroyedOnCollisionWithWall/unit":false,"collidesWith":{"debris":true,"item":true,"items":true,"projectiles":true,"unit":true,"units":true,"walls":true},"fixedRotation":false,"fixtures":[{"density":3,"friction":0.01,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":40,"isFlying":false,"linearDamping":5,"name":"Human-body","rotationSpeed":2,"spriteScale":1,"type":"dynamic","width":40,"z-index":{"depth":3,"layer":3}},"canBePurchasedBy":[],"canBuyItem":true,"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588274010931_Funny Man Poo.png"},"confinedWithinMapBoundaries":true,"controls":{"abilities":{"b":{"keyDown":{"cost":{},"scriptName":"5BUXtByxVf"},"keyUp":{"cost":{},"scriptName":""}},"button1":{"keyDown":{"cost":{},"isEntityScript":true,"scriptName":"umIqJLd7De"},"keyUp":{"cost":{},"isEntityScript":true,"scriptName":"OJ9Po4VSQg"}},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}}},"absoluteRotation":false,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"movementControlScheme":"wasd","movementMethod":"velocity","movementType":"wasd","permittedInventorySlots":[]},"defaultItem":[{"key":"gun","name":"Gun","value":"Gun"},{"key":"crowbar","name":"Crowbar","value":"Crowbar"}],"defaultItems":[{"key":"bMDJQyFACm","name":"knife","value":"knife"}],"effects":{"attacked":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":"recoil"},"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"blood","runScript":"","sound":{}},"idle":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"move":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""}},"equipmentAllowed":5,"handle":"human","inventoryImage":"","inventorySize":5,"isPurchasable":false,"isUnTargetable":false,"name":"Pooper","particles":{},"price":{},"scripts":{"OJ9Po4VSQg":{"actions":[{"entity":{"entity":{"function":"thisEntity"},"function":"getItemCurrentlyHeldByUnit"},"hasFixedCSP":null,"type":"stopUsingItem"}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"OJ9Po4VSQg","name":"stop using item","order":1,"parent":null,"triggers":[]},"umIqJLd7De":{"actions":[{"entity":{"entity":{"function":"thisEntity"},"function":"getItemCurrentlyHeldByUnit"},"hasFixedCSP":null,"type":"startUsingItem"}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"umIqJLd7De","name":"use item","order":-1,"parent":null,"triggers":[]}},"skin":"https://s3-us-west-1.amazonaws.com/modd/halloween-0.18/spritesheet/man.png","sound":{"KK9JlU1UQy":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517554516253_man_cough.mp3","name":"Cough"},"fEhDyJ8knx":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517556903046_man_scream1.mp3","name":"Scream"}},"spawnPosition":{"x":1500,"y":2200},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}}},"variables":{}},"oTDQ3jlcMa":{"abilitiesJ8Gtv5HQ8JREnjD":{"a":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"b":{"keyDown":"shop","keyUp":"","mobilePosition":{"x":419,"y":32}},"button1":{"keyDown":"startUsingItem","keyUp":"stopUsingItem","mobilePosition":{"x":326,"y":132}},"d":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"down":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"e":{"keyDown":"pickUp","keyUp":"","mobilePosition":{"x":366,"y":85}},"f":{"keyDown":"pickUp","keyUp":""},"g":{"keyDown":"drop","keyUp":"","mobilePosition":{"x":365,"y":33}},"left":{"keyDown":"moveLeft","keyUp":"stopMovingLeft"},"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}},"right":{"keyDown":"moveRight","keyUp":"stopMovingRight"},"s":{"keyDown":"moveDown","keyUp":"stopMovingDown"},"up":{"keyDown":"moveUp","keyUp":"stopMovingUp"},"w":{"keyDown":"moveUp","keyUp":"stopMovingUp"}},"ai":{"attackResponse":"fight","enabled":false,"idleBehaviour":"stay","letGoDistance":"","maxAttackRange":10,"maxTravelDistance":500,"pathFindingMethod":"simple","sensorRadius":150,"sensorResponse":"none"},"animations":{"default":{"frames":[1],"framesPerSecond":0,"loopCount":0,"name":"default"}},"attributes":{"G3adwzJecn":{"color":"white","dataType":"","decimalPlaces":0,"displayValue":false,"isVisible":[],"max":100,"min":0,"name":"move","regenerateSpeed":-15,"showAsHUD":true,"showWhen":"","value":100},"health":{"color":"#327117","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":["centerBar","unitBarFriendly","unitBarNeutral","unitBarHostile"],"max":100,"min":0,"name":"health ","regenerateSpeed":0,"showAsHUD":true,"showWhen":"valueChanges","value":100},"speed":{"color":"#00fff0","dataType":"","decimalPlaces":0,"displayValue":true,"isVisible":[],"max":200,"min":0,"name":"speed","regenerateSpeed":0,"showAsHUD":true,"value":0}},"backpackSize":12,"baseSpeed":53,"bodies":{"default":{"affectedByGravity":false,"allowSleep":true,"angularDamping":10,"bullet":false,"collidesWith":{"debris":true,"items":true,"projectiles":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":1,"friction":0,"isSensor":false,"restitution":0,"shape":{"type":"rectangle"}}],"height":28,"itemAnchor":{"lowerAngle":0,"upperAngle":0,"x":0,"y":0},"jointType":"weldJoint","linearDamping":8,"name":"default","rotationSpeed":1,"spriteScale":1,"type":"dynamic","unitAnchor":{"rotation":0,"x":0,"y":33},"width":30,"z-index":{"depth":3,"layer":3}}},"body":{"allowSleep":true,"angularDamping":1,"collidesWith":{"debris":true,"item":true,"items":true,"projectiles":true,"unit":true,"units":true,"walls":true},"constantSpeed +DestroyedOnCollisionWithWall/unit":false,"fixedRotation":false,"fixtures":[{"density":3,"friction":0.01,"restitution":0.01,"shape":{"type":"rectangle"}}],"height":40,"isFlying":false,"linearDamping":5,"name":"Human-body","rotationSpeed":2,"spriteScale":1,"type":"dynamic","width":40,"z-index":{"depth":3,"layer":3}},"canBePurchasedBy":[],"canBuyItem":true,"cellSheet":{"columnCount":1,"rowCount":1,"url":"https://cache.modd.io/asset/spriteImage/1588431285926_Frog.png"},"confinedWithinMapBoundaries":true,"controls":{"abilities":{"lookWheel":{"mobilePosition":{"x":407,"y":204}},"movementWheel":{"mobilePosition":{"x":35,"y":204}}},"absoluteRotation":false,"mouseBehaviour":{"flipSpriteHorizontallyWRTMouse":false,"rotateToFaceMouseCursor":true},"movementControlScheme":"wasd","movementMethod":"velocity","movementType":"wasd","permittedInventorySlots":[]},"defaultItem":[],"defaultItems":[{"key":"BBCDO38dr7","name":"Frog Tongue","value":"Frog Tongue"}],"effects":{"attacked":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"create":{"animation":"","projectileType":"","runScript":"","sound":{}},"destroy":{"animation":"","projectileType":"","runScript":"","sound":{}},"idle":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""},"move":{"animation":"","projectileType":"","runScript":"","sound":{},"tween":""}},"handle":"human","inventoryImage":"","inventorySize":5,"isPurchasable":false,"name":"Frog","particles":{},"price":{},"scripts":{"XUAEBhSryo":{"actions":[{"comment":"wdwadawd","type":"comment"}],"conditions":[{"operandType":"boolean","operator":"=="},true,true],"key":"XUAEBhSryo","name":"New Script","order":-1,"parent":null,"triggers":[]}},"skin":"https://s3-us-west-1.amazonaws.com/modd/halloween-0.18/spritesheet/man.png","sound":{"KK9JlU1UQy":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517554516253_man_cough.mp3","name":"Cough"},"fEhDyJ8knx":{"file":"https://modd.s3.amazonaws.com/asset/sound/1517556903046_man_scream1.mp3","name":"Scream"}},"spawnPosition":{"x":1500,"y":2200},"states":{"default":{"animation":"default","body":"default","name":"default","particles":{},"sound":{}}},"variables":{"sensorRadius":{"dataType":"number","default":400,"defaultKey":"sensorRadius","key":"sensorRadius"},"targetUnit":{"dataType":"unit"}}}},"variables":{"AI":{"dataType":"player","default":"computer1"},"bossTimer":{"dataType":"number","default":0},"dwadawd":{"dataType":"unitGroup"},"randomgroup":{"dataType":"itemTypeGroup","default":{"BBCDO38dr7":{"probability":20,"quantity":1},"bMDJQyFACm":{"probability":20,"quantity":1},"tmAlzggQX4":{"probability":20,"quantity":1}}},"tempUnit":{"dataType":"unit"},"timer":{"dataType":"number","default":0},"unittypegroup":{"dataType":"unitTypeGroup","default":{"TyaKyQzgKc":{"probability":20,"quantity":1},"fighter":{"probability":20,"quantity":1},"oTDQ3jlcMa":{"probability":20,"quantity":1}}}}},"defaultMaxPlayers":32,"discordInviteLink":null,"dontResize":false,"enableMiniMap":false,"enablePersistedData":false,"enableVideoChat":false,"extrapolation":true,"facebookLink":null,"featuredOrderNo":-1,"frameRate":15,"gamePlayInstructions":"","gameSlug":"froge","heightBasedZIndex":false,"hidden":true,"highScores":[],"invitedUsers":[],"iosLink":null,"isDeleted":false,"isFeatured":false,"isGuestPlayerAllowed":true,"isLobbyEnabled":false,"isMod":false,"isModdable":false,"lastPlayedAt":"2023-02-17T14:59:38.654Z","lifeSpanHours":5,"link":null,"lobbyUnitKey":"","mapBackgroundColor":"#000000","maxLobbySize":4,"minLobbySize":2,"mobileReady":false,"moreIoGames":false,"owner":"5dc7aca54006dc3c67a150c8","parentGameId":null,"patchNotes":null,"physicsEngine":"planck","playCount":4,"preferredRegion":"","privateServerIdleTimeout":0.1,"reasonForTakingDown":"","redirect":"off","releases":[{"_id":"6311661c535ef4072260feb3","isStable":false,"release":"6311661c535ef4072260feb0","version":0.01}],"revenueSharing":false,"sandboxMode":"advanced","solanaWalletLoginEnabled":false,"tier":"1","title":"Froge","totalPlayCount":110,"twitterLink":null,"updatedAt":"2023-02-24T00:37:58.233Z","version":0.01,"youtubeLink":null} \ No newline at end of file diff --git a/pymodd/_pymodd_helper.pyi b/pymodd/_pymodd_helper.pyi index a289a2e..8de99e0 100644 --- a/pymodd/_pymodd_helper.pyi +++ b/pymodd/_pymodd_helper.pyi @@ -1,40 +1,42 @@ def generate_project_from_json_file_path(json_file_path): - """Generates a pymodd project from a modd.io game json file + '''Generates a pymodd project from a modd.io game json file Args: json_file_path (str): path to the modd.io game json file - """ + ''' def log_success(message): - """Logs a success message with colorful formatting + '''Logs a success message with colorful formatting Args: message (str): message to log - """ + ''' def log_error(message): - """Logs an error message with colorful formatting + '''Logs an error message with colorful formatting Args: message (str): message to log - """ + ''' def log_cli_start_message(action, pymodd_project_name): - """Logs a start message for pymodd commands with colorful formatting + '''Logs a start message for pymodd commands with colorful formatting Args: action (str): the action that the command is doing + pymodd_project_name (str): name of the project - """ + ''' def log_cli_end_message(completed_action, ended_successfully): - """Logs an end message for pymodd commands with colorful formatting + '''Logs an end message for pymodd commands with colorful formatting Args: - completed_action (str): the action the the command completed + completed_action (str): the action the command completed + ended_successfully (bool): did the command end successfully - """ + ''' diff --git a/pymodd/actions.py b/pymodd/actions.py index 15c4188..f57a1dd 100644 --- a/pymodd/actions.py +++ b/pymodd/actions.py @@ -1,8 +1,8 @@ from __future__ import annotations import functools -from .functions import Condition, Number, String -from .script import Script, to_dict +from pymodd.functions import Condition, Number, String +from pymodd.script import Script, to_dict def action(func): @@ -29,16 +29,6 @@ def parse_optional_arguments_into_dictionary(comment, disabled, run_on_client): return dictionary -@action -def if_else(condition: Condition, then_actions=[], else_actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'condition', - 'conditions': to_dict(condition), - 'then': then_actions, - 'else': else_actions, - } - - @action def set_player_variable(variable_type, player, value, comment=None, disabled=False, run_on_client=False): return { @@ -174,13 +164,6 @@ def open_dialogue_for_player(dialogue, player, comment=None, disabled=False, run } -@action -def continue_loop(comment=None, disabled=False, run_on_client=False): - return { - 'type': 'continue', - } - - @action def open_website_for_player(string: String, player, comment=None, disabled=False, run_on_client=False): return { @@ -306,15 +289,6 @@ def move_debris_to_position(entity, position, comment=None, disabled=False, run_ } -@action -def for_all_items_in(item_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllItems', - 'itemGroup': to_dict(item_group), - 'actions': actions, - } - - @action def remove_player_from_player_group(player, player_group, comment=None, disabled=False, run_on_client=False): return { @@ -370,13 +344,6 @@ def hide_unit_in_minimap_for_player(unit, player, comment=None, disabled=False, } -@action -def return_loop(comment=None, disabled=False, run_on_client=False): - return { - 'type': 'return', - } - - @action def run_script(script: Script, comment=None, disabled=False, run_on_client=False): return { @@ -444,7 +411,7 @@ def create_entity_at_position_with_dimensions(entity, position, height: Number, def set_variable(variable, value, comment=None, disabled=False, run_on_client=False): return { 'type': 'setVariable', - 'variableName': variable.name, + 'variableName': variable.id, 'value': to_dict(value), } @@ -578,15 +545,6 @@ def attach_debris_to_unit(debris, unit, comment=None, disabled=False, run_on_cli } -@action -def repeat(count: Number, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'repeat', - 'count': to_dict(count), - 'actions': actions, - } - - @action def stop_music_for_everyone(comment=None, disabled=False, run_on_client=False): return { @@ -657,15 +615,6 @@ def start_accepting_players(comment=None, disabled=False, run_on_client=False): } -@action -def for_all_entities_in(entity_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllEntities', - 'entityGroup': to_dict(entity_group), - 'actions': actions, - } - - @action def make_player_select_unit(player, unit, comment=None, disabled=False, run_on_client=False): return { @@ -685,15 +634,6 @@ def set_entity_attribute(attribute, entity, value: Number, comment=None, disable } -@action -def for_all_item_types_in(item_type_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllItemTypes', - 'itemTypeGroup': to_dict(item_type_group), - 'actions': actions, - } - - @action def create_entity_for_player_at_position_with_dimensions(entity, player, position, height: Number, width: Number, angle: Number, comment=None, disabled=False, run_on_client=False): return { @@ -723,24 +663,6 @@ def update_ui_text_for_everyone(target, value: String, comment=None, disabled=Fa } -@action -def for_all_units_in(unit_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllUnits', - 'unitGroup': to_dict(unit_group), - 'actions': actions, - } - - -@action -def for_all_projectiles_in(projectile_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllProjectiles', - 'projectileGroup': to_dict(projectile_group), - 'actions': actions, - } - - @action def stop_music_for_player(player, comment=None, disabled=False, run_on_client=False): return { @@ -796,15 +718,6 @@ def change_scale_of_entity_body(scale: Number, entity, comment=None, disabled=Fa } -@action -def for_all_regions_in(region_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllRegions', - 'regionGroup': to_dict(region_group), - 'actions': actions, - } - - @action def rotate_entity_loss_tolerant_to_radians(entity, radians: Number, comment=None, disabled=False, run_on_client=False): return { @@ -834,15 +747,6 @@ def set_player_attribute_regeneration_rate(attribute_type, player, number: Numbe } -@action -def for_all_unit_types_in(unit_type_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllUnitTypes', - 'unitTypeGroup': to_dict(unit_type_group), - 'actions': actions, - } - - @action def decrease_variable_by_number(variable, number: Number, comment=None, disabled=False, run_on_client=False): return { @@ -860,15 +764,6 @@ def kick_player(entity, comment=None, disabled=False, run_on_client=False): } -@action -def for_all_players_in(player_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllPlayers', - 'playerGroup': to_dict(player_group), - 'actions': actions, - } - - @action def remove_unit_from_unit_group(unit, unit_group, comment=None, disabled=False, run_on_client=False): return { @@ -879,11 +774,15 @@ def remove_unit_from_unit_group(unit, unit_group, comment=None, disabled=False, @action -def flip_sprite_of_entity(flip, entity, comment=None, disabled=False, run_on_client=False): +def flip_sprite_of_entity(entity, flip, comment=None, disabled=False, run_on_client=False): '''Flip the sprite of an entity + example: + `flip_sprite_of_entity(LastTriggeringUnit(), Flip.HORIZONTAL)` + Args: entity (Entity): the entity that will be flipped + flip (Flip): the flip direction from `Flip` enum class ''' return { @@ -945,17 +844,6 @@ def move_entity_to_position(entity, position, comment=None, disabled=False, run_ } -@action -def for_range(variable, start: Number, stop: Number, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'for', - 'variableName': variable.name, - 'start': to_dict(start), - 'stop': to_dict(stop), - 'actions': actions, - } - - @action def show_menu_to_player_and_select_best_server(player, comment=None, disabled=False, run_on_client=False): return { @@ -1014,15 +902,6 @@ def change_unit_type_of_entity(unit_type, entity, comment=None, disabled=False, } -@action -def for_all_debris_in(debris_group, actions=[], comment=None, disabled=False, run_on_client=False): - return { - 'type': 'forAllDebris', - 'debrisGroup': to_dict(debris_group), - 'actions': actions, - } - - @action def play_music_for_player_repeatedly(music, player, comment=None, disabled=False, run_on_client=False): return { @@ -1084,13 +963,6 @@ def make_unit_invisible_to_hostile_players(entity, comment=None, disabled=False, } -@action -def break_loop(comment=None, disabled=False, run_on_client=False): - return { - 'type': 'break', - } - - @ action def change_scale_of_sprite_for_entity(scale: Number, entity, comment=None, disabled=False, run_on_client=False): return { @@ -1613,3 +1485,214 @@ def command_ai_to_idle(unit, comment=None, disabled=False, run_on_client=False): 'type': 'aiGoIdle', 'unit': to_dict(unit), } + + +# ---------------------------------------------------------------------------- # +# Deprecated Actions # +# ---------------------------------------------------------------------------- # + +@action +def break_loop(comment=None, disabled=False, run_on_client=False): + '''Deprecated, use the python `break` keyword instead''' + return { + 'type': 'break', + } + + +@action +def continue_loop(comment=None, disabled=False, run_on_client=False): + '''Deprecated, use the python `continue` keyword instead''' + return { + 'type': 'continue', + } + + +@action +def return_loop(comment=None, disabled=False, run_on_client=False): + '''Deprecated, use the python `return` keyword instead''' + return { + 'type': 'return', + } + + +@action +def if_else(condition: Condition, then_actions=[], else_actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python if statement instead: + ``` + if NumberOfPlayers() > 10 & Variables.TIMER <= 0: + ... + ``` + ''' + return { + 'type': 'condition', + 'conditions': to_dict(condition), + 'then': then_actions, + 'else': else_actions, + } + + +@action +def repeat(count: Number, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for _ in repeat(5): + ... + ``` + ''' + return { + 'type': 'repeat', + 'count': to_dict(count), + 'actions': actions, + } + + +@action +def for_range(variable, start: Number, stop: Number, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for Variables.I in range(5): + ... + ``` + ''' + return { + 'type': 'for', + 'variableName': variable.id, + 'start': to_dict(start), + 'stop': to_dict(stop), + 'actions': actions, + } + + +@action +def for_all_entities_in(entity_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for entity in AllEntitiesInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllEntities', + 'entityGroup': to_dict(entity_group), + 'actions': actions, + } + + +@action +def for_all_projectiles_in(projectile_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for projectile in AllProjectilesInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllProjectiles', + 'projectileGroup': to_dict(projectile_group), + 'actions': actions, + } + + +@action +def for_all_items_in(item_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for items in AllItemsInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllItems', + 'itemGroup': to_dict(item_group), + 'actions': actions, + } + + +@action +def for_all_units_in(unit_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for unit in AllUnitsInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllUnits', + 'unitGroup': to_dict(unit_group), + 'actions': actions, + } + + +@action +def for_all_players_in(player_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for player in AllPlayersInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllPlayers', + 'playerGroup': to_dict(player_group), + 'actions': actions, + } + + +@action +def for_all_item_types_in(item_type_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for item_type in AllItemTypesInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllItemTypes', + 'itemTypeGroup': to_dict(item_type_group), + 'actions': actions, + } + + +@action +def for_all_unit_types_in(unit_type_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for unit_type in AllUnitTypesInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllUnitTypes', + 'unitTypeGroup': to_dict(unit_type_group), + 'actions': actions, + } + + +@action +def for_all_regions_in(region_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for region in AllRegionsInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllRegions', + 'regionGroup': to_dict(region_group), + 'actions': actions, + } + + +@action +def for_all_debris_in(debris_group, actions=[], comment=None, disabled=False, run_on_client=False): + '''Deprecated, use a python for loop instead: + ``` + for debris in AllDebrisInTheGame() + ... + ``` + ''' + return { + 'type': 'forAllDebris', + 'debrisGroup': to_dict(debris_group), + 'actions': actions, + } diff --git a/pymodd/console_scripts/pymodd_command.py b/pymodd/console_scripts/pymodd_command.py index 735179c..1dff028 100644 --- a/pymodd/console_scripts/pymodd_command.py +++ b/pymodd/console_scripts/pymodd_command.py @@ -8,21 +8,32 @@ from pymodd.script import Game, EntityScripts +VARIABLE_TYPE_CLASS_NAMES = [ + 'UnitTypes', 'PlayerTypes', 'ItemTypes', 'ProjectileTypes', 'Regions', 'Variables', + 'EntityVariables', 'PlayerVariables', 'AnimationTypes', 'AttributeTypes', 'ItemTypeGroups', + 'UnitTypeGroups', 'States', 'Shops', 'Dialogues', 'Musics', 'Sounds' +] + + def generate_project(args): _pymodd_helper.generate_project_from_json_file_path(args.json_file_path) def compile_project(_args): - if not os.path.isfile('mapping.py'): - _pymodd_helper.log_error( - 'mapping.py file not found: is your current working directory a pymodd project?') - return + required_files = ['mapping.py'] + for file in required_files: + if not os.path.isfile(file): + _pymodd_helper.log_error( + f'{file} file not found: is your current working directory a pymodd project?') + return + project_directory_name = os.getcwd().split(os.sep)[-1] _pymodd_helper.log_cli_start_message("Compiling", project_directory_name) sys.path.append(os.path.abspath(f'../{project_directory_name}/')) - mapping_file_data = runpy.run_path(f'mapping.py') - game_classes = find_game_classes_in_file_data(mapping_file_data) + project_data = runpy.run_path('mapping.py') + + game_classes = find_game_classes_in_project_data(project_data) if len(game_classes) == 0: _pymodd_helper.log_error( 'no class subclassing Game was found in mapping.py, one is required') @@ -31,7 +42,10 @@ def compile_project(_args): _pymodd_helper.log_error( 'more than one class subclassing Game was found in mapping.py, only one is required') return - game = game_classes[0]('utils/game.json') + + variable_classes = find_variable_classes_in_project_data( + project_data) + game = game_classes[0]('utils/game.json', variable_classes, project_data) compiled_json_output_path = f'output/{game.name}.json' if not os.path.exists('output/'): @@ -43,7 +57,7 @@ def compile_project(_args): _pymodd_helper.log_cli_end_message("compilation", True) -def find_game_classes_in_file_data(file_data): +def find_game_classes_in_project_data(project_data: dict): return list(filter( lambda object_data: # is a class @@ -53,7 +67,17 @@ def find_game_classes_in_file_data(file_data): # is not the Game class object_data != Game and # does not subclass the EntityScripts class - not issubclass(object_data, EntityScripts), file_data.values())) + not issubclass(object_data, EntityScripts), + project_data.values())) + + +def find_variable_classes_in_project_data(project_data: dict): + def is_class_data_of_variable_type(pair): + key, _value = pair + return key in VARIABLE_TYPE_CLASS_NAMES + return list(dict(filter( + is_class_data_of_variable_type, + project_data.items())).values()) def main_cli(): diff --git a/pymodd/functions.py b/pymodd/functions.py index 491c358..de70ca8 100644 --- a/pymodd/functions.py +++ b/pymodd/functions.py @@ -1,6 +1,7 @@ +import pymodd from caseconverter import camelcase -from .script import Base, to_dict +from pymodd.script import Base, to_dict class Function(Base): @@ -20,25 +21,6 @@ def to_dict(self): data.update(self.options) return data - # condition functions - def __eq__(self, other): - return Condition(self, '==', other) - - def __ne__(self, other): - return Condition(self, '!=', other) - - def __ge__(self, other): - return Condition(self, '>=', other) - - def __gt__(self, other): - return Condition(self, '>', other) - - def __le__(self, other): - return Condition(self, '<=', other) - - def __lt__(self, other): - return Condition(self, '<', other) - # calculation functions def __add__(self, other): if 'string' in [type_of_item(self).lower(), type_of_item(other).lower()]: @@ -77,6 +59,12 @@ def __rpow__(self, other): return Exponent(other, self) +# only subclasses of Function requires these types +# (also prevents a circular import) +from .variable_types import (AttributeType, EntityVariable, ItemType, PlayerType, PlayerVariable, + ProjectileType, State, UnitType, Variable) + + # ---------------------------------------------------------------------------- # # Other # # ---------------------------------------------------------------------------- # @@ -94,7 +82,7 @@ def type_of_item(item): if (primitive := primitive_to_type.get(type(item))): return primitive if isinstance(item, Variable): - return camelcase(item.type) + return item.data_type.value if isinstance(item, Function): base_classes = item.__class__.mro() for i, base_class in enumerate(base_classes): @@ -105,23 +93,23 @@ def type_of_item(item): class Condition(Function): def __init__(self, item_a: Base, operator: str, item_b: Base): - """The comparison type of the condition is determined based on the type of item_a + '''The comparison type of the condition is determined based on the type of item_a Args: item_a (Base): any object + operator (str): can be regular comparisons (==, !=, >=, ...) or 'AND' and 'OR' + item_b (Base): any object - """ + ''' self.item_a = item_a self.operator = operator.upper() self.item_b = item_b - comparison = None - if (operator := operator.lower()) == 'and' or operator == 'or': - comparison = operator + if self.operator == 'AND' or self.operator == 'OR': + self.comparison = operator.lower() else: - comparison = type_of_item(item_a) or type_of_item(item_b) - self.comparison = comparison + self.comparison = type_of_item(item_a) or type_of_item(item_b) def to_dict(self): return [ @@ -133,12 +121,6 @@ def to_dict(self): to_dict(self.item_b) ] - def __and__(self, other): - return Condition(self, 'AND', other) - - def __or__(self, other): - return Condition(self, 'OR', other) - class Undefined(Function): def __init__(self): @@ -587,15 +569,7 @@ def __init__(self): # ---------------------------------------------------------------------------- # -class State(Function): - def __init__(self, state_id): - self.function = { - 'direct': True, - 'value': state_id, - } - - -class EntityState(State): +class CurrentStateOfEntity(State): def __init__(self, entity): self.function = 'getEntityState' self.options = { @@ -681,7 +655,7 @@ def __init__(self, attribute, entity): } -class PlayerAttribute(Number): +class ValueOfPlayerAttribute(Number): def __init__(self, attribute, entity): self.function = 'getPlayerAttribute' self.options = { @@ -915,7 +889,7 @@ def __init__(self, number): } -class EntityAttribute(Number): +class ValueOfEntityAttribute(Number): def __init__(self, attribute, entity): self.function = 'getEntityAttribute' self.options = { @@ -955,7 +929,7 @@ def __init__(self, item_type, item_type_group): } -class NumberOfItemsPresent(Number): +class NumberOfItems(Number): def __init__(self): self.function = 'getNumberOfItemsPresent' self.options = {} @@ -1173,7 +1147,7 @@ def __init__(self, source_string, match_string, new_string): class UnixTimeToFormattedString(String): def __init__(self, seconds): - """formats to (hh::mm:ss)""" + '''formats to (hh::mm:ss)''' self.function = 'getTimeString' self.options = { 'seconds': to_dict(seconds), @@ -1452,39 +1426,15 @@ def __init__(self, particle_type, entity): # ---------------------------------------------------------------------------- # -class Variable(Function): - def __init__(self, variable_name, variable_type=None): - self.function = 'getVariable' - self.name = variable_name - self.type = variable_type - self.options = { - 'variableName': variable_name - } - - # ---------------------------------------------------------------------------- # # Entity Variables # # ---------------------------------------------------------------------------- # -class EntityVariable(Variable): - def __init__(self, variable_name, variable_type): - self.function = 'getEntityVariable' - self.type = variable_type - self.options = { - 'variable': { - 'text': f'{variable_name}', - 'dataType': f'{variable_type}', - 'entity': 'null', - 'key': f'{variable_name}' - } - } - - -class ValueOfEntityVariable(Variable): +class ValueOfEntityVariable(EntityVariable): def __init__(self, entity_variable_type, entity): self.function = 'getValueOfEntityVariable' - self.type = entity_variable_type.type + self.data_type = entity_variable_type.data_type self.options = { 'variable': to_dict(entity_variable_type), 'entity': to_dict(entity) @@ -1496,24 +1446,10 @@ def __init__(self, entity_variable_type, entity): # ---------------------------------------------------------------------------- # -class PlayerVariable(Variable): - def __init__(self, variable_name, variable_type): - self.function = 'getPlayerVariable' - self.type = variable_type - self.options = { - 'variable': { - 'text': f'{variable_name}', - 'dataType': f'{variable_type}', - 'entity': 'null', - 'key': f'{variable_name}' - } - } - - -class ValueOfPlayerVariable(Variable): +class ValueOfPlayerVariable(PlayerVariable): def __init__(self, player_variable_type, player): self.function = 'getValueOfPlayerVariable' - self.type = player_variable_type.type + self.data_type = player_variable_type.data_type self.options = { 'variable': to_dict(player_variable_type), 'player': to_dict(player) @@ -1571,14 +1507,6 @@ def __init__(self, x, y, width, height): # ---------------------------------------------------------------------------- # -class UnitType(Function): - def __init__(self, unit_type_id): - self.function = { - 'direct': True, - 'value': unit_type_id, - } - - class UnitTypeOfUnit(UnitType): def __init__(self, entity): self.function = 'getUnitTypeOfUnit' @@ -1612,14 +1540,6 @@ def __init__(self): # ---------------------------------------------------------------------------- # -class ItemType(Function): - def __init__(self, item_type_id): - self.function = { - 'direct': True, - 'value': item_type_id, - } - - class SelectedItemType(ItemType): def __init__(self): self.function = 'selectedItemType' @@ -1647,14 +1567,6 @@ def __init__(self, item_type_group): # ---------------------------------------------------------------------------- # -class ProjectileType(Function): - def __init__(self, projectile_type_id): - self.function = { - 'direct': True, - 'value': projectile_type_id, - } - - class ProjectileTypeOfProjectile(ProjectileType): def __init__(self, entity): self.function = 'getProjectileTypeOfProjectile' @@ -1668,14 +1580,6 @@ def __init__(self, entity): # ---------------------------------------------------------------------------- # -class PlayerType(Function): - def __init__(self, player_type_id): - self.function = { - 'direct': True, - 'value': player_type_id, - } - - class PlayerTypeOfPlayer(PlayerType): def __init__(self, player): self.function = 'playerTypeOfPlayer' @@ -1689,14 +1593,6 @@ def __init__(self, player): # ---------------------------------------------------------------------------- # -class AttributeType(Function): - def __init__(self, attribute_type_id): - self.function = { - 'direct': True, - 'value': attribute_type_id, - } - - class AttributeTypeOfAttribute(AttributeType): def __init__(self, entity): self.function = 'getAttributeTypeOfAttribute' @@ -1711,7 +1607,11 @@ def __init__(self, entity): class Group(Function): - pass + def _get_iterating_action(self): + raise NotImplementedError('_get_iteration_object not implemented') + + def _get_iteration_object(self): + raise NotImplementedError('_get_iteration_object not implemented') # ---------------------------------------------------------------------------- # @@ -1720,7 +1620,11 @@ class Group(Function): class EntityGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_entities_in + + def _get_iteration_object(self): + return SelectedEntity() class AllEntitiesCollidingWithLastRaycast(EntityGroup): @@ -1729,7 +1633,7 @@ def __init__(self): self.options = {} -class AllEntitesInTheGame(EntityGroup): +class AllEntitiesInTheGame(EntityGroup): def __init__(self): self.function = 'allEntities' self.options = {} @@ -1769,7 +1673,11 @@ def __init__(self, position_a, position_b): class UnitGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_units_in + + def _get_iteration_object(self): + return SelectedUnit() class AllUnitsOwnedByPlayer(UnitGroup): @@ -1824,7 +1732,11 @@ def __init__(self, region): class ProjectileGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_projectiles_in + + def _get_iteration_object(self): + return SelectedProjectile() class AllProjectilesAttachedToUnit(ProjectileGroup): @@ -1847,7 +1759,11 @@ def __init__(self): class ItemGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_items_in + + def _get_iteration_object(self): + return SelectedItem() class AllItemsDroppedOnGround(ItemGroup): @@ -1884,28 +1800,32 @@ def __init__(self, entity): class PlayerGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_players_in + + def _get_iteration_object(self): + return SelectedPlayer() -class AllHumanPlayers(PlayerGroup): +class AllHumanPlayersInTheGame(PlayerGroup): def __init__(self): self.function = 'humanPlayers' self.options = {} -class AllComputerPlayers(PlayerGroup): +class AllComputerPlayersInTheGame(PlayerGroup): def __init__(self): self.function = 'computerPlayers' self.options = {} -class AllPlayers(PlayerGroup): +class AllPlayersInTheGame(PlayerGroup): def __init__(self): self.function = 'allPlayers' self.options = {} -class AllBotPlayers(PlayerGroup): +class AllBotPlayersInTheGame(PlayerGroup): def __init__(self): self.function = 'botPlayers' self.options = {} @@ -1917,10 +1837,14 @@ def __init__(self): class ItemTypeGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_item_types_in + + def _get_iteration_object(self): + return SelectedItemType() -class AllItemTypesInGame(ItemTypeGroup): +class AllItemTypesInTheGame(ItemTypeGroup): def __init__(self): self.function = 'allItemTypesInGame' self.options = {} @@ -1932,10 +1856,14 @@ def __init__(self): class UnitTypeGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_unit_types_in + def _get_iteration_object(self): + return SelectedUnitType() -class AllUnitTypesInGame(UnitTypeGroup): + +class AllUnitTypesInTheGame(UnitTypeGroup): def __init__(self): self.function = 'allUnitTypesInGame' self.options = {} @@ -1947,10 +1875,14 @@ def __init__(self): class DebrisGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_debris_in + + def _get_iteration_object(self): + return SelectedDebris() -class AllDebris(DebrisGroup): +class AllDebrisInTheGame(DebrisGroup): def __init__(self): self.function = 'allDebris' self.options = {} @@ -1962,7 +1894,11 @@ def __init__(self): class RegionGroup(Group): - pass + def _get_iterating_action(self): + return pymodd.actions.for_all_regions_in + + def _get_iteration_object(self): + return SelectedRegion() class AllRegionsInTheGame(RegionGroup): @@ -1976,61 +1912,21 @@ def __init__(self): # ---------------------------------------------------------------------------- # -class Shop(Function): - def __init__(self, shop_id): - self.function = { - 'direct': True, - 'value': shop_id, - } - - # ---------------------------------------------------------------------------- # # Animations # # ---------------------------------------------------------------------------- # -class AnimationType(Function): - def __init__(self, animation_type_id): - self.function = { - 'direct': True, - 'value': animation_type_id, - } - - # ---------------------------------------------------------------------------- # # Music # # ---------------------------------------------------------------------------- # -class Music(Function): - def __init__(self, music_id): - self.function = { - 'direct': True, - 'value': music_id, - } - - # ---------------------------------------------------------------------------- # # Sounds # # ---------------------------------------------------------------------------- # -class Sound(Function): - def __init__(self, sound_id): - self.function = { - 'direct': True, - 'value': sound_id, - } - - # ---------------------------------------------------------------------------- # # Dialogues # # ---------------------------------------------------------------------------- # - - -class Dialogue(Function): - def __init__(self, dialogue_id): - self.function = { - 'direct': True, - 'value': dialogue_id, - } diff --git a/pymodd/script.py b/pymodd/script.py index 4d0fcb5..a8973dd 100644 --- a/pymodd/script.py +++ b/pymodd/script.py @@ -1,29 +1,68 @@ +import ast +import inspect import json import random import string +import textwrap +from _ast import AnnAssign, Assign, Delete from enum import Enum from caseconverter import camelcase, snakecase +import pymodd +from pymodd import _pymodd_helper + class Base(): def to_dict(self): - raise NotImplementedError("to_dict method not implemented") + raise NotImplementedError('to_dict method not implemented') class Game(Base): - def __init__(self, json_file): - with open(json_file, 'r') as file: + def __init__(self, json_file_path, game_variable_classes, project_globals_data): + self.project_globals_data = project_globals_data + with open(json_file_path, 'r') as file: data = json.load(file) self.name = data.get('title') self.data = data self.entity_scripts = [] self.scripts = [] + self._update_data_with_variable_classes(game_variable_classes) self._build() # set position of scripts inside game for i, script in enumerate(self.scripts): script.set_position(i, None) + def _update_data_with_variable_classes(self, variable_classes): + # pull variable objects out from each class and place them in categories + variable_category_to_variables = {} + for klass in variable_classes: + variable_category = variable_category_name_from_variable_class_name( + klass.__name__) + variable_category_to_variables.setdefault(variable_category, []) + class_vars = [item for item in vars(klass) + if not item.startswith('_') and not callable(item)] + for var in class_vars: + variable_category_to_variables[variable_category].append(getattr( + klass, var)) + + # update game data with modified variable objects + for variable_category, variables in variable_category_to_variables.items(): + if variable_category not in self.data['data'].keys(): + continue + category_data = self.data['data'][variable_category] + unincluded_category_variable_ids = list( + category_data.keys()) + for variable in variables: + category_contains_variable = variable.id in category_data.keys() + category_data[variable.id] = variable.updated_data_with_user_provided_values( + category_data[variable.id] if category_contains_variable else variable.get_template_data()) + if variable.id in unincluded_category_variable_ids: + unincluded_category_variable_ids.remove(variable.id) + # remove variables no longer included + for unincluded_variable_id in unincluded_category_variable_ids: + category_data.pop(unincluded_variable_id) + def _build(): pass @@ -31,17 +70,17 @@ def to_dict(self): # replace game scripts with scripts defined in self.scripts self.data['data']['scripts'] = self.flatten_scripts_data(self.scripts) for script in self.entity_scripts: - entity_type_category, entity_type_id = f'{camelcase(script.entity_type.__class__.__name__)}s', script.entity_type_id + entity_type_category, entity_type_id = f'{camelcase(script.entity_type.__class__.__name__)}s', script.entity_type.id self.data['data'][entity_type_category][entity_type_id]['scripts'] = self.flatten_scripts_data( script.scripts) return self.data def flatten_scripts_data(self, scripts): - """Takes all scripts out of folders, transforms them into json, and put them all into one dictionary with the rest of the game's scripts + '''Takes all scripts out of folders, transforms them into json, and put them all into one dictionary with the rest of the game's scripts Returns: dict: keys are the script's key, values are the script's data - """ + ''' flattened_scripts = {} scripts_queue = scripts.copy() while len(scripts_queue) > 0: @@ -49,17 +88,22 @@ def flatten_scripts_data(self, scripts): # add folder's scripts to the queue if isinstance(script, Folder): scripts_queue += script.scripts - script_data = script.to_dict() + script_data = script.to_dict(self.project_globals_data) flattened_scripts[script_data['key']] = script_data return flattened_scripts - def variables_from_class(self, variable_class): - variables = [] - for enum_name, variable in vars(variable_class).items(): - if enum_name.startswith('__'): - continue - variables.append(variable) - return variables + +def variable_category_name_from_variable_class_name(variable_class_name): + if variable_class_name == 'EntityVariables': + return 'entityTypeVariables' + elif variable_class_name == 'PlayerVariables': + return 'playerTypeVariables' + elif variable_class_name == 'Musics': + return 'music' + elif variable_class_name in ['Regions', 'ItemTypeGroups', 'UnitTypeGroups']: + return 'variables' + else: + return camelcase(variable_class_name) class EntityScripts(Game): @@ -70,10 +114,6 @@ def __init__(self): # set position of scripts inside entity_scripts for i, script in enumerate(self.scripts): script.set_position(i, None) - self.entity_type_id = self.get_entity_type_id() - - def get_entity_type_id(self): - return self.entity_type.function.get('value') def to_dict(self): self.flatten_scripts_data(self.scripts) @@ -126,16 +166,31 @@ def __init__(self): self.key = Script._class_to_key[self.__class__] self.triggers = [] self.actions = [] + self.build_func_source_code = None + self.build_func_source_starting_line_num = None + self.build_func_source_file = None def _build(self): pass - def to_dict(self): - self._build() + def to_dict(self, project_globals_data): + script_actions_compiler = ScriptActionsCompiler(project_globals_data) + actions_data = None + try: + actions_data = script_actions_compiler.compile_script(self) + except ScriptActionsCompileError as compile_error: + print() + _pymodd_helper.log_error('Compile error!\n') + print(f''' File "{self.build_func_source_file}", line {self.build_func_source_starting_line_num + compile_error.error_line_num - 1}''', + f' {compile_error.error_line_code}\n', + f'{type(compile_error.error).__name__}: {compile_error.error}\n', + sep='\n') + import sys + sys.exit(1) return { 'triggers': [{'type': trigger.value} for trigger in self.triggers], 'conditions': [{'operator': '==', 'operandType': 'boolean'}, True, True], - 'actions': self.actions, + 'actions': actions_data, 'name': self.name, 'parent': self.parent, 'key': self.key, @@ -144,11 +199,13 @@ def to_dict(self): def script(triggers=[], name=None): - """ + '''turn a class into a script + Args: triggers (list, optional): triggers for the script. Defaults to []. + name (str, optional): name to override the default name of the script. Defaults to the class name of the script. - """ + ''' def wrapper_script(cls): class NewScript(Script): def __init__(self): @@ -158,6 +215,10 @@ def __init__(self): self.name = name else: self.name = snakecase(cls.__name__).replace('_', ' ') + sourcelines = inspect.getsourcelines(cls._build) + self.build_func_source_code = ''.join(sourcelines[0]) + self.build_func_source_starting_line_num = sourcelines[1] + self.build_func_source_file = inspect.getsourcefile(cls._build) def _build(self): cls._build(self) @@ -166,6 +227,193 @@ def _build(self): return wrapper_script +class ScriptActionsCompileError(Exception): + '''Exception raised for errors while compiling script actions''' + + def __init__(self, error_line_num, error_line_code, error) -> None: + self.error_line_num = error_line_num + self.error_line_code = error_line_code + self.error = error + # handle recursive errors + if isinstance(error, ScriptActionsCompileError): + self.error_line_num = error.error_line_num + self.error_line_code = error.error_line_code + self.error = error.error + + +class ScriptActionsCompiler(ast.NodeVisitor): + def __init__(self, project_globals_data): + self.project_globals_data = project_globals_data + + def compile_script(self, script: Script): + self.depth = 0 + self.depth_to_locals_data = {0: {}} + self.actions_data = [] + tree = ast.parse(textwrap.dedent(script.build_func_source_code)) + self.visit(tree) + return self.actions_data + + def visit(self, node: ast.AST): + '''Visit a node.''' + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + + try: + if visitor == self.generic_visit or visitor in [self.visit_Assign, self.visit_AnnAssign, self.visit_Delete]: + return visitor(node) + + if visitor in [self.visit_If, self.visit_While, self.visit_For]: + self.depth += 1 + self.depth_to_locals_data[self.depth] = {} + action_data = visitor(node) + self.depth_to_locals_data.pop(self.depth) + self.depth -= 1 + else: + action_data = visitor(node) + if self.depth == 0: + self.actions_data.append(action_data) + return action_data + except Exception as error: + raise ScriptActionsCompileError( + node.lineno if 'lineno' in node._attributes else 1, + ast.unparse(node).splitlines()[0], + error + ) + + def visit_Expr(self, node: ast.Expr): + action = self.eval_node(node.value) + return action + + def visit_If(self, node: ast.If): + then_actions_data = self.parse_actions_of_node_body(node.body) + else_actions_data = self.parse_actions_of_node_body(node.orelse) + if_action_data = pymodd.actions.if_else( + self.eval_condition(node.test), then_actions_data, else_actions_data) + return if_action_data + + def visit_While(self, node: ast.While): + actions_data = self.parse_actions_of_node_body(node.body) + return pymodd.actions.while_do(self.eval_condition(node.test), actions_data) + + def visit_For(self, node: ast.For): + evaled_iter = self.eval_node(node.iter) + # repeat action + if isinstance((repeat_action_data := evaled_iter), dict) and repeat_action_data.get('type') == 'repeat': + repeat_action_data['actions'] = self.parse_actions_of_node_body( + node.body) + return repeat_action_data + # for _ in group_function action + elif isinstance((group_function := evaled_iter), pymodd.functions.Function): + if not isinstance(group_function, pymodd.functions.Group): + raise TypeError( + f"'{ast.unparse(node.iter)}' is not iterable" + ) + if isinstance(node.target, ast.Name): + self.add_local_var_to_curr_depth_locals_data( + node.target.id, group_function._get_iteration_object()) + action = group_function._get_iterating_action() + return action(group_function, self.parse_actions_of_node_body(node.body)) + # for _ in group_variable action + elif isinstance((variable := evaled_iter), pymodd.variable_types.Variable): + if variable.data_type not in [pymodd.variable_types.DataType.ITEM_GROUP, pymodd.variable_types.DataType.UNIT_GROUP, + pymodd.variable_types.DataType.PLAYER_GROUP, pymodd.variable_types.DataType.ITEM_TYPE_GROUP, + pymodd.variable_types.DataType.UNIT_TYPE_GROUP]: + raise TypeError( + f"DataType of '{ast.unparse(node.iter)}' must be DataType.ITEM_GROUP, UNIT_GROUP, PLAYER_GROUP, ITEM_TYPE_GROUP, or UNIT_TYPE_GROUP" + ) + if isinstance(node.target, ast.Name): + self.add_local_var_to_curr_depth_locals_data( + node.target.id, variable._get_iteration_object()) + action = variable._get_iterating_action() + return action(variable, self.parse_actions_of_node_body(node.body)) + # for loop action + elif isinstance((range_function := evaled_iter), range): + for_loop_var = self.eval_code(ast.unparse(node.target)) + if for_loop_var.data_type != pymodd.variable_types.DataType.NUMBER: + raise TypeError( + f"DataType of '{ast.unparse(node.iter)}' must be DataType.NUMBER" + ) + return pymodd.actions.for_range(for_loop_var, range_function.start, range_function.stop, self.parse_actions_of_node_body(node.body)) + + def visit_Break(self, node: ast.Break): + return pymodd.actions.break_loop() + + def visit_Continue(self, node: ast.Continue): + return pymodd.actions.continue_loop() + + def visit_Return(self, node: ast.Return): + return pymodd.actions.return_loop() + + def visit_Assign(self, node: Assign): + for target in node.targets: + if isinstance(target, ast.Name): + self.add_local_var_to_curr_depth_locals_data( + target.id, self.eval_node(node.value)) + elif isinstance(target, ast.Tuple): + for tuple_target in target.elts: + self.add_local_var_to_curr_depth_locals_data( + tuple_target.id, self.eval_node(node.value)) + + def visit_AnnAssign(self, node: AnnAssign): + if isinstance(node.target, ast.Name): + self.add_local_var_to_curr_depth_locals_data( + node.target.id, self.eval_node(node.value)) + + def visit_Delete(self, node: Delete): + for target in node.targets: + if isinstance(target, ast.Name): + self.depth_to_locals_data[self.depth].pop(target.id) + + def parse_actions_of_node_body(self, node_body): + actions_data = [] + for node in node_body: + action_data = self.visit(node) + if action_data is not None: + actions_data.append(action_data) + return actions_data + + def get_current_locals_data(self): + locals_data = {} + for value in self.depth_to_locals_data.values(): + locals_data.update(value) + return locals_data + + def add_local_var_to_curr_depth_locals_data(self, var_name, var_value): + self.depth_to_locals_data[self.depth][var_name] = var_value + + def eval_condition(self, condition_node: ast.AST): + if isinstance(condition_node, ast.BoolOp): + return pymodd.functions.Condition( + self.eval_condition(condition_node.values[0]), + 'AND' if isinstance(condition_node.op, ast.And) else 'OR', + self.eval_condition(condition_node.values[1])) + + if isinstance(condition_node, ast.Compare): + ast_operator_to_string = { + ast.Eq: '==', ast.NotEq: '!=', + ast.Gt: '>', ast.Lt: '<', + ast.GtE: '>=', ast.LtE: '<=' + } + if len(condition_node.ops) == 0 or (operator := ast_operator_to_string.get(type(condition_node.ops[0]))) is None: + raise ValueError( + f"Condition '{ast.unparse(condition_node)}' contains an invalid comparison operator" + ) + return pymodd.functions.Condition( + self.eval_node(condition_node.left), + operator, + self.eval_node(condition_node.comparators[0])) + + raise ValueError( + f"Condition '{ast.unparse(condition_node)}' must include a comparison operator" + ) + + def eval_node(self, node: ast.AST): + return self.eval_code(compile(ast.Expression(body=node), filename='', mode='eval')) + + def eval_code(self, code): + return eval(code, self.project_globals_data, self.get_current_locals_data()) + + def generate_random_key(): return ''.join(random.choices(string.ascii_letters + string.digits, k=10)) diff --git a/pymodd/variable_types.py b/pymodd/variable_types.py new file mode 100644 index 0000000..77ceec2 --- /dev/null +++ b/pymodd/variable_types.py @@ -0,0 +1,1119 @@ +from enum import Enum + +import pymodd + +from pymodd.script import generate_random_key +from pymodd.functions import Function + + +class VariableType(Function): + def __init__(self, id=None, **data_keys_to_new_values_kwargs): + self.id = generate_random_key() if id is None else id + self.data_keys_to_new_values = data_keys_to_new_values_kwargs.items() + self.function = { + 'direct': True, + 'value': self.id, + } + + def updated_data_with_user_provided_values(self, data): + for key, value in self.data_keys_to_new_values: + if key in data.keys(): + data[key] = value + return data + + def get_template_data(self) -> dict: + raise NotImplementedError('_get_template_data method not implemented') + + +class DataType(Enum): + NUMBER = 'number' + STRING = 'string' + BOOLEAN = 'boolean' + ITEM = 'item' + UNIT = 'unit' + PLAYER = 'player' + PROJECTILE = 'projectile' + ITEM_TYPE = 'itemType' + UNIT_TYPE = 'unitType' + PLAYER_TYPE = 'playerType' + PROJECTILE_TYPE = 'projectileType' + ITEM_GROUP = 'itemGroup' + UNIT_GROUP = 'unitGroup' + PLAYER_GROUP = 'playerGroup' + ITEM_TYPE_GROUP = 'itemTypeGroup' + UNIT_TYPE_GROUP = 'unitTypeGroup' + REGION = 'region' + + +class Variable(VariableType): + def __init__(self, variable_name, data_type: DataType, default_value=None): + super().__init__(variable_name) + self.data_type = data_type + self.default_value = default_value + self.function = 'getVariable' + self.options = { + 'variableName': variable_name, + } + + # group types take in a list of types as their default values + if data_type in [DataType.ITEM_TYPE_GROUP, DataType.UNIT_TYPE_GROUP] and type(default_value) is list: + # convert the list of types into modd.io data + self.default_value = {} + for type_ in default_value: + self.default_value[type_.id] = { + 'probability': 20, + 'quantity': 1 + } + # regions have additional parameters for their default value + if data_type == DataType.REGION: + self.default_value = { + 'x': 0, + 'y': 0, + 'width': 100, + 'height': 100, + 'inside': '#FFFFFF', + 'outside': '', + 'alpha': 100, + 'videoChatEnabled': False + } + + def get_template_data(self): + return { + 'dataType': f'{self.data_type.value}', + 'default': self.default_value if self.default_value is not None else None + } + + def _get_iterating_action(self): + '''For group data types only. Used during script compilation''' + if self.data_type == DataType.ITEM_GROUP: + return pymodd.functions.ItemGroup()._get_iterating_action() + elif self.data_type == DataType.UNIT_GROUP: + return pymodd.functions.UnitGroup()._get_iterating_action() + elif self.data_type == DataType.PLAYER_GROUP: + return pymodd.functions.PlayerGroup()._get_iterating_action() + elif self.data_type == DataType.ITEM_TYPE_GROUP: + return pymodd.functions.ItemTypeGroup()._get_iterating_action() + elif self.data_type == DataType.UNIT_TYPE_GROUP: + return pymodd.functions.UnitTypeGroup()._get_iterating_action() + return None + + def _get_iteration_object(self): + '''For group data types only. Used during script compilation''' + if self.data_type == DataType.ITEM_GROUP: + return pymodd.functions.ItemGroup()._get_iteration_object() + elif self.data_type == DataType.UNIT_GROUP: + return pymodd.functions.UnitGroup()._get_iteration_object() + elif self.data_type == DataType.PLAYER_GROUP: + return pymodd.functions.PlayerGroup()._get_iteration_object() + elif self.data_type == DataType.ITEM_TYPE_GROUP: + return pymodd.functions.ItemTypeGroup()._get_iteration_object() + elif self.data_type == DataType.UNIT_TYPE_GROUP: + return pymodd.functions.UnitTypeGroup()._get_iteration_object() + return None + + +class EntityVariable(Variable): + def __init__(self, variable_name, data_type): + super().__init__(variable_name, data_type) + self.function = 'getEntityVariable' + self.options = { + 'variable': { + 'text': f'{variable_name}', + 'dataType': f'{data_type.value}', + 'entity': 'null', + 'key': f'{variable_name}' + } + } + + +class PlayerVariable(Variable): + def __init__(self, variable_name, data_type): + super().__init__(variable_name, data_type) + self.function = 'getPlayerVariable' + self.options = { + 'variable': { + 'text': f'{variable_name}', + 'dataType': f'{data_type.value}', + 'entity': 'null', + 'key': f'{variable_name}' + } + } + + +class UnitType(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'backpackSize': 0, + 'defaultItem': [], + 'controls': { + 'permittedInventorySlots': [], + 'movementMethod': 'velocity', + 'movementControlScheme': 'wasd', + 'abilities': { + 'movementWheel': { + 'mobilePosition': { + 'y': 204, + 'x': 35 + } + }, + 'lookWheel': { + 'mobilePosition': { + 'y': 204, + 'x': 407 + } + }, + 'e': { + 'keyUp': { + 'scriptName': '', + 'cost': {} + }, + 'keyDown': { + 'scriptName': 'w2VrnZHyom', + 'cost': {}, + 'isEntityScript': True + } + }, + 'g': { + 'keyUp': { + 'scriptName': '', + 'cost': {} + }, + 'keyDown': { + 'scriptName': 'yP67J1MMRN', + 'cost': {}, + 'isEntityScript': True + } + }, + 'button1': { + 'keyUp': { + 'scriptName': 'DOrbWp0AGz', + 'cost': {}, + 'isEntityScript': True + }, + 'keyDown': { + 'scriptName': 'YFeMQ20gBX', + 'cost': {}, + 'isEntityScript': True + } + } + }, + 'mouseBehaviour': { + 'flipSpriteHorizontallyWRTMouse': False, + 'rotateToFaceMouseCursor': True + }, + 'movementType': 'wasd', + 'absoluteRotation': False + }, + 'inventoryImage': '', + 'animations': { + 'default': { + 'name': 'default', + 'frames': [ + 1 + ], + 'loopCount': 0, + 'framesPerSecond': 0 + } + }, + 'canBePurchasedBy': [], + 'isPurchasable': False, + 'states': { + 'default': { + 'name': 'default', + 'sound': {}, + 'particles': {}, + 'animation': 'default', + 'body': 'default' + } + }, + 'sound': { + 'KK9JlU1UQy': { + 'name': 'Cough', + 'file': 'https://modd.s3.amazonaws.com/asset/sound/1517554516253_man_cough.mp3' + }, + 'fEhDyJ8knx': { + 'name': 'Scream', + 'file': 'https://modd.s3.amazonaws.com/asset/sound/1517556903046_man_scream1.mp3' + } + }, + 'particles': {}, + 'body': { + 'spriteScale': 1, + 'fixtures': [ + { + 'shape': { + 'type': 'rectangle' + }, + 'restitution': 0.01, + 'friction': 0.01, + 'density': 3 + } + ], + 'isFlying': False, + 'fixedRotation': False, + 'constantSpeed +DestroyedOnCollisionWithWall/unit': False, + 'allowSleep': True, + 'angularDamping': 1, + 'linearDamping': 5, + 'rotationSpeed': 2, + 'type': 'dynamic', + 'height': 40, + 'width': 40, + 'collidesWith': { + 'units': True, + 'items': True, + 'projectiles': True, + 'walls': True, + 'unit': True, + 'item': True, + 'debris': True + }, + 'z-index': { + 'layer': 3, + 'depth': 3 + }, + 'name': 'Human-body' + }, + 'spawnPosition': { + 'y': 2200, + 'x': 1500 + }, + 'attributes': { + 'speed': { + 'decimalPlaces': 0, + 'dataType': '', + 'name': 'speed', + 'min': 0, + 'max': 200, + 'value': 10, + 'regenerateSpeed': 0, + 'isVisible': [], + 'showAsHUD': True, + 'color': '#00fff0', + 'displayValue': True + }, + 'health': { + 'decimalPlaces': 0, + 'color': '#ffff0f', + 'showAsHUD': True, + 'displayValue': True, + 'isVisible': [ + 'centerBar' + ], + 'regenerateSpeed': 0, + 'value': 100, + 'dataType': '', + 'max': 100, + 'min': 0, + 'name': 'health ' + } + }, + 'abilities': { + 'movementWheel': { + 'mobilePosition': { + 'y': 204, + 'x': 35 + } + }, + 'lookWheel': { + 'mobilePosition': { + 'y': 204, + 'x': 407 + } + }, + 'w': { + 'keyUp': 'stopMovingUp', + 'keyDown': 'moveUp' + }, + 'a': { + 'keyUp': 'stopMovingLeft', + 'keyDown': 'moveLeft' + }, + 's': { + 'keyUp': 'stopMovingDown', + 'keyDown': 'moveDown' + }, + 'd': { + 'keyUp': 'stopMovingRight', + 'keyDown': 'moveRight' + }, + 'button1': { + 'keyUp': 'stopUsingItem', + 'keyDown': 'startUsingItem', + 'mobilePosition': { + 'x': 326, + 'y': 132 + } + }, + 'up': { + 'keyUp': 'stopMovingUp', + 'keyDown': 'moveUp' + }, + 'down': { + 'keyUp': 'stopMovingDown', + 'keyDown': 'moveDown' + }, + 'left': { + 'keyUp': 'stopMovingLeft', + 'keyDown': 'moveLeft' + }, + 'right': { + 'keyUp': 'stopMovingRight', + 'keyDown': 'moveRight' + }, + 'e': { + 'keyUp': '', + 'keyDown': 'pickUp', + 'mobilePosition': { + 'x': 366, + 'y': 85 + } + }, + 'f': { + 'keyUp': '', + 'keyDown': 'pickUp' + }, + 'g': { + 'keyUp': '', + 'keyDown': 'drop', + 'mobilePosition': { + 'x': 365, + 'y': 33 + } + }, + 'b': { + 'keyUp': '', + 'keyDown': 'shop', + 'mobilePosition': { + 'x': 419, + 'y': 32 + } + } + }, + 'baseSpeed': 53, + 'price': {}, + 'skin': 'https://s3-us-west-1.amazonaws.com/modd/halloween-0.18/spritesheet/man.png', + 'canBuyItem': True, + 'handle': 'human', + 'name': 'New Unit Type', + 'inventorySize': 5, + 'cellSheet': { + 'url': 'https://cache.modd.io/asset/spriteImage/1588303353803_Human Circle Person.png', + 'rowCount': 1, + 'columnCount': 1 + }, + 'bodies': { + 'default': { + 'bullet': False, + 'name': 'default', + 'type': 'dynamic', + 'width': 54, + 'height': 54, + 'z-index': { + 'layer': 3, + 'depth': 3 + }, + 'fixedRotation': False, + 'constantSpeed +DestroyedOnCollisionWithWall/unit': False, + 'allowSleep': True, + 'collidesWith': { + 'units': True, + 'items': True, + 'projectiles': True, + 'walls': True, + 'debris': True + }, + 'angularDamping': 1, + 'linearDamping': 8, + 'rotationSpeed': 1, + 'spriteScale': 1, + 'fixtures': [ + { + 'density': 1, + 'friction': 0, + 'restitution': 0, + 'shape': { + 'type': 'rectangle' + }, + 'isSensor': False + } + ], + 'jointType': 'weldJoint', + 'unitAnchor': { + 'x': 0, + 'y': 33, + 'rotation': 0 + }, + 'itemAnchor': { + 'x': 0, + 'y': 0, + 'lowerAngle': 0, + 'upperAngle': 0 + } + } + }, + 'variables': {}, + 'effects': { + 'attacked': { + 'projectileType': '', + 'sound': {}, + 'animation': '', + 'tween': '' + }, + 'create': { + 'projectileType': '', + 'sound': {}, + 'animation': '' + }, + 'destroy': { + 'projectileType': '', + 'sound': {}, + 'animation': '' + } + }, + 'confinedWithinMapBoundaries': True, + 'ai': { + 'pathFindingMethod': 'simple', + 'idleBehaviour': 'stay', + 'sensorResponse': 'none', + 'attackResponse': 'none', + 'maxTravelDistance': 300, + 'sensorRadius': 150, + 'maxAttackRange': 400 + }, + 'defaultItems': [], + 'scripts': { + 'YnK58YN6ZD': { + 'key': 'YnK58YN6ZD', + 'folderName': 'abilities', + 'parent': None, + 'order': -1, + 'expanded': True + }, + 'DOrbWp0AGz': { + 'triggers': [], + 'conditions': [ + { + 'operator': '==', + 'operandType': 'boolean' + }, + True, + True + ], + 'actions': [ + { + 'type': 'stopUsingItem', + 'entity': { + 'function': 'getItemCurrentlyHeldByUnit', + 'entity': { + 'function': 'thisEntity' + } + }, + 'hasFixedCSP': None, + 'runOnClient': True + } + ], + 'name': 'stop using item', + 'parent': 'YnK58YN6ZD', + 'key': 'DOrbWp0AGz', + 'order': 1 + }, + 'YFeMQ20gBX': { + 'triggers': [], + 'conditions': [ + { + 'operator': '==', + 'operandType': 'boolean' + }, + True, + True + ], + 'actions': [ + { + 'type': 'startUsingItem', + 'entity': { + 'function': 'getItemCurrentlyHeldByUnit', + 'entity': { + 'function': 'thisEntity' + } + }, + 'hasFixedCSP': None, + 'runOnClient': True + } + ], + 'name': 'start using item', + 'parent': 'YnK58YN6ZD', + 'key': 'YFeMQ20gBX', + 'order': 0 + }, + 'w2VrnZHyom': { + 'triggers': [], + 'conditions': [ + { + 'operator': '==', + 'operandType': 'boolean' + }, + True, + True + ], + 'actions': [ + { + 'type': 'forAllEntities', + 'entityGroup': { + 'function': 'entitiesInRegion', + 'region': { + 'function': 'entityBounds', + 'entity': { + 'function': 'thisEntity' + } + } + }, + 'actions': [ + { + 'type': 'condition', + 'conditions': [ + { + 'operandType': 'string', + 'operator': '==' + }, + { + 'function': 'getEntityType', + 'entity': { + 'function': 'getSelectedEntity' + } + }, + 'item' + ], + 'then': [ + { + 'type': 'makeUnitPickupItem', + 'unit': { + 'function': 'thisEntity' + }, + 'item': { + 'function': 'getSelectedEntity' + } + } + ], + 'else': [] + } + ] + } + ], + 'name': 'pick up item', + 'parent': 'YnK58YN6ZD', + 'key': 'w2VrnZHyom', + 'order': 2 + }, + 'yP67J1MMRN': { + 'triggers': [], + 'conditions': [ + { + 'operator': '==', + 'operandType': 'boolean' + }, + True, + True + ], + 'actions': [ + { + 'type': 'dropItemAtPosition', + 'item': { + 'function': 'getItemCurrentlyHeldByUnit', + 'entity': { + 'function': 'thisEntity' + } + }, + 'position': { + 'function': 'getEntityPosition', + 'entity': { + 'function': 'thisEntity' + } + } + } + ], + 'name': 'drop item', + 'parent': 'YnK58YN6ZD', + 'key': 'yP67J1MMRN', + 'order': 3 + } + } + } + + +class ItemType(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'delayBeforeUse': 0, + 'bulletStartPosition': { + 'rotation': 0, + 'y': 0, + 'x': 0 + }, + 'frames': {}, + 'name': 'New Item Type', + 'handle': '', + 'attributes': {}, + 'variables': {}, + 'cellSheet': { + 'columnCount': 1, + 'rowCount': 1, + 'url': 'https://cache.modd.io/asset/spriteImage/1588259311826_Small Stick Tree Branch.png' + }, + 'inventoryImage': 'https://cache.modd.io/asset/spriteImage/1588879714036_test.png', + 'isStackable': False, + 'isPurchasable': True, + 'canBePurchasedBy': [], + 'isGun': False, + 'bulletDestroyedOnCollisionWithWall/unitType': 'raycast', + 'type': 'weapon', + 'hits': [], + 'states': { + 'selected': { + 'name': 'selected', + 'animation': 'default', + 'body': 'selected', + 'particles': {}, + 'sound': {} + }, + 'unselected': { + 'name': 'unselected', + 'animation': 'none', + 'body': 'none', + 'particles': {}, + 'sound': {} + }, + 'dropped': { + 'name': 'dropped', + 'animation': 'dropped', + 'body': 'dropped', + 'particles': {}, + 'sound': {} + } + }, + 'animations': { + 'default': { + 'framesPerSecond': 0, + 'loopCount': 0, + 'frames': [ + 1 + ], + 'name': 'default' + } + }, + 'bodies': { + 'selected': { + 'name': 'selected', + 'type': 'spriteOnly', + 'width': 12, + 'height': 27, + 'z-index': { + 'layer': 3, + 'depth': 4 + }, + 'fixedRotation': False, + 'constantSpeed +DestroyedOnCollisionWithWall/unit': False, + 'allowSleep': True, + 'collidesWith': { + 'units': True, + 'items': True, + 'projectiles': True, + 'walls': True, + 'debris': False + }, + 'angularDamping': 1, + 'linearDamping': 5, + 'rotationSpeed': 3, + 'spriteScale': 1, + 'fixtures': [ + { + 'density': 1, + 'friction': 0.01, + 'restitution': 0.01, + 'shape': { + 'type': 'rectangle' + }, + 'isSensor': False + } + ], + 'jointType': 'weldJoint', + 'unitAnchor': { + 'x': 0, + 'y': 30 + }, + 'itemAnchor': { + 'x': 0, + 'y': 58 + } + }, + 'dropped': { + 'name': 'dropped', + 'type': 'dynamic', + 'width': 12, + 'height': 27, + 'z-index': { + 'layer': 1, + 'depth': 2 + }, + 'fixedRotation': False, + 'constantSpeed +DestroyedOnCollisionWithWall/unit': False, + 'allowSleep': True, + 'collidesWith': { + 'units': False, + 'items': False, + 'projectiles': False, + 'walls': True, + 'debris': False + }, + 'angularDamping': 1, + 'linearDamping': 1, + 'rotationSpeed': 1, + 'spriteScale': 1, + 'fixtures': [ + { + 'density': 1, + 'friction': 0, + 'restitution': 0, + 'shape': { + 'type': 'rectangle' + }, + 'isSensor': False + } + ], + 'jointType': 'weldJoint', + 'unitAnchor': { + 'x': 0, + 'y': 48 + }, + 'itemAnchor': { + 'x': 0, + 'y': 58 + }, + 'bullet': False + } + }, + 'hideIfUnaffordable': False, + 'projectileType': '', + 'quantity': None, + 'maxQuantity': None, + 'description': None, + 'reloadRate': 2800, + 'recoilForce': 0, + 'fireRate': 500, + 'bulletDestroyedOnCollisionWithWall/unitForce': 14, + 'knockbackForce': 0, + 'effects': { + 'reload': { + 'animation': '', + 'sound': {} + }, + 'empty': { + 'animation': '', + 'sound': {} + }, + 'destroy': { + 'runScript': '', + 'animation': '', + 'sound': {}, + 'projectileType': '' + }, + 'create': { + 'runScript': '', + 'animation': '', + 'sound': {}, + 'projectileType': '' + }, + 'use': { + 'runScript': '', + 'tween': 'none', + 'animation': 'use', + 'sound': {}, + 'projectileType': '' + } + }, + 'bulletDestroyedOnCollisionWithWall/unitStartPosition': { + 'x': 0, + 'y': 0, + 'rotation': 0 + }, + 'bulletDestroyedOnCollisionWithWall/unitDistance': 1300, + 'penetration': False, + 'destroyTimer': 30000, + 'particles': {}, + 'damage': { + 'unitAttributes': { + 'health': 10 + } + }, + 'sound': {}, + 'canBeUsedBy': [], + 'isUsedOnPickup': False, + 'removeWhenEmpty': False, + 'bonus': { + 'consume': { + 'playerAttribute': {}, + 'unitAttribute': {} + }, + 'passive': { + 'playerAttribute': {}, + 'unitAttribute': {} + } + }, + 'cost': { + 'quantity': 0 + }, + 'buffTypes': [], + 'carriedBy': [], + 'controls': { + 'undroppable': False, + 'permittedInventorySlots': [], + 'mouseBehaviour': { + 'rotateToFaceMouseCursor': True, + 'flipSpriteHorizontallyWRTMouse': False + } + }, + 'damageHitBox': { + 'width': 60, + 'height': 30, + 'offsetX': 0, + 'offsetY': 50 + }, + 'damageDelay': 0, + 'projectileStreamMode': '0', + 'lifeSpan': None, + 'ignoreServerStream': False, + 'confinedWithinMapBoundaries': True, + 'scripts': {} + } + + +class ProjectileType(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'inventoryImage': '', + 'name': 'New Projectile Type', + 'attributes': {}, + 'variables': {}, + 'states': { + 'zTzPFYOZkc': { + 'name': 'default', + 'sound': {}, + 'particles': {}, + 'animation': 'default', + 'body': 'default' + } + }, + 'animations': { + 'default': { + 'framesPerSecond': 0, + 'loopCount': 0, + 'frames': [ + 1 + ], + 'name': 'default' + } + }, + 'bodies': { + 'default': { + 'bullet': True, + 'name': 'default', + 'type': 'dynamic', + 'width': 10, + 'height': 32, + 'z-index': { + 'layer': 3, + 'depth': 1 + }, + 'fixedRotation': False, + 'constantSpeed +DestroyedOnCollisionWithWall/unit': True, + 'allowSleep': False, + 'collidesWith': { + 'units': True, + 'items': True, + 'projectiles': False, + 'walls': True, + 'debris': False + }, + 'angularDamping': 1, + 'linearDamping': 0, + 'rotationSpeed': 1, + 'spriteScale': 1, + 'fixtures': [ + { + 'density': 1, + 'friction': 0.01, + 'restitution': 0.01, + 'shape': { + 'type': 'rectangle' + }, + 'isSensor': True + } + ], + 'jointType': 'weldJoint', + 'unitAnchor': { + 'x': 0, + 'y': 33, + 'rotation': 0 + }, + 'itemAnchor': { + 'x': 0, + 'y': 0, + 'lowerAngle': 0, + 'upperAngle': 0 + } + } + }, + 'destroyTimer': 1500, + 'cellSheet': { + 'url': 'https://cache.modd.io/asset/spriteImage/1588265261495_Long Yellow Bullet.png', + 'rowCount': 1, + 'columnCount': 1 + }, + 'lifeSpan': 1500, + 'effects': { + 'create': { + 'projectileType': '', + 'sound': {}, + 'animation': '', + 'runScript': '' + }, + 'destroy': { + 'projectileType': '', + 'sound': {}, + 'animation': '', + 'runScript': '' + } + }, + 'destroyOnContactWith': { + 'units': True, + 'items': True, + 'projectiles': True, + 'walls': True, + 'debris': True + } + } + + +class PlayerType(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'name': 'New Player Type', + 'attributes': {}, + 'color': 'white', + 'relationships': {}, + 'showNameLabel': True + } + + +class AttributeType(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'color': 'white', + 'dataType': '', + 'decimalPlaces': 0, + 'displayValue': False, + 'isVisible': False, + 'max': 100, + 'min': 0, + 'name': 'New Attribute Type', + 'regenerateSpeed': 0, + 'showAsHUD': True, + 'showWhen': '', + 'value': 0 + } + + +class AnimationType(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'frames': [ + 1 + ], + 'framesPerSecond': 0, + 'loopCount': 0, + 'name': 'New Animation Type' + } + + +class State(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'animation': 'default', + 'body': 'default', + 'name': 'New State', + 'particles': {}, + 'sound': {} + } + + +class Shop(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'dismissible': True, + 'itemTypes': {}, + 'name': 'New Shop', + 'unitTypes': {} + } + + +class Music(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'file': '', + 'name': 'New Song', + 'volume': 25 + } + + +class Sound(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'name': 'New Sound', + 'file': '', + 'volume': 100 + } + + +class Dialogue(VariableType): + def __init__(self, id=None, name=None): + super().__init__(id, name=name) + + def get_template_data(self): + return { + 'name': 'New Dialogue', + 'dialogueTitle': 'New Dialogue', + 'message': '', + 'image': '', + 'letterPrintSpeed': 20, + 'options': [] + } diff --git a/src/game_data/variable_categories.rs b/src/game_data/variable_categories.rs index ac0d211..105e1a5 100644 --- a/src/game_data/variable_categories.rs +++ b/src/game_data/variable_categories.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use heck::ToPascalCase; use serde_json::{Map, Value}; use crate::project_generator::utils::enum_name_of; @@ -27,25 +26,33 @@ pub const SEPERATED_VARIABLE_CATEGORIES: [&str; 3] = ["regions", "itemTypeGroups", "unitTypeGroups"]; const VARIABLE_CATEGORIES_ITERATION_ORDER: [&str; 17] = [ - "unitTypes", - "playerTypes", "itemTypes", "projectileTypes", - "regions", + "unitTypes", + "playerTypes", + "itemTypeGroups", + "unitTypeGroups", "variables", "entityTypeVariables", "playerTypeVariables", - "animationTypes", - "attributeTypes", - "itemTypeGroups", - "unitTypeGroups", - "states", + "regions", "shops", "dialogues", "music", "sound", + "states", + "animationTypes", + "attributeTypes", ]; +#[derive(Debug, PartialEq, Eq)] +pub struct Variable { + pub id: String, + pub name: String, + pub enum_name: String, + pub data_type: Option, +} + pub struct CategoriesToVariables { pub categories_to_variables: HashMap<&'static str, Vec>, } @@ -110,16 +117,18 @@ fn variables_from_category_data(category_data: &Value) -> Vec { .as_object() .unwrap_or(&Map::new()) .iter() - .map(|(var_id, var)| Variable { - id: var_id.clone(), - enum_name: enum_name_of( - var.get("name") - .unwrap_or(&Value::String(var_id.clone())) - .as_str() - .unwrap(), - ) - .to_string(), - data_type: parse_data_type(var.get("dataType")), + .map(|(var_id, var)| { + let var_name = var + .get("name") + .unwrap_or(&Value::Null) + .as_str() + .unwrap_or(var_id); + Variable { + id: var_id.clone(), + name: var_name.to_string(), + enum_name: enum_name_of(var_name).to_string(), + data_type: parse_data_type(var.get("dataType")), + } }) .collect() } @@ -183,43 +192,6 @@ fn seperated_variables_categories( seperated_category_to_variables } -pub fn pymodd_class_name_of_category(category: &'static str) -> String { - let mut class_name = match category { - "entityTypeVariables" => "EntityVariables", - "playerTypeVariables" => "PlayerVariables", - _ => category, - } - .to_pascal_case() - .to_string(); - if !class_name.ends_with("s") { - class_name.push('s') - } - class_name -} - -pub fn pymodd_class_type_of_category(category: &'static str) -> String { - // in order to match with classes defined in pymodd/functions.py - if VARIABLES_CATEGORY_NAME == category || SEPERATED_VARIABLE_CATEGORIES.contains(&category) { - return String::from("Variable"); - } - pymodd_class_name_of_category(&category) - .strip_suffix('s') - .unwrap() - .to_string() -} - -pub fn is_category_of_variable_type(category: &'static str) -> bool { - category.to_lowercase().contains("variables") - || SEPERATED_VARIABLE_CATEGORIES.contains(&category) -} - -#[derive(Debug, PartialEq, Eq)] -pub struct Variable { - pub id: String, - pub enum_name: String, - pub data_type: Option, -} - #[cfg(test)] mod tests { use std::collections::HashMap; @@ -234,9 +206,10 @@ mod tests { }; impl Variable { - pub fn new(id: &str, enum_name: &str, data_type: Option<&str>) -> Variable { + pub fn new(id: &str, name: &str, enum_name: &str, data_type: Option<&str>) -> Variable { Variable { id: id.to_string(), + name: name.to_string(), enum_name: enum_name.to_string(), data_type: data_type.map(|val| val.to_string()), } @@ -257,11 +230,16 @@ mod tests { CategoriesToVariables::new(HashMap::from([ ( "unitTypeGroups", - vec![Variable::new("O23FJW2", "BANANA", Some("unitTypeGroup"))] + vec![Variable::new( + "O23FJW2", + "banana", + "BANANA", + Some("unitTypeGroup") + )] ), ( "regions", - vec![Variable::new("WDWI313", "WATER", Some("region"))] + vec![Variable::new("WDWI313", "water", "WATER", Some("region"))] ), ("variables", vec![]), ])) @@ -269,7 +247,7 @@ mod tests { .unwrap(), ( "regions", - &Variable::new("WDWI313", "WATER", Some("region")) + &Variable::new("WDWI313", "water", "WATER", Some("region")) ) ); } @@ -284,9 +262,9 @@ mod tests { })) .as_slice(), [ - Variable::new("FW3513W", "APPLE", None), - Variable::new("O23FJW2", "BANANA", None), - Variable::new("WDWI313", "WATER", Some("region")), + Variable::new("FW3513W", "apple", "APPLE", None), + Variable::new("O23FJW2", "banana", "BANANA", None), + Variable::new("WDWI313", "water", "WATER", Some("region")), ] ); } @@ -295,15 +273,15 @@ mod tests { fn ensure_no_duplicated_enum_names() { assert_eq!( resolve_duplicate_variable_enum_names(vec![ - Variable::new("FW3513W", "APPLE", None), - Variable::new("O23FJW2", "APPLE", None), - Variable::new("WDWI313", "APPLE", None), + Variable::new("FW3513W", "apple", "APPLE", None), + Variable::new("O23FJW2", "apple", "APPLE", None), + Variable::new("WDWI313", "apple", "APPLE", None), ]) .as_slice(), [ - Variable::new("FW3513W", "APPLE", None), - Variable::new("O23FJW2", "APPLE_1", None), - Variable::new("WDWI313", "APPLE_2", None), + Variable::new("FW3513W", "apple", "APPLE", None), + Variable::new("O23FJW2", "apple", "APPLE_1", None), + Variable::new("WDWI313", "apple", "APPLE_2", None), ] ); } @@ -319,15 +297,25 @@ mod tests { HashMap::from([ ( "itemTypeGroups", - vec![Variable::new("FW3513W", "APPLE", Some("itemTypeGroup"))] + vec![Variable::new( + "FW3513W", + "apple", + "APPLE", + Some("itemTypeGroup") + )] ), ( "unitTypeGroups", - vec![Variable::new("O23FJW2", "BANANA", Some("unitTypeGroup"))] + vec![Variable::new( + "O23FJW2", + "banana", + "BANANA", + Some("unitTypeGroup") + )] ), ( "regions", - vec![Variable::new("WDWI313", "WATER", Some("region"))] + vec![Variable::new("WDWI313", "water", "WATER", Some("region"))] ), ("variables", vec![]), ]) diff --git a/src/project_generator/entity_scripts_file.rs b/src/project_generator/entity_scripts_file.rs index 1f9ec73..7b7def0 100644 --- a/src/project_generator/entity_scripts_file.rs +++ b/src/project_generator/entity_scripts_file.rs @@ -1,5 +1,6 @@ -use crate::game_data::{ - entity_types::EntityType, variable_categories::pymodd_class_name_of_category, GameData, +use crate::{ + game_data::{entity_types::EntityType, GameData}, + project_generator::game_variables_file::pymodd_class_name_of_category, }; use super::{ diff --git a/src/project_generator/game_variables_file.rs b/src/project_generator/game_variables_file.rs index 8418dd9..0926a05 100644 --- a/src/project_generator/game_variables_file.rs +++ b/src/project_generator/game_variables_file.rs @@ -1,36 +1,36 @@ use std::ops::Add; -use crate::game_data::{ - variable_categories::{ - is_category_of_variable_type, pymodd_class_name_of_category, pymodd_class_type_of_category, - Variable, - }, - GameData, +use heck::ToPascalCase; + +use crate::{ + game_data::{variable_categories::Variable, GameData}, + project_generator::utils::surround_string_with_quotes, }; +use super::utils::to_pymodd_maps::VARIABLE_DATA_TYPES_TO_PYMODD_ENUM; + pub struct GameVariablesFile {} impl GameVariablesFile { pub fn build_content(game_data: &GameData) -> String { - let mut importing_classes: Vec = Vec::new(); let mut file_content = String::new(); game_data .categories_to_variables .iter() .for_each(|(category, variables)| { - let importing_class_for_category = pymodd_class_type_of_category(&category); - if variables.len() > 0 && !importing_classes.contains(&importing_class_for_category) - { - importing_classes.push(importing_class_for_category); - } file_content.push_str( &build_class_content_of_category(&category, &variables).add("\n\n\n"), ); }); + let classes_to_import = game_data + .categories_to_variables + .iter() + .map(|(category, _variables)| pymodd_class_type_of_category(&category)) + .collect::>(); format!( - "from pymodd.functions import {}\n\n\n{}", - importing_classes.join(", "), + "from pymodd.variable_types import {}, DataType\n\n\n{}", + classes_to_import.join(", "), file_content, ) } @@ -58,17 +58,19 @@ fn build_class_variables_of_category( .iter() .map(|variable| { format!( - "{} = {}(\"{}\"{})", + "{} = {}({}{})", variable.enum_name, pymodd_class_type_of_category(&category), - variable.id, - if is_category_of_variable_type(&category) { + surround_string_with_quotes(&variable.id), + if variable_category_requires_data_type(&category) { format!( - ", variable_type='{}'", - variable.data_type.as_ref().unwrap_or(&String::from("None")) + ", {}", + VARIABLE_DATA_TYPES_TO_PYMODD_ENUM + .get(variable.data_type.as_ref().unwrap_or(&String::new())) + .unwrap_or(&String::from("None")) ) } else { - String::new() + format!(", name={}", surround_string_with_quotes(&variable.name)) } ) .to_string() @@ -76,6 +78,42 @@ fn build_class_variables_of_category( .collect() } +pub fn pymodd_class_name_of_category(category: &'static str) -> String { + let mut class_name = match category { + "entityTypeVariables" => "EntityVariables", + "playerTypeVariables" => "PlayerVariables", + _ => category, + } + .to_pascal_case() + .to_string(); + if !class_name.ends_with("s") { + class_name.push('s') + } + class_name +} + +fn pymodd_class_type_of_category(category: &'static str) -> String { + match category { + "itemTypeGroups" | "unitTypeGroups" | "regions" => String::from("Variable"), + _ => pymodd_class_name_of_category(&category) + .strip_suffix('s') + .unwrap() + .to_string(), + } +} + +fn variable_category_requires_data_type(category: &'static str) -> bool { + [ + "variables", + "entityTypeVariables", + "playerTypeVariables", + "itemTypeGroups", + "unitTypeGroups", + "regions", + ] + .contains(&category) +} + #[cfg(test)] mod tests { use crate::{ @@ -89,14 +127,14 @@ mod tests { build_class_content_of_category( "itemTypes", &vec![ - Variable::new("FW3513W", "APPLE", None), - Variable::new("OE51DW2", "BANANA", None) + Variable::new("FW3513W", "apple", "APPLE", None), + Variable::new("OE51DW2", "banana", "BANANA", None) ], ), String::from( "class ItemTypes:\ - \n\tAPPLE = ItemType(\"FW3513W\")\ - \n\tBANANA = ItemType(\"OE51DW2\")" + \n\tAPPLE = ItemType('FW3513W', name='apple')\ + \n\tBANANA = ItemType('OE51DW2', name='banana')" ) ); } diff --git a/src/project_generator/scripts_file.rs b/src/project_generator/scripts_file.rs index 0e02ca2..7cd60cd 100644 --- a/src/project_generator/scripts_file.rs +++ b/src/project_generator/scripts_file.rs @@ -1,39 +1,44 @@ use std::ops::Add; +use heck::{ToSnakeCase, ToUpperCamelCase}; use serde_json::Value; use crate::game_data::{ actions::Action, directory::{Directory, Script}, - variable_categories::{pymodd_class_name_of_category, CategoriesToVariables}, + variable_categories::CategoriesToVariables, GameData, }; -use super::utils::{ - iterators::{ - argument_values_iterator::{ArgumentValueIterItem, ArgumentValuesIterator, Operation}, - directory_iterator::DirectoryIterItem, +use super::{ + game_variables_file::pymodd_class_name_of_category, + utils::{ + iterators::{ + argument_values_iterator::{ArgumentValueIterItem, ArgumentValuesIterator, Operation}, + directory_iterator::DirectoryIterItem, + }, + surround_string_with_quotes, }, - surround_string_with_quotes, }; pub struct ScriptsFile {} impl ScriptsFile { pub fn build_content(game_data: &GameData) -> String { - let content = format!( + format!( "from pymodd.actions import *\n\ from pymodd.functions import *\n\ from pymodd.script import Trigger, UiTarget, Flip, script\n\n\ - from game_variables import *\n\n\n" - ); - content.add(&build_directory_content( - &game_data.root_directory, - &ScriptsContentBuilder::new( - &game_data.categories_to_variables, + from game_variables import *\n\n\n\ + {}\n\n", + &build_directory_content( &game_data.root_directory, - ), - )) + &ScriptsContentBuilder::new( + &game_data.categories_to_variables, + &game_data.root_directory, + ), + ) + ) } } @@ -85,20 +90,21 @@ impl<'a> ScriptsContentBuilder<'a> { "@script(triggers=[{}]{})\n\ class {class_name}():\n\ \tdef _build(self):\n\ - \t\tself.actions = [\n\ - {}\ - \t\t\t\n\ - \t\t]\n", + {}", script.triggers_into_pymodd_enums().join(", "), - if !script.name.is_ascii() { - format!(", name={}", surround_string_with_quotes(&script.name)) - } else { + if script.name.is_ascii() { String::new() + } else { + format!(", name={}", surround_string_with_quotes(&script.name)) }, - self.build_actions_content(&script.actions) - .lines() - .map(|action| format!("{}{action}\n", "\t".repeat(3))) - .collect::(), + if script.actions.len() > 0 { + self.build_actions_content(&script.actions) + .lines() + .map(|action| format!("{}{action}\n", "\t".repeat(2))) + .collect::() + } else { + String::from("\t\tpass\n") + } ) } @@ -110,10 +116,88 @@ impl<'a> ScriptsContentBuilder<'a> { } fn build_action_content(&self, action: &Action) -> String { + // for use while converting arguments of special actions + let (none, pass) = (String::from("None"), String::from("\t\tpass\n")); match action.name.as_str() { + // convert break, continue, and return actions into keywords + "break" | "continue" | "return" => format!("{}\n", &action.name), + + // convert condition actions into if statements + "condition" => { + let args = self.build_arguments_of_action_seperately(action); + let (condition, then_actions, else_actions) = ( + args.get(0).unwrap_or(&none), + args.get(1).unwrap_or(&pass), + args.get(2).unwrap_or(&pass), + ); + format!( + "if {condition}:{}{}", + then_actions.strip_suffix("\n").unwrap(), + if else_actions != "\n\tpass\n" { + format!("\nelse:{else_actions}") + } else { + String::from("\n") + } + ) + } + + // convert variable for loop actions into for loops + "for" => { + let args = self.build_arguments_of_action_seperately(action); + let (variable, start, stop, actions) = ( + args.get(0).unwrap_or(&none), + args.get(1).unwrap_or(&none), + args.get(2).unwrap_or(&none), + args.get(3).unwrap_or(&pass), + ); + format!("for {variable} in range({start}, {stop}):{actions}") + } + + // convert for each type in function/variable actions into for loops + "forAllEntities" | "forAllProjectiles" | "forAllItems" | "forAllUnits" + | "forAllPlayers" | "forAllItemTypes" | "forAllUnitTypes" | "forAllRegions" + | "forAllDebris" => { + let args = self.build_arguments_of_action_seperately(action); + let (group, actions) = (args.get(0).unwrap_or(&none), args.get(1).unwrap_or(&pass)); + let group_type = match action + .name + .strip_prefix("forAll") + .unwrap() + .to_snake_case() + .strip_suffix("s") + .unwrap() + { + "entitie" => "entity", + "debri" => "debris", + group_type => group_type, + } + .to_string(); + // use the variable provided by the for loop instead of functions + let actions = actions.replace( + &format!("Selected{}()", group_type.to_upper_camel_case()), + &group_type, + ); + format!("for {group_type} in {group}:{actions}") + } + + // convert repeat actions into for loops + "repeat" => { + let args = self.build_arguments_of_action_seperately(action); + let (count, actions) = (args.get(0).unwrap_or(&none), args.get(1).expect(&pass)); + format!("for _ in repeat({count}):{actions}") + } + + // convert while actions into while loops + "while" => { + let args = self.build_arguments_of_action_seperately(action); + let (condition, actions) = + (args.get(0).unwrap_or(&none), args.get(1).unwrap_or(&pass)); + format!("while {condition}:{actions}") + } + "comment" => { format!( - "{}({}{}),\n", + "{}({}{})\n", action.pymodd_class_name(), // set argument manually for comments surround_string_with_quotes( @@ -126,12 +210,11 @@ impl<'a> ScriptsContentBuilder<'a> { .collect::(), ) } + _ => format!( - "{}({}", + "{}({}{})\n", action.pymodd_class_name(), - self.build_arguments_content(action.iter_flattened_argument_values()) - ) - .add( + self.build_arguments_content(action.iter_flattened_argument_values()), &self .build_optional_arguments_contents(&action) .into_iter() @@ -144,11 +227,21 @@ impl<'a> ScriptsContentBuilder<'a> { } }) .collect::(), - ) - .add("),\n"), + ), } } + /// used while parsing if statements, for loops, and while loops + fn build_arguments_of_action_seperately(&self, action: &Action) -> Vec { + action + .args + .iter() + .map(|arg| { + self.build_arguments_content(ArgumentValuesIterator::new(&vec![arg.clone()])) + }) + .collect::>() + } + fn build_arguments_content(&self, args_iter: ArgumentValuesIterator) -> String { args_iter .fold(String::from("("), |pymodd_args, arg| { @@ -158,11 +251,25 @@ impl<'a> ScriptsContentBuilder<'a> { + &format!( "{}{}", String::from(if include_seperator { ", " } else { "" }), - match arg { - // surround entire condition with parenthesis - ArgumentValueIterItem::Condition(_) => - format!("({})", self.build_argument_content(arg)), - _ => self.build_argument_content(arg), + { + // remove parentheses surrounding the outermost layer of conditions + if let ArgumentValueIterItem::Condition(_) = arg { + let condition_content = self.build_argument_content(arg); + if condition_content.starts_with("(") + && condition_content.ends_with(")") + { + condition_content + .strip_prefix("(") + .unwrap() + .strip_suffix(")") + .unwrap() + .to_string() + } else { + condition_content + } + } else { + self.build_argument_content(arg) + } } ) }) @@ -178,11 +285,15 @@ impl<'a> ScriptsContentBuilder<'a> { } ArgumentValueIterItem::Actions(actions) => { format!( - "[\n{}\t\n]", - self.build_actions_content(actions) - .lines() - .map(|line| format!("\t{line}\n")) - .collect::() + "\n{}", + if actions.len() > 0 { + self.build_actions_content(actions) + .lines() + .map(|line| format!("\t{line}\n")) + .collect::() + } else { + String::from("\tpass\n") + } ) } ArgumentValueIterItem::Value(value) => match value { @@ -233,22 +344,30 @@ impl<'a> ScriptsContentBuilder<'a> { ArgumentValueIterItem::from_argument(&operator.item_b), ); - format!( + let operator = if let ArgumentValueIterItem::Value(operator_val) = operator { + into_operator(operator_val.as_str().unwrap_or("")).unwrap_or("") + } else { + "" + }; + + let content = format!( "{} {} {}", self.build_operation_item_content(item_a), - if let ArgumentValueIterItem::Value(operator_value) = operator { - into_operator(operator_value.as_str().unwrap_or("")).unwrap_or("") - } else { - "" - }, + operator, self.build_operation_item_content(item_b) - ) + ); + // surround `and` and `or` conditions with parentheses + if ["and", "or"].contains(&operator) { + format!("({content})") + } else { + content + } } fn build_operation_item_content(&self, operation_item: ArgumentValueIterItem) -> String { match operation_item { - // only surround conditions and calculations with parenthesis - ArgumentValueIterItem::Condition(_) | ArgumentValueIterItem::Calculation(_) => { + // surround calculations with parentheses + ArgumentValueIterItem::Calculation(_) => { format!("({})", self.build_argument_content(operation_item)) } ArgumentValueIterItem::StartOfFunction(_) => self.build_arguments_content( @@ -281,8 +400,8 @@ fn into_operator(string: &str) -> Option<&str> { return Some(string); } match string.to_lowercase().as_str() { - "and" => Some("&"), - "or" => Some("|"), + "and" => Some("and"), + "or" => Some("or"), _ => None, } } @@ -318,9 +437,7 @@ mod tests { "@script(triggers=[Trigger.GAME_START])\n\ class Initialize():\n\ \tdef _build(self):\n\ - \t\tself.actions = [\n\ - \t\t\t\n\ - \t\t]\n", + \t\tpass\n", )) ); } @@ -342,9 +459,7 @@ mod tests { "@script(triggers=[Trigger.GAME_START], name='【 𝚒𝚗𝚒𝚝𝚒𝚊𝚕𝚒𝚣𝚎 イ】')\n\ class q():\n\ \tdef _build(self):\n\ - \t\tself.actions = [\n\ - \t\t\t\n\ - \t\t]\n", + \t\tpass\n", )) ); } @@ -355,7 +470,7 @@ mod tests { ScriptsContentBuilder::new( &CategoriesToVariables::new(HashMap::from([( "shops", - vec![Variable::new("OJbEQyc7is", "WEAPONS", None)] + vec![Variable::new("OJbEQyc7is", "weapons", "WEAPONS", None)] )])), &Directory::new("root", "null", Vec::new()) ) @@ -365,10 +480,7 @@ mod tests { "type": "openShopForPlayer", "player": { "function": "getOwner", - "entity": { - "function": "getLastCastingUnit", - "vars": [] - }, + "entity": { "function": "getLastCastingUnit", "vars": [] }, "vars": [] }, "shop": "OJbEQyc7is", @@ -378,7 +490,7 @@ mod tests { .as_array() .unwrap() )), - "open_shop_for_player(Shops.WEAPONS, OwnerOfEntity(LastCastingUnit())),\n" + "open_shop_for_player(Shops.WEAPONS, OwnerOfEntity(LastCastingUnit()))\n" ) } @@ -393,9 +505,7 @@ mod tests { &json!([ { "type": "startUsingItem", - "entity": { - "function": "getTriggeringItem" - }, + "entity": { "function": "getTriggeringItem" }, "comment": "hi!", "runOnClient": true, "disabled": true, @@ -404,7 +514,7 @@ mod tests { .as_array() .unwrap() )), - "use_item_continuously_until_stopped(LastTriggeringItem(), comment='hi!', disabled=True, run_on_client=True),\n" + "use_item_continuously_until_stopped(LastTriggeringItem(), comment='hi!', disabled=True, run_on_client=True)\n" ) } @@ -417,17 +527,12 @@ mod tests { ) .build_actions_content(&parse_actions( &json!([ - { - "type": "return", - "comment": "hi!", - "runOnClient": true, - "disabled": false, - } + { "type": "stopMusic", "comment": "hi!", "runOnClient": true, "disabled": false, } ]) .as_array() .unwrap() )), - "return_loop(comment='hi!', run_on_client=True),\n" + "stop_music_for_everyone(comment='hi!', run_on_client=True)\n" ) } @@ -440,16 +545,12 @@ mod tests { ) .build_actions_content(&parse_actions( &json!([ - { - "type": "updateUiTextForEveryone", - "target": "top", - "value": "Hello!" - } + { "type": "updateUiTextForEveryone", "target": "top", "value": "Hello!" } ]) .as_array() .unwrap() )), - "update_ui_text_for_everyone(UiTarget.TOP, 'Hello!'),\n" + "update_ui_text_for_everyone(UiTarget.TOP, 'Hello!')\n" ) } @@ -462,15 +563,30 @@ mod tests { ) .build_actions_content(&parse_actions( &json!([ - { - "type": "comment", - "comment": "hey there", - } + { "type": "comment", "comment": "hey there", } ]) .as_array() .unwrap() )), - "comment('hey there'),\n" + "comment('hey there')\n" + ); + } + + #[test] + fn parse_keyword_actions_into_pymodd() { + assert_eq!( + ScriptsContentBuilder::new( + &CategoriesToVariables::new(HashMap::new()), + &Directory::new("root", "null", Vec::new()) + ) + .build_actions_content(&parse_actions( + &json!([ { "type": "break" }, { "type": "continue" }, { "type": "return" } ]) + .as_array() + .unwrap() + )), + "break\n\ + continue\n\ + return\n" ); } @@ -504,7 +620,7 @@ mod tests { .as_array() .unwrap() )), - "increase_variable_by_number(None, RandomNumberBetween(0, 5) * ((CurrentUnixTimeStamp() ** 2) + 3)),\n" + "increase_variable_by_number(None, RandomNumberBetween(0, 5) * ((CurrentUnixTimeStamp() ** 2) + 3))\n" ); } @@ -526,9 +642,7 @@ mod tests { "function": "concat", "textA": { "function": "getPlayerId", - "player": { - "function": "getTriggeringPlayer" - } + "player": { "function": "getTriggeringPlayer" } }, "textB": " player!" } @@ -538,7 +652,7 @@ mod tests { .as_array() .unwrap() )), - "send_chat_message_to_everyone('hi ' + IdOfPlayer(LastTriggeringPlayer()) + ' player!'),\n" + "send_chat_message_to_everyone('hi ' + IdOfPlayer(LastTriggeringPlayer()) + ' player!')\n" ); } @@ -553,56 +667,39 @@ mod tests { json!([ { "type": "condition", - "conditions": [ - { "operandType": "boolean", "operator": "==" }, - true, - true - ], + "conditions": [ { "operandType": "boolean", "operator": "==" }, true, true ], "then": [ { "type": "condition", - "conditions": [ - { "operandType": "boolean", "operator": "==" }, - true, - true - ], + "conditions": [ { "operandType": "boolean", "operator": "==" }, true, true ], "then": [ { "type": "condition", - "conditions": [ - { "operandType": "boolean", "operator": "==" }, - true, - true - ], - "then": [], - "else": [] + "conditions": [ { "operandType": "boolean", "operator": "==" }, true, true ], + "then": [ { "type": "sendChatMessage", "message": "hi" } ], + "else": [ { "type": "sendChatMessage", "message": "hi" } ] } ], - "else": [] - } - ], - "else": [] + "else": [ { "type": "sendChatMessage", "message": "hi" } ] + } + ], + "else": [ { "type": "sendChatMessage", "message": "hi" } ] } ]) .as_array() .unwrap(), )) .as_str(), - "if_else((True == True), [\n\ - \tif_else((True == True), [\n\ - \t\tif_else((True == True), [\n\ - \t\t\t\n\ - \t\t], [\n\ - \t\t\t\n\ - \t\t]),\n\ - \t\t\n\ - \t], [\n\ - \t\t\n\ - \t]),\n\ - \t\n\ - ], [\n\ - \t\n\ - ]),\n" + "if True == True:\n\ + \tif True == True:\n\ + \t\tif True == True:\n\ + \t\t\tsend_chat_message_to_everyone('hi')\n\ + \t\telse:\n\ + \t\t\tsend_chat_message_to_everyone('hi')\n\ + \telse:\n\ + \t\tsend_chat_message_to_everyone('hi')\n\ + else:\n\ + \tsend_chat_message_to_everyone('hi')\n" ) } @@ -613,36 +710,175 @@ mod tests { &CategoriesToVariables::new(HashMap::new()), &Directory::new("root", "null", Vec::new()) ) - .build_actions_content(&parse_actions( - json!([ - { - "type": "condition", - "conditions": [ - { "operandType": "and", "operator": "AND" }, - [ - { "operandType": "boolean", "operator": "==" }, - { "function": "getNumberOfUnitsOfUnitType", "unitType": "oTDQ3jlcMa" }, - 5 - ], - [ - { "operandType": "boolean", "operator": "==" }, - true, - true - ] - ], - "then": [], - "else": [] - } - ]) - .as_array() - .unwrap(), - )) - .as_str(), - "if_else(((NumberOfUnitsOfUnitType('oTDQ3jlcMa') == 5) & (True == True)), [\n\ - \t\n\ - ], [\n\ - \t\n\ - ]),\n" + .build_actions_content(&parse_actions( + json!([ + { + "type": "condition", + "conditions": [ + { "operandType": "and", "operator": "AND" }, + [ { "operandType": "boolean", "operator": "==" }, true, true ], + [ + { "operandType": "or", "operator": "OR" }, + [ { "operandType": "boolean", "operator": "==" }, true, true ], + [ { "operandType": "boolean", "operator": "==" }, true, true ] + ] + ], + "then": [], + "else": [] + }]) + .as_array() + .unwrap(), + )) + .as_str(), + "if True == True and (True == True or True == True):\n\ + \tpass\n" + ); + } + + #[test] + fn parse_variable_for_loop_into_pymodd() { + assert_eq!( + ScriptsContentBuilder::new( + &CategoriesToVariables::new(HashMap::from([( + "variables", + vec![Variable::new("i", "i", "I", Some("number"))] + )])), + &Directory::new("root", "null", Vec::new()) + ) + .build_actions_content(&parse_actions( + json!([ + { "type": "for", "variableName": "i", "start": 0, "stop": 5, "actions": [] } + ]) + .as_array() + .unwrap(), + )) + .as_str(), + "for Variables.I in range(0, 5):\n\ + \tpass\n" + ); + } + + #[test] + fn parse_for_each_type_in_function_action_into_pymodd() { + assert_eq!( + ScriptsContentBuilder::new( + &CategoriesToVariables::new(HashMap::new()), + &Directory::new("root", "null", Vec::new()) + ) + .build_actions_content(&parse_actions( + json!([ + { "type": "forAllEntities", "entityGroup": { "function": "allEntities" }, "actions": [ + { "type": "destroyEntity", "entity": { "function": "getSelectedEntity" } } + ] } + ]) + .as_array() + .unwrap(), + )) + .as_str(), + "for entity in AllEntitiesInTheGame():\n\ + \tdestroy_entity(entity)\n" + ); + } + + #[test] + fn parse_for_each_type_in_variable_action_into_pymodd() { + assert_eq!( + ScriptsContentBuilder::new( + &CategoriesToVariables::new(HashMap::from([( + "itemTypeGroups", + vec![Variable::new("specialItemTypes", "specialItemTypes", "SPECIAL_ITEM_TYPES", None)] + )])), + &Directory::new("root", "null", Vec::new()) + ) + .build_actions_content(&parse_actions( + json!([ + { + "type": "forAllItemTypes", + "itemTypeGroup": { "function": "getVariable", "variableName": "specialItemTypes" }, + "actions": [] + } + ]) + .as_array() + .unwrap(), + )) + .as_str(), + "for item_type in ItemTypeGroups.SPECIAL_ITEM_TYPES:\n\ + \tpass\n" + ); + } + + #[test] + fn parse_for_each_type_in_multi_arg_function_action_into_pymodd() { + assert_eq!( + ScriptsContentBuilder::new( + &CategoriesToVariables::new(HashMap::new()), + &Directory::new("root", "null", Vec::new()) + ) + .build_actions_content(&parse_actions( + json!([ + { + "type": "forAllUnits", + "unitGroup": { "function": "allUnitsInRegion", "region": { + "function": "dynamicRegion", + "x": 0, "y": 0, "width": 5, "height": 5 } + }, + "actions": [] + } + ]) + .as_array() + .unwrap(), + )) + .as_str(), + "for unit in AllUnitsInRegion(DynamicRegion(0, 0, 5, 5)):\n\ + \tpass\n" + ); + } + + #[test] + fn parse_repeat_action_into_python() { + assert_eq!( + ScriptsContentBuilder::new( + &CategoriesToVariables::new(HashMap::new()), + &Directory::new("root", "null", Vec::new()) + ) + .build_actions_content(&parse_actions( + json!([ + { "type": "repeat", "count": 5, "actions": [] } + ]) + .as_array() + .unwrap(), + )) + .as_str(), + "for _ in repeat(5):\n\ + \tpass\n" + ); + } + + #[test] + fn parse_while_action_into_python() { + assert_eq!( + ScriptsContentBuilder::new( + &CategoriesToVariables::new(HashMap::new()), + &Directory::new("root", "null", Vec::new()) + ) + .build_actions_content(&parse_actions( + json!([ + { + "type": "while", + "conditions": [ + { "operandType": "boolean", "operator": "==" }, + { "function": "entityExists", "entity": { "function": "getTriggeringUnit" } }, + true + ], + "actions": [] + } + ]) + .as_array() + .unwrap(), + )) + .as_str(), + "while EntityExists(LastTriggeringUnit()) == True:\n\ + \tpass\n" ); } @@ -677,7 +913,7 @@ mod tests { .unwrap(), )) .as_str(), - "run_script(SpawnBoss()),\n" + "run_script(SpawnBoss())\n" ) } } diff --git a/src/project_generator/utils/iterators/argument_values_iterator.rs b/src/project_generator/utils/iterators/argument_values_iterator.rs index 52ee402..20a31b5 100644 --- a/src/project_generator/utils/iterators/argument_values_iterator.rs +++ b/src/project_generator/utils/iterators/argument_values_iterator.rs @@ -7,7 +7,7 @@ use crate::game_data::{ impl Action { pub fn iter_flattened_argument_values(&self) -> ArgumentValuesIterator { - ArgumentValuesIterator::new(self) + ArgumentValuesIterator::new(&self.args) } } @@ -16,10 +16,9 @@ pub struct ArgumentValuesIterator<'a> { } impl<'a> ArgumentValuesIterator<'a> { - fn new(action: &Action) -> ArgumentValuesIterator { + pub fn new(arguments: &Vec) -> ArgumentValuesIterator { ArgumentValuesIterator { - stack: action - .args + stack: arguments .iter() .map(|arg| ArgumentValueIterItem::from_argument(arg)) .collect(), diff --git a/src/project_generator/utils/to_pymodd_maps.rs b/src/project_generator/utils/to_pymodd_maps.rs index a857d0f..dc6bbea 100644 --- a/src/project_generator/utils/to_pymodd_maps.rs +++ b/src/project_generator/utils/to_pymodd_maps.rs @@ -8,10 +8,12 @@ use lazy_static::lazy_static; const PYMODD_SCRIPT_FILE_CONTENT: &str = include_str!("../../../pymodd/script.py"); const PYMODD_ACTIONS_FILE_CONTENT: &str = include_str!("../../../pymodd/actions.py"); const PYMODD_FUNCTIONS_FILE_CONTENT: &str = include_str!("../../../pymodd/functions.py"); +const PYMODD_VARIABLE_TYPES_FILE_CONTENT: &str = include_str!("../../../pymodd/variable_types.py"); lazy_static! { // enum maps pub static ref TRIGGERS_TO_PYMODD_ENUM: HashMap = generate_to_pymodd_enums_map_for_type("Trigger", PYMODD_SCRIPT_FILE_CONTENT); + pub static ref VARIABLE_DATA_TYPES_TO_PYMODD_ENUM: HashMap = generate_to_pymodd_enums_map_for_type("DataType", PYMODD_VARIABLE_TYPES_FILE_CONTENT); pub static ref UI_TARGET_CONSTANTS_TO_PYMODD_ENUM:HashMap = generate_to_pymodd_enums_map_for_type("UiTarget", PYMODD_SCRIPT_FILE_CONTENT); pub static ref FLIP_CONSTANTS_TO_PYMODD_ENUM:HashMap = generate_to_pymodd_enums_map_for_type("Flip", PYMODD_SCRIPT_FILE_CONTENT); @@ -69,10 +71,13 @@ fn generate_actions_to_pymodd_structure_map() -> HashMap