diff --git a/Gamemodes/Clicker.owpy b/Clicker.owpy similarity index 73% rename from Gamemodes/Clicker.owpy rename to Clicker.owpy index 5999ffa..38708c7 100644 --- a/Gamemodes/Clicker.owpy +++ b/Clicker.owpy @@ -1,122 +1,14 @@ -%Global - Event - On Global -%Each(team_) - Event - On Each Player - team_ - All -%GameText(who, text, pos, scale) - World Text - Visible_To: who - Header: text - Position: pos - Scale: scale - Clipping: Clip Against Surfaces - Reevaluation: Visible To And String -%CodeText(who, code, pos, scale) - GameText(who, `Save: {} + {} + {} + {} + {}`(code[0], code[1], code[2], code[3], code[4]), pos, scale) -%BigHud(loc, text, color) - Hud - Visible_To: Event Player - Header: text - Subheader: Null - Text: Null - Location: loc - Sort_Order: 0 - Header_Color: color - Subheader_Color: White - Text_Color: White - Reevaluation: Visible To And String -%SmallHud(loc, text, color) - Hud - Visible_To: Event Player - Header: Null - Subheader: Null - Text: text - Location: loc - Sort_Order: 999 - Header_Color: White - Subheader_Color: White - Text_Color: color - Reevaluation: Visible To And String -%Sound(type) - Play Effect - Visible_To: Event Player - Type: type - Color: White - Position: Event Player - Radius: 50 -%SuccessSound - Sound(Buff Explosion Sound) -%FailSound - Sound(Debuff Impact Sound) -%WooshSound - Sound(Ring Explosion Sound) -%BoomSound - Sound(Explosion Sound) -%MissingFunds - Big Msg(Event Player, `Go Find More Money`) -%Warp(player, destination, facing) - Teleport(player, destination) - Set Facing - Player: Event Player - Direction: Vector Towards - Start: Event Player - End: facing - Relative: To World - Wait(0.1s) - Event Player.halt() -%Portal(pos, type, color, text) - Create Effect - Visible_To: Everyone - Type: type - Color: color - Position: pos - Radius: 1.5 - Reevaluation: Visible To - GameText(Everyone, text, (pos + Up), 1.5) -%UpgradePortal(pos) - Portal(pos, Good Aura, Yellow, "Upgrades") -%ShopPortal(pos) - Portal(pos, Good Aura, Purple, `Current Boss`) -%NextBossPortal(pos, text) - Portal(pos, Good Aura, Blue, text) -%UpgradeEffect(pos, color) - Create Effect - Visible_To: Everyone - Type: Orb - Color: color - Position: pos - Radius: 1.5 - Reevaluation: Visible To -%UpgradeText(upg, cost_var) - GameText(Event Player, `{}: {}`(upgrade_names[upg], cost_var), upgrade_positions[upg] + Up * 0.5, 1.5) -%SaveIcon(pos, icon, color) - Create Icon - Visible_To: Filter - Everyone - LOS - pos - Cur Elem - Barriers Do Not Block LOS - Position: pos - Icon: icon - Reevaluation: Visible To - Icon_Color: White - Show_When_Offscreen: False - Create Effect - Visible_To: Everyone - Type: Ring - Color: color - Position: pos - Radius: 1 - Reevaluation: Visible To Position And Radius +#import "lib/effects" +#import "lib/events" +#import "lib/gui" +#import "lib/util" + %SpawnBoss(boss) Teleport boss_player boss_spawns[Index(boss_heroes, boss)] -%ResetPlayer + +%ResetPlayer() pvar location = 0 pvar cur_boss = 0 pvar bosses_killed = 0 @@ -145,6 +37,8 @@ Rule "Initialize Constants" Global() Actions + sound = Sound() + messager = Messager() /* Define Player Variables */ pvar location = 0 pvar cur_boss = 0 @@ -168,7 +62,7 @@ Rule "Initialize Constants" shop_pos = <2.500, 3.500, 75> player_spawns = [<-40, -1.5, 145.5>, <-29, 8, 56>, <-77.5, 1.5, 65.5>, <-50.5, 1.5, 117>, <43.5, 3.5, 73.5>, <-115, 1.5, 112.5>] boss_spawns = [<-31.5, 0, 148>, <-22.5, 7.5, 66.5>, <-82.5, 1.5, 61>, <-59, 1, 104>, <53.5, 3.5, 72.5>, <-129, 2.5, 108.5>] - boss_heroes = [Hero(Roadhog), Hero(Soldier: 76), Hero(Mei), Hero(Lucio), Hero(Ana), Hero(Reaper)] + boss_heroes = [Roadhog, Soldier: 76, Mei, Lucio, Ana, Reaper] ability2_pos = <12.5, 2.5, 71> ability1_pos = <12.5, 2.5, 71 + 2.5> ability1_cost = 25000 @@ -176,7 +70,7 @@ Rule "Initialize Constants" Set Match Time(90min) Rule "Initialize Player Stats" - Each(Team 1) + EachPlayer(Team 1) Actions /* Player Variables */ ResetPlayer() @@ -196,19 +90,22 @@ Rule "Initialize Effects (Portals / Upgrades / Saves / Boundaries)" soldier_temp_pos = <3, 3, 77.5> x_offset = <2.5, 0, 0> z_offset = <0, 0, 2.5> - upgrade_names = ["Heal", "Damage", "Faster", "Money", "Defend"] - upgrade_rates = [100, 1.003, 1.04, 1.045, 1.03] - upgrade_positions = [] - for i in range(-2, 3): - upgrade_positions.append(upgr_pos + i * x_offset) - upgrade_colors = [Purple, Red, Yellow, Green, Blue] + + // Upgrade(name, rate, pos, color) + upgrades = [] + upgrades.append(Upgrade("Heal", 100, hp_cost, upgr_pos - 2 * x_offset, Purple)) + upgrades.append(Upgrade("Damage", 1.003, damage_scale_cost, upgr_pos - x_offset, Red)) + upgrades.append(Upgrade("Faster", 1.04, reload_speed_cost, upgr_pos, Yellow)) + upgrades.append(Upgrade("Money", 1.045, money_multiplier_cost, upgr_pos + x_offset, Green)) + upgrades.append(Upgrade("Defend", 1.03, defense_cost, upgr_pos + 2 * x_offset, Blue)) // Bosses 1-6 -> Shop for portal in portals: UpgradePortal(portal) ShopPortal(shop_portal) // HP, Damage, Reload Speed, Money Multiplier, Damage Resistance - for i in range(5): - UpgradeEffect(upgrade_positions[i], upgrade_colors[i]) + for upgrade in upgrades: + UpgradeEffect(upgrade.pos, upgrade.color) + UpgradeText(upgrade.name, upgrade.pos, upgrade.cost) // Next Boss for i in range(5): NextBossPortal(next_boss_portals[i], `Next Boss: {}`(next_boss_cost[i])) @@ -227,10 +124,10 @@ Rule "Initialize Effects (Portals / Upgrades / Saves / Boundaries)" GameText(All Players(Team 1), `Unlock {}: {} Credit`(Hero(Soldier: 76), 1), soldier_temp_pos + Up * 0.5, 1.5) // Secrets secret2_pos = <31, 2.5, 49.5> - CodeText(Players In Radius(secret2_pos, 5, Team(All), Off), ["Left", "Up", "Down", "Up", "Right"], secret2_pos, 0.75) + CodeText(["Left", "Up", "Down", "Up", "Right"], secret2_pos, 0.75, Players In Radius(secret2_pos, 5, Team(All), Off)) Rule "Initialize Player HUD Stats" - Each(Team 1) + EachPlayer(Team 1) Actions BigHud(Top, `Money: {}`(pvar money), White) SmallHud(Top, `{} Credits ({} / {} Boss Kills)`(pvar credits, pvar bosses_killed, 6), Purple) @@ -302,17 +199,8 @@ Rule "Respawn Bosses" Wait(0.1s) Teleport(Event Player, boss_spawns[Index(boss_heroes, Event Player.hero)]) -Rule "Initialize Upgrade Text" - Each(Team 1) - Actions - UpgradeText(0, pvar hp_cost) - UpgradeText(1, pvar damage_scale_cost) - UpgradeText(2, pvar reload_speed_cost) - UpgradeText(3, pvar money_multiplier_cost) - UpgradeText(4, pvar defense_cost) - Rule "Teleport to Shop" - Each(Team 1) + EachPlayer(Team 1) Conditions Any True Array: portals @@ -322,11 +210,11 @@ Rule "Teleport to Shop" <= 2.0 Actions Warp(Event Player, shop_pos, upgr_pos) - WooshSound() + sound.Woosh() pvar location = -1 Rule "Teleport from Shop" - Each(Team 1) + EachPlayer(Team 1) Conditions Distance Between Event Player @@ -337,10 +225,10 @@ Rule "Teleport from Shop" pvar location = pvar cur_boss Wait(0.1s) Warp(Event Player, player_spawns[pvar location], Closest Player To(Event Player, Team 2)) - WooshSound() + sound.Woosh() Rule "Shop Boundary & Heal" - Each(Team 1) + EachPlayer(Team 1) Conditions pvar location == -1 Actions @@ -350,19 +238,19 @@ Rule "Shop Boundary & Heal" Skip If(Not((Event Player.pos.x <= -12) or (Event Player.pos.z <= 25)), 6) Warp(Event Player, shop_pos, upgr_pos) Msg(Event Player, `Avoid Going Here`) - FailSound() + sound.Fail() %BossBoundary(loc, hero_) if Event Player in All Players(Team 1): if pvar location == loc: Teleport(Event Player, player_spawns[pvar cur_boss]) Msg(Event Player, `Avoid Going Here`) - FailSound() + sound.Fail() elif Event Player.hero == hero_: Teleport(Event Player, boss_spawns[Index(boss_heroes, hero_)]) Rule "Boss Boundaries (Soldier: 76)" - Each(All) + EachPlayer(All) Conditions Event Player.pos.y < 4.5 Actions @@ -370,7 +258,7 @@ Rule "Boss Boundaries (Soldier: 76)" Wait(2s) Loop If Condition Is True Rule "Boss Boundaries (Mei)" - Each(All) + EachPlayer(All) Conditions Event Player.pos.x > -72 Actions @@ -378,7 +266,7 @@ Rule "Boss Boundaries (Mei)" Wait(2s) Loop If Condition Is True Rule "Boss Boundaries (Lucio)" - Each(All) + EachPlayer(All) Conditions not Event Player in Players In Radius(boss_spawns[3], 20, Team(All), Off) Actions @@ -386,7 +274,7 @@ Rule "Boss Boundaries (Lucio)" Wait(2s) Loop If Condition Is True Rule "Boss Boundaries (Reaper)" - Each(All) + EachPlayer(All) Conditions Event Player.pos.x > -94 Actions @@ -403,23 +291,23 @@ Rule "Boss Boundaries (Reaper)" Wait(0.1s) Loop If Condition Is True Rule "Buy HP" - Each(Team 1) - ShopCondition(upgrade_positions[0]) + EachPlayer(Team 1) + ShopCondition(upgrades[0].pos) Actions if pvar money >= pvar hp_cost: pvar money -= pvar hp_cost - pvar hp_cost = ceil(pvar hp_cost + upgrade_rates[0]) + pvar hp_cost = ceil(pvar hp_cost + upgrades[0].rate) pvar hp += 10 Set Max Health(Event Player, pvar hp) - SuccessSound() + sound.Success() ShopAutobuy() else: - MissingFunds() - FailSound() + messager.messager.MissingFunds() + sound.Fail() Rule "Buy Damage %" - Each(Team 1) - ShopCondition(upgrade_positions[1]) + EachPlayer(Team 1) + ShopCondition(upgrades[1].pos) Actions if pvar money >= pvar damage_scale_cost: pvar money -= pvar damage_scale_cost @@ -428,91 +316,91 @@ Rule "Buy Damage %" Skip If(pvar damage_scale < 75, 1) pvar damage_scale += 2 Set Damage Dealt(Event Player, pvar damage_scale) - pvar damage_scale_cost = ceil(pvar damage_scale_cost ^ upgrade_rates[1]) - SuccessSound() + pvar damage_scale_cost = ceil(pvar damage_scale_cost ^ upgrades[1].rate) + sound.Success() ShopAutobuy() else: - MissingFunds() - FailSound() + messager.MissingFunds() + sound.Fail() Rule "Buy Reload Speed" - Each(Team 1) - ShopCondition(upgrade_positions[2]) + EachPlayer(Team 1) + ShopCondition(upgrades[2].pos) Actions if pvar money >= pvar reload_speed_cost: pvar money -= pvar reload_speed_cost - pvar reload_speed_cost = ceil(pvar reload_speed_cost ^ upgrade_rates[2]) + pvar reload_speed_cost = ceil(pvar reload_speed_cost ^ upgrades[2].rate) pvar reload_speed = max(pvar reload_speed * 0.95, 0) - SuccessSound() + sound.Success() ShopAutobuy() else: - MissingFunds() - FailSound() + messager.MissingFunds() + sound.Fail() Rule "Buy Money Multiplier" - Each(Team 1) - ShopCondition(upgrade_positions[3]) + EachPlayer(Team 1) + ShopCondition(upgrades[3].pos) Actions if pvar money >= pvar money_multiplier_cost: pvar money -= pvar money_multiplier_cost - pvar money_multiplier_cost = ceil(pvar money_multiplier_cost ^ upgrade_rates[3]) + pvar money_multiplier_cost = ceil(pvar money_multiplier_cost ^ upgrades[3].rate) pvar money_multiplier += 0.075 - SuccessSound() + sound.Success() ShopAutobuy() else: - MissingFunds() - FailSound() + messager.MissingFunds() + sound.Fail() Rule "Buy Defense" - Each(Team 1) - ShopCondition(upgrade_positions[4]) + EachPlayer(Team 1) + ShopCondition(upgrades[4].pos) Actions if (pvar money >= pvar defense_cost) and (pvar defense > 5): pvar money -= pvar defense_cost - pvar defense_cost = ceil(pvar defense_cost ^ upgrade_rates[4]) + pvar defense_cost = ceil(pvar defense_cost ^ upgrades[4].rate) pvar defense = Max(pvar defense - 2, 5) Set Damage Received(Event Player, pvar defense) - SuccessSound() + sound.Success() ShopAutobuy() elif pvar defense == 5: Msg(Event Player, `Max Defend`) - FailSound() + sound.Fail() else: - MissingFunds() - FailSound() + messager.MissingFunds() + sound.Fail() -Rule "Buy Ability 1" - Each(Team 1) +/* Rule "Buy Ability 1" + EachPlayer(Team 1) ShopCondition(ability1_pos) Actions if (pvar money >= ability1_cost) and (not pvar ability1): pvar money -= ability1_cost pvar ability1 = True Set Ability 1 Enabled(Event Player, True) - SuccessSound() + sound.Success() elif pvar ability1: Msg(Event Player, `You Bought Ability 1`) - FailSound() + sound.Fail() else: - MissingFunds() + messager.MissingFunds() Rule "Buy Ability 2" - Each(Team 1) + EachPlayer(Team 1) ShopCondition(ability2_pos) Actions if (pvar money >= ability2_cost) and (not pvar ability2): pvar money -= ability2_cost pvar ability2 = True Set Ability 2 Enabled(Event Player, True) - SuccessSound() + sound.Success() elif pvar ability2: Msg(Event Player, `You Bought Ability 2`) - FailSound() + sound.Fail() else: - MissingFunds() + messager.MissingFunds() Rule "Teleport Player to Start" - Each(Team 1) + EachPlayer(Team 1) Conditions Has Spawned(Event Player) Actions @@ -521,7 +409,7 @@ Rule "Teleport Player to Start" player_spawns[pvar cur_boss] Rule "Shooting Control" - Each(Team 1) + EachPlayer(Team 1) Conditions Has Spawned(Event Player) Is Firing Primary(Event Player) @@ -560,7 +448,7 @@ Rule "Player Death" Warp(Event Player, shop_pos, upgr_pos) Rule "Next Boss" - Each(Team 1) + EachPlayer(Team 1) Conditions Event Player in Players In Radius(next_boss_portals[pvar cur_boss], 2, Team(All), Off) Actions @@ -570,24 +458,24 @@ Rule "Next Boss" Wait(0.1s) Warp(Event Player, player_spawns[pvar cur_boss], boss_spawns[pvar cur_boss]) pvar location = pvar cur_boss - WooshSound() + sound.Woosh() elif pvar money < next_boss_cost[pvar cur_boss]: - MissingFunds() - FailSound() + messager.MissingFunds() + sound.Fail() else: Big Msg(Event Player, `Go Kill Boss`) - FailSound() + sound.Fail() %SaveInput(name, value, pos) Rule "Save Input " + name - Each(Team 1) + EachPlayer(Team 1) Conditions Distance Between(Event Player, pos) <= 1.25 Event Player.interacting Actions Msg(Event Player, name) pvar save_code.append(value) - BoomSound() + sound.Boom() SaveInput("Up", 0, save_pos - z_offset) SaveInput("Down", 1, save_pos + z_offset) @@ -600,11 +488,11 @@ SaveInput("Right", 3, save_pos + x_offset) Set Hero(Event Player, hero_) Wait(0.5s) Big Msg(Event Player, `You Unlocked {}`(Hero Icon String(hero_))) - SuccessSound() + sound.Success() Wait(0.25) Rule "Buy Prestige Item" - Each(Team 1) + EachPlayer(Team 1) ShopCondition(soldier_temp_pos) Actions if pvar credits >= 1: @@ -614,7 +502,7 @@ Rule "Buy Prestige Item" Big Msg(Event Player, `Defeat Final Boss`) Rule "Check Save Code" - Each(Team 1) + EachPlayer(Team 1) Conditions Count Of(pvar save_code) == 5 Actions @@ -624,19 +512,19 @@ Rule "Check Save Code" // 3: Right if pvar save_code == [0, 0, 0, 0, 0]: UnlockHero(Hero(McCree)) - CodeText(Event Player, ["Up", "Up", "Up", "Up", "Up"], save_pos + Up * 1.25, 2) + CodeText(["Up", "Up", "Up", "Up", "Up"], save_pos + Up * 1.25, 2) elif pvar save_code == [3, 1, 2, 3, 2]: UnlockHero(Hero(Soldier: 76)) - CodeText(Event Player, ["Right", "Down", "Left", "Right", "Left"], save_pos + Up * 1.25, 2) + CodeText(["Right", "Down", "Left", "Right", "Left"], save_pos + Up * 1.25, 2) elif pvar save_code == [0, 2, 2, 1, 3]: - UnlockHero(Hero(Ashe)) - CodeText(Event Player, ["Up", "Left", "Left", "Down", "Right"], save_pos + Up * 1.25, 2) + UnlockHero(Ashe) + CodeText(["Up", "Left", "Left", "Down", "Right"], save_pos + Up * 1.25, 2) elif pvar save_code == [2, 3, 2, 0, 0]: - UnlockHero(Hero(Genji)) - CodeText(Event Player, ["Left", "Right", "Left", "Up", "Up"], save_pos + Up * 1.25, 2) + UnlockHero(Genji) + CodeText(["Left", "Right", "Left", "Up", "Up"], save_pos + Up * 1.25, 2) elif pvar save_code == [1, 1, 3, 1, 2]: - UnlockHero(Hero(Hanzo)) - CodeText(Event Player, ["Down", "Down", "Right", "Down", "Left"], save_pos + Up * 1.25, 2) + UnlockHero(Hanzo) + CodeText(["Down", "Down", "Right", "Down", "Left"], save_pos + Up * 1.25, 2) elif pvar save_code == [2, 0, 1, 0, 3]: // Secrets Big Msg(Event Player, "Hacked") // You Unlocked Hidden Save 2 @@ -645,14 +533,14 @@ Rule "Check Save Code" pvar save_code = [] Rule "Prestige Confirm" - Each(Team 1) + EachPlayer(Team 1) Conditions Distance Between(Event Player, prestige_pos) <= 1.5 Actions Msg(Event Player, `Start Over? (Jump)`) Rule "Prestige" - Each(Team 1) + EachPlayer(Team 1) Conditions Distance Between(Event Player, prestige_pos) <= 1.5 Event Player.jumping @@ -666,13 +554,13 @@ Rule "Prestige" Set Slow Motion(100) Warp(Event Player, player_spawns[0], boss_spawns[0]) Msg(Event Player, `{} Credits`(pvar credits)) - SuccessSound() + sound.Success() else: Big Msg(Event Player, `Defeat Final Boss`) Rule "Money Bonus (Ability 2 / E)" - Each(Team 1) + EachPlayer(Team 1) Conditions Is Using Ability 2(Event Player) Actions @@ -685,7 +573,7 @@ Rule "Money Bonus (Ability 2 / E)" Msg(Event Player, `Cooldown: {} sec`(pvar money_cd)) Rule "Damage Bonus (Ability 1 / Shift)" - Each(Team 1) + EachPlayer(Team 1) Conditions Is Using Ability 1(Event Player) Actions @@ -700,7 +588,7 @@ Rule "Damage Bonus (Ability 1 / Shift)" Msg(Event Player, `Cooldown: {} sec`(pvar damage_cd)) Rule "Money/Damage Cooldowns" - Each(Team 1) + EachPlayer(Team 1) Conditions (pvar damage_cd > 0) or (pvar money_cd > 0) Actions @@ -712,13 +600,16 @@ Rule "Money/Damage Cooldowns" Loop If Condition Is True Rule "Secret 1" // Flight after jumping by statue - Each(Team 1) + EachPlayer(Team 1) Rule "Secret 2" // Grandma giving passive income every 5s? - Each(Team 1) + EachPlayer(Team 1) + +Rule "Secret 3" // 30% faster ability cooldowns + EachPlayer(Team 1) Disabled Rule "Coordinate Viewer" - Each(Team 1) + EachPlayer(Team 1) Conditions Has Spawned(Event Player) Event Player.moving @@ -745,11 +636,11 @@ Disabled Rule "Coordinate Viewer" Reevaluation: Visible To And String Disabled Rule "Cheats" - Each(Team 1) + EachPlayer(Team 1) Conditions Event Player.jumping Actions pvar money += 1000000 pvar reload_speed = 0.01 Set Damage Received(Event Player, 0) - Set Damage Dealt(Event Player, 10000) \ No newline at end of file + Set Damage Dealt(Event Player, 10000) */ \ No newline at end of file diff --git a/Examples/aimbot.owpy b/Examples/aimbot.owpy deleted file mode 100644 index 45da1c4..0000000 --- a/Examples/aimbot.owpy +++ /dev/null @@ -1,34 +0,0 @@ -Rule "Start Aimbot" - Event - On Each Player - All - All - Conditions - Is Button Held(Event Player, Primary Fire) - Event Player.hero != Hero(Widowmaker) - Event Player.hero != Hero(Soldier: 76) - Is Alive(Player Closest To Reticle(Event Player, Opposite Team Of(Event Player.team))) - Players In Slot(1, All Teams) - Actions - Start Facing - Event Player - Direction Towards - Event Player - Player Closest To Reticle - Event Player - Opposite Team Of(Event Player.team) + <0, 0.240, 0> - 10000 - To World - Direction and Turn Rate - -Rule "Stop Aimbot" - Event - On Each Player - All - All - Conditions - not Event Player.LMB - Event Player.hero != Hero(Widowmaker) - Players In Slot(1, All Teams) - Actions - Stop Facing(Event Player) \ No newline at end of file diff --git a/Examples/arithmetic.owpy b/Examples/arithmetic.owpy deleted file mode 100644 index 6a84cdb..0000000 --- a/Examples/arithmetic.owpy +++ /dev/null @@ -1,13 +0,0 @@ -Rule "Arithmetic Operations" - Actions - z = Count Of(Allowed Heroes(Event Player)) - y = 1 + 1 - y += 2 - 1 - y *= 3 / 3 - y = 2 ^ 2 - y = (3 + 1) % 4 - pvar num_heroes = 3 - pvar formula = \ No newline at end of file diff --git a/Examples/arrays.owpy b/Examples/arrays.owpy deleted file mode 100644 index 637d7ac..0000000 --- a/Examples/arrays.owpy +++ /dev/null @@ -1,13 +0,0 @@ -Rule "Advanced Arrays" - Event - On Global - Actions - array = [] - array2 = [1, 2, 3] - array[0] = 2 - array[1] = array2[1] + array2[2] - array.append(<1, 2, 3>) - array.append(<6, 6, 6>) - array3 = [1, "Rank B", "Rank A"] - for elem in array3: - Msg(Everyone, elem) \ No newline at end of file diff --git a/Examples/attributes.owpy b/Examples/attributes.owpy deleted file mode 100644 index 2277c4d..0000000 --- a/Examples/attributes.owpy +++ /dev/null @@ -1,10 +0,0 @@ -Rule "Attributes" - Event - On Each Player - All - All - - Conditions - Position Of(Event Player).x < 10 - Event Player.moving - Event Player.jumping \ No newline at end of file diff --git a/Examples/basic.owpy b/Examples/basic.owpy deleted file mode 100644 index 9ef1085..0000000 --- a/Examples/basic.owpy +++ /dev/null @@ -1,19 +0,0 @@ -Rule "My First Rule" - Event - On Global - All - All - - Conditions - All True - Array: All Players - Team: Team 2 - Condition: Has Spawned - Element: Current Array Element - == True - - Actions - pvar h@Event Player = 0 - h = 1 - b = h - c = pvar h \ No newline at end of file diff --git a/Examples/bezier.owpy b/Examples/bezier.owpy deleted file mode 100644 index ae0365f..0000000 --- a/Examples/bezier.owpy +++ /dev/null @@ -1,12 +0,0 @@ -Rule "Bezier Curve" - Event - On Global - Actions - a = 0 - b = 1 - c = floor(b) * 3 - Chase Global Variable At Rate - Variable: a - Destination: a[c] * ((1 - b % 1)^3) + (((a[1 + c] * 3) * 3) * b % 1) * ((1 - b % 1)^2) + ((a[2 + c * 3] * 3) * (b % 1)^2 * (1 - b % 1) + a[3 + c * 3]) * (b % 1) * 3 - Rate: 0.2 - Reevaluation: Destination And Rate \ No newline at end of file diff --git a/Examples/booleans.owpy b/Examples/booleans.owpy deleted file mode 100644 index f617052..0000000 --- a/Examples/booleans.owpy +++ /dev/null @@ -1,6 +0,0 @@ -Rule "Boolean Operators" - Event - On Global - - Actions - n = 1 and 2 or 3 and not 4 \ No newline at end of file diff --git a/Examples/chase.owpy b/Examples/chase.owpy deleted file mode 100644 index 888d4ce..0000000 --- a/Examples/chase.owpy +++ /dev/null @@ -1,9 +0,0 @@ -Rule "Chase Test" - Actions - pvar chase_var = 100 - Chase Global Variable At Rate - Variable: chase_var - Destination: 0 - Rate: -1 - Reevaluation: Destination And Rate - Set Move Speed(Event Player, chase_var) \ No newline at end of file diff --git a/Examples/comments.owpy b/Examples/comments.owpy deleted file mode 100644 index edf6821..0000000 --- a/Examples/comments.owpy +++ /dev/null @@ -1,11 +0,0 @@ -Rule "Ton commentaire n'est pas necessaire" - Event - On Global - Actions - /* We should ignore - all dis text */ - // x = 1 - Msg(Event Player, /* even inline comments - should work */ "Hello") - var = 1 // Yes, it is indeed - /* Comments are the best! */ \ No newline at end of file diff --git a/Examples/conditionals.owpy b/Examples/conditionals.owpy deleted file mode 100644 index 1857c0c..0000000 --- a/Examples/conditionals.owpy +++ /dev/null @@ -1,17 +0,0 @@ -Rule "If and Else" - Event - On Global - Actions - z = 1 - h = 2 - if z == 1: - z = 3 - y = 4 - elif h > 1: - h = 2 - y = 3 - y = 4 - elif h < 1: - z = 1 - else: - z = 'yes' \ No newline at end of file diff --git a/Examples/conditions.owpy b/Examples/conditions.owpy deleted file mode 100644 index 1595060..0000000 --- a/Examples/conditions.owpy +++ /dev/null @@ -1,9 +0,0 @@ -Rule "Multiple Conditions" - Event - On Global - Conditions - Distance Between - Event Player - <10, 20, 30> - <= 1.5 - 123 < 456 \ No newline at end of file diff --git a/Examples/const.owpy b/Examples/const.owpy deleted file mode 100644 index 27f2330..0000000 --- a/Examples/const.owpy +++ /dev/null @@ -1,7 +0,0 @@ -Rule "Constants for cleaner code!" - Event - On Each Player - Actions - const speed = 100 - Set Move Speed(Event Player, speed) - // speed = 150 // const is immutable, so this causes an error \ No newline at end of file diff --git a/Examples/contains.owpy b/Examples/contains.owpy deleted file mode 100644 index 414e9bf..0000000 --- a/Examples/contains.owpy +++ /dev/null @@ -1,6 +0,0 @@ -Rule "x in array?" - Event - On Global - Actions - a = Event Player in Everyone - b = 1 not in [1, 2, 3] \ No newline at end of file diff --git a/Examples/error_parameter.owpy b/Examples/error_parameter.owpy deleted file mode 100644 index 3dd4c7c..0000000 --- a/Examples/error_parameter.owpy +++ /dev/null @@ -1,5 +0,0 @@ -Rule "Wrong Parameter!" - Event - On Global - Actions - Set Facing(Event Player, Event Player.eyepos, "No") \ No newline at end of file diff --git a/Examples/for.owpy b/Examples/for.owpy deleted file mode 100644 index f6a69cd..0000000 --- a/Examples/for.owpy +++ /dev/null @@ -1,18 +0,0 @@ -Rule "For Loop" - Event - On Global - Actions - angles = [15, 30, 45, 60, 75, 90] - angles2 = range(15, 91, 15) - for ang in angles: - Set Facing - Event Player - Direction From Angles - horizontal: ang - vertical: 45 - To World - Msg(Everyone, "HEllo") - for i in range(3): - Msg(Everyone, i) - for player in Everyone: - Msg(player, "Hello") \ No newline at end of file diff --git a/Examples/func_args.owpy b/Examples/func_args.owpy deleted file mode 100644 index 10145af..0000000 --- a/Examples/func_args.owpy +++ /dev/null @@ -1,33 +0,0 @@ -// Functions can be used as rule factories -%create_portal(origin, destination, radius) - Rule "Create Portal" - Event - On Each Player - All - All - Actions - Create Effect - Visible: Event Player - Type: Good Aura - Color: Yellow - Position: origin - Radius: radius - Reeval: Visible To, Position, and Radius - Rule "Teleportation" - Event - On Each Player - All - All - Conditions - Event Player in Players In Radius - Center: origin - Radius: radius - Team: All - LOS: Surfaces - == True - Actions - Teleport - Event Player - destination - -create_portal(<0, 1, 2>, <3, 4, 5>, 10) \ No newline at end of file diff --git a/Examples/functions.owpy b/Examples/functions.owpy deleted file mode 100644 index 52edf00..0000000 --- a/Examples/functions.owpy +++ /dev/null @@ -1,13 +0,0 @@ -%event_func - Event - On Each Player - All - All -%add_rule(a, b, name_) - Rule "test" - event_func() - Actions - c = a + b -Rule "Function Demo" - event_func() -add_rule(1, 5, "Add Two") \ No newline at end of file diff --git a/Examples/imports.owpy b/Examples/imports.owpy deleted file mode 100644 index 5e25feb..0000000 --- a/Examples/imports.owpy +++ /dev/null @@ -1,5 +0,0 @@ -#import "lib/child" - -Rule "Debug Import" - Actions - debug_func("Hello!") \ No newline at end of file diff --git a/Examples/lib/child.owpy b/Examples/lib/child.owpy deleted file mode 100644 index 3f951a2..0000000 --- a/Examples/lib/child.owpy +++ /dev/null @@ -1,5 +0,0 @@ -#import 'lib2/child2.owpy' - -%debug_func(text) - Msg(Everyone, text) - nested(Lucio) \ No newline at end of file diff --git a/Examples/lib/lib2/child2.owpy b/Examples/lib/lib2/child2.owpy deleted file mode 100644 index 289b16a..0000000 --- a/Examples/lib/lib2/child2.owpy +++ /dev/null @@ -1,2 +0,0 @@ -%nested(hero_) - Set Hero(Event Player, hero_) \ No newline at end of file diff --git a/Examples/nested.owpy b/Examples/nested.owpy deleted file mode 100644 index ae6ad80..0000000 --- a/Examples/nested.owpy +++ /dev/null @@ -1,10 +0,0 @@ -Rule "Nested Blocks" - Event - On Global - Actions - if a == 1: - b = 2 - for i in range(4): - Msg(Everyone, i) - elif a == 2: - b = 3 \ No newline at end of file diff --git a/Examples/optional_args.owpy b/Examples/optional_args.owpy deleted file mode 100644 index 4158b0f..0000000 --- a/Examples/optional_args.owpy +++ /dev/null @@ -1,14 +0,0 @@ -%CreateEffect(pos, type?=Ring, color?=White) - Create Effect - Visible_To: Everyone - Type: type - Color: color - Position: pos - Radius: 1.5 - Reevaluation: Visible To - -Rule "Optional/Default Arguments" - Event - On Global - Actions - CreateEffect(<0,0,0>) \ No newline at end of file diff --git a/Examples/strings.owpy b/Examples/strings.owpy deleted file mode 100644 index 3077ff3..0000000 --- a/Examples/strings.owpy +++ /dev/null @@ -1,21 +0,0 @@ -Rule "String Builder" - Event - On Each Player - All - All - Actions - pvar money = 100 - test = "Hello" - Msg - Everyone - `Money: {}!` - pvar money - `#use ultimate ability, up` - `{}`(pvar money) - -/*%RuleFactory(name_) - Rule "My Custom " name_ - Event - On Global*/ - -//RuleFactory("Portal") \ No newline at end of file diff --git a/Examples/time.owpy b/Examples/time.owpy deleted file mode 100644 index cbdc554..0000000 --- a/Examples/time.owpy +++ /dev/null @@ -1,5 +0,0 @@ -Rule "Time Shorthands" - Actions - Wait(16ms) - Wait /* It takes a parameter, so indent if you please! */ - 0.35min \ No newline at end of file diff --git a/Examples/trigonometry.owpy b/Examples/trigonometry.owpy deleted file mode 100644 index dde8c85..0000000 --- a/Examples/trigonometry.owpy +++ /dev/null @@ -1,3 +0,0 @@ -Rule "Trigonometry In Vectors" - Actions - pvar vec1 = \ No newline at end of file diff --git a/Examples/variables.owpy b/Examples/variables.owpy deleted file mode 100644 index 36002dd..0000000 --- a/Examples/variables.owpy +++ /dev/null @@ -1,6 +0,0 @@ -Rule "Variables" - Event - On Global - - Actions - pvar h@Event Player = 1 \ No newline at end of file diff --git a/Examples/vectors.owpy b/Examples/vectors.owpy deleted file mode 100644 index b2f0779..0000000 --- a/Examples/vectors.owpy +++ /dev/null @@ -1,9 +0,0 @@ -Rule "Variables & Vectors" - Actions - first_Vector = Vector(1, 2, 3) - gvar vec2 = Vector - X: 1 - 2 - this_is_a_comment_lol_gottem: 3 - pVar CoolV3ctor = <1, 2, 3> - // Vectors can span multiple lines \ No newline at end of file diff --git a/Examples/while.owpy b/Examples/while.owpy deleted file mode 100644 index 1f7b49d..0000000 --- a/Examples/while.owpy +++ /dev/null @@ -1,7 +0,0 @@ -Rule "While Loop" - Event - On Global - Actions - n = 0 - while n < 5: - n += 1 \ No newline at end of file diff --git a/OWScript/AST.py b/OWScript/AST.py index d20c1ae..1f37643 100644 --- a/OWScript/AST.py +++ b/OWScript/AST.py @@ -421,7 +421,9 @@ def __init__(self, elements=None): self.elements = elements or [] def append(self, tp, elem): - elem = Raw(code=tp.visit(elem, tp.scope)) + elem = tp.visit(elem, tp.scope) + if type(elem) != Object: + elem = Raw(code=elem) self.elements.append(elem) def index(self, elem): @@ -450,19 +452,6 @@ class Compare(BinaryOp): class Assign(BinaryOp): pass -# class GlobalVar(Data): -# vartype = 'global' - -# class PlayerVar(Data): -# vartype = 'player' -# def __init__(self, name, player=None): -# super().__init__(name) -# self.player = player or Constant(name='Event Player') -# class VarType: -# # Compares whether a value is a GlobalVar or PlayerVar -# def __eq__(self, other): -# return other in (GlobalVar, PlayerVar) - class GlobalVar(AST): def __init__(self, letter, index=None): self.letter = letter @@ -579,7 +568,7 @@ def __init__(self, name, body): def __repr__(self): return 'class {}'.format(self.name) -class Object(AST): +class Object(): def __init__(self, type_): self.type = type_ self.env = {} diff --git a/OWScript/Importer.py b/OWScript/Importer.py index 3f97df0..ab34b6d 100644 --- a/OWScript/Importer.py +++ b/OWScript/Importer.py @@ -1,19 +1,14 @@ -from . import Errors from .Lexer import Lexer from .Parser import Parser def import_file(path): - error_text = Errors.TEXT with open(path) as f: text = f.read() + '\n' try: - Errors.TEXT = text lexer = Lexer(text=text) tokens = lexer.lex() parser = Parser(tokens=tokens) tree = parser.script() - Errors.TEXT = error_text return tree except Exception as ex: - Errors.TEXT = error_text raise ex \ No newline at end of file diff --git a/OWScript/Parser.py b/OWScript/Parser.py index 20bcc5d..0d6e8a3 100644 --- a/OWScript/Parser.py +++ b/OWScript/Parser.py @@ -187,6 +187,11 @@ def ruledef(self): var = Var(self.curvalue, type_=Var.STRING) var._pos = self.curpos name.append(var) + elif self.curtype == 'DOT': + self.eat('DOT') + node = Attribute(name=self.curvalue, parent=name.pop()) + node._pos = self.curpos + name.append(node) else: raise Errors.ParseError('Unexpected token \'{}\' in rule name'.format(self.curvalue), pos=self.curpos) self.eat(self.curtype) diff --git a/OWScript/Transpiler.py b/OWScript/Transpiler.py index 345ad62..c1a5e78 100644 --- a/OWScript/Transpiler.py +++ b/OWScript/Transpiler.py @@ -194,7 +194,6 @@ def visitImport(self, node, scope): if path not in self.imports: self.imports.add(path) result = Importer.import_file(path) - print(result) else: self.logger.info('Skipping duplicate import {}'.format(path)) result = Script() @@ -289,6 +288,7 @@ def visitOWID(self, node, scope): if not var: raise Errors.NameError('\'{}\' is undefined'.format(child.name), pos=node._pos) node.children[index] = Raw(code=var.data.letter) + print(var.data.letter) continue values = list(map(lambda x: x.replace(',', ''), flatten(arg.get_values()))) value = self.visit(child, scope).upper() @@ -391,6 +391,8 @@ def visitAssign(self, node, scope): raise Errors.SyntaxError('Cannot assign value to attributes') resolved = self.resolve_name(value, scope) var = Var(name=node.left.name, type_=Var.INTERNAL, value=resolved) + if type(resolved) == String: + var.type = Var.STRING obj.env.assign(node.left.name, var) return code else: @@ -623,7 +625,7 @@ def visitArray(self, node, scope): else: elements = [] for elem in node.elements: - if type(elem) in (String, Constant): + if type(elem) in (String, Constant, Var): elements.append(Constant(name='Null')) else: elements.append(elem) @@ -634,35 +636,37 @@ def visitArray(self, node, scope): code += 'Empty Array, ' + '), '.join(self.visit(elem, scope) for elem in elements) + ')' return code - def visitItem(self, node, scope): + def visitItem(self, node, scope, visit=True): """An item is accessing an element of an array.""" # Try to access an array element by interpreting the number? if type(node.index) == Number and type(node.parent) == Var: var = scope.get(node.parent.name) if not var: raise Errors.NameError('\'{}\' is undefined'.format(node.parent.name), pos=node.parent._pos) - try: - index = int(node.index.value) - array = var.value - assert type(array) == Array - if not 0 <= index < len(array): - return self.visit(Number(value='0'), scope) + index = int(node.index.value) + array = var.value + if not type(array) == Array: + raise Errors.SyntaxError('Cannot get item from non-array \'{}\''.format(type(array).__name__), pos=node.parent._pos) + if not 0 <= index < len(array): + return self.visit(Number(value='0'), scope) + else: + if not visit: + return var.value[index] + if var.type == Var.GLOBAL: + return 'Value In Array(Value In Array(Global Variable({})), {}, {})'.format(var.data.letter, var.data.index, index) + elif var.type == Var.PLAYER: + player = self.visit(var.data.player if node.parent.player is None else node.parent.player, scope) + return 'Value In Array(Value In Array(Player Variable({}, {})), {}, {})'.format(player, var.data.letter, var.data.index, index) else: - if var.type == Var.GLOBAL: - return 'Value In Array(Value In Array(Global Variable({})), {}, {})'.format(var.data.letter, var.data.index, index) - elif var.type == Var.PLAYER: - player = self.visit(var.data.player if node.parent.player is None else node.parent.player, scope) - return 'Value In Array(Value In Array(Player Variable({}, {})), {}, {})'.format(player, var.data.letter, var.data.index, index) - else: - return self.visit(var.value[index], scope) - except AssertionError: - raise Errors.SyntaxError('Cannot get item from non-array type {}'.format(type(var.value)), pos=node.parent._pos) + return self.visit(var.value[index], scope) else: try: - index = int(scope.get(node.index.name).value) + index = scope.get(node.index.name) + assert hasattr(index, 'value') + index = int(index.value) item = scope.get(node.parent.name).value[index] - return self.visit(item, scope) - except (ValueError, TypeError, AttributeError): + return self.visit(item, scope) if visit else item + except (ValueError, TypeError, AssertionError): array = self.visit(node.parent, scope) index = self.visit(node.index, scope) return 'Value In Array({}, {})'.format(array, index) @@ -674,12 +678,17 @@ def visitAttribute(self, node, scope): parent = scope.get(node.parent.name).value else: parent = node.parent + if type(parent) == Item: + item = self.visitItem(parent, scope, visit=False) + node.parent = item + result = self.visitAttribute(node, scope) + return result try: attribute = getattr(parent, attr) except AttributeError: - name = node.parent.name - if type(parent) != Object: - name = parent.name.title() + name = node.parent + if type(parent) != Object and type(name) == str: + name = name.title() raise Errors.AttributeError('\'{}\' has no attribute \'{}\''.format(name, attr), pos=node._pos) if type(parent) == Object: code = self.visit(attribute, parent.env) @@ -692,9 +701,10 @@ def visitCall(self, node, scope): parent = node.parent base_node = self.base_node(node) var = scope.get(base_node.name) + is_object = type(var) == Var and var.type == Var.OBJECT lines = [] # Handle method (attribute access followed by a call) - if type(parent) == Attribute and not var.type == Var.OBJECT: + if type(parent) == Attribute and not is_object: if var is not None: method = getattr(var.value, parent.name) else: @@ -736,11 +746,11 @@ def visitCall(self, node, scope): var = Var(name=child.name, type_=Var.METHOD, value=child) scope.assign(var.name, var) obj.env = scope - init = obj.env.get('init').value + init = obj.env.get('init') if init is not None: obj_var = Var(name=obj.name, type_=Var.OBJECT, value=obj) scope.assign('this', obj_var) - init_call = Call(args=node.args, parent=init) + init_call = Call(args=node.args, parent=init.value) self.visit(init_call, scope) return obj elif var.type != Var.BUILTIN: diff --git a/README.md b/README.md deleted file mode 100644 index f02e7d6..0000000 --- a/README.md +++ /dev/null @@ -1,320 +0,0 @@ -# OWScript -Python-like scripting language which transpiles into Overwatch Workshop script rulesets. - -Setup -===== -## Installation & Usage -1. Install Python with `pip` if you have not done so already. -2. Run the command `python OWScript.py` with the following arguments: -- `input` Path to input file, blank for stdin -- `-m | --min` Optional: minifies the output by stripping whitespace -- `-s | --save [FILE]` Optional: saves to the target output file instead of stdout -- `-c | --copy` Optional: copies code to clipboard (must have *pyperclip* installed: `pip install pyperclip`) - -**NPM Integration** by @MatthewSH -[OWScript NPM Package](https://www.npmjs.com/package/owscript) - -## Syntax Highlighting - -**Visual Studio Code** -Download the latest [OWScript extension](https://marketplace.visualstudio.com/items?itemName=adapap.owscript) from the marketplace. - -**Sublime Text 3** -In the `Syntax/` folder, you can find the raw Iro code which I used to generate a Sublime Text file with modifications. You can directly import the `OWScript.sublime-syntax` file by putting it in your ST3 `User` folder. - -Projects -======== -- **Cookie Clicker** [![Discord Shield](https://discordapp.com/api/guilds/572937743114436619/widget.png?style=shield "Made by @adapap")](https://discord.gg/5Nst8g5) -- [**Upgrade Shop**](https://github.com/overwatchworkshop/upgrade-shop) - -Documentation -============= -*See example code in the `Examples/` folder.* - -**Input** `*.owpy` - -**Output** `*.ows` (standard as agreed upon voting results) - -**Semantic** -* [Values / Actions](#values--actions) -* [Annotations / Comments](#annotations--comments) -* [Assignment / Arithmetic](#assignment--arithmetic) -* [Logic](#logic) -* [Functions](#functions) -* [Loops](#loops) -* [Attributes / Methods](#attributes--methods) -* [Imports](#imports) - -**Data Types & Structures** -* [Variables](#variables) -* [Strings](#strings) -* [Vectors](#vectors) -* [Time](#time) -* [Arrays](#arrays) -* [Alias Table](#alias-table) - -## Notes -- Be sure not to conflict variable/function names with built-in functions such as `Add`, `Wait`, or `Damage`. -- Many commonly used values have been aliased in order to reduce verbosity. See the table at the bottom for the list of built-in aliases. -- If you have an unexpected error/suggestion, feel free to submit an issue - - Alternatively, I am open to pull requests if you want to contribute - -## Values / Actions -Values and actions are the main types that come up when working in the Workshop. In general, anything with parameters can be written in two ways (which can be interchanged): - -**Indented Blocks** -``` -Round - Count Of - All Players - Team 2 - Up -``` -**Parenthesized / Literal** -``` -Round(Count Of(All Players(Team 2)), Up) /* Same as output */ -``` - -## Annotations / Comments -Annotations are ways to remind yourself what the type of a variable. It is written as text followed by a colon. Comments are written as most traditional languages (`// line comment`, `/* multiline comment */`). Both are ignored in the code output. -``` -Event - /* Set up event attributes */ - Event_Type: Ongoing - Event Player // Event_Type is an annotation (cannot have spaces!) - Annotation_2: All -``` - -## Assignment / Arithmetic -Assignment (regular and augmented), as well as most arithmetic operators work as they do in Python or other traditional programming languages. Operators include: `+ - * / ^ %` as well as the augmented equivalents: `+= -= *= /= ^= %=` -``` -a = 1 -a += -1 -a *= 3 -a = a ^ (a + a) % 3 -``` - -## Logic -Boolean logic is implemented exactly as in Python. The operators `and`, `or`, and `not` function as C-style `&&`, `| -|`, and `!`. Comparison operators include the traditional `<`, `>`, `<=`, `>=`, `!=`, `==` as well as containment operators `in` and `not in`. -``` -b = True and not True -Count Of - Everyone -== 12 // The reason why == 12 is here is to distinguish between the constant "Everyone" and the value "Count Of". -// You can choose to write this expression inline for less ambiguity: -Count Of(Everyone) == 12 -y = Event Player in Players In Radius(<1, 2, 3>, 15) -``` - -## Variables -Variables are ways to reference values using a name. Their type is stored when they are defined. - -**Global Variables (default)** -``` -gvar hero_index = 1 -global_time = 60s // default type is global -``` -**Player Variables** -``` -pvar score = 2 // pvar is only needed when defining a variable -pvar score@Event Player = 3 // Event Player (default) is the player which the variable will be bound to -score += 1 // modifies the pvar score -``` -**Const** -``` -const cost = 100 -/* const cannot be modified and directly outputs the value, -rather than outputting Value In Array(...) */ -``` - -Using the technique from [@ItsDeltin](https://github.com/ItsDeltin), the limit to -the number of variables that can be created is the maximum length of an array (\~1000 variables). - -## Strings -String literals are enclosed with quotes. Formatted strings are made with enclosing backticks, using `{}` whenever you want to use a variable instead of a string constant. -``` -Rule "String Demo" - Event - On Each Player - All - All - Actions - Msg(Event Player, "Hello") // Alias for Small Message - Big Msg(Event Player, `Money: {}`(pvar money)) // Example formatted string - Small Msg(Event Player, `Unlocked {} / {}: Victory!`(5, 5)) // More advanced formatted string -``` - -## Vectors -Vectors can be created in 3 ways as well: - -**Literal** -``` -Vector(1, 2, 3) -``` -**Block** -``` -Vector - 1 - 2 - 3 -``` -**Idiomatic** -``` -<1, 2, 3> -``` - -## Time -Time can be represented in *ms*, *s*, or *min* as a shorthand for the number value. -``` -Wait(1s + 500ms) -Wait - 0.025min -``` - -## Arrays -Arrays are created, modified, and accessed as in Python notation. Arrays can be nested inside the global/player variables, which allows for more complex operations on arrays. (No slice support yet) - -**Creation** -``` -empty = [] -costs = [5, 15, 30] -``` -**Modification** -``` -costs[1] = 20 -total = costs[0] + costs[1] + costs[2] -``` - -## Functions -Functions allow you to write a block of code once and reuse it many times. They can be used to generate HUDs like a macro or used as a rule factory. All functions must be defined before they are called, and they must be defined at the top level scope (same as where rules are defined). Parameters can be optional, denoted by `?`, which sets the value to `Null` when omitted. Alternatively, specify a default value e.g. `pos?=Event Player.pos`. - -*Note: Functions can access global-scope variables; however, the global scope cannot access variables defined locally in functions* - -``` -%event_func - Event - On Each Player - All - All -%add_rule(a, b, name_) - Rule name_ - event_func() - c = a + b -%say(text, who?=Everyone) // optional parameter, default to Everyone - Msg(who, text) -Rule "Function Demo" - event_func() - Actions - say("Thanks!") -add_rule(1, 5, "Add Two") -``` -**Builtin Functions** - -|Function|Parameters|Description| -|:------:|----------|-----------| -|range|*stop* or *start[, stop[, step]]*|Creates an array of numbers from start to stop (exclusive), counting by step| -|floor|*n*|Rounds a numeric expression down to the nearest integer -|ceil|*n*|Rounds a numeric expression up to the nearest integer -|get_map|Returns the current map ID. This can be compared with map names which alias to their respective ID: `get_map() == Dorado`. For the list of maps and their corresponding IDs, please review [@Xerxes post](https://us.forums.blizzard.com/en/overwatch/t/workshop-resource-map-identifier-map-detection-script-v2-0-only-2-actions/341132). - -## Loops -The while loop is syntactic sugar for using the `Loop` action in the Workshop. At the moment, only use while loops if the purpose of the rule is solely to repeat code until a condition is met. -``` -while pvar life > 10: - Damage(Event Player, Null, 10) -``` -A for loop lets you iterate over custom iterables, such as an array of values, a range, or workshop values such as All Players. -``` -for i in range(1, 10, 2): - Msg(Event Player, i) -for y in [Genji, Tracer, Widowmaker]: - Kill - Players On Hero(y) -``` - -## Attributes / Methods -Attributes are properties of an object that can be accessed using the dot operator `.`, which refers to the value before it in order to access a property. A method is simply an attribute followed by a call, which has parameters. Refer to the table below for builtin attributes and methods. -``` -pvar xpos = Event Player.x // Attribute -y = Victim.jumping and Attacker.moving -scores.append(123) // Method -``` - -**Attribute Table** - -|Name|Description| -|:--:|-----------| -|x|The X component of a vector| -|y|The Y component of a vector| -|z|The Z component of a vector| -|facing|The facing direction of a player| -|pos|The position of a player| -|eyepos|The eye position of a player| -|hero|The hero of a player| -|team|The team of a player| -|jumping|Check if a player is holding the Jump key| -|crouching|Check if a player is holding the Crouch key| -|moving|Check if the speed of a player is non-zero| - -**Method Table** - -|Name|Parameters|Description| -|:--:|:--------:|-----------| -|append|*element*|Appends an element to the given array| -|index|*element*|Returns the numeric index of an array element| -|halt||Mitigates the motion of a player| - -## Alias Table -|Alias|Output| -|-----|------| -|Abs|Absolute Value| -|Any True|Is True For Any| -|All True|Is True For All| -|Chateau Guillard|Château Guillard| -|Cos|Cosine From Degrees| -|Cosr|Cosine From Radians| -|Cur Elem|Current Array Element| -|Filter|Filtered Array| -|Everyone|All Players(Team(All))| -|LOS|Is In Line Of Sight| -|Index|Index Of Array Value| -|Lucio|Lúcio| -|On Each Player|Ongoing - Each Player| -|On Global|Ongoing - Global| -|Players In Radius|Players Within Radius| -|Round|Round To Integer| -|Sin|Sine From Degrees| -|Sinr|Sine From Radians| -|Torbjorn|Torbjörn| - -## Imports -OWScript allows bigger scripts and scripts that use common funcitonality to be broken up into modules and imported into a base file. All the "imported" files are evaluated into a parse tree, which is transpiled to workshop code by the base file. - -You can import a file by using the `#import 'filepath'`. If the file is in a folder, put the relative path to the file as shown in the examples below: - -**Imported File** `lib/functions.owpy` -``` -%CreateEffect(pos, type, color) - Create Effect - Visible_To: Everyone - Type: type - Color: color - Position: pos - Radius: 1.5 - Reevaluation: Visible To -``` - -**Imported File** `src/setup.owpy` -``` -Rule "Setup Effects" - Event - On Global - Actions - CreateEffect(<0,0,0>, Ring, Red) -``` - -**Base File** `src/game.owpy` -``` -#import 'lib/functions' -#import 'src/setup' -``` \ No newline at end of file diff --git a/Syntax/Comments.tmPreferences b/Syntax/Comments.tmPreferences deleted file mode 100644 index 38f1de6..0000000 --- a/Syntax/Comments.tmPreferences +++ /dev/null @@ -1,34 +0,0 @@ - - - - - name - Comments - scope - source.OWScript - settings - - shellVariables - - - name - TM_COMMENT_START - value - // - - - name - TM_COMMENT_START_2 - value - /* - - - name - TM_COMMENT_END_2 - value - */ - - - - - \ No newline at end of file diff --git a/Syntax/OWScript.sublime-syntax b/Syntax/OWScript.sublime-syntax deleted file mode 100644 index 78ae670..0000000 --- a/Syntax/OWScript.sublime-syntax +++ /dev/null @@ -1,176 +0,0 @@ -%YAML 1.2 ---- -name: OWScript -scope: source.OWScript -file_extensions: [ owpy ] - -contexts: - main: - - match: '(\%([_a-zA-Z][_a-zA-Z0-9]*))(?=\()' - push: param_list - captures: - 0: entity.name.function.OWScript - - match: '(\%([_a-zA-Z][_a-zA-Z0-9]*)\b)' - captures: - 0: entity.name.function.OWScript - - match: '(\s+)' - captures: - 0: empty.OWScript - push: - - match: '(?=\S)' - pop: true - captures: - 0: empty.OWScript - - match: '(.)' - captures: - 0: empty.OWScript - - match: '(;)' - captures: - 0: punctuation.OWScript - - match: '(\b([_a-zA-Z][_a-zA-Z0-9]*)\:\s+(?=.))' - push: expr - captures: - 0: comment.annotation.OWScript - - include: rule - param_list: - - match: '(\))' - pop: true - captures: - 0: punctuation.OWScript - - match: '(\()' - captures: - 0: punctuation.OWScript - - match: '(,)' - captures: - 0: punctuation.OWScript - - match: '([_a-zA-Z][_a-zA-Z0-9]*)' - captures: - 0: variable.parameter.OWScript - - include: multiline_comment - rule: - - match: '(?i)(Rule)' - captures: - 0: storage.type.rule.OWScript - - include: expr - expr: - - match: '(\n)' - pop: true - captures: - 0: empty.OWScript - - match: '(\s+)' - captures: - 0: empty.OWScript - push: - - match: '(?=\S)' - pop: true - captures: - 0: empty.OWScript - - match: '(.)' - captures: - 0: empty.OWScript - - match: '(//.*)' - captures: - 0: comment.OWScript - - include: multiline_comment - - match: '([_a-zA-Z][_a-zA-Z0-9]*)(?=\()' - push: arg_list - captures: - 0: variable.function.OWScript - - match: '\b(Team 1|Team 2)\b' - captures: - 0: constant.language.OWScript - - match: '(?i)\b(?=|>|!=|=|\+|\-|\*|\/|\^|%)(?=[^,\)\]]+)' - captures: - 0: keyword.operator.OWScript - vector : - - match: '(>)' - pop: true - captures: - 0: punctuation.vector.OWScript - - match: '(,)' - captures: - 0: punctuation.OWScript - - include: expr - arg_list: - - match: '(\))' - pop: true - captures: - 0: punctuation.OWScript - - match: '(\()' - captures: - 0: punctuation.OWScript - - match: '(,)' - captures: - 0: punctuation.OWScript - - include: expr - fstring: - - match: '(`)' - pop: true - captures: - 0: string.OWScript - - match: '(\{)' - captures: - 0: constant.language.OWScript - push: - - match: '(\})' - pop: true - captures: - 0: constant.language.OWScript - - match: '(.)' - captures: - 0: constant.language.OWScript - - match: '([^\x{007b}\x{007d}\x{0060}]*)' - captures: - 0: string.OWScript - multiline_comment: - - match: '(\s*/\*)' - captures: - 0: comment.OWScript - push: - - match: '(\*/)' - pop: true - captures: - 0: comment.OWScript - - match: '(.)' - captures: - 0: comment.OWScript diff --git a/lib/effects.owpy b/lib/effects.owpy new file mode 100644 index 0000000..f696e2d --- /dev/null +++ b/lib/effects.owpy @@ -0,0 +1,53 @@ +%Portal(pos, type, color, text) + Create Effect + Visible_To: Everyone + Type: type + Color: color + Position: pos + Radius: 1.5 + Reevaluation: Visible To + GameText(Everyone, text, pos + Up, 1.5) +%UpgradePortal(pos) + Portal(pos, Good Aura, Yellow, "Upgrades") +%ShopPortal(pos) + Portal(pos, Good Aura, Purple, `Current Boss`) +%NextBossPortal(pos, text) + Portal(pos, Good Aura, Blue, text) +%UpgradeEffect(pos, color) + Create Effect + Visible_To: Everyone + Type: Orb + Color: color + Position: pos + Radius: 1.5 + Reevaluation: Visible To +%UpgradeText(text, pos, cost_var) + GameText(Event Player, `{}: {}`(text, cost_var), pos + Up * 0.5, 1.5) +%SaveIcon(pos, icon, color) + Create Icon + Visible_To: Filter + Everyone + LOS + pos + Cur Elem + Barriers Do Not Block LOS + Position: pos + Icon: icon + Reevaluation: Visible To + Icon_Color: White + Show_When_Offscreen: False + Create Effect + Visible_To: Everyone + Type: Ring + Color: color + Position: pos + Radius: 1 + Reevaluation: Visible To Position And Radius + +class Upgrade: + %init(name, rate, cost, pos, color) + this.name = name + this.rate = rate + this.pos = pos + this.color = color + this.cost = cost \ No newline at end of file diff --git a/lib/events.owpy b/lib/events.owpy new file mode 100644 index 0000000..ad92041 --- /dev/null +++ b/lib/events.owpy @@ -0,0 +1,8 @@ +%Global + Event + On Global +%EachPlayer(team_?=All) + Event + On Each Player + team_ + All \ No newline at end of file diff --git a/lib/gui.owpy b/lib/gui.owpy new file mode 100644 index 0000000..eeed396 --- /dev/null +++ b/lib/gui.owpy @@ -0,0 +1,34 @@ +%GameText(text, pos, scale?=1.5, who?=Everyone) + World Text + Visible_To: who + Header: text + Position: pos + Scale: scale + Clipping: Clip Against Surfaces + Reevaluation: Visible To And String +%CodeText(code, pos, scale?=1.0, who?=Event Player) + GameText(who, `Save: {} + {} + {} + {} + {}`(code[0], code[1], code[2], code[3], code[4]), pos, scale) +%BigHud(loc, text, color?=White) + Hud + Visible_To: Event Player + Header: text + Subheader: Null + Text: Null + Location: loc + Sort_Order: 0 + Header_Color: color + Subheader_Color: White + Text_Color: White + Reevaluation: Visible To And String +%SmallHud(loc, text, color?=White) + Hud + Visible_To: Event Player + Header: Null + Subheader: Null + Text: text + Location: loc + Sort_Order: 999 + Header_Color: White + Subheader_Color: White + Text_Color: color + Reevaluation: Visible To And String \ No newline at end of file diff --git a/lib/util.owpy b/lib/util.owpy new file mode 100644 index 0000000..b65fea4 --- /dev/null +++ b/lib/util.owpy @@ -0,0 +1,31 @@ +class Sound: + %PlaySound(type) + Play Effect + Visible_To: Event Player + Type: type + Color: White + Position: Event Player + Radius: 50 + %Success() + this.PlaySound(Buff Explosion Sound) + %Fail + this.PlaySound(Debuff Impact Sound) + %Woosh + this.PlaySound(Ring Explosion Sound) + %Boom + this.PlaySound(Explosion Sound) + +class Messager: + %MissingFunds() + Big Msg(Event Player, `Go Find More Money`) + +%Warp(player, destination, facing) + Teleport(player, destination) + Set Facing + Player: Event Player + Direction: Vector Towards + Start: Event Player + End: facing + Relative: To World + Wait(0.1s) + Event Player.halt() \ No newline at end of file