From 5686e4ca9c1ee4d8948d9b1abc1519768687c77e Mon Sep 17 00:00:00 2001 From: aratama <16192627+aratama@users.noreply.github.com> Date: Sat, 25 Jan 2025 07:36:45 +0900 Subject: [PATCH] SpellType as String --- assets/registry.actor.ron | 15 +- assets/registry.game.ron | 510 +++++++++++++++++++++++++++++++++ assets/registry.senario.ron | 122 ++++---- assets/registry.spell.ron | 552 +----------------------------------- src/actor.rs | 67 +++-- src/actor/chest.rs | 10 +- src/actor/chicken.rs | 4 +- src/actor/sandbug.rs | 4 +- src/asset.rs | 4 + src/cast.rs | 8 +- src/controller/player.rs | 6 +- src/enemy/eyeball.rs | 4 +- src/enemy/salamander.rs | 4 +- src/enemy/slime.rs | 4 +- src/entity/dropped_item.rs | 18 +- src/game.rs | 2 + src/interpreter.rs | 8 +- src/inventory.rs | 20 +- src/inventory_item.rs | 8 +- src/level/entities.rs | 8 +- src/level/map.rs | 2 +- src/page/in_game.rs | 22 +- src/player_state.rs | 12 +- src/registry.rs | 35 ++- src/spell.rs | 78 +---- src/ui/floating.rs | 22 +- src/ui/inventory.rs | 2 +- src/ui/item_panel.rs | 24 +- src/ui/new_spell.rs | 6 +- src/ui/popup.rs | 18 +- src/ui/spell_list.rs | 31 +- src/wand.rs | 18 +- 32 files changed, 799 insertions(+), 849 deletions(-) create mode 100644 assets/registry.game.ron diff --git a/assets/registry.actor.ron b/assets/registry.actor.ron index 2cbe8b3..1409065 100644 --- a/assets/registry.actor.ron +++ b/assets/registry.actor.ron @@ -1,4 +1,7 @@ +// https://github.com/ron-rs/ron/blob/master/docs/extensions.md +#![enable(unwrap_newtypes)] +#![enable(implicit_some)] ActorRegistry( dumping_on_ice: 0.1, dumping_on_air: 0.5, @@ -12,7 +15,7 @@ ActorRegistry( move_force: 40000.0, jump: 0.0, linear_damping: 6.0, - blood: Some(Red), + blood: Red, defreeze: 1, auto_levitation: false, cry: true @@ -22,7 +25,7 @@ ActorRegistry( move_force: 40000.0, jump: 1.5, linear_damping: 10.0, - blood: Some(Red), + blood: Red, defreeze: 1, auto_levitation: false, cry: true @@ -32,7 +35,7 @@ ActorRegistry( move_force: 60000.0, jump: 1.5, linear_damping: 10.0, - blood: Some(Red), + blood: Red, defreeze: 1, auto_levitation: false, cry: true @@ -42,7 +45,7 @@ ActorRegistry( move_force: 100000.0, jump: 0.0, linear_damping: 10.0, - blood: Some(Red), + blood: Red, defreeze: 1, auto_levitation: true, cry: true @@ -62,7 +65,7 @@ ActorRegistry( move_force: 50000.0, jump: 0.0, linear_damping: 10.0, - blood: Some(Blue), + blood: Blue, defreeze: 1, auto_levitation: false, cry: true @@ -72,7 +75,7 @@ ActorRegistry( move_force: 100000.0, jump: 0.0, linear_damping: 10.0, - blood: Some(Red), + blood: Red, defreeze: 2, auto_levitation: false, cry: true diff --git a/assets/registry.game.ron b/assets/registry.game.ron new file mode 100644 index 0000000..d3082d9 --- /dev/null +++ b/assets/registry.game.ron @@ -0,0 +1,510 @@ +// https://github.com/ron-rs/ron/blob/master/docs/extensions.md +#![enable(unwrap_newtypes)] +#![enable(implicit_some)] +GameRegistry( + debug_wands: [ + ["InfinityClone", None, None, None, None, None, None, None], + ["QuickCast", "QuickCast", "HeavyShot", "HeavyShot", "TripleCast", "MagicBolt", "MagicBolt", "MagicBolt"], + ["Bomb", None, None, None, None, None, None, None], + ["Dash", "Lantern", None, None, None, None, None, None] + ], + + debug_items: [ + "MagicBolt", + "MagicBolt", + "LightBall", + "WaterBall", + "SlimeCharge", + "Heal", + "BulletSpeedUp", + "BulletSpeedUp", + "BulletSpeedUp", + "BulletSpeedDoown", + "BulletSpeedDoown", + "BulletSpeedDoown", + "PurpleBolt", + "DualCast", + "TripleCast", + "Lantern", + "Lantern", + "SpikeBoots", + "Telescope", + "Magnifier", + "Homing", + "Homing", + "HeavyShot", + "HeavyShot", + "SummonFriendSlime", + "SummonEnemySlime", + "SummonFriendEyeball", + "SummonEnemyEyeball", + "Dash", + "QuickCast", + "QuickCast", + "Impact", + "PrecisionUp", + "PrecisionUp", + "Bomb", + "LightSword", + "SpawnBookshelf", + "SpawnJar", + "RockFall", + "Fireball", + "SummonHugeSlime", + "SummonChiken", + "Servant", + "Web", + "Freeze", + "Levitation", + "ApplyLevitation", + "Jump", + "Metamorphosis", + "Slash", + "Dispel", + "Clone", + "InfinityClone", + ], + + levels: [ + ( + name: Dict ( + ja: "ウサギ族のキャンプ", + en: "Rabbit's Camp", + zh_cn: "兔子的营地", + zh_tw: "兔子的營地", + es: "Campamento de Conejos", + fr: "Camp des Lapins", + pt: "Acampamento dos Coelhos", + de: "Kaninchenlager", + ko: "토끼 캠프", + ru: "Лагерь кроликов", + ), + enemies: 0, + enemy_types: [], + items: 0, + item_ranks: [], + biome: StoneTile + ), + ( + name: Dict ( + ja: "図書館跡", + en: "Library Ruins", + zh_cn: "图书馆废墟", + zh_tw: "圖書館廢墟", + es: "Ruinas de la Biblioteca", + fr: "Ruines de la Bibliothèque", + pt: "Ruínas da Biblioteca", + de: "Bibliotheksruinen", + ko: "도서관 폐허", + ru: "Руины библиотеки", + ), + enemies: 10, + enemy_types: [Slime], + items: 3, + item_ranks: [0, 1, 2], + biome: StoneTile + ), + ( + name: Dict ( + ja: "地下草原", + en: "Underground Grassland", + zh_cn: "地下草原", + zh_tw: "地下草原", + es: "Pradera Subterránea", + fr: "Prairie Souterraine", + pt: "Pradaria Subterrânea", + de: "Unterirdisches Grasland", + ko: "지하 초원", + ru: "Подземные луга", + ), + enemies: 15, + enemy_types: [Slime, Spider], + items: 3, + item_ranks: [1, 2, 3], + biome: Grassland + ), + ( + name: Dict ( + ja: "古城", + en: "Ancient Castle", + zh_cn: "古城", + zh_tw: "古城", + es: "Castillo Antiguo", + fr: "Château Ancien", + pt: "Castelo Antigo", + de: "Alte Burg", + ko: "고대 성", + ru: "Древний замок", + ), + enemies: 20, + enemy_types: [Spider, EyeBall], + items: 3, + item_ranks: [2, 3, 4], + biome: StoneTile + ), + ( + name: Dict ( + ja: "スライムの巣窟", + en: "Slime Nest", + zh_cn: "史莱姆巢穴", + zh_tw: "史萊姆巢穴", + es: "Nido de Slimes", + fr: "Nid de Slimes", + pt: "Ninho de Slimes", + de: "Schleimnest", + ko: "슬라임 둥지", + ru: "Гнездо слизней", + ), + enemies: 20, + enemy_types: [EyeBall, Shadow], + items: 3, + item_ranks: [3, 4, 5], + biome: StoneTile + ), + ( + name: Dict ( + ja: "氷の洞窟", + en: "Ice Cave", + zh_cn: "冰洞", + zh_tw: "冰洞", + es: "Cueva de Hielo", + fr: "Grotte de Glace", + pt: "Caverna de Gelo", + de: "Eishöhle", + ko: "얼음 동굴", + ru: "Ледяная пещера", + ), + enemies: 15, + enemy_types: [Shadow, Salamander], + items: 3, + item_ranks: [4, 5, 6], + biome: Ice + ), + ( + name: Dict ( + ja: "古の回廊", + en: "Ancient Corridor", + zh_cn: "古代走廊", + zh_tw: "古代走廊", + es: "Corredor Antiguo", + fr: "Couloir Ancien", + pt: "Corredor Antigo", + de: "Alter Korridor", + ko: "고대 회랑", + ru: "Древний коридор", + ), + enemies: 30, + enemy_types: [Slime, Spider, EyeBall, Shadow, Salamander], + items: 3, + item_ranks: [4, 5, 6], + biome: StoneTile + ), + ( + name: Dict ( + ja: "大空洞", + en: "Great Cavern", + zh_cn: "大洞穴", + zh_tw: "大洞穴", + es: "Gran Caverna", + fr: "Grande Caverne", + pt: "Grande Caverna", + de: "Große Höhle", + ko: "큰 동굴", + ru: "Большая пещера", + ), + enemies: 0, + enemy_types: [], + items: 3, + item_ranks: [], + biome: StoneTile + ), + ], + arena: ( + name: Dict ( + ja: "対決の洞窟", + en: "Cave of Confrontation", + zh_cn: "对决洞穴", + zh_tw: "對決洞穴", + es: "Cueva de Confrontación", + fr: "Grotte de Confrontation", + pt: "Caverna de Confronto", + de: "Höhle der Konfrontation", + ko: "대결의 동굴", + ru: "Пещера противостояния" + ), + enemies: 0, + enemy_types: [], + items: 3, + item_ranks: [], + biome: StoneTile + ), + + + tiles: { + (203, 219, 252, 255): ( + tile: None, + zone: Dungeon, + entity: None, + entry_point: false, + ), + (234, 255, 214, 255): ( + tile: None, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (82, 75, 36, 255): ( + tile: Wall, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (118, 66, 138, 255): ( + tile: None, + zone: SafeZone, + entity: Some(Actor ( + actor_type: BookShelf, + actor_group: Entity, + )), + entry_point: false, + ), + (251, 242, 54, 255): ( + tile: None, + zone: SafeZone, + entity: RandomChest, + entry_point: false, + ), + (255, 155, 87, 255): ( + tile: None, + zone: SafeZone, + entity: RandomChest, + entry_point: false, + ), + // (81, 28) 水路の奥の隠し部屋 + (255, 155, 88, 255): ( + tile: None, + zone: SafeZone, + entity: Some(SpellInChest ( + spell: "Dash", + )), + entry_point: false, + ), + // (30, 69) ジャンプ練習場の奥 + (255, 155, 89, 255): ( + tile: None, + zone: SafeZone, + entity: Some(SpellInChest ( + spell: "Levitation", + )), + entry_point: false, + ), + // (53, 24) Z字型の裂け目の奥の隠し部屋 + (255, 155, 90, 255): ( + tile: None, + zone: SafeZone, + entity: Some(SpellInChest ( + spell: "Bomb", + )), + entry_point: false, + ), + // (100, 66) 溶岩流を渡った先 + (255, 155, 91, 255): ( + tile: None, + zone: SafeZone, + entity: Some(SpellInChest ( + spell: "LightSword", + )), + entry_point: false, + ), + (48, 96, 130, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: MagicCircle, + entry_point: false, + ), + (47, 96, 130, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: MultiPlayArenaMagicCircle, + entry_point: false, + ), + (56, 111, 161, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: MagicCircleHome, + entry_point: false, + ), + (46, 96, 130, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: MagicCircleDemoEnding, + entry_point: false, + ), + (255, 0, 0, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: BrokenMagicCircle, + entry_point: true, + ), + (255, 0, 255, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: Usage, + entry_point: false, + ), + (254, 0, 255, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: Routes, + entry_point: false, + ), + (223, 113, 38, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: Some(Actor ( + actor_type: Lantern, + actor_group: Entity, + )), + entry_point: false, + ), + (0, 222, 255, 255): ( + tile: None, + zone: SafeZone, + entity: ShopSpell, + entry_point: false, + ), + (102, 57, 49, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: RandomChest, + entry_point: false, + ), + (184, 0, 255, 255): ( + tile: None, + zone: SafeZone, + entity: Some(Boss ( + actor_type: HugeSlime, + name: Dict ( + ja: "スライムの王 エミルス", + en: "Slime King Emils", + zh_cn: "史莱姆之王 艾米尔斯", + zh_tw: "史萊姆之王 艾米爾斯", + es: "Rey Slime Emils", + fr: "Roi Slime Emils", + pt: "Rei Slime Emils", + de: "Schleimkönig Emils", + ko: "슬라임 왕 에밀스", + ru: "Король слизней Эмильс", + ), + )), + entry_point: false, + ), + (255, 243, 0, 255): ( + tile: None, + zone: SafeZone, + entity: Rabbit(Shop), + entry_point: false, + ), + (255, 244, 0, 255): ( + tile: None, + zone: SafeZone, + entity: Rabbit(Training), + entry_point: false, + ), + (255, 245, 0, 255): ( + tile: None, + zone: SafeZone, + entity: Rabbit(Guide), + entry_point: false, + ), + (255, 246, 0, 255): ( + tile: None, + zone: SafeZone, + entity: Rabbit(MultiPlay), + entry_point: false, + ), + (255, 247, 0, 255): ( + tile: None, + zone: SafeZone, + entity: Rabbit(Singleplay), + entry_point: false, + ), + (255, 248, 0, 255): ( + tile: None, + zone: SafeZone, + entity: Rabbit(Reading), + entry_point: false, + ), + (255, 249, 0, 255): ( + tile: None, + zone: SafeZone, + entity: Rabbit(SpellList), + entry_point: false, + ), + (182, 0, 255, 255): ( + tile: None, + zone: SafeZone, + entity: Some(Actor ( + actor_type: Sandbag, + actor_group: Neutral, + )), + entry_point: false, + ), + (197, 255, 142, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: ShopDoor, + entry_point: false, + ), + (68, 0, 94, 255): ( + tile: None, + zone: SafeZone, + entity: BGM, + entry_point: false, + ), + (153, 229, 80, 255): ( + tile: Grassland, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (156, 156, 156, 255): ( + tile: StoneTile, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (55, 79, 225, 255): ( + tile: Water, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (205, 121, 54, 255): ( + tile: Lava, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (43, 43, 43, 255): ( + tile: Crack, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (222, 233, 255, 255): ( + tile: Ice, + zone: SafeZone, + entity: None, + entry_point: false, + ), + (0, 0, 0, 255): ( + tile: PermanentWall, + zone: SafeZone, + entity: None, + entry_point: false, + ) + }, + + +) \ No newline at end of file diff --git a/assets/registry.senario.ron b/assets/registry.senario.ron index cb48eae..cee97a3 100644 --- a/assets/registry.senario.ron +++ b/assets/registry.senario.ron @@ -1,8 +1,12 @@ +// https://github.com/ron-rs/ron/blob/master/docs/extensions.md +#![enable(unwrap_newtypes)] +#![enable(implicit_some)] +#![enable(unwrap_variant_newtypes)] SenarioRegistry( senarios: { "HelloRabbit": [ - BGM (bgm: Some(Saihate)), - Speech (Dict ( + BGM (bgm: Saihate), + Speech ( ja: "おや、きみは魔法使いだね。ここはぼくらの商人キャンプだよ。来客は歓迎さ。", en: "Oh, you are a mage. This is our merchant camp. Visitors are welcome.", zh_cn: "哦,你是一个法师。这是我们的商人营地。欢迎来访。", @@ -13,8 +17,8 @@ SenarioRegistry( de: "Oh, du bist ein Magier. Dies ist unser Händlerlager. Besucher sind willkommen.", ko: "오, 당신은 마법사군요. 여기는 우리의 상인 캠프입니다. 방문객을 환영합니다.", ru: "О, вы маг. Это наш лагерь торговцев. Посетители приветствуются.", - )), - Speech (Dict ( + ), + Speech ( ja: "通りすがりに大鴉に襲われた?それは災難だったね。", en: "You were attacked by a large raven on the way? That's unfortunate.", zh_cn: "你在路上被一只大乌鸦袭击了?那真是不幸。", @@ -25,8 +29,8 @@ SenarioRegistry( de: "Wurden Sie auf dem Weg hierher von einem großen Raben angegriffen? Das ist bedauerlich.", ko: "여기 오는 길에 큰 까마귀에게 공격당했어? 그것 참 불운하군.", ru: "Тебя по пути сюда атаковал большой ворон? Это неудача.", - )), - Speech (Dict ( + ), + Speech ( ja: "おそらくはこの島に住む『漆黒の魔女』の使い魔のしわざだろう。", en: "It is probably the work of the 'Witch of Jet Black' who lives on this island.", zh_cn: "这可能是住在这个岛上的“漆黑女巫”的杰作。", @@ -37,8 +41,8 @@ SenarioRegistry( de: "Es ist wahrscheinlich das Werk der 'Hexe von Pechschwarz', die auf dieser Insel lebt.", ko: "아마도 이 섬에 사는 '칠흑의 마녀'의 짓일 거야.", ru: "Вероятно, это дело рук 'Ведьмы Черного Яшмы', которая живет на этом острове.", - )), - Speech (Dict ( + ), + Speech ( ja: "我々では折れた魔法の箒の修理はできないな。自分で直してもらうしかない。", en: "We can't repair your broken magic broom. You'll have to fix it yourself.", zh_cn: "我们无法修理你破损的魔法扫帚。你得自己修理。", @@ -49,8 +53,8 @@ SenarioRegistry( de: "Wir können deinen kaputten magischen Besen nicht reparieren. Du musst ihn selbst reparieren.", ko: "우리는 당신의 부러진 마법 빗자루를 고칠 수 없습니다. 당신이 직접 고쳐야 합니다.", ru: "Мы не можем починить вашу сломанную волшебную метлу. Вам придется починить ее самостоятельно." - )), - Speech (Dict ( + ), + Speech ( ja: "この島の迷宮に行けば、修理の役に立つ呪文があるかもしれない。迷宮の入り口はこの奥だよ。", en: "If you go to the labyrinth on this island, you might find a spell that can help with the repair. The entrance to the labyrinth is further in.", zh_cn: "如果你去这个岛上的迷宫,你可能会找到一个可以帮助修理的咒语。迷宫的入口在里面。", @@ -61,8 +65,8 @@ SenarioRegistry( de: "Wenn du in das Labyrinth auf dieser Insel gehst, könntest du einen Zauber finden, der bei der Reparatur hilft. Der Eingang zum Labyrinth ist weiter drinnen.", ko: "이 섬의 미로에 가면 수리에 도움이 될 수 있는 주문을 찾을 수 있을 거야. 미로의 입구는 더 안쪽에 있어.", ru: "Если ты пойдешь в лабиринт на этом острове, возможно, найдешь заклинание, которое поможет с ремонтом. Вход в лабиринт находится дальше.", - )), - Speech (Dict ( + ), + Speech ( ja: "迷宮に行く前に、ぼくらの店に立ち寄るといい。迷宮で拾った呪文を売っているんだ。", en: "Before going to the labyrinth, you should stop by our shop. We sell spells that we found in the labyrinth.", zh_cn: "在去迷宫之前,你应该先去我们的商店。我们出售在迷宫中找到的咒语。", @@ -73,10 +77,10 @@ SenarioRegistry( de: "Bevor du in das Labyrinth gehst, solltest du in unserem Laden vorbeischauen. Wir verkaufen Zauber, die wir im Labyrinth gefunden haben.", ko: "미로에 가기 전에 우리 가게에 들르는 것이 좋아. 우리는 미로에서 발견한 주문을 팔고 있어.", ru: "Перед тем как идти в лабиринт, тебе стоит заглянуть в наш магазин. Мы продаем заклинания, которые нашли в лабиринте.", - )) + ) ], "SingleplayRabbit": [ - Speech (Dict ( + Speech ( ja: "その魔法陣が地下迷宮の入り口だよ。探しものが見つかるよう、幸運を祈るよ。", en: "That magic circle is the entrance to the underground labyrinth. I wish you luck in finding what you're looking for.", zh_cn: "那个魔法阵是地下迷宫的入口。祝你好运找到你要找的东西。", @@ -87,8 +91,8 @@ SenarioRegistry( de: "Dieser magische Kreis ist der Eingang zum unterirdischen Labyrinth. Ich wünsche dir viel Glück bei der Suche nach dem, was du suchst.", ko: "그 마법진이 지하 미로의 입구야. 찾고 있는 것을 찾기를 바랄게.", ru: "Этот магический круг - вход в подземный лабиринт. Желаю удачи в поисках того, что ты ищешь.", - )), - Speech (Dict ( + ), + Speech ( ja: "そうそう、最近迷宮の奥に大きなスライムが現れるようになってね。気を付けたほうがいいよ。", en: "By the way, a huge slime has recently appeared deep in the labyrinth. You should be careful.", zh_cn: "顺便说一下,最近在迷宫深处出现了一个巨大的史莱姆。你应该小心。", @@ -99,10 +103,10 @@ SenarioRegistry( de: "Übrigens, tief im Labyrinth ist kürzlich ein riesiger Schleim aufgetaucht. Du solltest vorsichtig sein.", ko: "그런데 최근에 미로 깊숙한 곳에 거대한 슬라임이 나타났어. 조심하는 게 좋아.", ru: "Кстати, недавно в глубине лабиринта появился огромный слизень. Тебе следует быть осторожным.", - )) + ) ], "MultiplayerRabbit": [ - Speech (Dict ( + Speech ( ja: "この先はマルチプレイ用レベルだよ。気軽に遊んでいってね。誰かいるかはわからないけど。", en: "This is a multiplayer level. Feel free to play. I don't know if anyone is here though.", zh_cn: "这是一个多人游戏关卡。随便玩吧。不过我不知道有没有人在这里。", @@ -113,10 +117,10 @@ SenarioRegistry( de: "Dies ist ein Mehrspieler-Level. Fühlen Sie sich frei zu spielen. Ich weiß jedoch nicht, ob jemand hier ist.", ko: "이곳은 멀티플레이 레벨입니다. 마음껏 플레이하세요. 여기에 누가 있는지는 모르겠어요.", ru: "Это многопользовательский уровень. Играйте на здоровье. Не знаю, есть ли здесь кто-нибудь, правда.", - )) + ) ], "ReserchRabbit": [ - Speech (Dict ( + Speech ( ja: "昔はこの島にも多くのヒト族がいたらしいが、今は魔法使いが時折訪れるくらいさ。君たち魔法使いはこの地底でいったい何を探しているんだい?", en: "There used to be many humans on this island but now only witches occasionally visit. What are you witches looking for in the depths?", zh_cn: "这个岛上曾经有很多人类,但现在只有女巫偶尔会来访。你们女巫在深处寻找什么?", @@ -127,8 +131,8 @@ SenarioRegistry( de: "Früher gab es viele Menschen auf dieser Insel, aber jetzt besuchen nur noch gelegentlich Hexen. Was sucht ihr Hexen in den Tiefen?", ko: "예전에는 이 섬에 많은 인간이 있었지만 지금은 가끔 마녀들만 방문해. 너희 마녀들은 깊은 곳에서 무엇을 찾고 있니?", ru: "Раньше на этом острове было много людей, но теперь его изредка посещают только ведьмы. Что вы, ведьмы, ищете в глубинах?", - )), - Speech (Dict ( + ), + Speech ( ja: "ふうん、君は黒髪の魔女を探しているのか。たしか半年ほど前にそんな魔女がキャンプを訪れたな。それが君の探し人かはわからないが。", en: "Hmm, you're looking for a witch with black hair. I remember a witch like that visited the camp about half a year ago. I don't know if that's the person you're looking for.", zh_cn: "嗯,你在找一个黑发女巫。我记得大约半年前有一个这样的女巫来过营地。我不知道那是否是你要找的人。", @@ -139,8 +143,8 @@ SenarioRegistry( de: "Hmm, du suchst eine Hexe mit schwarzen Haaren. Ich erinnere mich, dass vor etwa einem halben Jahr eine solche Hexe das Lager besucht hat. Ich weiß nicht, ob das die Person ist, die du suchst.", ko: "흠, 검은 머리의 마녀를 찾고 있구나. 약 반년 전에 그런 마녀가 캠프를 방문한 적이 있어. 네가 찾는 사람이 맞는지는 모르겠어.", ru: "Хм, ты ищешь ведьму с черными волосами. Помню, такая ведьма посещала лагерь около полугода назад. Не знаю, та ли это, кого ты ищешь.", - )), - Speech (Dict ( + ), + Speech ( ja: "その魔女は迷宮に入っていった。それからはずっと姿を見ていない。まあ迷宮の中を探してみるほかないだろうな。", en: "That witch went into the labyrinth. I haven't seen her since. You'll have to search the labyrinth.", zh_cn: "那个女巫进入了迷宫。从那以后我就没见过她。你得在迷宫里找找。", @@ -151,8 +155,8 @@ SenarioRegistry( de: "Diese Hexe ging in das Labyrinth. Ich habe sie seitdem nicht mehr gesehen. Du musst im Labyrinth suchen.", ko: "그 마녀는 미로로 들어갔어. 그 이후로 그녀를 본 적이 없어. 미로에서 찾아봐야 할 거야.", ru: "Та ведьма пошла в лабиринт. С тех пор я ее не видел. Тебе придется искать в лабиринте.", - )), - Speech (Dict ( + ), + Speech ( ja: "ところで、キャンプにどこからかニワトリが入り込んでいて鬱陶しいな。鳴き声がうるさくて研究に差し支える", en: "By the way, a chicken has somehow gotten into the camp. Its clucking is annoying and it's disturbing my research.", zh_cn: "顺便说一下,一只鸡不知怎么进了营地。它的咯咯叫声很烦人,打扰了我的研究。", @@ -163,8 +167,8 @@ SenarioRegistry( de: "Übrigens, ein Huhn hat sich irgendwie ins Lager geschlichen. Sein Gackern ist nervig und stört meine Forschung.", ko: "그런데 닭 한 마리가 캠프에 들어왔어. 그 울음소리가 짜증나고 내 연구를 방해하고 있어.", ru: "Кстати, в лагерь как-то пробралась курица. Ее кудахтанье раздражает и мешает моим исследованиям.", - )), - Speech (Dict ( + ), + Speech ( ja: "ぼくらがニワトリを飼っているわけじゃない。あいつらはぼくらの食料を狙って勝手に入り込んでいるんだ。", en: "We don't keep chickens. They sneak in to steal our food.", zh_cn: "我们不养鸡。它们偷偷进来偷我们的食物。", @@ -175,8 +179,8 @@ SenarioRegistry( de: "Wir halten keine Hühner. Sie schleichen sich ein, um unser Essen zu stehlen.", ko: "우리는 닭을 키우지 않아. 그들은 우리의 음식을 훔치기 위해 몰래 들어와.", ru: "Мы не держим кур. Они проникают, чтобы украсть нашу еду.", - )), - Speech (Dict ( + ), + Speech ( ja: "ぼくらはニワトリなんて食べないよ。むしろニワトリがぼくらを食べようとしてるのさ。", en: "We don't eat chickens. Rather, the chickens are trying to eat us.", zh_cn: "我们不吃鸡。相反,鸡在试图吃我们。", @@ -187,10 +191,10 @@ SenarioRegistry( de: "Wir essen keine Hühner. Vielmehr versuchen die Hühner, uns zu essen.", ko: "우리는 닭을 먹지 않아. 오히려 닭들이 우리를 먹으려고 해.", ru: "Мы не едим кур. Скорее, куры пытаются съесть нас.", - )) + ) ], "TrainingRabbit": [ - Speech (Dict ( + Speech ( ja: "キミも強くなりたいのかい?ここで練習していくといい。サンドバッグくんたちが相手になってくれる。", en: "Do you want to become stronger too? You can practice here. The sandbags will be your opponents.", zh_cn: "你也想变得更强吗?你可以在这里练习。沙袋会成为你的对手。", @@ -201,8 +205,8 @@ SenarioRegistry( de: "Willst du auch stärker werden? Du kannst hier üben. Die Sandsäcke werden deine Gegner sein.", ko: "너도 강해지고 싶니? 여기서 연습할 수 있어. 샌드백이 네 상대가 될 거야.", ru: "Ты тоже хочешь стать сильнее? Ты можешь тренироваться здесь. Мешки с песком будут твоими противниками.", - )), - Speech (Dict ( + ), + Speech ( ja: "魔法使いはジャンプするのにも魔法を使うそうだね。よかったら左手の訓練所でジャンプの練習をするといい。", en: "I heard that witches use magic even to jump. You should practice jumping at the training ground on the left.", zh_cn: "我听说女巫甚至用魔法跳跃。你应该在左边的训练场练习跳跃。", @@ -213,11 +217,11 @@ SenarioRegistry( de: "Ich habe gehört, dass Hexen sogar Magie zum Springen verwenden. Du solltest das Springen auf dem Trainingsgelände links üben.", ko: "마녀들은 점프할 때도 마법을 사용한다고 들었어. 왼쪽 훈련장에서 점프 연습을 해보는 게 좋을 거야.", ru: "Я слышал, что ведьмы используют магию даже для прыжков. Тебе стоит попрактиковаться в прыжках на тренировочной площадке слева.", - )), + ), OnNewSpell ( - spell: Jump, + spell: "Jump", commands_then: [ - Speech (Dict ( + Speech ( ja: "そうそう、魔法使いはみんな体術が苦手だよね。この呪文を君にあげるよ。", en: "All witches are bad at physical techniques. Here, take this spell.", zh_cn: "所有女巫都不擅长体术。给你这个咒语。", @@ -228,8 +232,8 @@ SenarioRegistry( de: "Alle Hexen sind schlecht in körperlichen Techniken. Hier, nimm diesen Zauber.", ko: "모든 마녀들은 신체 기술에 서툴러. 여기, 이 주문을 받아.", ru: "Все ведьмы плохо владеют физическими техниками. Вот, возьми это заклинание.", - )), - Speech (Dict ( + ), + Speech ( ja: "この隣のジャンプ鍛錬場で試してみるといい。穴に落ちないように気を付けて。", en: "Try it out at the jump training ground next door. Be careful not to fall into the holes.", zh_cn: "在隔壁的跳跃训练场试试吧。小心不要掉进洞里。", @@ -240,12 +244,12 @@ SenarioRegistry( de: "Probier es auf dem Sprungtrainingsplatz nebenan aus. Pass auf, dass du nicht in die Löcher fällst.", ko: "옆의 점프 훈련장에서 시도해봐. 구멍에 빠지지 않도록 조심해.", ru: "Попробуй на тренировочной площадке для прыжков рядом. Будь осторожен, чтобы не упасть в ямы.", - )), + ), Close, - GetSpell (spell: Jump), + GetSpell (spell: "Jump"), ], commands_else: [ - Speech (Dict ( + Speech ( ja: "ところで最近、地下迷宮にとても大きなスライムが現れてね。大暴れして困っているんだ。", en: "Lately, a huge slime has appeared in the labyrinth. It's causing a lot of trouble.", zh_cn: "最近,一个巨大的史莱姆出现在迷宫里。它造成了很多麻烦。", @@ -256,8 +260,8 @@ SenarioRegistry( de: "In letzter Zeit ist ein riesiger Schleim im Labyrinth aufgetaucht. Es verursacht viele Probleme.", ko: "최근에 미로에 거대한 슬라임이 나타났어. 많은 문제를 일으키고 있어.", ru: "В последнее время в лабиринте появился огромный слизень. Он вызывает много проблем.", - )), - Speech (Dict ( + ), + Speech ( ja: "なにしろぼくらは地下迷宮で遺物を拾って生計を立てているからね。あんなのがうろついていたら落ち着いて探索もできやしない。", en: "After all, we make a living by picking up relics in the labyrinth. If such a thing is wandering around, we can't explore calmly.", zh_cn: "毕竟,我们是靠在迷宫里捡遗物谋生的。如果这样的东西四处游荡,我们就无法平静地探索。", @@ -268,8 +272,8 @@ SenarioRegistry( de: "Schließlich verdienen wir unseren Lebensunterhalt, indem wir Relikte im Labyrinth aufsammeln. Wenn so etwas herumwandert, können wir nicht ruhig erkunden.", ko: "결국 우리는 미로에서 유물을 주워 생계를 유지해. 그런 것이 돌아다니면 우리는 차분하게 탐험할 수 없어.", ru: "В конце концов, мы зарабатываем на жизнь, собирая реликвии в лабиринте. Если такое существо будет бродить вокруг, мы не сможем спокойно исследовать.", - )), - Speech (Dict ( + ), + Speech ( ja: "あなたがあのスライムを討伐してくれたら、とても助かるんだけど。", en: "If you could defeat that slime, I would be very grateful.", zh_cn: "如果你能打败那个史莱姆,我会非常感激。", @@ -280,8 +284,8 @@ SenarioRegistry( de: "Wenn du diesen Schleim besiegen könntest, wäre ich dir sehr dankbar.", ko: "네가 그 슬라임을 물리쳐 준다면 정말 고마울 거야.", ru: "Если бы ты мог победить этого слизня, я был бы очень благодарен.", - )), - Speech (Dict ( + ), + Speech ( ja: "その大きなスライムは体当たりで攻撃してくるが、足が早ければ逃げるのは難しくない。", en: "The huge slime attacks with a body blow, but if you have fast legs, it's not hard to escape.", zh_cn: "巨大的史莱姆会用身体冲击攻击,但如果你的腿很快", @@ -292,8 +296,8 @@ SenarioRegistry( de: "Der riesige Schleim greift mit einem Körperstoß an, aber wenn du schnelle Beine hast, ist es nicht schwer zu entkommen.", ko: "거대한 슬라임은 몸통 박치기로 공격하지만, 다리가 빠르면 도망치는 것은 어렵지 않아.", ru: "Огромный слизень атакует телесным ударом, но если у тебя быстрые ноги, убежать несложно.", - )), - Speech (Dict ( + ), + Speech ( ja: "それと、あいつは仲間の小さなスライムを呼び寄せるんだ。囲まれると逃げ道を失う。周囲のスライムは素早く倒したほうがいい。", en: "And it calls small slimes to its side. If you are surrounded, you will lose your escape route. It's better to defeat the surrounding slimes quickly.", zh_cn: "它会召唤小史莱姆来帮忙。如果你被包围,你就会失去逃跑的路线。最好快速击败周围的史莱姆。", @@ -304,12 +308,12 @@ SenarioRegistry( de: "Und es ruft kleine Schleime zu sich. Wenn du umzingelt bist, verlierst du deinen Fluchtweg. Es ist besser, die umliegenden Schleime schnell zu besiegen.", ko: "그리고 작은 슬라임들을 불러들여. 둘러싸이면 도망갈 길을 잃게 돼. 주변의 슬라임들을 빨리 물리치는 것이 좋아.", ru: "И он зовет к себе маленьких слизней. Если ты окажешься окружен, ты потеряешь путь к бегству. Лучше быстро победить окружающих слизней.", - )), + ), ] ) ], "SpellListRabbit": [ - Speech (Dict ( + Speech ( ja: "私は魔法使いたちの操る呪文に興味があってね。君の知っている呪文について教えてくれないか?", en: "I'm interested in the spells cast by witches. Can you tell me about the spells you know?", zh_cn: "我对女巫施展的咒语很感兴趣。你能告诉我你所知道的咒语吗?", @@ -320,8 +324,8 @@ SenarioRegistry( de: "Ich interessiere mich für die Zauber, die Hexen wirken. Kannst du mir von den Zaubern erzählen, die du kennst?", ko: "나는 마녀들이 사용하는 주문에 관심이 있어. 네가 알고 있는 주문에 대해 말해줄 수 있니?", ru: "Меня интересуют заклинания, которые используют ведьмы. Можешь рассказать мне о заклинаниях, которые ты знаешь?", - )), - Speech (Dict ( + ), + Speech ( ja: "……ふうむ、実に興味深い。もし新たな魔法を見つけたらぜひ教えてくれ。", en: "Hmmmm, very interesting. Please let me know if you find a new spell.", zh_cn: "嗯嗯,非常有趣。如果您发现新咒语,请告诉我。", @@ -332,8 +336,8 @@ SenarioRegistry( de: "Hmmmm, sehr interessant. Bitte lass mich wissen, wenn du einen neuen Zauber findest.", ko: "음, 매우 흥미로워. 새로운 주문을 발견하면 꼭 알려줘.", ru: "Хммм, очень интересно. Пожалуйста, сообщи мне, если найдешь новое заклинание.", - )), - Speech (Dict ( + ), + Speech ( ja: "皆にもその呪文を集めるよう伝えておこう。次からその呪文が店にも並ぶようになるはずだ。", en: "I'll tell everyone to collect that spells. It should be available in the shop from now on.", zh_cn: "我会告诉大家收集咒语。从现在开始,它应该可以在商店里买到。", @@ -344,7 +348,7 @@ SenarioRegistry( de: "Ich werde allen sagen, dass sie diese Zauber sammeln sollen. Sie sollten ab jetzt im Laden erhältlich sein.", ko: "모두에게 그 주문을 모으라고 말할게. 이제부터 그 주문이 가게에 있을 거야.", ru: "Я скажу всем собирать эти заклинания. Они должны быть доступны в магазине с этого момента.", - )) + ) ], "HugeSlime": [ BGM (bgm: None), @@ -368,7 +372,7 @@ SenarioRegistry( reverse: false, ), Wait (count: 180), - ShakeStart (value: Some(6.0)), + ShakeStart (value: 6.0), SE (se: Jishin), Flash ( position: Var (value: "position"), @@ -399,7 +403,7 @@ SenarioRegistry( SE (se: Break), SpawnRaven (name: "raven", position: (392.0, -2504.0,)), Wait (count: 120), - SetCameraTarget (name: Some("raven")), + SetCameraTarget (name: "raven"), Wait (count: 120), SetCameraTarget (name: None), Despawn (name: "raven") diff --git a/assets/registry.spell.ron b/assets/registry.spell.ron index 1bcb95d..213b976 100644 --- a/assets/registry.spell.ron +++ b/assets/registry.spell.ron @@ -1,446 +1,7 @@ +// https://github.com/ron-rs/ron/blob/master/docs/extensions.md +#![enable(unwrap_newtypes)] +#![enable(implicit_some)] SpellRegistry( - - levels: [ - ( - name: Dict ( - ja: "ウサギ族のキャンプ", - en: "Rabbit's Camp", - zh_cn: "兔子的营地", - zh_tw: "兔子的營地", - es: "Campamento de Conejos", - fr: "Camp des Lapins", - pt: "Acampamento dos Coelhos", - de: "Kaninchenlager", - ko: "토끼 캠프", - ru: "Лагерь кроликов", - ), - enemies: 0, - enemy_types: [], - items: 0, - item_ranks: [], - biome: StoneTile - ), - ( - name: Dict ( - ja: "図書館跡", - en: "Library Ruins", - zh_cn: "图书馆废墟", - zh_tw: "圖書館廢墟", - es: "Ruinas de la Biblioteca", - fr: "Ruines de la Bibliothèque", - pt: "Ruínas da Biblioteca", - de: "Bibliotheksruinen", - ko: "도서관 폐허", - ru: "Руины библиотеки", - ), - enemies: 10, - enemy_types: [Slime], - items: 3, - item_ranks: [0, 1, 2], - biome: StoneTile - ), - ( - name: Dict ( - ja: "地下草原", - en: "Underground Grassland", - zh_cn: "地下草原", - zh_tw: "地下草原", - es: "Pradera Subterránea", - fr: "Prairie Souterraine", - pt: "Pradaria Subterrânea", - de: "Unterirdisches Grasland", - ko: "지하 초원", - ru: "Подземные луга", - ), - enemies: 15, - enemy_types: [Slime, Spider], - items: 3, - item_ranks: [1, 2, 3], - biome: Grassland - ), - ( - name: Dict ( - ja: "古城", - en: "Ancient Castle", - zh_cn: "古城", - zh_tw: "古城", - es: "Castillo Antiguo", - fr: "Château Ancien", - pt: "Castelo Antigo", - de: "Alte Burg", - ko: "고대 성", - ru: "Древний замок", - ), - enemies: 20, - enemy_types: [Spider, EyeBall], - items: 3, - item_ranks: [2, 3, 4], - biome: StoneTile - ), - ( - name: Dict ( - ja: "スライムの巣窟", - en: "Slime Nest", - zh_cn: "史莱姆巢穴", - zh_tw: "史萊姆巢穴", - es: "Nido de Slimes", - fr: "Nid de Slimes", - pt: "Ninho de Slimes", - de: "Schleimnest", - ko: "슬라임 둥지", - ru: "Гнездо слизней", - ), - enemies: 20, - enemy_types: [EyeBall, Shadow], - items: 3, - item_ranks: [3, 4, 5], - biome: StoneTile - ), - ( - name: Dict ( - ja: "氷の洞窟", - en: "Ice Cave", - zh_cn: "冰洞", - zh_tw: "冰洞", - es: "Cueva de Hielo", - fr: "Grotte de Glace", - pt: "Caverna de Gelo", - de: "Eishöhle", - ko: "얼음 동굴", - ru: "Ледяная пещера", - ), - enemies: 15, - enemy_types: [Shadow, Salamander], - items: 3, - item_ranks: [4, 5, 6], - biome: Ice - ), - ( - name: Dict ( - ja: "古の回廊", - en: "Ancient Corridor", - zh_cn: "古代走廊", - zh_tw: "古代走廊", - es: "Corredor Antiguo", - fr: "Couloir Ancien", - pt: "Corredor Antigo", - de: "Alter Korridor", - ko: "고대 회랑", - ru: "Древний коридор", - ), - enemies: 30, - enemy_types: [Slime, Spider, EyeBall, Shadow, Salamander], - items: 3, - item_ranks: [4, 5, 6], - biome: StoneTile - ), - ( - name: Dict ( - ja: "大空洞", - en: "Great Cavern", - zh_cn: "大洞穴", - zh_tw: "大洞穴", - es: "Gran Caverna", - fr: "Grande Caverne", - pt: "Grande Caverna", - de: "Große Höhle", - ko: "큰 동굴", - ru: "Большая пещера", - ), - enemies: 0, - enemy_types: [], - items: 3, - item_ranks: [], - biome: StoneTile - ), - ], - arena: ( - name: Dict ( - ja: "対決の洞窟", - en: "Cave of Confrontation", - zh_cn: "对决洞穴", - zh_tw: "對決洞穴", - es: "Cueva de Confrontación", - fr: "Grotte de Confrontation", - pt: "Caverna de Confronto", - de: "Höhle der Konfrontation", - ko: "대결의 동굴", - ru: "Пещера противостояния" - ), - enemies: 0, - enemy_types: [], - items: 3, - item_ranks: [], - biome: StoneTile - ), - - - tiles: { - (203, 219, 252, 255): ( - tile: None, - zone: Dungeon, - entity: None, - entry_point: false, - ), - (234, 255, 214, 255): ( - tile: None, - zone: SafeZone, - entity: None, - entry_point: false, - ), - (82, 75, 36, 255): ( - tile: Some(Wall), - zone: SafeZone, - entity: None, - entry_point: false, - ), - (118, 66, 138, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Actor ( - actor_type: BookShelf, - actor_group: Entity, - )), - entry_point: false, - ), - (251, 242, 54, 255): ( - tile: None, - zone: SafeZone, - entity: Some(RandomChest), - entry_point: false, - ), - (255, 155, 87, 255): ( - tile: None, - zone: SafeZone, - entity: Some(RandomChest), - entry_point: false, - ), - // (81, 28) 水路の奥の隠し部屋 - (255, 155, 88, 255): ( - tile: None, - zone: SafeZone, - entity: Some(SpellInChest ( - spell: Dash, - )), - entry_point: false, - ), - // (30, 69) ジャンプ練習場の奥 - (255, 155, 89, 255): ( - tile: None, - zone: SafeZone, - entity: Some(SpellInChest ( - spell: Levitation, - )), - entry_point: false, - ), - // (53, 24) Z字型の裂け目の奥の隠し部屋 - (255, 155, 90, 255): ( - tile: None, - zone: SafeZone, - entity: Some(SpellInChest ( - spell: Bomb, - )), - entry_point: false, - ), - // (100, 66) 溶岩流を渡った先 - (255, 155, 91, 255): ( - tile: None, - zone: SafeZone, - entity: Some(SpellInChest ( - spell: LightSword, - )), - entry_point: false, - ), - (48, 96, 130, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(MagicCircle), - entry_point: false, - ), - (47, 96, 130, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(MultiPlayArenaMagicCircle), - entry_point: false, - ), - (56, 111, 161, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(MagicCircleHome), - entry_point: false, - ), - (46, 96, 130, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(MagicCircleDemoEnding), - entry_point: false, - ), - (255, 0, 0, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(BrokenMagicCircle), - entry_point: true, - ), - (255, 0, 255, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(Usage), - entry_point: false, - ), - (254, 0, 255, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(Routes), - entry_point: false, - ), - (223, 113, 38, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(Actor ( - actor_type: Lantern, - actor_group: Entity, - )), - entry_point: false, - ), - (0, 222, 255, 255): ( - tile: None, - zone: SafeZone, - entity: Some(ShopSpell), - entry_point: false, - ), - (102, 57, 49, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(RandomChest), - entry_point: false, - ), - (184, 0, 255, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Boss ( - actor_type: HugeSlime, - name: Dict ( - ja: "スライムの王 エミルス", - en: "Slime King Emils", - zh_cn: "史莱姆之王 艾米尔斯", - zh_tw: "史萊姆之王 艾米爾斯", - es: "Rey Slime Emils", - fr: "Roi Slime Emils", - pt: "Rei Slime Emils", - de: "Schleimkönig Emils", - ko: "슬라임 왕 에밀스", - ru: "Король слизней Эмильс", - ), - )), - entry_point: false, - ), - (255, 243, 0, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Rabbit(Shop)), - entry_point: false, - ), - (255, 244, 0, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Rabbit(Training)), - entry_point: false, - ), - (255, 245, 0, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Rabbit(Guide)), - entry_point: false, - ), - (255, 246, 0, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Rabbit(MultiPlay)), - entry_point: false, - ), - (255, 247, 0, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Rabbit(Singleplay)), - entry_point: false, - ), - (255, 248, 0, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Rabbit(Reading)), - entry_point: false, - ), - (255, 249, 0, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Rabbit(SpellList)), - entry_point: false, - ), - (182, 0, 255, 255): ( - tile: None, - zone: SafeZone, - entity: Some(Actor ( - actor_type: Sandbag, - actor_group: Neutral, - )), - entry_point: false, - ), - (197, 255, 142, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: Some(ShopDoor), - entry_point: false, - ), - (68, 0, 94, 255): ( - tile: None, - zone: SafeZone, - entity: Some(BGM), - entry_point: false, - ), - (153, 229, 80, 255): ( - tile: Some(Grassland), - zone: SafeZone, - entity: None, - entry_point: false, - ), - (156, 156, 156, 255): ( - tile: Some(StoneTile), - zone: SafeZone, - entity: None, - entry_point: false, - ), - (55, 79, 225, 255): ( - tile: Some(Water), - zone: SafeZone, - entity: None, - entry_point: false, - ), - (205, 121, 54, 255): ( - tile: Some(Lava), - zone: SafeZone, - entity: None, - entry_point: false, - ), - (43, 43, 43, 255): ( - tile: Some(Crack), - zone: SafeZone, - entity: None, - entry_point: false, - ), - (222, 233, 255, 255): ( - tile: Some(Ice), - zone: SafeZone, - entity: None, - entry_point: false, - ), - (0, 0, 0, 255): ( - tile: Some(PermanentWall), - zone: SafeZone, - entity: None, - entry_point: false, - ) - }, - spells: { "MagicBolt": ( rank: 0, @@ -561,7 +122,7 @@ SpellRegistry( icon: "lantern", price: 100, cast_delay: 0, - cast: None + cast: NoCast ), "SpawnJar": ( rank: 0, @@ -718,7 +279,7 @@ SpellRegistry( cast_delay: 0, icon: "zoom_out", price: 300, - cast: None + cast: NoCast ), "Magnifier": ( rank: 1, @@ -749,7 +310,7 @@ SpellRegistry( icon: "zoom_in", price: 300, cast_delay: 0, - cast: None + cast: NoCast ), "Jump": ( rank: 2, @@ -1574,7 +1135,7 @@ SpellRegistry( icon: "boots", price: 100, cast_delay: 0, - cast: None, + cast: NoCast, ), "ApplyLevitation": ( rank: 5, @@ -1889,103 +1450,4 @@ SpellRegistry( cast: InfinityClone, ), }, - - debug_items: [ - MagicBolt, - MagicBolt, - LightBall, - WaterBall, - SlimeCharge, - Heal, - BulletSpeedUp, - BulletSpeedUp, - BulletSpeedUp, - BulletSpeedDoown, - BulletSpeedDoown, - BulletSpeedDoown, - PurpleBolt, - DualCast, - TripleCast, - Lantern, - Lantern, - SpikeBoots, - Telescope, - Magnifier, - Homing, - Homing, - HeavyShot, - HeavyShot, - SummonFriendSlime, - SummonEnemySlime, - SummonFriendEyeball, - SummonEnemyEyeball, - Dash, - QuickCast, - QuickCast, - Impact, - PrecisionUp, - PrecisionUp, - Bomb, - LightSword, - SpawnBookshelf, - SpawnJar, - RockFall, - Fireball, - SummonHugeSlime, - SummonChiken, - Servant, - Web, - Freeze, - Levitation, - ApplyLevitation, - Jump, - Metamorphosis, - Slash, - Dispel, - Clone, - InfinityClone - ], - - debug_wands: [ - [ - Some(InfinityClone), - None, - None, - None, - None, - None, - None, - None, - ], - [ - Some(QuickCast), - Some(QuickCast), - Some(HeavyShot), - Some(HeavyShot), - Some(TripleCast), - Some(MagicBolt), - Some(MagicBolt), - Some(MagicBolt), - ], - [ - Some(Bomb), - None, - None, - None, - None, - None, - None, - None, - ], - [ - Some(Dash), - Some(Lantern), - None, - None, - None, - None, - None, - None, - ] - ] ) \ No newline at end of file diff --git a/src/actor.rs b/src/actor.rs index aaa660c..d864c73 100644 --- a/src/actor.rs +++ b/src/actor.rs @@ -57,7 +57,7 @@ use crate::registry::Registry; use crate::se::SEEvent; use crate::se::SE; use crate::set::FixedUpdateGameActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameState; use crate::ui::floating::FloatingContent; use crate::wand::Wand; @@ -356,21 +356,24 @@ impl Actor { FloatingContent::Inventory(index) => self .inventory .get(index) + .as_ref() .map(|i| i.item_type.get_icon(®istry)), FloatingContent::WandSpell(w, s) => { - self.wands[w].slots[s].map(|WandSpell { spell_type, .. }| { - registry.get_spell_props(spell_type).icon.clone() - }) + self.wands[w].slots[s] + .as_ref() + .map(|WandSpell { ref spell_type, .. }| { + registry.get_spell_props(spell_type).icon.clone() + }) } } } pub fn get_spell(&self, wand_index: usize, spell_index: usize) -> Option { - self.wands[wand_index].slots[spell_index] + self.wands[wand_index].slots[spell_index].clone() } pub fn get_wand_spell(&self, wand_index: usize, spell_index: usize) -> Option { - self.wands[wand_index].slots[spell_index] + self.wands[wand_index].slots[spell_index].clone() } /// 現在所持している有料呪文の合計金額を返します @@ -420,12 +423,13 @@ impl Actor { //todo for wand in self.wands.iter() { - for slot in wand.slots { + for slot in &wand.slots { force += match slot { - Some(WandSpell { - spell_type: SpellType::SpikeBoots, - .. - }) => 40000.0, + Some(WandSpell { spell_type, .. }) + if *spell_type == Spell::new("SpikeBoots") => + { + 40000.0 + } _ => 0.0, } } @@ -439,16 +443,18 @@ impl Actor { // todo for wand in self.wands.iter() { - for slot in wand.slots { + for slot in &wand.slots { scale_factor += match slot { - Some(WandSpell { - spell_type: SpellType::Telescope, - .. - }) => 0.5, - Some(WandSpell { - spell_type: SpellType::Magnifier, - .. - }) => -0.5, + Some(WandSpell { spell_type, .. }) + if *spell_type == Spell::new("Telescope") => + { + 0.5 + } + Some(WandSpell { spell_type, .. }) + if *spell_type == Spell::new("Magnifier") => + { + -0.5 + } _ => 0.0, } } @@ -457,13 +463,13 @@ impl Actor { scale_factor.max(-2.0).min(1.0) } - pub fn get_owned_spell_types(&self) -> HashSet { - let mut discovered_spells = HashSet::new(); + pub fn get_owned_spell_types(&self) -> HashSet { + let mut discovered_spells: HashSet = HashSet::new(); for item in self.inventory.0.iter() { if let Some(ref item) = item { - match item.item_type { + match &item.item_type { InventoryItemType::Spell(spell) if item.price == 0 => { - let _ = discovered_spells.insert(spell); + let _ = discovered_spells.insert(spell.clone()); } _ => {} }; @@ -471,9 +477,9 @@ impl Actor { } for wand in self.wands.iter() { for item in wand.slots.iter() { - if let Some(ref item) = item { + if let Some(ref item) = &item { if item.price == 0 { - let _ = discovered_spells.insert(item.spell_type); + let _ = discovered_spells.insert(item.spell_type.clone()); } } } @@ -621,12 +627,11 @@ fn update_actor_light( // 大量に複製すると明るくなりすぎるため if actor.cloned.is_none() { for wand in actor.wands.iter() { - for slot in wand.slots { + for slot in &wand.slots { match slot { - Some(WandSpell { - spell_type: SpellType::Lantern, - .. - }) => { + Some(WandSpell { spell_type, .. }) + if *spell_type == Spell::new("Lantern") => + { point_light_radius += 160.0; } _ => {} diff --git a/src/actor/chest.rs b/src/actor/chest.rs index fc87359..e7fd084 100644 --- a/src/actor/chest.rs +++ b/src/actor/chest.rs @@ -66,7 +66,7 @@ pub const CHEST_OR_BARREL: [ChestType; 12] = [ #[derive(Component, Reflect, Debug)] struct Chest; -#[derive(Reflect, Clone, Debug, Copy, Deserialize)] +#[derive(Reflect, Clone, Debug, Deserialize)] pub enum ChestItem { Gold, Item(InventoryItem), @@ -167,7 +167,7 @@ fn break_chest( let ActorExtra::Chest { chest_type, chest_item, - } = actor.extra + } = &actor.extra else { panic!("ActorExtra::Chest is expected"); }; @@ -198,7 +198,7 @@ fn break_chest( ®istry, position, "crate", - JarColor::Red, + &JarColor::Red, i, ); } @@ -210,7 +210,7 @@ fn break_chest( ®istry, position, "barrel", - JarColor::Red, + &JarColor::Red, i, ); } @@ -239,7 +239,7 @@ fn spawn_jar_piece( registry: &Registry, position: Vec2, type_name: &str, - color: JarColor, + color: &JarColor, index: u32, ) { spawn_broken_piece( diff --git a/src/actor/chicken.rs b/src/actor/chicken.rs index cc22140..3b4e2af 100644 --- a/src/actor/chicken.rs +++ b/src/actor/chicken.rs @@ -8,7 +8,7 @@ use crate::enemy::basic::spawn_basic_enemy; use crate::hud::life_bar::LifeBarResource; use crate::registry::Registry; use crate::set::FixedUpdateGameActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::wand::Wand; use bevy::prelude::*; use core::f32; @@ -36,7 +36,7 @@ pub fn default_chiken() -> Actor { Actor { extra: ActorExtra::Chicken, actor_group: ActorGroup::Neutral, - wands: Wand::single(Some(SpellType::Jump)), + wands: Wand::single(Some(Spell::new("Jump"))), life: 2, max_life: 2, ..default() diff --git a/src/actor/sandbug.rs b/src/actor/sandbug.rs index 645ecf1..eef7721 100644 --- a/src/actor/sandbug.rs +++ b/src/actor/sandbug.rs @@ -5,7 +5,7 @@ use crate::enemy::basic::spawn_basic_enemy; use crate::hud::life_bar::LifeBarResource; use crate::registry::Registry; use crate::set::FixedUpdateGameActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::wand::Wand; use bevy::prelude::*; @@ -25,7 +25,7 @@ pub fn default_sandbag() -> Actor { Actor { extra: ActorExtra::Sandbag, actor_group: ActorGroup::Neutral, - wands: Wand::single(Some(SpellType::Jump)), + wands: Wand::single(Some(Spell::new("Jump"))), life: 10000, max_life: 10000, ..default() diff --git a/src/asset.rs b/src/asset.rs index c4e032d..baa9091 100644 --- a/src/asset.rs +++ b/src/asset.rs @@ -1,4 +1,5 @@ use crate::registry::ActorRegistry; +use crate::registry::GameRegistry; use crate::registry::SenarioRegistry; use crate::registry::SpellRegistry; use bevy::asset::*; @@ -9,6 +10,9 @@ use bevy_asset_loader::prelude::*; #[derive(AssetCollection, Resource)] pub struct GameAssets { // 設定 ////////////////////////////////////////////////////////////////////////////////////////////////////// + #[asset(path = "registry.game.ron")] + pub game_registry: Handle, + #[asset(path = "registry.spell.ron")] pub spell_registry: Handle, diff --git a/src/cast.rs b/src/cast.rs index 239a8e8..ce8bb7a 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -75,7 +75,7 @@ pub struct SpellCastBullet { /// そのほかの魔法も動作の種別によって分類されています #[derive(Debug, serde::Deserialize, Clone)] pub enum SpellCast { - None, + NoCast, Bullet(SpellCastBullet), Heal, BulletSpeedUpDown { @@ -164,8 +164,8 @@ pub fn cast_spell( let actor_position = actor_transform.translation.truncate(); while 0 < multicast && spell_index < MAX_SPELLS_IN_WAND { - if let Some(spell) = actor.wands[wand_index as usize].slots[spell_index] { - let props = registry.get_spell_props(spell.spell_type); + if let Some(spell) = actor.wands[wand_index as usize].slots[spell_index].as_ref() { + let props = registry.get_spell_props(&spell.spell_type); let original_delay = props.cast_delay.max(1) as i32; let delay = (original_delay as i32 - actor.effects.quick_cast as i32).max(1); actor.effects.quick_cast -= (original_delay - delay) as u32; @@ -175,7 +175,7 @@ pub fn cast_spell( let actor_props = registry.get_actor_props(actor.to_type()); match props.cast { - SpellCast::None => {} + SpellCast::NoCast => {} SpellCast::Bullet(ref cast) => { let normalized = actor.pointer.normalize(); let angle = actor.pointer.to_angle(); diff --git a/src/controller/player.rs b/src/controller/player.rs index 7fde20d..4559d34 100644 --- a/src/controller/player.rs +++ b/src/controller/player.rs @@ -23,7 +23,7 @@ use crate::se::SEEvent; use crate::se::SE; use crate::set::FixedUpdateInGameSet; use crate::set::FixedUpdatePlayerActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameMenuState; use crate::states::GameState; use bevy::core::FrameCount; @@ -51,11 +51,11 @@ pub struct Player { pub last_idle_vy: f32, pub last_idle_life: u32, pub last_idle_max_life: u32, - pub discovered_spells: HashSet, + pub discovered_spells: HashSet, } impl Player { - pub fn new(name: String, discovered_spells: &HashSet) -> Self { + pub fn new(name: String, discovered_spells: &HashSet) -> Self { Self { name, last_idle_frame_count: FrameCount(0), diff --git a/src/enemy/eyeball.rs b/src/enemy/eyeball.rs index e57683f..dc3be3c 100644 --- a/src/enemy/eyeball.rs +++ b/src/enemy/eyeball.rs @@ -8,7 +8,7 @@ use crate::finder::Finder; use crate::hud::life_bar::LifeBarResource; use crate::registry::Registry; use crate::set::FixedUpdateGameActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::wand::Wand; use bevy::prelude::*; use bevy_rapier2d::prelude::*; @@ -24,7 +24,7 @@ pub fn default_eyeball() -> Actor { Actor { extra: ActorExtra::Eyeball, actor_group: ActorGroup::Enemy, - wands: Wand::single(Some(SpellType::PurpleBolt)), + wands: Wand::single(Some(Spell::new("PurpleBolt"))), life: 25, max_life: 25, ..default() diff --git a/src/enemy/salamander.rs b/src/enemy/salamander.rs index 3110b36..8558d7c 100644 --- a/src/enemy/salamander.rs +++ b/src/enemy/salamander.rs @@ -10,7 +10,7 @@ use crate::level::entities::SpawnEvent; use crate::random::randomize_velocity; use crate::registry::Registry; use crate::set::FixedUpdateGameActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::wand::Wand; use bevy::prelude::*; use bevy_rapier2d::prelude::*; @@ -43,7 +43,7 @@ pub fn default_salamander() -> Actor { Actor { extra: ActorExtra::Salamander, actor_group: ActorGroup::Enemy, - wands: Wand::single(Some(SpellType::Fireball)), + wands: Wand::single(Some(Spell::new("Fireball"))), life: 100, max_life: 100, golds: 10, diff --git a/src/enemy/slime.rs b/src/enemy/slime.rs index ea9ccf1..4666e97 100644 --- a/src/enemy/slime.rs +++ b/src/enemy/slime.rs @@ -8,7 +8,7 @@ use crate::finder::Finder; use crate::hud::life_bar::LifeBarResource; use crate::registry::Registry; use crate::set::FixedUpdateGameActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::wand::Wand; use bevy::prelude::*; use bevy_rapier2d::prelude::*; @@ -35,7 +35,7 @@ pub fn default_slime() -> Actor { Actor { extra: ActorExtra::Slime, actor_group: ActorGroup::Enemy, - wands: Wand::single(Some(SpellType::SlimeCharge)), + wands: Wand::single(Some(Spell::new("SlimeCharge"))), life: 15, max_life: 15, ..default() diff --git a/src/entity/dropped_item.rs b/src/entity/dropped_item.rs index 1addbcc..3a075a7 100644 --- a/src/entity/dropped_item.rs +++ b/src/entity/dropped_item.rs @@ -33,14 +33,14 @@ pub fn spawn_dropped_item( commands: &mut Commands, registry: &Registry, position: Vec2, - item: InventoryItem, + item: &InventoryItem, ) { - let item_type = item.item_type; + let item_type = &item.item_type; let icon = match item_type { - InventoryItemType::Spell(spell) => registry.get_spell_props(spell).icon.clone(), + InventoryItemType::Spell(spell) => registry.get_spell_props(&spell).icon.clone(), }; let name = match item_type { - InventoryItemType::Spell(spell) => registry.get_spell_props(spell).name.en.clone(), + InventoryItemType::Spell(spell) => registry.get_spell_props(&spell).name.en.clone(), }; let frame_slice = match item_type { InventoryItemType::Spell(_) if 0 < item.price => "spell_frame", @@ -56,7 +56,7 @@ pub fn spawn_dropped_item( .spawn(( Name::new(format!("dropped item {}", name)), StateScoped(GameState::InGame), - DroppedItemEntity { item }, + DroppedItemEntity { item: item.clone() }, EntityDepth::new(), Transform::from_translation(Vec3::new(position.x, position.y, 0.0)), GlobalTransform::default(), @@ -142,7 +142,7 @@ fn pickup_dropped_item( IdentifiedCollisionEvent::Started(item_entity, player_entity) => { let item = item_query.get(item_entity).unwrap(); let mut actor = player_query.get_mut(player_entity).unwrap(); - if actor.inventory.insert(item.item) { + if actor.inventory.insert(item.item.clone()) { commands.entity(item_entity).despawn_recursive(); se.send(SEEvent::new(SE::PickUp)); @@ -150,10 +150,12 @@ fn pickup_dropped_item( let InventoryItem { item_type: InventoryItemType::Spell(spell), price: _, - } = item.item; + } = &item.item; interpreter.send(InterpreterEvent::Play { - commands: vec![Cmd::GetSpell { spell }], + commands: vec![Cmd::GetSpell { + spell: spell.clone(), + }], }); } } diff --git a/src/game.rs b/src/game.rs index 0000fa4..3c185af 100644 --- a/src/game.rs +++ b/src/game.rs @@ -73,6 +73,7 @@ use crate::page::warp::WarpPagePlugin; use crate::physics::GamePhysicsPlugin; use crate::player_state::PlayerStatePlugin; use crate::registry::ActorRegistry; +use crate::registry::GameRegistry; use crate::registry::SenarioRegistry; use crate::registry::SpellRegistry; #[cfg(feature = "save")] @@ -180,6 +181,7 @@ pub fn run_game() { }), // ) + .add_plugins(RonAssetPlugin::::new(&["game.ron"])) .add_plugins(RonAssetPlugin::::new(&["spell.ron"])) .add_plugins(RonAssetPlugin::::new(&["actor.ron"])) .add_plugins(RonAssetPlugin::::new(&["senario.ron"])) diff --git a/src/interpreter.rs b/src/interpreter.rs index 95a0df8..fdc329a 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -19,7 +19,7 @@ use crate::page::in_game::LevelSetup; use crate::registry::Registry; use crate::se::SEEvent; use crate::se::SE; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameMenuState; use crate::states::GameState; use crate::states::TimeState; @@ -120,11 +120,11 @@ pub enum Cmd { }, GetSpell { - spell: SpellType, + spell: Spell, }, OnNewSpell { - spell: SpellType, + spell: Spell, commands_then: Vec, commands_else: Vec, }, @@ -398,7 +398,7 @@ fn interpret( Cmd::GetSpell { spell } => { if let Ok((mut actor, player)) = player_query.get_single_mut() { actor.inventory.insert(InventoryItem { - item_type: InventoryItemType::Spell(spell), + item_type: InventoryItemType::Spell(spell.clone()), price: 0, }); if !player.discovered_spells.contains(&spell) { diff --git a/src/inventory.rs b/src/inventory.rs index 956b681..45bfc26 100644 --- a/src/inventory.rs +++ b/src/inventory.rs @@ -1,11 +1,11 @@ use crate::constant::MAX_ITEMS_IN_INVENTORY; use crate::inventory_item::InventoryItemType; -use crate::spell::SpellType; +use crate::spell::Spell; use bevy::reflect::Reflect; use serde::Deserialize; use serde::Serialize; -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Reflect, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Reflect, Serialize, Deserialize)] pub struct InventoryItem { pub item_type: InventoryItemType, pub price: u32, @@ -28,7 +28,7 @@ impl Inventory { Inventory(vec![None; MAX_ITEMS_IN_INVENTORY]) } - pub fn from_vec(vec: Vec) -> Inventory { + pub fn from_vec(vec: Vec) -> Inventory { let mut inventory = Inventory(vec![None; MAX_ITEMS_IN_INVENTORY]); for i in 0..MAX_ITEMS_IN_INVENTORY { inventory.0[i] = vec @@ -38,9 +38,9 @@ impl Inventory { inventory } - pub fn get(&self, index: usize) -> Option { + pub fn get(&self, index: usize) -> &Option { let Inventory(ref inventory) = *self; - return inventory[index]; + &inventory[index] } pub fn set(&mut self, index: usize, item: Option) { @@ -76,7 +76,7 @@ impl Inventory { let Inventory(ref mut inventory) = *self; let mut i = 0; while i < MAX_ITEMS_IN_INVENTORY { - match inventory[i] { + match &inventory[i] { None => { inventory[i] = Some(item); return true; @@ -90,7 +90,7 @@ impl Inventory { } #[allow(dead_code)] - pub fn insert_spell(&mut self, item_type: SpellType) -> bool { + pub fn insert_spell(&mut self, item_type: Spell) -> bool { self.insert(InventoryItem { item_type: InventoryItemType::Spell(item_type), price: 0, @@ -106,7 +106,7 @@ impl Inventory { if b.is_none() { return std::cmp::Ordering::Less; } - match (a.unwrap(), b.unwrap()) { + match (a.as_ref().unwrap(), b.as_ref().unwrap()) { (a, b) => a.item_type.cmp(&b.item_type), } }); @@ -115,11 +115,11 @@ impl Inventory { if MAX_ITEMS_IN_INVENTORY <= i { break; } - let width = match item { + let width = match &item { Some(item) => item.item_type.get_width(), None => 1, }; - self.0[i] = item; + self.0[i] = item.clone(); for j in 1..width { self.0[i + j] = None; } diff --git a/src/inventory_item.rs b/src/inventory_item.rs index 672b8e0..ed5e054 100644 --- a/src/inventory_item.rs +++ b/src/inventory_item.rs @@ -1,12 +1,12 @@ use crate::registry::Registry; -use crate::spell::SpellType; +use crate::spell::Spell; use bevy::reflect::Reflect; use serde::Deserialize; use serde::Serialize; -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Reflect, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Reflect, Serialize, Deserialize)] pub enum InventoryItemType { - Spell(SpellType), + Spell(Spell), } impl InventoryItemType { @@ -18,7 +18,7 @@ impl InventoryItemType { pub fn get_icon(&self, registry: &Registry) -> String { match self { - InventoryItemType::Spell(spell) => registry.get_spell_props(*spell).icon.clone(), + InventoryItemType::Spell(spell) => registry.get_spell_props(spell).icon.clone(), } } diff --git a/src/level/entities.rs b/src/level/entities.rs index 25815b3..fe3d769 100644 --- a/src/level/entities.rs +++ b/src/level/entities.rs @@ -60,7 +60,7 @@ use crate::page::in_game::new_shop_item_queue; use crate::page::in_game::LevelSetup; use crate::registry::Registry; use crate::se::SEEvent; -use crate::spell::SpellType; +use crate::spell::Spell; use bevy::prelude::*; use bevy_aseprite_ultra::prelude::*; use bevy_rapier2d::plugin::DefaultRapierContext; @@ -130,7 +130,7 @@ pub enum Spawn { BGM, RandomChest, SpellInChest { - spell: SpellType, + spell: Spell, }, } @@ -244,7 +244,7 @@ pub fn spawn_entity( } Spawn::ShopSpell => { if let Some(item) = level.shop_items.pop() { - spawn_dropped_item(&mut commands, ®istry, *position, item); + spawn_dropped_item(&mut commands, ®istry, *position, &item); } } Spawn::Rabbit(rabbit_type) => { @@ -274,7 +274,7 @@ pub fn spawn_entity( } Spawn::SpellInChest { spell } => { let chest_item: ChestItem = - ChestItem::Item(InventoryItem::new(InventoryItemType::Spell(*spell))); + ChestItem::Item(InventoryItem::new(InventoryItemType::Spell(spell.clone()))); spawn_actor_internal( &mut commands, ®istry, diff --git a/src/level/map.rs b/src/level/map.rs index 6535fac..be599cc 100644 --- a/src/level/map.rs +++ b/src/level/map.rs @@ -167,7 +167,7 @@ pub fn image_to_tilemap( min_y: i32, max_y: i32, ) -> LevelChunk { - let map = ®istry.spell().tiles; + let map = ®istry.game().tiles; let texture_width = level_image.width(); let mut tiles: Vec = Vec::new(); for y in min_y..max_y { diff --git a/src/page/in_game.rs b/src/page/in_game.rs index ab84dfa..e21d341 100644 --- a/src/page/in_game.rs +++ b/src/page/in_game.rs @@ -33,7 +33,7 @@ use crate::player_state::PlayerState; use crate::registry::Registry; use crate::set::FixedUpdateAfterAll; use crate::set::FixedUpdateGameActiveSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameState; use crate::wand::Wand; use bevy::asset::*; @@ -90,17 +90,17 @@ impl Default for LevelSetup { pub fn new_shop_item_queue( registry: &Registry, - discovered_spells: Vec, + discovered_spells: Vec, ) -> Vec { let mut rng = rand::thread_rng(); let mut shop_items: Vec = registry .spells() .iter() - .filter(|s| discovered_spells.contains(&s) || registry.get_spell_props(**s).rank <= 1) + .filter(|s| discovered_spells.contains(&s) || registry.get_spell_props(*s).rank <= 1) .map(|s| InventoryItem { - item_type: InventoryItemType::Spell(*s), - price: registry.get_spell_props(*s).price, + item_type: InventoryItemType::Spell(s.clone()), + price: registry.get_spell_props(s).price, }) .collect(); @@ -121,6 +121,8 @@ pub fn setup_level( mut spawn: EventWriter, mut overlay: EventWriter, ) { + let game_registry = registry.game(); + overlay.send(OverlayEvent::SetOpen(true)); let mut rng = StdRng::from_entropy(); @@ -184,8 +186,8 @@ pub fn setup_level( .clone() .unwrap_or(if cfg!(feature = "item") { PlayerState { - inventory: Inventory::from_vec(registry.spell().debug_items.clone()), - wands: Wand::from_vec(registry.spell().debug_wands.clone()), + inventory: Inventory::from_vec(game_registry.debug_items.clone()), + wands: Wand::from_vec(game_registry.debug_wands.clone()), ..default() } } else { @@ -428,7 +430,7 @@ fn spawn_dropped_items( .spells() .iter() .filter(|i| { - let props = registry.get_spell_props(**i); + let props = registry.get_spell_props(*i); ranks.contains(&props.rank) }) .choose(&mut rng) @@ -437,8 +439,8 @@ fn spawn_dropped_items( &mut commands, ®istry, position, - InventoryItem { - item_type: InventoryItemType::Spell(*spell), + &InventoryItem { + item_type: InventoryItemType::Spell(spell.clone()), price: 0, }, ); diff --git a/src/player_state.rs b/src/player_state.rs index 1d81837..d803499 100644 --- a/src/player_state.rs +++ b/src/player_state.rs @@ -2,7 +2,7 @@ use crate::actor::Actor; use crate::constant::MAX_WANDS; use crate::controller::player::Player; use crate::inventory::Inventory; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::wand::Wand; use crate::wand::WandSpell; use bevy::prelude::*; @@ -19,7 +19,7 @@ pub struct PlayerState { pub wands: [Wand; MAX_WANDS], pub golds: u32, pub current_wand: u8, - pub discovered_spells: HashSet, + pub discovered_spells: HashSet, } impl Default for PlayerState { @@ -28,7 +28,7 @@ impl Default for PlayerState { let wands = [ Wand::with_slots([ - Some(WandSpell::new(SpellType::MagicBolt)), + Some(WandSpell::new(Spell::new("MagicBolt"))), None, None, None, @@ -40,8 +40,8 @@ impl Default for PlayerState { Wand::default(), Wand::default(), Wand::with_slots([ - Some(WandSpell::new(SpellType::LightBall)), - Some(WandSpell::new(SpellType::Lantern)), + Some(WandSpell::new(Spell::new("LightBall"))), + Some(WandSpell::new(Spell::new("Lantern"))), None, None, None, @@ -86,7 +86,7 @@ impl PlayerState { for wand in self.wands.iter() { for spell in wand.slots.iter() { if let Some(spell) = spell { - discovered_spells.insert(spell.spell_type); + discovered_spells.insert(spell.spell_type.clone()); } } } diff --git a/src/registry.rs b/src/registry.rs index 265199f..c010812 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -6,22 +6,25 @@ use crate::language::Dict; use crate::level::map::LevelTile; use crate::level::tile::Tile; use crate::page::in_game::GameLevel; +use crate::spell::Spell; use crate::spell::SpellProps; -use crate::spell::SpellType; use bevy::asset::Assets; use bevy::ecs::system::SystemParam; use bevy::prelude::Res; use std::collections::HashMap; -use strum::IntoEnumIterator; #[derive(serde::Deserialize, bevy::asset::Asset, bevy::reflect::TypePath)] -pub struct SpellRegistry { - pub spells: HashMap, +pub struct GameRegistry { pub levels: Vec, pub arena: LevelProps, pub tiles: HashMap<(u8, u8, u8, u8), LevelTile>, - pub debug_items: Vec, - pub debug_wands: Vec>>, + pub debug_items: Vec, + pub debug_wands: Vec>>, +} + +#[derive(serde::Deserialize, bevy::asset::Asset, bevy::reflect::TypePath)] +pub struct SpellRegistry { + pub spells: HashMap, } #[derive(serde::Deserialize)] @@ -91,12 +94,17 @@ pub struct SenarioRegistry { #[derive(SystemParam)] pub struct Registry<'w> { pub assets: Res<'w, GameAssets>, + game: Res<'w, Assets>, spell: Res<'w, Assets>, actor: Res<'w, Assets>, senario: Res<'w, Assets>, } impl<'w> Registry<'w> { + pub fn game(&self) -> &GameRegistry { + self.game.get(&self.assets.game_registry).unwrap() + } + pub fn spell(&self) -> &SpellRegistry { self.spell.get(&self.assets.spell_registry).unwrap() } @@ -120,22 +128,23 @@ impl<'w> Registry<'w> { .expect(format!("ActorType {:?} not found", name).as_str()) } - pub fn get_spell_props(&self, spell_type: SpellType) -> &SpellProps { + pub fn get_spell_props(&self, Spell(spell_type): &Spell) -> &SpellProps { let constants = self.spell.get(&self.assets.spell_registry).unwrap(); - let key = format!("{:?}", spell_type); - &constants.spells.get(&key).expect(key.as_str()) + &constants + .spells + .get(spell_type) + .expect(&format!("spell '{}' not found", spell_type)) } pub fn get_level_props(&self, level: GameLevel) -> &LevelProps { - let constants = self.spell.get(&self.assets.spell_registry).unwrap(); + let constants = self.game.get(&self.assets.game_registry).unwrap(); match level { GameLevel::Level(l) => constants.levels.get(l as usize).unwrap(), GameLevel::MultiPlayArena => &constants.arena, } } - pub fn spells(&self) -> Vec { - // todo - SpellType::iter().collect() + pub fn spells(&self) -> Vec { + self.spell().spells.keys().map(|k| Spell::new(k)).collect() } } diff --git a/src/spell.rs b/src/spell.rs index 6e56b1a..85407c4 100644 --- a/src/spell.rs +++ b/src/spell.rs @@ -5,79 +5,13 @@ use bevy::reflect::Reflect; use serde::Deserialize; use serde::Serialize; -#[derive( - Reflect, - Clone, - Copy, - Debug, - Eq, - PartialEq, - PartialOrd, - Ord, - strum::EnumIter, - Hash, - Serialize, - Deserialize, -)] -pub enum SpellType { - // ランク0 - Lantern, - LightBall, - MagicBolt, - // ランク1 - Magnifier, - PurpleBolt, - SlimeCharge, - SpawnJar, - Telescope, - // ランク2 - BulletSpeedDoown, - DualCast, - Jump, - Servant, - SummonEnemyEyeball, - SummonEnemySlime, - WaterBall, - Web, - // ランク3 - Fireball, - HeavyShot, - Homing, - PrecisionUp, - SpawnBookshelf, - SummonChiken, - SummonFriendSlime, - TripleCast, - // ランク4 - BulletSpeedUp, - Dash, - Impact, - Metamorphosis, - RockFall, - Slash, - SummonFriendEyeball, +#[derive(Reflect, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +pub struct Spell(pub String); - // ランク5 - ApplyLevitation, - Heal, - QuickCast, - SpikeBoots, - // ランク 6 - Dispel, - Freeze, - Clone, - - // Quick 時間加速魔法 - // Stop, // 時間停止魔法 - // ランク7 - Bomb, - Levitation, - LightSword, - SummonHugeSlime, - - // ランク 100 - // 基本的に入手不可能 - InfinityClone, +impl Spell { + pub fn new(name: &str) -> Self { + Self(name.to_string()) + } } #[derive(Debug, serde::Deserialize, Clone)] diff --git a/src/ui/floating.rs b/src/ui/floating.rs index febd3eb..bfd1a67 100644 --- a/src/ui/floating.rs +++ b/src/ui/floating.rs @@ -26,11 +26,11 @@ pub enum FloatingContent { impl FloatingContent { pub fn get_item(&self, actor: &Actor) -> Option { match self { - FloatingContent::Inventory(index) => actor.inventory.get(*index), + FloatingContent::Inventory(index) => actor.inventory.get(*index).clone(), FloatingContent::WandSpell(wand_index, spell_index) => { - match actor.wands[*wand_index].slots[*spell_index] { + match &actor.wands[*wand_index].slots[*spell_index] { Some(spell) => Some(InventoryItem { - item_type: InventoryItemType::Spell(spell.spell_type), + item_type: InventoryItemType::Spell(spell.spell_type.clone()), price: spell.price, }), None => None, @@ -157,7 +157,7 @@ fn drop( &mut commands, ®istry, pointer_in_world, - item, + &item, ); floating.content = None; @@ -176,8 +176,8 @@ fn drop( // 移動先のアイテムを取得 let item_optional_to = target.get_inventory_item(&actor); - if target.is_settable(item_optional_from) - && content.is_settable(item_optional_to) + if target.is_settable(&item_optional_from) + && content.is_settable(&item_optional_to) { // 移動先に書きこみ target.set_item(item_optional_from, &mut actor); @@ -193,18 +193,18 @@ fn drop( impl FloatingContent { pub fn get_inventory_item(&self, actor: &Actor) -> Option { match self { - FloatingContent::Inventory(i) => actor.inventory.get(*i), + FloatingContent::Inventory(i) => actor.inventory.get(*i).clone(), FloatingContent::WandSpell(w, i) => actor.get_spell(*w, *i).map(|w| InventoryItem { - item_type: InventoryItemType::Spell(w.spell_type), + item_type: InventoryItemType::Spell(w.spell_type.clone()), price: w.price, }), } } pub fn set_item(&self, item: Option, actor: &mut Actor) { - match (self, item) { + match (self, item.clone()) { (FloatingContent::Inventory(i), _) => { - actor.inventory.set(*i, item); + actor.inventory.set(*i, item.as_ref().cloned()); } ( @@ -224,7 +224,7 @@ impl FloatingContent { } } - pub fn is_settable(&self, item: Option) -> bool { + pub fn is_settable(&self, item: &Option) -> bool { match (self, item) { (FloatingContent::Inventory(_), _) => true, ( diff --git a/src/ui/inventory.rs b/src/ui/inventory.rs index d2f940f..fe106ec 100644 --- a/src/ui/inventory.rs +++ b/src/ui/inventory.rs @@ -72,7 +72,7 @@ fn update_inventory_slot( panel.0 = None; } _ => { - panel.0 = actor.inventory.get(slot.0); + panel.0 = actor.inventory.get(slot.0).clone(); } } } diff --git a/src/ui/item_panel.rs b/src/ui/item_panel.rs index 967cc00..a19d558 100644 --- a/src/ui/item_panel.rs +++ b/src/ui/item_panel.rs @@ -1,7 +1,7 @@ use crate::inventory::InventoryItem; use crate::inventory_item::InventoryItemType; use crate::registry::Registry; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameState; use bevy::prelude::*; use bevy_aseprite_ultra::prelude::*; @@ -113,7 +113,7 @@ fn update_inventory_slot(registry: Registry, mut slot_query: Query<(&ItemPanel, if let Some(InventoryItem { item_type: InventoryItemType::Spell(spell), .. - }) = slot.0 + }) = &slot.0 { aseprite.name = registry.get_spell_props(spell).icon.clone(); } else { @@ -128,7 +128,7 @@ fn update_panel_width( ) { for (parent, mut node) in frame_query.iter_mut() { let (slot, mut aseprite) = slot_query.get_mut(parent.get()).unwrap(); - if let Some(item) = slot.0 { + if let Some(item) = &slot.0 { let width = Val::Px(item.item_type.get_icon_width()); node.width = width; aseprite.width = width; @@ -165,7 +165,7 @@ fn update_charge_alert( ) { for (parent, mut aseprite) in children_query.iter_mut() { let slot = slot_query.get(parent.get()).unwrap(); - match slot.0 { + match &slot.0 { Some(item) if 0 < item.price => { aseprite.display = Display::default(); } @@ -182,10 +182,18 @@ fn update_friend_marker( ) { for (parent, mut aseprite) in children_query.iter_mut() { let slot = slot_query.get(parent.get()).unwrap(); - let visible = match slot.0 { - Some(item) => match item.item_type { - InventoryItemType::Spell(SpellType::SummonFriendSlime) => true, - InventoryItemType::Spell(SpellType::SummonFriendEyeball) => true, + let visible = match &slot.0 { + Some(item) => match &item.item_type { + InventoryItemType::Spell(spell) + if *spell == Spell::new("SummonFriendSlime") => + { + true + } + InventoryItemType::Spell(spell) + if *spell == Spell::new("SummonFriendEyeball") => + { + true + } _ => false, }, _ => false, diff --git a/src/ui/new_spell.rs b/src/ui/new_spell.rs index f48d1d2..b49c94b 100644 --- a/src/ui/new_spell.rs +++ b/src/ui/new_spell.rs @@ -6,7 +6,7 @@ use crate::registry::Registry; use crate::se::SEEvent; use crate::se::SE; use crate::set::FixedUpdateInGameSet; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameMenuState; use crate::states::TimeState; use bevy::prelude::*; @@ -19,14 +19,14 @@ pub fn spawn_new_spell( commands: &mut Commands, registry: &Registry, time: &mut ResMut>, - spell: SpellType, + spell: Spell, se: &mut EventWriter, ) { se.send(SEEvent::new(SE::Hakken)); time.set(TimeState::Inactive); - let props = registry.get_spell_props(spell); + let props = registry.get_spell_props(&spell); commands // 背景 .spawn(( diff --git a/src/ui/popup.rs b/src/ui/popup.rs index f98f330..c7fba8c 100644 --- a/src/ui/popup.rs +++ b/src/ui/popup.rs @@ -7,7 +7,7 @@ use crate::language::M18NTtext; use crate::message::UNPAID; use crate::registry::Registry; use crate::spell::get_spell_appendix; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameMenuState; use crate::states::GameState; use crate::ui::floating::Floating; @@ -22,10 +22,10 @@ const POPUP_WIDTH: f32 = 300.0; const POPUP_HEIGHT: f32 = 300.0; -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum PopupContent { FloatingContent(FloatingContent), - DiscoveredSpell(SpellType), + DiscoveredSpell(Spell), } #[derive(Component)] @@ -146,13 +146,13 @@ fn update_spell_icon( item_type: InventoryItemType::Spell(spell), .. }) => { - let props = registry.get_spell_props(spell); + let props = registry.get_spell_props(&spell); slice.name = props.icon.clone(); } None => {} }, PopupContent::DiscoveredSpell(spell) => { - let props = registry.get_spell_props(*spell); + let props = registry.get_spell_props(spell); slice.name = props.icon.clone(); } } @@ -183,11 +183,11 @@ fn update_spell_name( .. }) = content.get_item(actor) { - text.0 = registry.get_spell_props(spell).name.clone(); + text.0 = registry.get_spell_props(&spell).name.clone(); } } Some(PopupContent::DiscoveredSpell(spell)) => { - let props = registry.get_spell_props(*spell); + let props = registry.get_spell_props(spell); text.0 = props.name.clone(); } _ => {} @@ -216,7 +216,7 @@ fn update_item_description( .. }) = content.get_item(actor) { - let props = registry.get_spell_props(spell); + let props = registry.get_spell_props(&spell); let mut dict = props.description.clone(); let appendix = get_spell_appendix(&props.cast); // dict += format!("\n{}", appendix).as_str(); @@ -244,7 +244,7 @@ fn update_item_description( } } Some(PopupContent::DiscoveredSpell(spell)) => { - let props: &crate::spell::SpellProps = registry.get_spell_props(*spell); + let props: &crate::spell::SpellProps = registry.get_spell_props(spell); let mut dict = props.description.clone(); dict += get_spell_appendix(&props.cast); // dict += format!( diff --git a/src/ui/spell_list.rs b/src/ui/spell_list.rs index 4c78f85..a5d04c9 100644 --- a/src/ui/spell_list.rs +++ b/src/ui/spell_list.rs @@ -7,7 +7,7 @@ use crate::controller::player::Player; use crate::language::M18NTtext; use crate::message::DISCOVERED_SPELLS; use crate::registry::Registry; -use crate::spell::SpellType; +use crate::spell::Spell; use crate::states::GameState; use crate::ui::popup::PopUp; use crate::ui::popup::PopupContent; @@ -31,7 +31,7 @@ struct SpellList { #[derive(Component)] struct SpellListItem { - spell_type: Option, + spell_type: Option, } #[derive(Component)] @@ -41,11 +41,11 @@ fn setup(mut commands: Commands, registry: Registry) { let spells = registry.spells(); let spell_iter = spells.iter().cloned(); let count = spell_iter.clone().count(); - let mut spells: Vec> = spell_iter.map(|s| Some(s)).collect(); + let mut spells: Vec> = spell_iter.map(|s| Some(s)).collect(); spells.sort_by(|a, b| match (a, b) { (Some(a), Some(b)) => { - let a_props = registry.get_spell_props(*a); - let b_props = registry.get_spell_props(*b); + let a_props = registry.get_spell_props(a); + let b_props = registry.get_spell_props(b); a_props.rank.cmp(&b_props.rank) } (Some(_), None) => std::cmp::Ordering::Less, @@ -110,11 +110,12 @@ fn setup(mut commands: Commands, registry: Registry) { let y = i / COLUMNS; let icon = spell_type - .map(|spell| registry.get_spell_props(spell).icon.clone()) + .as_ref() + .map(|spell| registry.get_spell_props(&spell).icon.clone()) .unwrap_or("unknown".to_string()); builder.spawn(( SpellListItem { - spell_type: *spell_type, + spell_type: spell_type.clone(), }, AseUiSlice { aseprite: registry.assets.atlas.clone(), @@ -163,8 +164,8 @@ fn update_icons( ) { if let Ok(player) = player_query.get_single() { for (item, mut aseprite) in query.iter_mut() { - if let Some(spell_type) = item.spell_type { - let props = registry.get_spell_props(spell_type); + if let Some(spell_type) = &item.spell_type { + let props = registry.get_spell_props(&spell_type); let discovered = player.discovered_spells.contains(&spell_type); aseprite.name = (if discovered { props.icon.clone() @@ -206,17 +207,21 @@ fn interaction( match *interaction { Interaction::Pressed => {} Interaction::Hovered => { - if let Some(spell) = item.spell_type { + if let Some(spell) = &item.spell_type { if player.discovered_spells.contains(&spell) { - popup.set.insert(PopupContent::DiscoveredSpell(spell)); + popup + .set + .insert(PopupContent::DiscoveredSpell(spell.clone())); popup.anchor_left = false; popup.anchor_top = true; } } } Interaction::None => { - if let Some(spell) = item.spell_type { - popup.set.remove(&PopupContent::DiscoveredSpell(spell)); + if let Some(spell) = &item.spell_type { + popup + .set + .remove(&PopupContent::DiscoveredSpell(spell.clone())); } } } diff --git a/src/wand.rs b/src/wand.rs index 72b86d5..ca957f0 100644 --- a/src/wand.rs +++ b/src/wand.rs @@ -1,20 +1,20 @@ use crate::constant::MAX_SPELLS_IN_WAND; use crate::constant::MAX_WANDS; -use crate::spell::SpellType; +use crate::spell::Spell; use bevy::reflect::Reflect; use serde::Deserialize; use serde::Serialize; -#[derive(Reflect, Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Reflect, Clone, Debug, Serialize, Deserialize)] pub struct WandSpell { - pub spell_type: SpellType, + pub spell_type: Spell, pub price: u32, } impl Default for Wand { fn default() -> Self { Self { - slots: [None; MAX_SPELLS_IN_WAND], + slots: [None, None, None, None, None, None, None, None], index: 0, delay: 0, } @@ -22,7 +22,7 @@ impl Default for Wand { } impl WandSpell { - pub fn new(spell_type: SpellType) -> Self { + pub fn new(spell_type: Spell) -> Self { Self { spell_type, price: 0, @@ -50,7 +50,7 @@ impl Wand { } } - pub fn from_vec(slots: Vec>>) -> [Wand; MAX_WANDS] { + pub fn from_vec(slots: Vec>>) -> [Wand; MAX_WANDS] { let mut wands = [ Wand::default(), Wand::default(), @@ -59,14 +59,14 @@ impl Wand { ]; for (i, wand_slots) in slots.iter().enumerate().take(MAX_WANDS) { for (j, spell_type) in wand_slots.iter().enumerate().take(MAX_SPELLS_IN_WAND) { - wands[i].slots[j] = spell_type.map(WandSpell::new); + wands[i].slots[j] = spell_type.as_ref().map(|s| WandSpell::new(s.clone())); } } wands } - pub fn single(spell: Option) -> [Wand; MAX_WANDS] { - let mut slots = [None; MAX_SPELLS_IN_WAND]; + pub fn single(spell: Option) -> [Wand; MAX_WANDS] { + let mut slots = [None, None, None, None, None, None, None, None]; slots[0] = spell.map(|s| WandSpell::new(s)); [ Wand::with_slots(slots),