diff --git a/assets/images/destroyers/puzzle_buster.png b/assets/images/destroyers/puzzle_buster.png new file mode 100644 index 0000000..7d5076b Binary files /dev/null and b/assets/images/destroyers/puzzle_buster.png differ diff --git a/assets/images/destroyers/puzzle_buster.png~ b/assets/images/destroyers/puzzle_buster.png~ new file mode 100644 index 0000000..10a9e93 Binary files /dev/null and b/assets/images/destroyers/puzzle_buster.png~ differ diff --git a/assets/images/destroyers/sentry_buster.png b/assets/images/destroyers/sentry_buster.png new file mode 100644 index 0000000..e24b74b Binary files /dev/null and b/assets/images/destroyers/sentry_buster.png differ diff --git a/assets/images/destroyers/sentry_buster.png~ b/assets/images/destroyers/sentry_buster.png~ new file mode 100644 index 0000000..118027a Binary files /dev/null and b/assets/images/destroyers/sentry_buster.png~ differ diff --git a/assets/images/destroyers/sentry_friendly.png b/assets/images/destroyers/sentry_friendly.png new file mode 100644 index 0000000..118027a Binary files /dev/null and b/assets/images/destroyers/sentry_friendly.png differ diff --git a/assets/images/destroyers/sentry_friendly.png~ b/assets/images/destroyers/sentry_friendly.png~ new file mode 100644 index 0000000..f5c89a3 Binary files /dev/null and b/assets/images/destroyers/sentry_friendly.png~ differ diff --git a/assets/puzzles.txt b/assets/puzzles.txt index e6171f9..94baaac 100755 --- a/assets/puzzles.txt +++ b/assets/puzzles.txt @@ -1,13 +1,17 @@ P6;Start of it all;Move your puzzle cell with WASD.;H;<;eJxTSs/ILy6pMahJzS0oqaxxrHFS0lEqT8zJQRJyAwoRoQwoZKSjVFBaVZWTiiGMptZZSccUh2BiaUl+fFpOYjpB27CaYKQTrZSal5pbqaRjoKMElgBqdlTSqVYqzsxJzStRskpLzClOrQVJOynFYnGcE3H+xR4sADoBdsM=; -VX;Crash Course;Locks can only be opened when you have a key.;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NycEgllpbkx6flJKaTrpVMG8mTItMyJC7V5AaPdWS6pKC0qionlY5eyE4dHB4f+jFOZjbIyU/OHs3gQy+6yXVJXmouhKtUnJmTmleiZJWWmFOcSif/pCZmxyOcMOCBMeRTwVDPh6O5fjTXD1yupyQwBk+aGAplAJUtiwUASZsWEA==;eJyrVnJUslIqKUhWqgUAElEDQw==;9;13; +VX;Extra Help;The push cell can be moved around. Use it to kill the enemies without dying.;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyqCo1ahmaFBKXanIj1rrE0pL8+LScxHQyjC0orarKSSVLY3EGOV7MS82FcJWKM3NS80qUrNISc4pT6ROI1LGdvJwyvNMgna0bCmXcULYsFgApRUUJ;eJyrVnJUslIqKUhWqgUAElEDQw==;13;5; VX;Roundabout;Weak enemies don't kill you when you kill them.;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyqCo1FCxD4lJNbvBYl1hakh+flpOYToaxBaVVVTmp9PRHamJ2fGpeai6VA2HwRAedrRvq+W80t9MnocOznFJxZk5qXomSVVpiTnHqaK4fkqlgKOR6KlsWCwBgcdE4;eJyrVnJUslIqKUhWqgUAElEDQw==;9;; -VX;Traffic;Don't kill the friend cells!;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyqCo1ahmaFBKXanIj1rrE0pL8+LScxHQyjC0orarKSaWjP9KKMlPzUoaCheRliOGd1Ohs3VAoygZNuTlaSg9q68h1SV5qLoSrVJyZk5pXomSVlphTnDrIC8/R0nrkWTcUCtChbFksAFGuCpU=;eJyrVnJUslIqKUhWqgUAElEDQw==;13;9; VX;Flagging Along;Destroy the weak enemy and then move into the flag to win!;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyRqWIkCIzEJG4o3JEypEXQfhMLCitqspJpacXUhOz41PzUnPpGW5pOYnpgyK4R+XoVbyMShEViLEABzU68Q==;eJyrVnJUslIqKUhWqgUAElEDQw==;13;5; +VX;Crash Course;Locks can only be opened when you have a key.;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NycEgllpbkx6flJKaTrpVMG8mTItMyJC7V5AaPdWS6pKC0qionlY5eyE4dHB4f+jFOZjbIyU/OHs3gQy+6yXVJXmouhKtUnJmTmleiZJWWmFOcSif/pCZmxyOcMOCBMeRTwVDPh6O5fjTXD1yupyQwBk+aGAplAJUtiwUASZsWEA==;eJyrVnJUslIqKUhWqgUAElEDQw==;9;13; +VX;Traffic;Don't kill the friend cells!;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyqCo1ahmaFBKXanIj1rrE0pL8+LScxHQyjC0orarKSaWjP9KKMlPzUoaCheRliOGd1Ohs3VAoygZNuTlaSg9q68h1SV5qLoSrVJyZk5pXomSVlphTnDrIC8/R0nrkWTcUCtChbFksAFGuCpU=;eJyrVnJUslIqKUhWqgUAElEDQw==;13;9; VX;Devolving;Balanced Enemies turn into Weak Enemies on death.;eJztU7sKgDAM/JfMHZz9lSISNT4wtoVWRMV/d3DQWUprwfE4yOWSOymh67V1IDKxHwJoMm69QCEkLMjslUpB7AG9cd+Rw9npsmXsXow187YxBfQxkmf33/lDYLkUise6Hv+WR825oumCYAcm5SBvkS2F8VMho6qpKe81oh8k+SSkUHzPYsUJ2AHPWA==;eJyrVnJUslIqKUhWqgUAElEDQw==;9;; -VX;Extra Help;The push cell can be moved around. Use it to kill the enemies without dying.;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyqCo1ahmaFBKXanIj1rrE0pL8+LScxHQyjC0orarKSSVLY3EGOV7MS82FcJWKM3NS80qUrNISc4pT6ROI1LGdvJwyvNMgna0bCmXcULYsFgApRUUJ;eJyrVnJUslIqKUhWqgUAElEDQw==;13;5; VX;Two in One;Strong enemies turn into normal enemies when killed;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyqCo1FCxD4lJNbvBYl1hakh+flpOYToaxBaVVVTmpZGksziBDW3FJUX5eenxqXmoulUNh8MQHna0bChmQypbFAgBjf46r;eJyrVnJUslIqKUhWqgUAElEDQw==;9;5; VX;3 Keys, 3 Enemies;The balanced enemy (top) turns into a weak enemy when killed. The mobile enemy (middle) kills what its pushed into.;eJztlk0OwiAQRu/CmoX3IU1D60hNh58IxFjj3V10Y1y4mEAtlCX5wjwGyAMhmJqsD4yf+PPFGWgXHuug44LdJWLSqMG+oo9hsuywOBmD7S8oFaGsi8uCQJiIdpw3bH+QKM0I5x4MaEqBGRLv+n7Ov25cBsMQaTkab7I+GI64kuT6ytE28U3Qdrgi/DS7i35qit4rrnSJVdxa+ZerZj9vnREF7cPNGkX+ejdD/x1XgsZKhnVvqpXSzw==;eJyrVnJUslIqKUhWqgUAElEDQw==;13;; VX;Kablooey;The explosive enemy deletes everything surrounding it.;eJztVNsKwjAM/RbzXKS+7lfGkK5Nt0Jv9KJu4r87qYhPA8cUFB9PTpKTHELqGrrexQSEkvOFABqfhgIaUsORab0q9Q1iT3A1bk7OoikQotJoE1SS6YifyZwZjOXk9lKzbsG+Po+jxkWFsX+dwpPXLqpDUYTAhMoRqt2UKCXyNDEW4y1C6ZYSaAcfnMh88qW02lAgwFXgWbNwN4uAce3k3gP6iFm4wKxw5r3W/6/zJz7JymLNFWCe1LM=;eJyrVnJUslIqKUhWqgUAElEDQw==;9;5; VX;Back From The Dead;Use the checkpoints by walking into them, enemies can't respawn so use that to your advantage!;eJztlk0OwiAQhe/CehYad71K0xCsU2pKgfATYxvvLlEXrFyQhortcngD30CYl6lrwntlHYEDzA8gOGp3fwcN1OTGhFhUSoS1PbaDVlcZ9h5hjmJq0KIjlTMeIV5Hyc4CL6TqmLBBeuVRoz65OarO+kRRuJi2WRzzTtFOMJ5wrPbTJDDjPVI164ySPDQKjjmxaV3x3/8tM64EP8sLQzZ8bYTdr38al1jJSg5YirY79eq4EswzHs5PWx3OmydxUUOK;eJyrVnJUslIqKUhWqgUAElEDQw==;13;9; VX;Dumpster Diving;Trash Cells delete everything that moves into them. Move the mobile enemy into the trash cells to win!;eJyLjlZKz8gvLlHSMdCprtVRSs0tKKmEcGJ1opXKE3NyqCqFz7KSosTiDCrLDRrP4dGGxKWa3Ii1jkyXFJRWVeWk0tELuflJmTmp8al5qbnUNhqfXFpOYvqgCPChn9LobN2gKcmGbzEdCwC6sz5F;eJyrVnJUslIqKUhWqgUAElEDQw==;13;5; -P6;Fight 'em all;Kill all the enemies and then move into the flag to win.;N;<;eJzVVEFugzAQfEv37AM0PeUWwi+qChmzBITByDZtSenfu5CIJsVqiUgj5cgwOzO2x4ZdpoztvA7L2rbdpguAwRuX8gQKCbo5jaDVbPAZsMKyBeYxGGDS2wD7AJNLrCysUy4Nfva/Q3iZKGyB+QzqZr+XOHErsD3H/IUJAkpA9PdaKpO/4nRE8yRvDKzJCNMUhSVWhaZHPOLGba1V0ggSPcw9eDQpci0ayfXRiUGpYrIeP2uDTaI0rxJVOtJcEt6xff9yVL2XvzRcMLtuIJUo/mZdteJUOpNdxXMo5sWbu/DWiQxFUaucpHuxM8vvf5FGg2RudUNFPMGx4rHEZOzowIu0OnLHnCvX2fThkRfRsOLlG3G4Lm61RYV3grNP9L4aCFbzn2q+E50zHDppjwxSnWOV/C64dad5cjzoM/NND9Ll4Q59wdok393yEVpE+wLny+Ga; \ No newline at end of file +P6;Fight 'em all;Kill all the enemies and then move into the flag to win.;N;<;eJzVVEFugzAQfEv37AM0PeUWwi+qChmzBITByDZtSenfu5CIJsVqiUgj5cgwOzO2x4ZdpoztvA7L2rbdpguAwRuX8gQKCbo5jaDVbPAZsMKyBeYxGGDS2wD7AJNLrCysUy4Nfva/Q3iZKGyB+QzqZr+XOHErsD3H/IUJAkpA9PdaKpO/4nRE8yRvDKzJCNMUhSVWhaZHPOLGba1V0ggSPcw9eDQpci0ayfXRiUGpYrIeP2uDTaI0rxJVOtJcEt6xff9yVL2XvzRcMLtuIJUo/mZdteJUOpNdxXMo5sWbu/DWiQxFUaucpHuxM8vvf5FGg2RudUNFPMGx4rHEZOzowIu0OnLHnCvX2fThkRfRsOLlG3G4Lm61RYV3grNP9L4aCFbzn2q+E50zHDppjwxSnWOV/C64dad5cjzoM/NND9Ll4Q59wdok393yEVpE+wLny+Ga; +P6;Stationary yet Deadly;These sentries are lethal, when they see you they shoot, and the bullets are fast.;P;<;eJzVVctqwzAQ/Jc9iyCnDQXf4rQl/xCCUZ21I9g4RpITnLr/3lVflEZuVQrBPWo0uzsajWWotnvretnjrnFdP+8zEHBURJ+ge4YiaMs4GkOzEHhzBi4GmIlYgcXamQ6EFPCyw3PmIB6hautc1w7NQRGk0wnvP7RE6HLbIG4gTbhlaTTWG+ogLRVZFNAoa/UB84LVM8VX+Uavy5lfImHhjC7yZn9Ew6CUE/nkx2ewDshk7dfctz2dCH/04yoOHPLjYuWJP5Hdfr2NMHheDiWp6nszFqHJd0P9ItJ2G6bFuxMfyyAzkaMLq/98sMZdQJDVxFLfJn0UBJOweq8cx6HGZvI0PiFjszL4HvwP6b8MduQlZXFPzZ9+k8/MI4kI; +P6;A Real Mess;Friendly Sentries are great at killing large amounts of enemies. However, they may cause collateral damage or not understand which enemies are good and which are bad.;P;<;eJy1VctuwjAQ/Jbu2UIhPIpyK733B6oqMskmWHXiyA9QaPrvXQNCBQzClXr02DszO7uSoV4rY4dkwKaz/fAyLIHBlkv5C3oj6IFnHurcbifxHBynV09fCWXvYLC1ugeWMNjfEMELsC+oXZuL1qLecAlZOqL7lZMSbW46xBKyCYNKC2xL2UNmtUNS5saIDeYF+YRs7Gs8zeE480eUWFgtirxTW9QEJsko+fbiS/hgM/JzNHFpxwhJRiGruDR4KiAPRorystlQr9NY7kWIZeHjNetzvfQ2tealcIayILyqqHeKp0XjkcQn2ndala4g8UPdU0KVhdCFk1wfHTFo1Iosno6dQVcqzdtSNZeujzO5vyX7OMBYrdo6Jz9Nfx0g8s/Q1Ty4R4lPwD9+NNwb63jXU6RE5LhJnDur8kry+lx5Gqsc3L9ZLMtziCW9PZk/2IwsmIQczcMrF9yTaIv/31NwVvEsQZo0PuDIguuUl4/9E+Hv5AdEcCHG; +P6;Overpowered;The sentry is strong, but the sentry buster is stronger;L;<;eJytUstuwjAQ/Jc9W8i0RajcCJz6CwhZJmzSiMWx/AAF0n/vhnIAxVUQ7XFnZ2bHu4bys/ahlS3ubWjaeZuBgKMmuoGWDD1AW/wrjaE3AT5adIU2941xiv2SmsRMG08nwp5z3wAK0uXQoMVFvMPm2USvf1nSb4792ZMUk+UeTXCN2kQf0A1eoO+SPXw9oDrfDbMSZsnsU7G6hgchBVw6LJ+DOEMZjaoMP+igCWbjEfc3kQiD8hZxyxBbFq5Cs6UGZoUmj/wxtPfVAVXOAa6qzuinnHQlEubBVbmy9REdg1KO5Fc3PoN1+nO8P7uxjyTtG0s1R9o=; +P6;Autonomous Defenses;The sentries got you covered, but are they themselves safe?;P;<;eJzNV1FvmzAQ/i27Z1QBCc3GW9Nu2st+wTRZDhzBqjHMNq2Ssf8+A5kIwTRIrQJv4c6++77vzmcH9mmudOVWmBX6UD1UW3B+QkIjncsDOK4DjQMceADnD0TIOYRQlMcjR7IrlUb5yTVeJsyvF2qc/p3ZRONY5hrChHKFDhTpQbGo9p4Mv0sqNDtifLL8rTNt4ZcDr5TzMzjfTWwLxMtlX6cta8idCN2c2saBhNP9BIQZ1SkRZbZDacGZl8Kk9133zu1ka7ZwVIqgAXARsfVqFj2/nfwRHN+kVyi0rfj7UpBOjFUtxq7kHDVRBdZ8A8NQMhQxP0CoZVnLQ5ViL0giUxsIvXpPHab9DOpP5BhpySJS5K+Gbxj0iI2Wqw/GuwkYbyqc22jjDwr4NLV73NEDZ0KsF9YD/oyHdlxhnZMMo3SIKU8ShW9q3J+xKzuntgIjnIIPJWXwmOHUijhlgArMLLVQjKPQg1xFqdKLoAVTOhfV6kom2JtMkhqVroL6PDB+A3NcLSu9tc0aLKzlN7bZ/OUEzFgLTiMcXmiN+T9uFvd60LJ1KNACb4D7IfTHXm/4VyndL4ySP6T0NAJ9M+Ps86bDXC3rou7K7S+i3PPVcDxzitFzkZs8RGJzX7Vkz+wo6I7XIVtPs4x0MLrRMnIWzR3HJH7YYJpPxPWyunvW99C7ZvHW/jft7DF0eV5v/sD7YYX4D98TA5Y=; diff --git a/lib/layout/puzzles.dart b/lib/layout/puzzles.dart index d6a6b7d..a0011d9 100755 --- a/lib/layout/puzzles.dart +++ b/lib/layout/puzzles.dart @@ -5,7 +5,7 @@ var puzzles = []; int? puzzleIndex; Future loadAllPuzzles() async { - puzzles = (await loadFileData('assets/puzzles.txt')).split('\n'); + puzzles = (await loadFileData('assets/puzzles.txt')).split('\n')..removeWhere((l) => l.isEmpty); } Future loadFileData(String path) async { diff --git a/lib/logic/cell_data.dart b/lib/logic/cell_data.dart index 34b4502..569ac23 100755 --- a/lib/logic/cell_data.dart +++ b/lib/logic/cell_data.dart @@ -394,6 +394,8 @@ final cells = { "flipped_puzzle", "bullet", "sentry", + "sentry_buster", + "puzzle_buster", }.toList(); final modded = []; @@ -403,6 +405,8 @@ final cursorTextures = ["cursor", ...cells, "invis_tool", "trick_tool"]..removeW final textureMapBackup = HashMap.from(textureMap); HashMap textureMap = HashMap.from({ + "sentry_buster.png": "destroyers/sentry_buster.png", + "puzzle_buster.png": "destroyers/puzzle_buster.png", "sentry.png": "destroyers/sentry.png", "bullet.png": "destroyers/bullet.png", "anvil.png": "movers/anvil.png", @@ -1288,6 +1292,8 @@ final categories = [ ), "antigen", "sentry", + "sentry_buster", + "puzzle_buster", ], "trash", ), @@ -3305,6 +3311,14 @@ final cellInfo = { "Sentry", "Will kill enemies or players.", ), + "sentry_buster": CellProfile( + "Sentry Buster", + "When the sentry buster enters the area, it will go to the nearest sentry and blow it up. It does NOT care if the sentry is friendly or not.", + ), + "puzzle_buster": CellProfile( + "Puzzle Buster", + "It will hunt down puzzle cells and blow up when it gets near them", + ), }; enum CellPropertyType { @@ -3581,7 +3595,7 @@ Map> props = { "sentry": [ CellProperty("Shoot Interval", "The interval at which it shoots", "gun_interval", CellPropertyType.number, 2), CellProperty("Bullet Speed", "The speed of the bullet it shoots", "bullet_speed", CellPropertyType.integer, 1), - CellProperty("Friendly", "If true, it will kill enemies. If not, it will kill puzzle cells and keys. There are also common targets it will kill either way.", "friendly", CellPropertyType.boolean, true), + CellProperty("Friendly", "If true, it will kill enemies. If not, it will kill puzzle cells and keys. There are also common targets it will kill either way.", "friendly", CellPropertyType.boolean, false), CellProperty("Power Cost", "The amount of electric power the sentry consumes passively", "passive_cost", CellPropertyType.number, 1), CellProperty("Shoot Cost", "The amount of electric power the sentry consumes when shooting", "gun_cost", CellPropertyType.number, 5), CellProperty("Power", "The amount of electric power in the sentry gun", "electric_power", CellPropertyType.number, 500), diff --git a/lib/logic/core/game.dart b/lib/logic/core/game.dart index 5d01864..1238cdd 100644 --- a/lib/logic/core/game.dart +++ b/lib/logic/core/game.dart @@ -1685,6 +1685,7 @@ class PuzzleGame extends FlameGame with TapDetector, KeyboardEvents { await Flame.images.load('base.png'); await Flame.images.load(textureMap['missing.png'] ?? 'missing.png'); await Flame.images.load('empty.png'); + await Flame.images.load('destroyers/sentry_friendly.png'); // Load effects await Flame.images.loadAll([ "effects/stopped.png", diff --git a/lib/logic/core/rendering.dart b/lib/logic/core/rendering.dart index b3d9e5a..1f617ad 100644 --- a/lib/logic/core/rendering.dart +++ b/lib/logic/core/rendering.dart @@ -580,6 +580,11 @@ class GameRendering { ignoreSafety = true; } + if(cell.id == "sentry" && cell.data['friendly'] == true) { + file = "destroyers/sentry_friendly"; + ignoreSafety = true; + } + if (file.startsWith('totrick_')) { file = "interface/tools/trick_tool"; ignoreSafety = true; diff --git a/lib/logic/grid/subticks.dart b/lib/logic/grid/subticks.dart index f00d69c..527f52d 100755 --- a/lib/logic/grid/subticks.dart +++ b/lib/logic/grid/subticks.dart @@ -50,6 +50,7 @@ final subticks = [ dartys, floppys, puzzles, + weapons, pmerges, autoflag, checkpoints, diff --git a/lib/logic/logic.dart b/lib/logic/logic.dart index b5b78ea..c495ed6 100755 --- a/lib/logic/logic.dart +++ b/lib/logic/logic.dart @@ -111,6 +111,7 @@ part 'update/carriers.dart'; part 'update/stableton.dart'; part 'update/releasers.dart'; part 'update/anvil.dart'; +part 'update/weapons.dart'; extension SetX on Set { bool containsAny(Iterable strings) { diff --git a/lib/logic/move.dart b/lib/logic/move.dart index 2e8f12e..4a6f935 100755 --- a/lib/logic/move.dart +++ b/lib/logic/move.dart @@ -768,6 +768,7 @@ final withBias = [ "mystic_x", "platform", "carrier", + "bullet", ]; int addedForce(Cell cell, int dir, int force, MoveType mt) { @@ -931,7 +932,7 @@ bool acidic(Cell cell, int dir, int force, MoveType mt, Cell melting, int mx, in return true; } - if (const ["mover_trash", "mover_enemy"].contains(cell.id) && cell.rot == dir) { + if (const ["mover_trash", "mover_enemy", "bullet"].contains(cell.id) && cell.rot == dir) { return true; } @@ -952,7 +953,7 @@ void handleAcid(Cell cell, int dir, int force, MoveType mt, Cell melting, int mx grid.set(mx, my, cell); } - if (cell.id == "mobile_enemy" || cell.id == "mover_enemy" || cell.id == "explosive") { + if (cell.id == "mobile_enemy" || cell.id == "mover_enemy" || cell.id == "explosive" || cell.id == "bullet") { grid.addBroken(melting, mx, my, "shrinking"); grid.addBroken(cell, mx, my, "shrinking"); if (cell.id == "explosive") { @@ -1161,12 +1162,12 @@ NextCell nextCell(int x, int y, int dir, [bool skipFirst = false]) { } } -void doExplosive(Cell destroyer, int x, int y, [bool silent = false]) { - final radius = destroyer.data['radius'] ?? 1; - final effectiveness = (destroyer.data['effectiveness'] ?? 100) / 100; - final byproduct = destroyer.data['byproduct'] ?? "empty!0"; - final circular = destroyer.data['circular'] ?? false; - final pseudoRandom = destroyer.data['pseudorandom'] ?? false; +void doExplosive(Cell destroyer, int x, int y, [bool silent = false, Map data = const {}]) { + final radius = data['radius'] ?? destroyer.data['radius'] ?? 1; + final effectiveness = (data['effectiveness'] ?? destroyer.data['effectiveness'] ?? 100) / 100; + final byproduct = data['byproduct'] ?? destroyer.data['byproduct'] ?? "empty!0"; + final circular = data['circular'] ?? destroyer.data['circular'] ?? false; + final pseudoRandom = data['pseudorandom'] ?? destroyer.data['pseudorandom'] ?? false; grid.addBroken(destroyer, x, y, silent ? "silent_shrinking" : "shrinking"); diff --git a/lib/logic/update/quantum.dart b/lib/logic/update/quantum.dart index c0429f7..d4d5373 100755 --- a/lib/logic/update/quantum.dart +++ b/lib/logic/update/quantum.dart @@ -132,7 +132,7 @@ class RaycastInfo { RaycastInfo.broken() : successful = false; } -RaycastInfo raycast(int cx, int cy, int dx, int dy) { +RaycastInfo raycast(int cx, int cy, int dx, int dy, [Set ignore = const {}]) { var x = cx; var y = cy; var d = 0; @@ -146,7 +146,7 @@ RaycastInfo raycast(int cx, int cy, int dx, int dy) { final cell = grid.at(x, y); - if (cell.id != "empty") { + if (cell.id != "empty" && !ignore.contains(cell.id)) { return RaycastInfo.successful(cell, d, x, y); } } diff --git a/lib/logic/update/weapons.dart b/lib/logic/update/weapons.dart new file mode 100644 index 0000000..e2215c5 --- /dev/null +++ b/lib/logic/update/weapons.dart @@ -0,0 +1,132 @@ +part of logic; + +final sentryCommonTargets = []; +final sentryEnemyTargets = [ + "robot", + "assistant", + "puzzle", + "flipped_puzzle", + "molten_puzzle", + "frozen_puzzle", + "unstable_puzzle", + "trash_puzzle", + "mover_puzzle", + "temporal_puzzle", + "transform_puzzle", +]; +// Enemies are automatically friendly targets +final sentryFriendlyTargets = [ + "enemy", + "semi_enemy", + "mobile_enemy", + "physical_enemy", + "explosive", + "mech_enemy", + "friend", + "debt_enemy", + "roadblock", + "strong_enemy", + "weak_enemy", + "mech_enemy_gen", + "balanced_enemy", + "puzzle_buster", +]; + +void doSentry(Cell cell, int x, int y) { + final double interval = cell.data['gun_interval'].toDouble(); + final int bulletSpeed = cell.data['bullet_speed'].toInt(); + final bool isFriendly = cell.data['friendly']; + + // TODO: make this use power + + cell.data['time'] = (cell.data['time'] ?? 0.0) + 1.0; + if(cell.data['time'] >= interval) { + for(var rot in rotOrder) { + if(grid.at(frontX(x, rot), frontY(y, rot)).id != "empty") { + continue; + } + final seen = raycast(x, y, frontX(0, rot), frontY(0, rot), const {"bullet"}); + if(!seen.successful) { + continue; + } + var shoot = false; + if(isFriendly && (sentryFriendlyTargets.contains(seen.hitCell.id) || enemies.contains(seen.hitCell.id))) { + shoot = true; + } else if(!isFriendly && (sentryEnemyTargets.contains(seen.hitCell.id))) { + shoot = true; + } + + if(shoot) { + cell.data['time'] -= interval; + cell.rot = rot; + final bullet = Cell(x, y, rot)..id = "bullet"; + bullet.data['speed'] = bulletSpeed; + bullet.rot = rot; + grid.set(frontX(x, rot), frontY(y, rot), bullet); + return; + } + } + } + + cell.rot = (cell.rot + 1) % 4; +} + +void doBullet(Cell cell, int x, int y) { + final int speed = cell.data['speed'].toInt(); + var cx = x, cy = y; + for(int i = 0; i < speed; i++) { + if(push(cx, cy, cell.rot, 0)) { + cx = frontX(cx, cell.rot); + cy = frontY(cy, cell.rot); + if(grid.at(cx, cy).id != "bullet") { + break; + } + } else { + grid.set(cx, cy, Cell(cx, cy, 0)); + break; + } + } +} + +void doSentryBuster(Cell cell, int x, int y) { + var range = (grid.width * grid.height ~/ 4); + + final dirToSentry = pathFindToCell(x, y, ['sentry'], range); + if(dirToSentry == null) { + return; + } + + final c = grid.at(frontX(x, dirToSentry), frontY(y, dirToSentry)); + if(c.id == "sentry") { + doExplosive(cell, x, y, cell.data['silent'] == true, {"radius": 1}); + } else { + push(x, y, dirToSentry, 1); + } +} + +void doPuzzleBuster(Cell cell, int x, int y) { + var range = (grid.width * grid.height ~/ 4); + + final dirToPuzzle = pathFindToCell(x, y, ['puzzle'], range); + if(dirToPuzzle == null) { + return; + } + + final c = grid.at(frontX(x, dirToPuzzle), frontY(y, dirToPuzzle)); + if(c.id == "puzzle") { + doExplosive(cell, x, y, cell.data['silent'] == true, {"radius": 1}); + } else { + push(x, y, dirToPuzzle, 1); + } +} + +void weapons() { + grid.updateCell(doSentryBuster, null, "sentry_buster"); + grid.updateCell(doPuzzleBuster, null, "puzzle_buster"); + + grid.updateCell(doSentry, null, "sentry"); + + for(var rot in rotOrder) { + grid.updateCell(doBullet, rot, "bullet"); + } +}