From 65208cddba0fc0fbca1c47ef3b742e515b604fe9 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 18 Sep 2020 07:55:48 -0600 Subject: [PATCH 01/15] weapon shop --- data/shops/alt_grind.toml | 30 ++ data/shops/attribute1.toml | 99 +++++ data/shops/attribute2.toml | 99 +++++ data/shops/grind.toml | 30 ++ data/shops/hard/bluefull/weapon.toml | 107 ++++++ data/shops/hard/greenill/weapon.toml | 111 ++++++ data/shops/hard/oran/weapon.toml | 103 ++++++ data/shops/hard/pinkal/weapon.toml | 103 ++++++ data/shops/hard/purplenum/weapon.toml | 111 ++++++ data/shops/hard/redria/weapon.toml | 107 ++++++ data/shops/hard/skyly/weapon.toml | 103 ++++++ data/shops/hard/viridia/weapon.toml | 103 ++++++ data/shops/hard/whitill/weapon.toml | 107 ++++++ data/shops/hard/yellowboze/weapon.toml | 111 ++++++ data/shops/normal/bluefull/weapon.toml | 115 ++++++ data/shops/normal/greenill/weapon.toml | 111 ++++++ data/shops/normal/oran/weapon.toml | 115 ++++++ data/shops/normal/pinkal/weapon.toml | 107 ++++++ data/shops/normal/purplenum/weapon.toml | 115 ++++++ data/shops/normal/redria/weapon.toml | 107 ++++++ data/shops/normal/skyly/weapon.toml | 99 +++++ data/shops/normal/viridia/weapon.toml | 103 ++++++ data/shops/normal/whitill/weapon.toml | 103 ++++++ data/shops/normal/yellowboze/weapon.toml | 111 ++++++ data/shops/special.toml | 120 ++++++ data/shops/ultimate/bluefull/weapon.toml | 149 ++++++++ data/shops/ultimate/greenill/weapon.toml | 157 ++++++++ data/shops/ultimate/oran/weapon.toml | 145 ++++++++ data/shops/ultimate/pinkal/weapon.toml | 129 +++++++ data/shops/ultimate/purplenum/weapon.toml | 157 ++++++++ data/shops/ultimate/redria/weapon.toml | 153 ++++++++ data/shops/ultimate/skyly/weapon.toml | 125 +++++++ data/shops/ultimate/viridia/weapon.toml | 141 +++++++ data/shops/ultimate/whitill/weapon.toml | 157 ++++++++ data/shops/ultimate/yellowboze/weapon.toml | 129 +++++++ data/shops/veryhard/bluefull/weapon.toml | 111 ++++++ data/shops/veryhard/greenill/weapon.toml | 111 ++++++ data/shops/veryhard/oran/weapon.toml | 107 ++++++ data/shops/veryhard/pinkal/weapon.toml | 99 +++++ data/shops/veryhard/purplenum/weapon.toml | 111 ++++++ data/shops/veryhard/redria/weapon.toml | 107 ++++++ data/shops/veryhard/skyly/weapon.toml | 95 +++++ data/shops/veryhard/viridia/weapon.toml | 103 ++++++ data/shops/veryhard/whitill/weapon.toml | 111 ++++++ data/shops/veryhard/yellowboze/weapon.toml | 99 +++++ src/ship/mod.rs | 1 + src/ship/shops/mod.rs | 1 + src/ship/shops/weapon.rs | 405 +++++++++++++++++++++ 48 files changed, 5433 insertions(+) create mode 100644 data/shops/alt_grind.toml create mode 100644 data/shops/attribute1.toml create mode 100644 data/shops/attribute2.toml create mode 100644 data/shops/grind.toml create mode 100644 data/shops/hard/bluefull/weapon.toml create mode 100644 data/shops/hard/greenill/weapon.toml create mode 100644 data/shops/hard/oran/weapon.toml create mode 100644 data/shops/hard/pinkal/weapon.toml create mode 100644 data/shops/hard/purplenum/weapon.toml create mode 100644 data/shops/hard/redria/weapon.toml create mode 100644 data/shops/hard/skyly/weapon.toml create mode 100644 data/shops/hard/viridia/weapon.toml create mode 100644 data/shops/hard/whitill/weapon.toml create mode 100644 data/shops/hard/yellowboze/weapon.toml create mode 100644 data/shops/normal/bluefull/weapon.toml create mode 100644 data/shops/normal/greenill/weapon.toml create mode 100644 data/shops/normal/oran/weapon.toml create mode 100644 data/shops/normal/pinkal/weapon.toml create mode 100644 data/shops/normal/purplenum/weapon.toml create mode 100644 data/shops/normal/redria/weapon.toml create mode 100644 data/shops/normal/skyly/weapon.toml create mode 100644 data/shops/normal/viridia/weapon.toml create mode 100644 data/shops/normal/whitill/weapon.toml create mode 100644 data/shops/normal/yellowboze/weapon.toml create mode 100644 data/shops/special.toml create mode 100644 data/shops/ultimate/bluefull/weapon.toml create mode 100644 data/shops/ultimate/greenill/weapon.toml create mode 100644 data/shops/ultimate/oran/weapon.toml create mode 100644 data/shops/ultimate/pinkal/weapon.toml create mode 100644 data/shops/ultimate/purplenum/weapon.toml create mode 100644 data/shops/ultimate/redria/weapon.toml create mode 100644 data/shops/ultimate/skyly/weapon.toml create mode 100644 data/shops/ultimate/viridia/weapon.toml create mode 100644 data/shops/ultimate/whitill/weapon.toml create mode 100644 data/shops/ultimate/yellowboze/weapon.toml create mode 100644 data/shops/veryhard/bluefull/weapon.toml create mode 100644 data/shops/veryhard/greenill/weapon.toml create mode 100644 data/shops/veryhard/oran/weapon.toml create mode 100644 data/shops/veryhard/pinkal/weapon.toml create mode 100644 data/shops/veryhard/purplenum/weapon.toml create mode 100644 data/shops/veryhard/redria/weapon.toml create mode 100644 data/shops/veryhard/skyly/weapon.toml create mode 100644 data/shops/veryhard/viridia/weapon.toml create mode 100644 data/shops/veryhard/whitill/weapon.toml create mode 100644 data/shops/veryhard/yellowboze/weapon.toml create mode 100644 src/ship/shops/mod.rs create mode 100644 src/ship/shops/weapon.rs diff --git a/data/shops/alt_grind.toml b/data/shops/alt_grind.toml new file mode 100644 index 0000000..f787222 --- /dev/null +++ b/data/shops/alt_grind.toml @@ -0,0 +1,30 @@ +[[grind]] +level = 0 +min = 0 +max = 1 + +[[grind]] +level = 3 +min = 0 +max = 3 + +[[grind]] +level = 10 +min = 1 +max = 5 + +[[grind]] +level = 25 +min = 2 +max = 8 + +[[grind]] +level = 40 +min = 3 +max = 11 + +[[grind]] +level = 55 +min = 3 +max = 16 + diff --git a/data/shops/attribute1.toml b/data/shops/attribute1.toml new file mode 100644 index 0000000..9f567bd --- /dev/null +++ b/data/shops/attribute1.toml @@ -0,0 +1,99 @@ +[[attributes]] +level = 0 +percent_min = 5 +percent_max = 25 +none = 60 +native = 20 +abeast = 20 +machine = 0 +dark = 0 +hit = 0 + +[[attributes]] +level = 3 +percent_min = 5 +percent_max = 25 +none = 50 +native = 15 +abeast = 20 +machine = 15 +dark = 0 +hit = 0 + +[[attributes]] +level = 10 +percent_min = 5 +percent_max = 30 +none = 30 +native = 10 +abeast = 15 +machine = 25 +dark = 20 +hit = 0 + +[[attributes]] +level = 17 +percent_min = 5 +percent_max = 30 +none = 10 +native = 25 +abeast = 15 +machine = 20 +dark = 30 +hit = 0 + +[[attributes]] +level = 25 +percent_min = 5 +percent_max = 35 +none = 10 +native = 25 +abeast = 25 +machine = 20 +dark = 20 +hit = 0 + +[[attributes]] +level = 35 +percent_min = 5 +percent_max = 35 +none = 10 +native = 20 +abeast = 20 +machine = 30 +dark = 20 +hit = 0 + +[[attributes]] +level = 45 +percent_min = 5 +percent_max = 35 +none = 10 +native = 25 +abeast = 20 +machine = 20 +dark = 25 +hit = 0 + +[[attributes]] +level = 60 +percent_min = 5 +percent_max = 40 +none = 10 +native = 20 +abeast = 20 +machine = 20 +dark = 25 +hit = 5 + +[[attributes]] +level = 75 +percent_min = 5 +percent_max = 50 +none = 10 +native = 20 +abeast = 20 +machine = 20 +dark = 20 +hit = 10 + diff --git a/data/shops/attribute2.toml b/data/shops/attribute2.toml new file mode 100644 index 0000000..b9022ea --- /dev/null +++ b/data/shops/attribute2.toml @@ -0,0 +1,99 @@ +[[attributes]] +level = 0 +percent_min = 5 +percent_max = 20 +none = 100 +native = 0 +abeast = 0 +machine = 0 +dark = 0 +hit = 0 + +[[attributes]] +level = 5 +percent_min = 5 +percent_max = 25 +none = 100 +native = 0 +abeast = 0 +machine = 0 +dark = 0 +hit = 0 + +[[attributes]] +level = 10 +percent_min = 5 +percent_max = 25 +none = 65 +native = 5 +abeast = 10 +machine = 10 +dark = 10 +hit = 0 + +[[attributes]] +level = 17 +percent_min = 5 +percent_max = 25 +none = 45 +native = 10 +abeast = 10 +machine = 15 +dark = 20 +hit = 0 + +[[attributes]] +level = 25 +percent_min = 5 +percent_max = 30 +none = 30 +native = 25 +abeast = 20 +machine = 10 +dark = 10 +hit = 5 + +[[attributes]] +level = 35 +percent_min = 5 +percent_max = 30 +none = 15 +native = 15 +abeast = 20 +machine = 25 +dark = 20 +hit = 5 + +[[attributes]] +level = 45 +percent_min = 5 +percent_max = 35 +none = 15 +native = 15 +abeast = 20 +machine = 25 +dark = 15 +hit = 10 + +[[attributes]] +level = 60 +percent_min = 5 +percent_max = 35 +none = 10 +native = 15 +abeast = 20 +machine = 20 +dark = 20 +hit = 15 + +[[attributes]] +level = 75 +percent_min = 5 +percent_max = 50 +none = 10 +native = 20 +abeast = 15 +machine = 15 +dark = 20 +hit = 20 + diff --git a/data/shops/grind.toml b/data/shops/grind.toml new file mode 100644 index 0000000..158d122 --- /dev/null +++ b/data/shops/grind.toml @@ -0,0 +1,30 @@ +[[grind]] +level = 0 +min = 0 +max = 2 + +[[grind]] +level = 3 +min = 0 +max = 3 + +[[grind]] +level = 10 +min = 0 +max = 4 + +[[grind]] +level = 25 +min = 0 +max = 6 + +[[grind]] +level = 40 +min = 0 +max = 8 + +[[grind]] +level = 55 +min = 0 +max = 10 + diff --git a/data/shops/hard/bluefull/weapon.toml b/data/shops/hard/bluefull/weapon.toml new file mode 100644 index 0000000..8d8a846 --- /dev/null +++ b/data/shops/hard/bluefull/weapon.toml @@ -0,0 +1,107 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 6 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 3 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 7 + + diff --git a/data/shops/hard/greenill/weapon.toml b/data/shops/hard/greenill/weapon.toml new file mode 100644 index 0000000..042386c --- /dev/null +++ b/data/shops/hard/greenill/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 5 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 11 + + diff --git a/data/shops/hard/oran/weapon.toml b/data/shops/hard/oran/weapon.toml new file mode 100644 index 0000000..97d2abb --- /dev/null +++ b/data/shops/hard/oran/weapon.toml @@ -0,0 +1,103 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 16 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 5 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + + diff --git a/data/shops/hard/pinkal/weapon.toml b/data/shops/hard/pinkal/weapon.toml new file mode 100644 index 0000000..3e5af60 --- /dev/null +++ b/data/shops/hard/pinkal/weapon.toml @@ -0,0 +1,103 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 30 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 5 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 4 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 7 + + diff --git a/data/shops/hard/purplenum/weapon.toml b/data/shops/hard/purplenum/weapon.toml new file mode 100644 index 0000000..32e03b7 --- /dev/null +++ b/data/shops/hard/purplenum/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 4 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 11 + + diff --git a/data/shops/hard/redria/weapon.toml b/data/shops/hard/redria/weapon.toml new file mode 100644 index 0000000..dd3ae00 --- /dev/null +++ b/data/shops/hard/redria/weapon.toml @@ -0,0 +1,107 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 5 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 9 + + diff --git a/data/shops/hard/skyly/weapon.toml b/data/shops/hard/skyly/weapon.toml new file mode 100644 index 0000000..438d1c7 --- /dev/null +++ b/data/shops/hard/skyly/weapon.toml @@ -0,0 +1,103 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 3 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 3 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + + diff --git a/data/shops/hard/viridia/weapon.toml b/data/shops/hard/viridia/weapon.toml new file mode 100644 index 0000000..e16e61e --- /dev/null +++ b/data/shops/hard/viridia/weapon.toml @@ -0,0 +1,103 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 4 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 5 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 9 + + diff --git a/data/shops/hard/whitill/weapon.toml b/data/shops/hard/whitill/weapon.toml new file mode 100644 index 0000000..cc6b59f --- /dev/null +++ b/data/shops/hard/whitill/weapon.toml @@ -0,0 +1,107 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 3 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 3 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + + diff --git a/data/shops/hard/yellowboze/weapon.toml b/data/shops/hard/yellowboze/weapon.toml new file mode 100644 index 0000000..4610eb8 --- /dev/null +++ b/data/shops/hard/yellowboze/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 12 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 3 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + + diff --git a/data/shops/normal/bluefull/weapon.toml b/data/shops/normal/bluefull/weapon.toml new file mode 100644 index 0000000..0752835 --- /dev/null +++ b/data/shops/normal/bluefull/weapon.toml @@ -0,0 +1,115 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 7 + + diff --git a/data/shops/normal/greenill/weapon.toml b/data/shops/normal/greenill/weapon.toml new file mode 100644 index 0000000..c78f5e1 --- /dev/null +++ b/data/shops/normal/greenill/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 8 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + + diff --git a/data/shops/normal/oran/weapon.toml b/data/shops/normal/oran/weapon.toml new file mode 100644 index 0000000..252fa5e --- /dev/null +++ b/data/shops/normal/oran/weapon.toml @@ -0,0 +1,115 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + + diff --git a/data/shops/normal/pinkal/weapon.toml b/data/shops/normal/pinkal/weapon.toml new file mode 100644 index 0000000..ac7c32f --- /dev/null +++ b/data/shops/normal/pinkal/weapon.toml @@ -0,0 +1,107 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 30 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + diff --git a/data/shops/normal/purplenum/weapon.toml b/data/shops/normal/purplenum/weapon.toml new file mode 100644 index 0000000..383b645 --- /dev/null +++ b/data/shops/normal/purplenum/weapon.toml @@ -0,0 +1,115 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + + diff --git a/data/shops/normal/redria/weapon.toml b/data/shops/normal/redria/weapon.toml new file mode 100644 index 0000000..f6b6ae9 --- /dev/null +++ b/data/shops/normal/redria/weapon.toml @@ -0,0 +1,107 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 8 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + + diff --git a/data/shops/normal/skyly/weapon.toml b/data/shops/normal/skyly/weapon.toml new file mode 100644 index 0000000..a44ee4f --- /dev/null +++ b/data/shops/normal/skyly/weapon.toml @@ -0,0 +1,99 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 12 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 12 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 12 + + diff --git a/data/shops/normal/viridia/weapon.toml b/data/shops/normal/viridia/weapon.toml new file mode 100644 index 0000000..02f8f89 --- /dev/null +++ b/data/shops/normal/viridia/weapon.toml @@ -0,0 +1,103 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 8 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + + diff --git a/data/shops/normal/whitill/weapon.toml b/data/shops/normal/whitill/weapon.toml new file mode 100644 index 0000000..7aba633 --- /dev/null +++ b/data/shops/normal/whitill/weapon.toml @@ -0,0 +1,103 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 3 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 3 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 3 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 3 + + diff --git a/data/shops/normal/yellowboze/weapon.toml b/data/shops/normal/yellowboze/weapon.toml new file mode 100644 index 0000000..c810437 --- /dev/null +++ b/data/shops/normal/yellowboze/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 13 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 16 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + + diff --git a/data/shops/special.toml b/data/shops/special.toml new file mode 100644 index 0000000..c49f0a4 --- /dev/null +++ b/data/shops/special.toml @@ -0,0 +1,120 @@ +[[specials]] +level = 0 +[[specials.special]] +tier = 0 +probability = 85 + +[[specials.special]] +tier = 1 +probability = 15 + +[[specials.special]] +tier = 2 +probability = 0 + + +[[specials]] +level = 10 +[[specials.special]] +tier = 0 +probability = 70 + +[[specials.special]] +tier = 1 +probability = 30 + +[[specials.special]] +tier = 2 +probability = 0 + + +[[specials]] +level = 17 +[[specials.special]] +tier = 0 +probability = 50 + +[[specials.special]] +tier = 1 +probability = 50 + +[[specials.special]] +tier = 2 +probability = 0 + + +[[specials]] +level = 25 +[[specials.special]] +tier = 0 +probability = 20 + +[[specials.special]] +tier = 1 +probability = 80 + +[[specials.special]] +tier = 2 +probability = 0 + + +[[specials]] +level = 35 +[[specials.special]] +tier = 0 +probability = 20 + +[[specials.special]] +tier = 1 +probability = 60 + +[[specials.special]] +tier = 2 +probability = 20 + + +[[specials]] +level = 45 +[[specials.special]] +tier = 0 +probability = 20 + +[[specials.special]] +tier = 1 +probability = 40 + +[[specials.special]] +tier = 2 +probability = 40 + + +[[specials]] +level = 60 +[[specials.special]] +tier = 0 +probability = 10 + +[[specials.special]] +tier = 1 +probability = 30 + +[[specials.special]] +tier = 2 +probability = 60 + + +[[specials]] +level = 75 +[[specials.special]] +tier = 0 +probability = 10 + +[[specials.special]] +tier = 1 +probability = 10 + +[[specials.special]] +tier = 2 +probability = 80 + + diff --git a/data/shops/ultimate/bluefull/weapon.toml b/data/shops/ultimate/bluefull/weapon.toml new file mode 100644 index 0000000..003648d --- /dev/null +++ b/data/shops/ultimate/bluefull/weapon.toml @@ -0,0 +1,149 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Cutter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sawcer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Berdys" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Ripper" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Diska" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gungnir" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Raygun" +probability = 10 + + diff --git a/data/shops/ultimate/greenill/weapon.toml b/data/shops/ultimate/greenill/weapon.toml new file mode 100644 index 0000000..12878a6 --- /dev/null +++ b/data/shops/ultimate/greenill/weapon.toml @@ -0,0 +1,157 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 17 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Launcher" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Gatling" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Beam" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Club" +probability = 10 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Raygun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Arms" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Vulcan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Laser" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Club" +probability = 10 + + diff --git a/data/shops/ultimate/oran/weapon.toml b/data/shops/ultimate/oran/weapon.toml new file mode 100644 index 0000000..4d920ed --- /dev/null +++ b/data/shops/ultimate/oran/weapon.toml @@ -0,0 +1,145 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 16 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 8 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Beam" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Club" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Baton" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pillar" +probability = 7 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Laser" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Club" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Scepter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Striker" +probability = 7 + + diff --git a/data/shops/ultimate/pinkal/weapon.toml b/data/shops/ultimate/pinkal/weapon.toml new file mode 100644 index 0000000..03aaa6b --- /dev/null +++ b/data/shops/ultimate/pinkal/weapon.toml @@ -0,0 +1,129 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 30 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 17 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Pillar" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Claymore" +probability = 18 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Striker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Calibur" +probability = 18 + + diff --git a/data/shops/ultimate/purplenum/weapon.toml b/data/shops/ultimate/purplenum/weapon.toml new file mode 100644 index 0000000..b422652 --- /dev/null +++ b/data/shops/ultimate/purplenum/weapon.toml @@ -0,0 +1,157 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 8 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 17 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Launcher" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gatling" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Beam" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Club" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Baton" +probability = 7 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Arms" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Vulcan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Laser" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Club" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Scepter" +probability = 7 + + diff --git a/data/shops/ultimate/redria/weapon.toml b/data/shops/ultimate/redria/weapon.toml new file mode 100644 index 0000000..b949558 --- /dev/null +++ b/data/shops/ultimate/redria/weapon.toml @@ -0,0 +1,153 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Cutter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 7 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sawcer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Berdys" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Launcher" +probability = 7 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Ripper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Diska" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gungnir" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Raygun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Arms" +probability = 7 + + diff --git a/data/shops/ultimate/skyly/weapon.toml b/data/shops/ultimate/skyly/weapon.toml new file mode 100644 index 0000000..b5a7370 --- /dev/null +++ b/data/shops/ultimate/skyly/weapon.toml @@ -0,0 +1,125 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 3 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Baton" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pillar" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Scepter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Striker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + + diff --git a/data/shops/ultimate/viridia/weapon.toml b/data/shops/ultimate/viridia/weapon.toml new file mode 100644 index 0000000..676d3be --- /dev/null +++ b/data/shops/ultimate/viridia/weapon.toml @@ -0,0 +1,141 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 4 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 11 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Claymore" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Berdys" +probability = 10 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Calibur" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Ripper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gungnir" +probability = 10 + + diff --git a/data/shops/ultimate/whitill/weapon.toml b/data/shops/ultimate/whitill/weapon.toml new file mode 100644 index 0000000..49281fb --- /dev/null +++ b/data/shops/ultimate/whitill/weapon.toml @@ -0,0 +1,157 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 3 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Cutter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 17 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Sawcer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Berdys" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Launcher" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gatling" +probability = 7 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Diska" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Gungnir" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Raygun" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Arms" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Vulcan" +probability = 7 + + diff --git a/data/shops/ultimate/yellowboze/weapon.toml b/data/shops/ultimate/yellowboze/weapon.toml new file mode 100644 index 0000000..e00ce77 --- /dev/null +++ b/data/shops/ultimate/yellowboze/weapon.toml @@ -0,0 +1,129 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 12 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 4 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + + +[[weapon_tier]] +level = 99 +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Claymore" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + + +[[weapon_tier]] +level = 150 +[[weapon_tier.weapons]] +weapon = "Gladius" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Calibur" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Ripper" +probability = 7 + + diff --git a/data/shops/veryhard/bluefull/weapon.toml b/data/shops/veryhard/bluefull/weapon.toml new file mode 100644 index 0000000..c87d54a --- /dev/null +++ b/data/shops/veryhard/bluefull/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Cutter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + + diff --git a/data/shops/veryhard/greenill/weapon.toml b/data/shops/veryhard/greenill/weapon.toml new file mode 100644 index 0000000..9735738 --- /dev/null +++ b/data/shops/veryhard/greenill/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 17 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + + diff --git a/data/shops/veryhard/oran/weapon.toml b/data/shops/veryhard/oran/weapon.toml new file mode 100644 index 0000000..5062747 --- /dev/null +++ b/data/shops/veryhard/oran/weapon.toml @@ -0,0 +1,107 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 16 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Assault" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 8 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + + diff --git a/data/shops/veryhard/pinkal/weapon.toml b/data/shops/veryhard/pinkal/weapon.toml new file mode 100644 index 0000000..3d73553 --- /dev/null +++ b/data/shops/veryhard/pinkal/weapon.toml @@ -0,0 +1,99 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 30 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 7 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 17 + + diff --git a/data/shops/veryhard/purplenum/weapon.toml b/data/shops/veryhard/purplenum/weapon.toml new file mode 100644 index 0000000..714fd98 --- /dev/null +++ b/data/shops/veryhard/purplenum/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 8 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 17 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + + diff --git a/data/shops/veryhard/redria/weapon.toml b/data/shops/veryhard/redria/weapon.toml new file mode 100644 index 0000000..f8db04a --- /dev/null +++ b/data/shops/veryhard/redria/weapon.toml @@ -0,0 +1,107 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 25 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 6 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 5 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Cutter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 7 + + diff --git a/data/shops/veryhard/skyly/weapon.toml b/data/shops/veryhard/skyly/weapon.toml new file mode 100644 index 0000000..883137c --- /dev/null +++ b/data/shops/veryhard/skyly/weapon.toml @@ -0,0 +1,95 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 16 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Gigush" +probability = 3 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 3 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Staff" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pole" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + + diff --git a/data/shops/veryhard/viridia/weapon.toml b/data/shops/veryhard/viridia/weapon.toml new file mode 100644 index 0000000..5a5e586 --- /dev/null +++ b/data/shops/veryhard/viridia/weapon.toml @@ -0,0 +1,103 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 4 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Buster" +probability = 9 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 9 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 11 + + diff --git a/data/shops/veryhard/whitill/weapon.toml b/data/shops/veryhard/whitill/weapon.toml new file mode 100644 index 0000000..0dc8975 --- /dev/null +++ b/data/shops/veryhard/whitill/weapon.toml @@ -0,0 +1,111 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 25 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 15 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Sniper" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Brand" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Sword" +probability = 3 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Slicer" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Partisan" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 12 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Wand" +probability = 7 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Spread" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blaster" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Mace" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Cutter" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Glaive" +probability = 17 + +[[weapon_tier.weapons]] +weapon = "Railgun" +probability = 11 + +[[weapon_tier.weapons]] +weapon = "Cannon" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Repeater" +probability = 7 + + diff --git a/data/shops/veryhard/yellowboze/weapon.toml b/data/shops/veryhard/yellowboze/weapon.toml new file mode 100644 index 0000000..7049d90 --- /dev/null +++ b/data/shops/veryhard/yellowboze/weapon.toml @@ -0,0 +1,99 @@ +[[weapon_tier]] +level = 0 +[[weapon_tier.weapons]] +weapon = "Saber" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Dagger" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Handgun" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Rifle" +probability = 20 + +[[weapon_tier.weapons]] +weapon = "Cane" +probability = 20 + + +[[weapon_tier]] +level = 10 +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Mechgun" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Stick" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 12 + + +[[weapon_tier]] +level = 25 +[[weapon_tier.weapons]] +weapon = "Knife" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Autogun" +probability = 5 + +[[weapon_tier.weapons]] +weapon = "Rod" +probability = 4 + +[[weapon_tier.weapons]] +weapon = "Shot" +probability = 4 + + +[[weapon_tier]] +level = 42 +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Blade" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Spinner" +probability = 8 + +[[weapon_tier.weapons]] +weapon = "Halbert" +probability = 18 + +[[weapon_tier.weapons]] +weapon = "Lockgun" +probability = 10 + + +[[weapon_tier]] +level = 60 +[[weapon_tier.weapons]] +weapon = "Pallasch" +probability = 10 + +[[weapon_tier.weapons]] +weapon = "Breaker" +probability = 7 + +[[weapon_tier.weapons]] +weapon = "Edge" +probability = 7 + + diff --git a/src/ship/mod.rs b/src/ship/mod.rs index 4a9aa5a..b9b9268 100644 --- a/src/ship/mod.rs +++ b/src/ship/mod.rs @@ -9,3 +9,4 @@ pub mod monster; pub mod drops; pub mod packet; pub mod quests; +pub mod shops; diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs new file mode 100644 index 0000000..e22b3b2 --- /dev/null +++ b/src/ship/shops/mod.rs @@ -0,0 +1 @@ +pub mod weapon; diff --git a/src/ship/shops/weapon.rs b/src/ship/shops/weapon.rs new file mode 100644 index 0000000..c3a3267 --- /dev/null +++ b/src/ship/shops/weapon.rs @@ -0,0 +1,405 @@ + +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; +use serde::Deserialize; +use rand::{Rng, SeedableRng}; +use rand::distributions::{WeightedIndex, Distribution}; +use rand::seq::{SliceRandom, IteratorRandom}; +use crate::entity::character::SectionID; +use crate::ship::room::Difficulty; +use crate::entity::item::weapon::{WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; + + +const TIER1_SPECIAL: [WeaponSpecial; 8] = [WeaponSpecial::Draw, WeaponSpecial::Heart, WeaponSpecial::Ice, WeaponSpecial::Bind, + WeaponSpecial::Heat, WeaponSpecial::Shock, WeaponSpecial::Dim, WeaponSpecial::Panic]; + +const TIER2_SPECIAL: [WeaponSpecial; 10] = [WeaponSpecial::Drain, WeaponSpecial::Mind, WeaponSpecial::Masters, WeaponSpecial::Charge, WeaponSpecial::Frost, + WeaponSpecial::Hold, WeaponSpecial::Fire, WeaponSpecial::Thunder, WeaponSpecial::Shadow, WeaponSpecial::Riot]; + +#[derive(Debug)] +pub struct ShopWeapon { + weapon: WeaponType, + special: Option, + grind: usize, + attributes: [Option; 2], +} + + +#[derive(Debug, Deserialize)] +struct WeaponTableTierEntry { + weapon: WeaponType, + probability: usize, +} + +#[derive(Debug, Deserialize)] +struct WeaponTableTier { + level: usize, + weapons: Vec, +} + +#[derive(Debug)] +struct WeaponTable(Vec); + +#[derive(Debug, Deserialize)] +struct GrindTier { + level: usize, + min: usize, + max: usize, +} + +#[derive(Debug)] +struct GrindTable(Vec); + +#[derive(Debug, Deserialize)] +struct AttributeTier { + level: usize, + percent_min: isize, + percent_max: isize, + none: usize, + native: usize, + abeast: usize, + machine: usize, + dark: usize, + hit: usize, +} + +#[derive(Debug)] +struct AttributeTable(Vec); + +#[derive(Debug, Deserialize)] +struct SpecialTierEntry { + tier: usize, + probability: usize, +} + +#[derive(Debug, Deserialize)] +struct SpecialTier { + level: usize, + special: Vec, +} + +#[derive(Debug)] +struct SpecialTable(Vec); + + + + + + + +/* +trait WeaponTableLoader { + fn load(difficulty: Difficulty, section_id: SectionID) -> WeaponTable where Self::Sized; +} + +struct WeaponTableLoaderImpl; +impl WeaponTableLoader for WeaponTableLoaderImpl { + fn load(difficulty: Difficulty, section_id: SectionID) -> WeaponTable { + let mut path = PathBuf::from("data/shops/"); + path.push(difficulty.to_string().to_lowercase()); + path.push(section_id.to_string().to_lowercase()); + path.push("weapon.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s); + + let table: Vec = toml::from_str(s.as_str()).unwrap(); + println!("table {:?}", table); + + WeaponTable { + + } + } +} +*/ + +fn load_weapon_table(difficulty: Difficulty, section_id: SectionID) -> WeaponTable { + let mut path = PathBuf::from("data/shops/"); + path.push(difficulty.to_string().to_lowercase()); + path.push(section_id.to_string().to_lowercase()); + path.push("weapon.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + + WeaponTable(table.remove("weapon_tier".into()).unwrap()) +} + +fn load_special_table() -> SpecialTable { + let mut path = PathBuf::from("data/shops/special.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + + SpecialTable(table.remove("specials".into()).unwrap()) +} + +fn load_grind_table() -> GrindTable { + let mut path = PathBuf::from("data/shops/grind.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + + GrindTable(table.remove("grind".into()).unwrap()) +} + +fn load_alt_grind_table() -> GrindTable { + let mut path = PathBuf::from("data/shops/alt_grind.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + + GrindTable(table.remove("grind".into()).unwrap()) +} + +fn load_attribute1_table() -> AttributeTable { + let mut path = PathBuf::from("data/shops/attribute1.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + + AttributeTable(table.remove("attributes".into()).unwrap()) +} + +fn load_attribute2_table() -> AttributeTable { + let mut path = PathBuf::from("data/shops/attribute2.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + + AttributeTable(table.remove("attributes".into()).unwrap()) +} + +#[derive(Debug)] +struct WeaponShop { + difficulty: Difficulty, + section_id: SectionID, + weapon: WeaponTable, + special: SpecialTable, + grind: GrindTable, + alt_grind: GrindTable, + attr1: AttributeTable, + attr2: AttributeTable, + rng: R, +} + +impl WeaponShop { + pub fn new(difficulty: Difficulty, section_id: SectionID) -> WeaponShop { + WeaponShop { + difficulty: difficulty, + section_id: section_id, + weapon: load_weapon_table(difficulty, section_id), + special: load_special_table(), + grind: load_grind_table(), + alt_grind: load_alt_grind_table(), + attr1: load_attribute1_table(), + attr2: load_attribute1_table(), + rng: R::from_entropy(), + } + } + + + fn generate_type(&mut self, level: usize) -> WeaponType { + let tier = self.weapon.0.iter() + .filter(|t| t.level < level) + .last() + .unwrap(); + + let weapon_choice = WeightedIndex::new(tier.weapons.iter().map(|t| t.probability)).unwrap(); + tier.weapons.get(weapon_choice.sample(&mut self.rng)).unwrap().weapon + } + + fn generate_special(&mut self, level: usize) -> Option { + let tier = self.special.0.iter() + .filter(|t| t.level < level) + .last() + .unwrap(); + + let special_tier = WeightedIndex::new(tier.special.iter().map(|t| t.probability)).unwrap(); + match special_tier.sample(&mut self.rng) { + 1 => TIER1_SPECIAL.choose(&mut self.rng).cloned(), + 2 => TIER2_SPECIAL.choose(&mut self.rng).cloned(), + _ => None + } + } + + fn generate_grind(&mut self, level: usize) -> usize { + let tier = self.grind.0.iter() + .filter(|t| t.level < level) + .last() + .unwrap(); + + self.rng.gen_range(tier.min, tier.max+1) + } + + fn generate_alt_grind(&mut self, level: usize) -> usize { + let tier = self.alt_grind.0.iter() + .filter(|t| t.level < level) + .nth(0) + .unwrap(); + + self.rng.gen_range(tier.min, tier.max+1) + } + + fn generate_attribute1(&mut self, level: usize) -> Option { + let tier = self.attr1.0.iter() + .filter(|t| t.level < level) + .last() + .unwrap(); + + let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); + let attr = match attr_choice.sample(&mut self.rng) { + 0 => return None, + 1 => Attribute::Native, + 2 => Attribute::ABeast, + 3 => Attribute::Machine, + 4 => Attribute::Dark, + 5 => Attribute::Hit, + _ => panic!() + }; + + let percent = (tier.percent_min..tier.percent_max+1) + .filter(|p| p % 5 == 0) + .choose(&mut self.rng)?; + + Some(WeaponAttribute { + attr: attr, + value: percent as i8, + }) + } + + fn generate_attribute2(&mut self, level: usize) -> Option { + let tier = self.attr2.0.iter() + .filter(|t| t.level < level) + .last() + .unwrap(); + + let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); + let attr = match attr_choice.sample(&mut self.rng) { + 0 => return None, + 1 => Attribute::Native, + 2 => Attribute::ABeast, + 3 => Attribute::Machine, + 4 => Attribute::Dark, + 5 => Attribute::Hit, + _ => panic!() + }; + + let percent = (tier.percent_min..tier.percent_max+1) + .filter(|p| p % 5 == 0) + .choose(&mut self.rng)?; + + Some(WeaponAttribute { + attr: attr, + value: percent as i8, + }) + } + + fn is_alt_grind(&self, weapon: &WeaponType) -> bool { + match (self.section_id, weapon) { + (SectionID::Viridia, WeaponType::Shot) => true, + (SectionID::Viridia, WeaponType::Spread) => true, + (SectionID::Viridia, WeaponType::Cannon) => true, + (SectionID::Viridia, WeaponType::Launcher) => true, + (SectionID::Viridia, WeaponType::Arms) => true, + (SectionID::Greenill, WeaponType::Rifle) => true, + (SectionID::Greenill, WeaponType::Sniper) => true, + (SectionID::Greenill, WeaponType::Blaster) => true, + (SectionID::Greenill, WeaponType::Beam) => true, + (SectionID::Greenill, WeaponType::Laser) => true, + (SectionID::Skyly, WeaponType::Sword) => true, + (SectionID::Skyly, WeaponType::Gigush) => true, + (SectionID::Skyly, WeaponType::Breaker) => true, + (SectionID::Skyly, WeaponType::Claymore) => true, + (SectionID::Skyly, WeaponType::Calibur) => true, + (SectionID::Bluefull, WeaponType::Partisan) => true, + (SectionID::Bluefull, WeaponType::Halbert) => true, + (SectionID::Bluefull, WeaponType::Glaive) => true, + (SectionID::Bluefull, WeaponType::Berdys) => true, + (SectionID::Bluefull, WeaponType::Gungnir) => true, + (SectionID::Purplenum, WeaponType::Mechgun) => true, + (SectionID::Purplenum, WeaponType::Assault) => true, + (SectionID::Purplenum, WeaponType::Repeater) => true, + (SectionID::Purplenum, WeaponType::Gatling) => true, + (SectionID::Purplenum, WeaponType::Vulcan) => true, + (SectionID::Pinkal, WeaponType::Cane) => true, + (SectionID::Pinkal, WeaponType::Stick) => true, + (SectionID::Pinkal, WeaponType::Mace) => true, + (SectionID::Pinkal, WeaponType::Club) => true, + (SectionID::Oran, WeaponType::Dagger) => true, + (SectionID::Oran, WeaponType::Knife) => true, + (SectionID::Oran, WeaponType::Blade) => true, + (SectionID::Oran, WeaponType::Edge) => true, + (SectionID::Oran, WeaponType::Ripper) => true, + (SectionID::Whitill, WeaponType::Slicer) => true, + (SectionID::Whitill, WeaponType::Spinner) => true, + (SectionID::Whitill, WeaponType::Cutter) => true, + (SectionID::Whitill, WeaponType::Sawcer) => true, + (SectionID::Whitill, WeaponType::Diska) => true, + _ => false, + } + } + + pub fn generate_weapon(&mut self, level: usize) -> ShopWeapon { + let weapon = self.generate_type(level); + let grind = if self.is_alt_grind(&weapon) { + self.generate_alt_grind(level) + } else { + self.generate_grind(level) + }; + let special = self.generate_special(level); + let (attr1, attr2) = { + match self.generate_attribute1(level) { + Some(a1) => { + let a2 = loop { + let attr = self.generate_attribute2(level); + match attr { + Some(a2) => { + if a2.attr != a1.attr { + break Some(a2); + } + }, + None => break None, + } + }; + (Some(a1), a2) + }, + None => { + let a2 = self.generate_attribute2(level); + (a2, None) + } + } + }; + + ShopWeapon { + weapon: weapon, + grind: grind, + special: special, + attributes: [attr1, attr2], + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_loading_weapons() { + WeaponShop::::new(Difficulty::Ultimate, SectionID::Pinkal); + } +} From 991a71e1ca29501e3982107235065331ed8cd06e Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 21 Sep 2020 00:37:50 -0600 Subject: [PATCH 02/15] tool shop --- data/shops/techniques.toml | 299 +++++++++++++++++++++++++++++++++++++ data/shops/tools.toml | 1 + src/ship/shops/mod.rs | 1 + src/ship/shops/tool.rs | 268 +++++++++++++++++++++++++++++++++ 4 files changed, 569 insertions(+) create mode 100644 data/shops/techniques.toml create mode 100644 data/shops/tools.toml create mode 100644 src/ship/shops/tool.rs diff --git a/data/shops/techniques.toml b/data/shops/techniques.toml new file mode 100644 index 0000000..4982b64 --- /dev/null +++ b/data/shops/techniques.toml @@ -0,0 +1,299 @@ +[[techniques]] +level = 0 + +[techniques.techs.Foie] +probability = 18 +level_divisor = 3 +[techniques.techs.Barta] +probability = 18 +level_divisor = 4 +[techniques.techs.Zonde] +probability = 18 +level_divisor = 6 +[techniques.techs.Resta] +probability = 18 +level_divisor = 3 +[techniques.techs.Anti] +probability = 18 +level_divisor = 35 +[techniques.techs.Shifta] +probability = 2 +set_level = 1 +[techniques.techs.Deband] +probability = 3 +set_level = 1 +[techniques.techs.Jellen] +probability = 3 +set_level = 1 +[techniques.techs.Zalure] +probability = 2 +set_level = 1 +[techniques.techs.Gifoie] +probability = 0 +set_level = 1 +[techniques.techs.Gibarta] +probability = 0 +set_level = 1 +[techniques.techs.Gizonde] +probability = 0 +set_level = 1 +[techniques.techs.Ryuker] +probability = 0 +set_level = 1 +[techniques.techs.Reverser] +probability = 0 +set_level = 1 +[techniques.techs.Rafoie] +probability = 0 +set_level = 1 +[techniques.techs.Rabarta] +probability = 0 +set_level = 1 +[techniques.techs.Razonde] +probability = 0 +set_level = 1 +[[techniques]] +level = 10 + +[techniques.techs.Foie] +probability = 7 +level_divisor = 6 +[techniques.techs.Barta] +probability = 7 +level_divisor = 7 +[techniques.techs.Zonde] +probability = 7 +level_divisor = 8 +[techniques.techs.Resta] +probability = 7 +level_divisor = 6 +[techniques.techs.Anti] +probability = 7 +level_divisor = 35 +[techniques.techs.Shifta] +probability = 6 +level_divisor = 9 +[techniques.techs.Deband] +probability = 6 +level_divisor = 7 +[techniques.techs.Jellen] +probability = 6 +level_divisor = 6 +[techniques.techs.Zalure] +probability = 7 +level_divisor = 8 +[techniques.techs.Gifoie] +probability = 8 +level_divisor = 9 +[techniques.techs.Gibarta] +probability = 8 +level_divisor = 12 +[techniques.techs.Gizonde] +probability = 8 +level_divisor = 8 +[techniques.techs.Ryuker] +probability = 5 +set_level = 1 +[techniques.techs.Reverser] +probability = 5 +set_level = 1 +[techniques.techs.Rafoie] +probability = 2 +set_level = 1 +[techniques.techs.Rabarta] +probability = 2 +set_level = 1 +[techniques.techs.Razonde] +probability = 2 +set_level = 1 +[[techniques]] +level = 25 + +[techniques.techs.Foie] +probability = 5 +min = 3 +max = 10 +[techniques.techs.Barta] +probability = 5 +min = 3 +max = 10 +[techniques.techs.Zonde] +probability = 5 +min = 3 +max = 10 +[techniques.techs.Resta] +probability = 6 +min = 3 +max = 10 +[techniques.techs.Anti] +probability = 5 +level_divisor = 35 +[techniques.techs.Shifta] +probability = 5 +level_divisor = 8 +[techniques.techs.Deband] +probability = 5 +level_divisor = 7 +[techniques.techs.Jellen] +probability = 5 +level_divisor = 5 +[techniques.techs.Zalure] +probability = 5 +level_divisor = 6 +[techniques.techs.Gifoie] +probability = 5 +level_divisor = 8 +[techniques.techs.Gibarta] +probability = 5 +level_divisor = 9 +[techniques.techs.Gizonde] +probability = 5 +level_divisor = 10 +[techniques.techs.Ryuker] +probability = 6 +set_level = 1 +[techniques.techs.Reverser] +probability = 6 +set_level = 1 +[techniques.techs.Rafoie] +probability = 9 +level_divisor = 10 +[techniques.techs.Rabarta] +probability = 9 +level_divisor = 11 +[techniques.techs.Razonde] +probability = 9 +level_divisor = 12 +[[techniques]] +level = 42 + +[techniques.techs.Foie] +probability = 6 +min = 4 +max = 12 +[techniques.techs.Barta] +probability = 6 +min = 4 +max = 12 +[techniques.techs.Zonde] +probability = 6 +min = 4 +max = 12 +[techniques.techs.Resta] +probability = 5 +min = 4 +max = 12 +[techniques.techs.Anti] +probability = 5 +level_divisor = 35 +[techniques.techs.Shifta] +probability = 6 +min = 4 +max = 12 +[techniques.techs.Deband] +probability = 6 +min = 4 +max = 12 +[techniques.techs.Jellen] +probability = 6 +min = 4 +max = 12 +[techniques.techs.Zalure] +probability = 6 +min = 4 +max = 12 +[techniques.techs.Gifoie] +probability = 6 +min = 3 +max = 10 +[techniques.techs.Gibarta] +probability = 6 +min = 3 +max = 10 +[techniques.techs.Gizonde] +probability = 6 +min = 3 +max = 10 +[techniques.techs.Ryuker] +probability = 6 +set_level = 1 +[techniques.techs.Reverser] +probability = 6 +set_level = 1 +[techniques.techs.Rafoie] +probability = 6 +level_divisor = 12 +[techniques.techs.Rabarta] +probability = 6 +level_divisor = 13 +[techniques.techs.Razonde] +probability = 6 +level_divisor = 11 +[[techniques]] +level = 60 + +[techniques.techs.Foie] +probability = 6 +min = 5 +max = 14 +[techniques.techs.Barta] +probability = 6 +min = 5 +max = 14 +[techniques.techs.Zonde] +probability = 6 +min = 5 +max = 14 +[techniques.techs.Resta] +probability = 5 +min = 5 +max = 14 +[techniques.techs.Anti] +probability = 5 +level_divisor = 35 +[techniques.techs.Shifta] +probability = 6 +min = 5 +max = 14 +[techniques.techs.Deband] +probability = 6 +min = 5 +max = 14 +[techniques.techs.Jellen] +probability = 6 +min = 5 +max = 14 +[techniques.techs.Zalure] +probability = 6 +min = 5 +max = 14 +[techniques.techs.Gifoie] +probability = 6 +min = 4 +max = 13 +[techniques.techs.Gibarta] +probability = 6 +min = 4 +max = 13 +[techniques.techs.Gizonde] +probability = 6 +min = 4 +max = 13 +[techniques.techs.Ryuker] +probability = 6 +set_level = 1 +[techniques.techs.Reverser] +probability = 6 +set_level = 1 +[techniques.techs.Rafoie] +probability = 6 +min = 3 +max = 13 +[techniques.techs.Rabarta] +probability = 6 +min = 3 +max = 13 +[techniques.techs.Razonde] +probability = 6 +min = 3 +max = 13 diff --git a/data/shops/tools.toml b/data/shops/tools.toml new file mode 100644 index 0000000..d0731bb --- /dev/null +++ b/data/shops/tools.toml @@ -0,0 +1 @@ +tools = [ "Monomate", "Dimate", "Trimate", "Monofluid", "Difluid", "Trifluid", "Antidote", "Antiparalysis", "SolAtomizer", "MoonAtomizer", "StarAtomizer", "Telepipe",] diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs index e22b3b2..d24e7a1 100644 --- a/src/ship/shops/mod.rs +++ b/src/ship/shops/mod.rs @@ -1 +1,2 @@ pub mod weapon; +pub mod tool; diff --git a/src/ship/shops/tool.rs b/src/ship/shops/tool.rs new file mode 100644 index 0000000..e3a7534 --- /dev/null +++ b/src/ship/shops/tool.rs @@ -0,0 +1,268 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; +use serde::Deserialize; +use rand::{Rng, SeedableRng}; +use rand::distributions::{WeightedIndex, Distribution}; +use rand::seq::{SliceRandom, IteratorRandom}; +use crate::entity::character::SectionID; +use crate::ship::room::Difficulty; +use crate::entity::item::tool::{Tool, ToolType}; +use crate::entity::item::tech::{Technique, TechniqueDisk}; + + +#[derive(Debug, PartialEq, Eq)] +pub enum ShopTool { + Tool(ToolType), + Tech(TechniqueDisk), +} + +impl Ord for ShopTool { + fn cmp(&self, other: &ShopTool) -> std::cmp::Ordering { + let a = match self { + ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ShopTool::Tech(t) => t.as_bytes(), + }; + let b = match other { + ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ShopTool::Tech(t) => t.as_bytes(), + }; + + a.cmp(&b) + } +} + +impl PartialOrd for ShopTool { + fn partial_cmp(&self, other: &ShopTool) -> Option { + let a = match self { + ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ShopTool::Tech(t) => t.as_bytes(), + }; + let b = match other { + ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ShopTool::Tech(t) => t.as_bytes(), + }; + + a.partial_cmp(&b) + } +} + +#[derive(Debug, Deserialize)] +struct ToolTable(Vec); + +#[derive(Debug, Deserialize, Clone)] +#[serde(untagged)] +enum TechLevel { + Set { + set_level: usize, + }, + Level { + level_divisor: usize, + }, + Range { + min: usize, + max: usize, + } +} + +#[derive(Debug, Deserialize, Clone)] +struct TechEntry { + probability: usize, + #[serde(flatten)] + level: TechLevel, +} + +#[derive(Debug, Deserialize)] +struct TechTierDeserialize { + level: usize, + techs: HashMap, +} + +#[derive(Debug, Clone)] +struct TechTier { + level: usize, + techs: HashMap, +} + +#[derive(Debug)] +struct TechTable(Vec); + + +fn load_tool_table() -> ToolTable { + let path = PathBuf::from("data/shops/tools.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + + ToolTable(table.remove("tools".into()).unwrap()) +} + +fn load_tech_table() -> TechTable { + let path = PathBuf::from("data/shops/techniques.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut table: HashMap> = toml::from_str(s.as_str()).unwrap(); + let techniques = table.remove("techniques".into()).unwrap(); + let techniques = techniques.into_iter() + .map(|tech_tier| { + TechTier { + level: tech_tier.level, + techs: tech_tier.techs.into_iter() + .map(|(tech_name, tech_entry)| { + (tech_name.parse().unwrap(), tech_entry) + }).collect() + } + }).collect(); + + TechTable(techniques) +} + +fn number_of_techs_to_generate(character_level: usize) -> usize { + if character_level <= 10 { + 4 + } + else if character_level <= 25 { + 5 + } + else if character_level <= 42 { + 6 + } + else { + 7 + } +} + + +#[derive(Debug)] +struct ToolShop { + tools: ToolTable, + techs: TechTable, + rng: R, +} + +impl ToolShop { + pub fn new() -> ToolShop { + ToolShop { + tools: load_tool_table(), + techs: load_tech_table(), + rng: R::from_entropy(), + } + } + + fn generate_tech(&mut self, character_level: usize) -> ShopTool { + let tier = self.techs.0.iter() + .filter(|t| t.level <= character_level) + .last() + .unwrap(); + + let mut tier = tier.techs.iter() + .map(|(tech, entry)| { + (tech, entry) + }); + + + let tech_choice = WeightedIndex::new(tier.clone().map(|(_, e)| e.probability)).unwrap(); + let tech_detail = tier.nth(tech_choice.sample(&mut self.rng)).unwrap(); + let tech_level = match tech_detail.1.level { + TechLevel::Set{set_level} => set_level, + TechLevel::Level{level_divisor} => std::cmp::max(std::cmp::min(character_level, 99)/level_divisor, 1), + TechLevel::Range{min, max} => self.rng.gen_range(min, max+1), + }; + + ShopTool::Tech( + TechniqueDisk { + tech: *tech_detail.0, + level: tech_level as u32, + } + ) + } + + fn generate_tech_types(&mut self, character_level: usize) -> Vec { + let tier = self.techs.0.iter() + .filter(|t| t.level <= character_level) + .last() + .unwrap(); + + let possible_techs = tier.techs.iter() + .filter(|(_, entry)| entry.probability > 0) + .collect::>(); + + let number_of_techs = std::cmp::min(possible_techs.len(), number_of_techs_to_generate(character_level)); + if number_of_techs == possible_techs.len() { + possible_techs.into_iter() + .map(|(tech, _entry)| { + tech + }) + .cloned() + .collect() + } + else { + let mut techs = Vec::new(); + let tier = tier.techs.iter() + .map(|(tech, entry)| { + (tech, entry) + }) + .collect::>(); + + let tech_choice = WeightedIndex::new(tier.iter().map(|(_, e)| e.probability)).unwrap(); + while techs.len() < number_of_techs { + let tech_detail = tier.get(tech_choice.sample(&mut self.rng)).unwrap(); + if techs.iter().find(|t| *t == tech_detail.0).is_none() { + techs.push(*tech_detail.0); + } + } + techs + } + + } + + fn generate_techs(&mut self, character_level: usize) -> Vec { + let tier = self.techs.0.iter() + .filter(|t| t.level <= character_level) + .last() + .cloned() + .unwrap(); + + let tech_types = self.generate_tech_types(character_level); + tech_types.into_iter() + .map(|tech| { + let tech_detail = tier.techs.get(&tech).unwrap().clone(); + let level = match tech_detail.level { + TechLevel::Set{set_level} => set_level, + TechLevel::Level{level_divisor} => std::cmp::max(std::cmp::min(character_level, 99)/level_divisor, 1), + TechLevel::Range{min, max} => self.rng.gen_range(min, max+1), + }; + + ShopTool::Tech(TechniqueDisk { + tech: tech, + level: level as u32, + }) + }) + .collect() + } + + pub fn generate_tool_list(&mut self, character_level: usize) -> Vec { + let mut tools = Vec::new().into_iter() + .chain(self.tools.0.clone().into_iter().map(|t| ShopTool::Tool(t))) + .chain(self.generate_techs(character_level).into_iter()) + .collect::>(); + tools.sort(); + tools + } + +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_loading_tool_shop() { + ToolShop::::new(); + } +} From 80f50c49cc166019da21daf4e9718aef2daa735f Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 21 Sep 2020 00:38:12 -0600 Subject: [PATCH 03/15] small fixes in weapon shop --- src/ship/shops/weapon.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ship/shops/weapon.rs b/src/ship/shops/weapon.rs index c3a3267..723a980 100644 --- a/src/ship/shops/weapon.rs +++ b/src/ship/shops/weapon.rs @@ -1,4 +1,3 @@ - use std::collections::HashMap; use std::fs::File; use std::io::Read; @@ -130,7 +129,7 @@ fn load_weapon_table(difficulty: Difficulty, section_id: SectionID) -> WeaponTab } fn load_special_table() -> SpecialTable { - let mut path = PathBuf::from("data/shops/special.toml"); + let path = PathBuf::from("data/shops/special.toml"); let mut f = File::open(path).unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); @@ -141,7 +140,7 @@ fn load_special_table() -> SpecialTable { } fn load_grind_table() -> GrindTable { - let mut path = PathBuf::from("data/shops/grind.toml"); + let path = PathBuf::from("data/shops/grind.toml"); let mut f = File::open(path).unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); @@ -152,7 +151,7 @@ fn load_grind_table() -> GrindTable { } fn load_alt_grind_table() -> GrindTable { - let mut path = PathBuf::from("data/shops/alt_grind.toml"); + let path = PathBuf::from("data/shops/alt_grind.toml"); let mut f = File::open(path).unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); @@ -163,7 +162,7 @@ fn load_alt_grind_table() -> GrindTable { } fn load_attribute1_table() -> AttributeTable { - let mut path = PathBuf::from("data/shops/attribute1.toml"); + let path = PathBuf::from("data/shops/attribute1.toml"); let mut f = File::open(path).unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); @@ -174,7 +173,7 @@ fn load_attribute1_table() -> AttributeTable { } fn load_attribute2_table() -> AttributeTable { - let mut path = PathBuf::from("data/shops/attribute2.toml"); + let path = PathBuf::from("data/shops/attribute2.toml"); let mut f = File::open(path).unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); @@ -207,7 +206,7 @@ impl WeaponShop { grind: load_grind_table(), alt_grind: load_alt_grind_table(), attr1: load_attribute1_table(), - attr2: load_attribute1_table(), + attr2: load_attribute2_table(), rng: R::from_entropy(), } } @@ -215,7 +214,7 @@ impl WeaponShop { fn generate_type(&mut self, level: usize) -> WeaponType { let tier = self.weapon.0.iter() - .filter(|t| t.level < level) + .filter(|t| t.level <= level) .last() .unwrap(); @@ -225,7 +224,7 @@ impl WeaponShop { fn generate_special(&mut self, level: usize) -> Option { let tier = self.special.0.iter() - .filter(|t| t.level < level) + .filter(|t| t.level <= level) .last() .unwrap(); @@ -239,7 +238,7 @@ impl WeaponShop { fn generate_grind(&mut self, level: usize) -> usize { let tier = self.grind.0.iter() - .filter(|t| t.level < level) + .filter(|t| t.level <= level) .last() .unwrap(); @@ -248,7 +247,7 @@ impl WeaponShop { fn generate_alt_grind(&mut self, level: usize) -> usize { let tier = self.alt_grind.0.iter() - .filter(|t| t.level < level) + .filter(|t| t.level <= level) .nth(0) .unwrap(); @@ -257,7 +256,7 @@ impl WeaponShop { fn generate_attribute1(&mut self, level: usize) -> Option { let tier = self.attr1.0.iter() - .filter(|t| t.level < level) + .filter(|t| t.level <= level) .last() .unwrap(); @@ -284,7 +283,7 @@ impl WeaponShop { fn generate_attribute2(&mut self, level: usize) -> Option { let tier = self.attr2.0.iter() - .filter(|t| t.level < level) + .filter(|t| t.level <= level) .last() .unwrap(); @@ -399,7 +398,7 @@ mod test { use super::*; #[test] - fn test_loading_weapons() { + fn test_loading_weapon_shop() { WeaponShop::::new(Difficulty::Ultimate, SectionID::Pinkal); } } From 514e18fff3e2c0bc6274e93281431a9da3fcd043 Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 22 Sep 2020 22:39:28 -0600 Subject: [PATCH 04/15] armor shop --- data/shops/barrier.toml | 219 ++++++++++++++++++++++++++++ data/shops/frame.toml | 251 ++++++++++++++++++++++++++++++++ data/shops/unit.toml | 300 +++++++++++++++++++++++++++++++++++++++ src/ship/shops/armor.rs | 259 +++++++++++++++++++++++++++++++++ src/ship/shops/mod.rs | 1 + src/ship/shops/tool.rs | 8 ++ src/ship/shops/weapon.rs | 7 + 7 files changed, 1045 insertions(+) create mode 100644 data/shops/barrier.toml create mode 100644 data/shops/frame.toml create mode 100644 data/shops/unit.toml create mode 100644 src/ship/shops/armor.rs diff --git a/data/shops/barrier.toml b/data/shops/barrier.toml new file mode 100644 index 0000000..6d80c05 --- /dev/null +++ b/data/shops/barrier.toml @@ -0,0 +1,219 @@ +[[barrier]] +level = 0 +[[barrier.item]] +item = "Barrier" +probability = 34 + +[[barrier.item]] +item = "Shield" +probability = 34 + +[[barrier.item]] +item = "CoreShield" +probability = 15 + +[[barrier.item]] +item = "GigaShield" +probability = 15 + +[[barrier.item]] +item = "BraveBarrier" +probability = 2 + + +[[barrier]] +level = 10 +[[barrier.item]] +item = "Barrier" +probability = 5 + +[[barrier.item]] +item = "Shield" +probability = 10 + +[[barrier.item]] +item = "CoreShield" +probability = 14 + +[[barrier.item]] +item = "GigaShield" +probability = 18 + +[[barrier.item]] +item = "SoulBarrier" +probability = 18 + +[[barrier.item]] +item = "HardShield" +probability = 14 + +[[barrier.item]] +item = "BraveBarrier" +probability = 10 + +[[barrier.item]] +item = "SolidShield" +probability = 5 + +[[barrier.item]] +item = "FlameBarrier" +probability = 2 + +[[barrier.item]] +item = "PlasmaBarrier" +probability = 2 + +[[barrier.item]] +item = "FreezeBarrier" +probability = 2 + + +[[barrier]] +level = 25 +[[barrier.item]] +item = "GigaShield" +probability = 6 + +[[barrier.item]] +item = "SoulBarrier" +probability = 10 + +[[barrier.item]] +item = "HardShield" +probability = 15 + +[[barrier.item]] +item = "BraveBarrier" +probability = 19 + +[[barrier.item]] +item = "SolidShield" +probability = 18 + +[[barrier.item]] +item = "FlameBarrier" +probability = 14 + +[[barrier.item]] +item = "PlasmaBarrier" +probability = 9 + +[[barrier.item]] +item = "FreezeBarrier" +probability = 4 + +[[barrier.item]] +item = "PsychicBarrier" +probability = 3 + +[[barrier.item]] +item = "ProtectBarrier" +probability = 2 + + +[[barrier]] +level = 42 +[[barrier.item]] +item = "SoulBarrier" +probability = 5 + +[[barrier.item]] +item = "HardShield" +probability = 5 + +[[barrier.item]] +item = "BraveBarrier" +probability = 5 + +[[barrier.item]] +item = "SolidShield" +probability = 10 + +[[barrier.item]] +item = "FlameBarrier" +probability = 14 + +[[barrier.item]] +item = "PlasmaBarrier" +probability = 15 + +[[barrier.item]] +item = "FreezeBarrier" +probability = 14 + +[[barrier.item]] +item = "PsychicBarrier" +probability = 11 + +[[barrier.item]] +item = "GeneralShield" +probability = 9 + +[[barrier.item]] +item = "ProtectBarrier" +probability = 6 + +[[barrier.item]] +item = "GloriousShield" +probability = 4 + +[[barrier.item]] +item = "GuardianShield" +probability = 2 + + +[[barrier]] +level = 60 +[[barrier.item]] +item = "HardShield" +probability = 4 + +[[barrier.item]] +item = "BraveBarrier" +probability = 5 + +[[barrier.item]] +item = "SolidShield" +probability = 5 + +[[barrier.item]] +item = "FlameBarrier" +probability = 8 + +[[barrier.item]] +item = "PlasmaBarrier" +probability = 11 + +[[barrier.item]] +item = "FreezeBarrier" +probability = 13 + +[[barrier.item]] +item = "PsychicBarrier" +probability = 13 + +[[barrier.item]] +item = "GeneralShield" +probability = 14 + +[[barrier.item]] +item = "ProtectBarrier" +probability = 14 + +[[barrier.item]] +item = "GloriousShield" +probability = 9 + +[[barrier.item]] +item = "ImperialBarrier" +probability = 2 + +[[barrier.item]] +item = "GuardianShield" +probability = 1 + +[[barrier.item]] +item = "DivinityBarrier" +probability = 1 + + diff --git a/data/shops/frame.toml b/data/shops/frame.toml new file mode 100644 index 0000000..1f9d456 --- /dev/null +++ b/data/shops/frame.toml @@ -0,0 +1,251 @@ +[[frame]] +level = 0 +[[frame.item]] +item = "Frame" +probability = 33 + +[[frame.item]] +item = "Armor" +probability = 33 + +[[frame.item]] +item = "PsyArmor" +probability = 15 + +[[frame.item]] +item = "GigaFrame" +probability = 10 + +[[frame.item]] +item = "SoulFrame" +probability = 5 + +[[frame.item]] +item = "SolidFrame" +probability = 4 + + +[[frame]] +level = 10 +[[frame.item]] +item = "Frame" +probability = 5 + +[[frame.item]] +item = "Armor" +probability = 5 + +[[frame.item]] +item = "PsyArmor" +probability = 10 + +[[frame.item]] +item = "GigaFrame" +probability = 15 + +[[frame.item]] +item = "SoulFrame" +probability = 19 + +[[frame.item]] +item = "CrossArmor" +probability = 19 + +[[frame.item]] +item = "SolidFrame" +probability = 10 + +[[frame.item]] +item = "BraveArmor" +probability = 10 + +[[frame.item]] +item = "HyperFrame" +probability = 5 + +[[frame.item]] +item = "KingsFrame" +probability = 2 + + +[[frame]] +level = 25 +[[frame.item]] +item = "SoulFrame" +probability = 5 + +[[frame.item]] +item = "CrossArmor" +probability = 5 + +[[frame.item]] +item = "SolidFrame" +probability = 10 + +[[frame.item]] +item = "BraveArmor" +probability = 15 + +[[frame.item]] +item = "HyperFrame" +probability = 19 + +[[frame.item]] +item = "GrandArmor" +probability = 19 + +[[frame.item]] +item = "ShockFrame" +probability = 10 + +[[frame.item]] +item = "KingsFrame" +probability = 10 + +[[frame.item]] +item = "DragonFrame" +probability = 5 + +[[frame.item]] +item = "GeneralArmor" +probability = 2 + + +[[frame]] +level = 42 +[[frame.item]] +item = "SolidFrame" +probability = 2 + +[[frame.item]] +item = "BraveArmor" +probability = 4 + +[[frame.item]] +item = "HyperFrame" +probability = 5 + +[[frame.item]] +item = "GrandArmor" +probability = 5 + +[[frame.item]] +item = "ShockFrame" +probability = 10 + +[[frame.item]] +item = "KingsFrame" +probability = 12 + +[[frame.item]] +item = "DragonFrame" +probability = 14 + +[[frame.item]] +item = "AbsorbArmor" +probability = 14 + +[[frame.item]] +item = "ProtectFrame" +probability = 10 + +[[frame.item]] +item = "GeneralArmor" +probability = 9 + +[[frame.item]] +item = "PerfectFrame" +probability = 5 + +[[frame.item]] +item = "ValiantFrame" +probability = 5 + +[[frame.item]] +item = "ImperialArmor" +probability = 3 + +[[frame.item]] +item = "HolinessArmor" +probability = 2 + + +[[frame]] +level = 60 +[[frame.item]] +item = "BraveArmor" +probability = 2 + +[[frame.item]] +item = "HyperFrame" +probability = 5 + +[[frame.item]] +item = "GrandArmor" +probability = 5 + +[[frame.item]] +item = "ShockFrame" +probability = 5 + +[[frame.item]] +item = "KingsFrame" +probability = 6 + +[[frame.item]] +item = "DragonFrame" +probability = 10 + +[[frame.item]] +item = "AbsorbArmor" +probability = 13 + +[[frame.item]] +item = "ProtectFrame" +probability = 14 + +[[frame.item]] +item = "GeneralArmor" +probability = 14 + +[[frame.item]] +item = "PerfectFrame" +probability = 14 + +[[frame.item]] +item = "ValiantFrame" +probability = 7 + +[[frame.item]] +item = "ImperialArmor" +probability = 3 + +[[frame.item]] +item = "HolinessArmor" +probability = 1 + +[[frame.item]] +item = "GuardianArmor" +probability = 1 + + +[[slot_rate]] +slot = 0 +probability = 75 + +[[slot_rate]] +slot = 1 +probability = 18 + +[[slot_rate]] +slot = 2 +probability = 6 + +[[slot_rate]] +slot = 3 +probability = 1 + +[[slot_rate]] +slot = 4 +probability = 0 + diff --git a/data/shops/unit.toml b/data/shops/unit.toml new file mode 100644 index 0000000..4e71152 --- /dev/null +++ b/data/shops/unit.toml @@ -0,0 +1,300 @@ +[[unit]] +level = 10 +[[unit.item]] +item = "KnightPower" +probability = 10 + +[[unit.item]] +item = "PriestMind" +probability = 10 + +[[unit.item]] +item = "MarksmanArm" +probability = 10 + +[[unit.item]] +item = "ThiefLegs" +probability = 10 + +[[unit.item]] +item = "DiggerHp" +probability = 10 + +[[unit.item]] +item = "WarriorBody" +probability = 10 + +[[unit.item]] +item = "ResistFire" +probability = 10 + +[[unit.item]] +item = "ResistCold" +probability = 10 + +[[unit.item]] +item = "ResistShock" +probability = 10 + +[[unit.item]] +item = "ResistLight" +probability = 5 + +[[unit.item]] +item = "ResistDark" +probability = 5 + + +[[unit]] +level = 25 +[[unit.item]] +item = "KnightPower" +probability = 10 + +[[unit.item]] +item = "PriestMind" +probability = 10 + +[[unit.item]] +item = "MarksmanArm" +probability = 10 + +[[unit.item]] +item = "ThiefLegs" +probability = 10 + +[[unit.item]] +item = "DiggerHp" +probability = 10 + +[[unit.item]] +item = "WarriorBody" +probability = 10 + +[[unit.item]] +item = "ResistFire" +probability = 10 + +[[unit.item]] +item = "ResistCold" +probability = 10 + +[[unit.item]] +item = "ResistShock" +probability = 10 + +[[unit.item]] +item = "ResistLight" +probability = 5 + +[[unit.item]] +item = "ResistDark" +probability = 5 + + +[[unit]] +level = 42 +[[unit.item]] +item = "KnightPower" +probability = 4 + +[[unit.item]] +item = "PriestMind" +probability = 4 + +[[unit.item]] +item = "MarksmanArm" +probability = 4 + +[[unit.item]] +item = "ThiefLegs" +probability = 4 + +[[unit.item]] +item = "DiggerHp" +probability = 4 + +[[unit.item]] +item = "WarriorBody" +probability = 4 + +[[unit.item]] +item = "ResistFire" +probability = 4 + +[[unit.item]] +item = "ResistCold" +probability = 4 + +[[unit.item]] +item = "ResistShock" +probability = 4 + +[[unit.item]] +item = "ResistLight" +probability = 5 + +[[unit.item]] +item = "ResistDark" +probability = 5 + +[[unit.item]] +item = "GeneralPower" +probability = 5 + +[[unit.item]] +item = "GeneralMind" +probability = 5 + +[[unit.item]] +item = "GeneralArm" +probability = 5 + +[[unit.item]] +item = "GeneralLegs" +probability = 5 + +[[unit.item]] +item = "GeneralHp" +probability = 5 + +[[unit.item]] +item = "GeneralBody" +probability = 5 + +[[unit.item]] +item = "ResistFlame" +probability = 5 + +[[unit.item]] +item = "ResistFreeze" +probability = 5 + +[[unit.item]] +item = "ResistThunder" +probability = 5 + +[[unit.item]] +item = "ResistSaint" +probability = 3 + +[[unit.item]] +item = "ResistEvil" +probability = 3 + +[[unit.item]] +item = "HpRestorate" +probability = 1 + +[[unit.item]] +item = "TpRestorate" +probability = 1 + +[[unit.item]] +item = "PbAmplifier" +probability = 1 + + +[[unit]] +level = 60 +[[unit.item]] +item = "KnightPower" +probability = 3 + +[[unit.item]] +item = "PriestMind" +probability = 3 + +[[unit.item]] +item = "MarksmanArm" +probability = 3 + +[[unit.item]] +item = "ThiefLegs" +probability = 3 + +[[unit.item]] +item = "DiggerHp" +probability = 3 + +[[unit.item]] +item = "WarriorBody" +probability = 3 + +[[unit.item]] +item = "ResistFire" +probability = 4 + +[[unit.item]] +item = "ResistCold" +probability = 4 + +[[unit.item]] +item = "ResistShock" +probability = 4 + +[[unit.item]] +item = "ResistLight" +probability = 4 + +[[unit.item]] +item = "ResistDark" +probability = 5 + +[[unit.item]] +item = "GeneralPower" +probability = 5 + +[[unit.item]] +item = "GeneralMind" +probability = 5 + +[[unit.item]] +item = "GeneralArm" +probability = 5 + +[[unit.item]] +item = "GeneralLegs" +probability = 5 + +[[unit.item]] +item = "GeneralHp" +probability = 5 + +[[unit.item]] +item = "GeneralBody" +probability = 5 + +[[unit.item]] +item = "ResistFlame" +probability = 5 + +[[unit.item]] +item = "ResistFreeze" +probability = 5 + +[[unit.item]] +item = "ResistThunder" +probability = 5 + +[[unit.item]] +item = "ResistSaint" +probability = 5 + +[[unit.item]] +item = "ResistEvil" +probability = 5 + +[[unit.item]] +item = "HpRestorate" +probability = 2 + +[[unit.item]] +item = "TpRestorate" +probability = 2 + +[[unit.item]] +item = "PbAmplifier" +probability = 2 + + diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs new file mode 100644 index 0000000..8944350 --- /dev/null +++ b/src/ship/shops/armor.rs @@ -0,0 +1,259 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; +use serde::Deserialize; +use rand::{Rng, SeedableRng}; +use rand::distributions::{WeightedIndex, Distribution}; +use rand::seq::{SliceRandom, IteratorRandom}; +use crate::entity::character::SectionID; +use crate::ship::room::Difficulty; +use crate::entity::item::armor::ArmorType; +use crate::entity::item::shield::ShieldType; +use crate::entity::item::unit::UnitType; + + +enum ShopArmor { + Frame(ArmorType, usize), + Barrier(ShieldType), + Unit(UnitType), +} + + + +#[derive(Debug, Deserialize, Clone)] +struct FrameTierItem { + item: ArmorType, + probability: usize, +} + +#[derive(Debug, Deserialize, Clone)] +struct FrameTier { + level: usize, + item: Vec, +} + +#[derive(Debug, Deserialize)] +struct SlotRate { + slot: usize, + probability: usize, +} + +#[derive(Debug, Deserialize)] +struct FrameTable { + frame: Vec, + slot_rate: Vec, +} + + +#[derive(Debug, Deserialize, Clone)] +struct BarrierTierItem { + item: ShieldType, + probability: usize, +} + +#[derive(Debug, Deserialize, Clone)] +struct BarrierTier { + level: usize, + item: Vec, +} + +#[derive(Debug, Deserialize)] +struct BarrierTable { + barrier: Vec, +} + +#[derive(Debug, Deserialize, Clone)] +struct UnitTierItem { + item: UnitType, + probability: usize, +} + +#[derive(Debug, Deserialize, Clone)] +struct UnitTier { + level: usize, + item: Vec, +} + +#[derive(Debug, Deserialize)] +struct UnitTable { + unit: Vec, +} + + + +fn load_frame_table() -> FrameTable { + let path = PathBuf::from("data/shops/frame.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let table: FrameTable = toml::from_str(s.as_str()).unwrap(); + table +} + +fn load_barrier_table() -> BarrierTable { + let path = PathBuf::from("data/shops/barrier.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let table: BarrierTable = toml::from_str(s.as_str()).unwrap(); + table +} + +fn load_unit_table() -> UnitTable { + let path = PathBuf::from("data/shops/unit.toml"); + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let table: UnitTable = toml::from_str(s.as_str()).unwrap(); + table +} + + +fn number_of_frames_to_generate(character_level: usize) -> usize { + if character_level <= 10 { + 4 + } + else if character_level <= 25 { + 6 + } + else if character_level <= 42 { + 7 + } + else { + 8 + } +} + +fn number_of_barriers_to_generate(character_level: usize) -> usize { + if character_level <= 10 { + 4 + } + else if character_level <= 25 { + 5 + } + else if character_level <= 42 { + 6 + } + else { + 7 + } +} + +fn number_of_units_to_generate(character_level: usize) -> usize { + if character_level <= 10 { + 0 + } + else if character_level <= 25 { + 3 + } + else if character_level <= 42 { + 5 + } + else { + 6 + } +} + +#[derive(Debug)] +struct ArmorShop { + frame: FrameTable, + barrier: BarrierTable, + unit: UnitTable, + rng: R, +} + +impl ArmorShop { + pub fn new() -> ArmorShop { + ArmorShop { + frame: load_frame_table(), + barrier: load_barrier_table(), + unit: load_unit_table(), + rng: R::from_entropy(), + } + } + + fn generate_frame_list(&mut self, character_level: usize) -> Vec { + let tier = self.frame.frame.iter() + .filter(|t| t.level <= character_level) + .last() + .cloned() + .unwrap(); + + let frame_choice = WeightedIndex::new(tier.item.iter().map(|f| f.probability)).unwrap(); + let slot_choice = WeightedIndex::new(self.frame.slot_rate.iter().map(|sr| sr.probability)).unwrap(); + (0..number_of_frames_to_generate(character_level)) + .map(|_| { + let frame_detail = tier.item.get(frame_choice.sample(&mut self.rng)).unwrap(); + let slot = self.frame.slot_rate.get(slot_choice.sample(&mut self.rng)).unwrap(); + + ShopArmor::Frame(frame_detail.item, slot.slot) + }) + .collect() + } + + fn generate_barrier_list(&mut self, character_level: usize) -> Vec { + let tier = self.barrier.barrier.iter() + .filter(|t| t.level <= character_level) + .last() + .cloned() + .unwrap(); + + let barrier_choice = WeightedIndex::new(tier.item.iter().map(|b| b.probability)).unwrap(); + (0..number_of_barriers_to_generate(character_level)) + .map(|_| { + let barrier_detail = tier.item.get(barrier_choice.sample(&mut self.rng)).unwrap(); + + ShopArmor::Barrier(barrier_detail.item) + }) + .collect() + } + + fn generate_unit_list(&mut self, character_level: usize) -> Vec { + self.unit.unit.iter() + .filter(|t| t.level <= character_level) + .last() + .cloned() + .map(|tier| { + let unit_choice = WeightedIndex::new(tier.item.iter().map(|u| u.probability)).unwrap(); + (0..number_of_units_to_generate(character_level)) + .map(|_| { + let unit_detail = tier.item.get(unit_choice.sample(&mut self.rng)).unwrap(); + + ShopArmor::Unit(unit_detail.item) + }) + .collect() + }) + .unwrap_or(Vec::new()) + } + + pub fn generate_armor_list(&mut self, character_level: usize) -> Vec { + self.generate_frame_list(character_level).into_iter() + .chain(self.generate_barrier_list(character_level).into_iter()) + .chain(self.generate_unit_list(character_level).into_iter()) + .collect() + } +} + + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_loading_tool_shop() { + ArmorShop::::new(); + } + + #[test] + fn test_generating_some_armor() { + let mut fs = ArmorShop::::new(); + for i in 0..200 { + fs.generate_armor_list(i); + } + } +} diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs index d24e7a1..e8753d1 100644 --- a/src/ship/shops/mod.rs +++ b/src/ship/shops/mod.rs @@ -1,2 +1,3 @@ pub mod weapon; pub mod tool; +pub mod armor; diff --git a/src/ship/shops/tool.rs b/src/ship/shops/tool.rs index e3a7534..1b3df5d 100644 --- a/src/ship/shops/tool.rs +++ b/src/ship/shops/tool.rs @@ -265,4 +265,12 @@ mod test { fn test_loading_tool_shop() { ToolShop::::new(); } + + #[test] + fn test_generating_some_tools() { + let mut ts = ToolShop::::new(); + for i in 0..200 { + ts.generate_tool_list(i); + } + } } diff --git a/src/ship/shops/weapon.rs b/src/ship/shops/weapon.rs index 723a980..f2aead2 100644 --- a/src/ship/shops/weapon.rs +++ b/src/ship/shops/weapon.rs @@ -401,4 +401,11 @@ mod test { fn test_loading_weapon_shop() { WeaponShop::::new(Difficulty::Ultimate, SectionID::Pinkal); } + #[test] + fn test_generating_some_weapons() { + let mut ws = WeaponShop::::new(Difficulty::Ultimate, SectionID::Pinkal); + for i in 0..200 { + ws.generate_weapon(i); + } + } } From c13c071946bef7ff82906aeb8f929730e010db7b Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 23 Sep 2020 19:13:45 -0600 Subject: [PATCH 05/15] weapon stats --- data/item_stats/weapon_stats.toml | 2165 +++++++++++++++++++++++++++++ src/ship/item_stats.rs | 29 +- 2 files changed, 2192 insertions(+), 2 deletions(-) create mode 100644 data/item_stats/weapon_stats.toml diff --git a/data/item_stats/weapon_stats.toml b/data/item_stats/weapon_stats.toml new file mode 100644 index 0000000..8f95377 --- /dev/null +++ b/data/item_stats/weapon_stats.toml @@ -0,0 +1,2165 @@ +[Saber] +grind = 35 +atp_min = 40 +atp_max = 55 +shop_multiplier = 15.0 + +[Brand] +grind = 32 +atp_min = 80 +atp_max = 100 +shop_multiplier = 15.0 + +[Buster] +grind = 30 +atp_min = 120 +atp_max = 160 +shop_multiplier = 15.0 + +[Pallasch] +grind = 26 +atp_min = 170 +atp_max = 220 +shop_multiplier = 15.0 + +[Gladius] +grind = 18 +atp_min = 240 +atp_max = 280 +shop_multiplier = 15.0 + +[DbsSaber] +grind = 9 +atp_min = 140 +atp_max = 168 +shop_multiplier = 1.0 + +[Kaladbolg] +grind = 25 +atp_min = 260 +atp_max = 320 +shop_multiplier = 15.0 + +[Durandal] +grind = 37 +atp_min = 300 +atp_max = 376 +shop_multiplier = 15.0 + +[Galatine] +grind = 9 +atp_min = 330 +atp_max = 420 +shop_multiplier = 15.0 + +[Sword] +grind = 46 +atp_min = 25 +atp_max = 60 +shop_multiplier = 12.0 + +[Gigush] +grind = 32 +atp_min = 55 +atp_max = 100 +shop_multiplier = 12.0 + +[Breaker] +grind = 18 +atp_min = 100 +atp_max = 150 +shop_multiplier = 12.0 + +[Claymore] +grind = 16 +atp_min = 150 +atp_max = 200 +shop_multiplier = 12.0 + +[Calibur] +grind = 10 +atp_min = 210 +atp_max = 255 +shop_multiplier = 12.0 + +[FlowensSword] +grind = 21 +atp_min = 230 +atp_max = 300 +shop_multiplier = 12.0 + +[LastSurvivor] +grind = 31 +atp_min = 275 +atp_max = 321 +shop_multiplier = 12.0 + +[DragonSlayer] +grind = 34 +atp_min = 345 +atp_max = 352 +shop_multiplier = 12.0 + +[Dagger] +grind = 65 +atp_min = 25 +atp_max = 40 +shop_multiplier = 4.5 + +[Knife] +grind = 50 +atp_min = 50 +atp_max = 70 +shop_multiplier = 4.5 + +[Blade] +grind = 35 +atp_min = 80 +atp_max = 100 +shop_multiplier = 4.5 + +[Edge] +grind = 25 +atp_min = 105 +atp_max = 130 +shop_multiplier = 4.5 + +[Ripper] +grind = 15 +atp_min = 125 +atp_max = 160 +shop_multiplier = 4.5 + +[BladeDance] +grind = 30 +atp_min = 110 +atp_max = 180 +shop_multiplier = 4.5 + +[BloodyArt] +grind = 42 +atp_min = 120 +atp_max = 175 +shop_multiplier = 4.5 + +[CrossScar] +grind = 28 +atp_min = 135 +atp_max = 220 +shop_multiplier = 4.5 + +[ZeroDivide] +grind = 99 +atp_min = 200 +atp_max = 300 +shop_multiplier = 4.5 + +[TwoKamui] +grind = 0 +atp_min = 600 +atp_max = 650 +shop_multiplier = 4.5 + +[Partisan] +grind = 35 +atp_min = 30 +atp_max = 40 +shop_multiplier = 4.5 + +[Halbert] +grind = 30 +atp_min = 65 +atp_max = 75 +shop_multiplier = 4.5 + +[Glaive] +grind = 25 +atp_min = 95 +atp_max = 110 +shop_multiplier = 4.5 + +[Berdys] +grind = 20 +atp_min = 130 +atp_max = 145 +shop_multiplier = 4.5 + +[Gungnir] +grind = 10 +atp_min = 150 +atp_max = 180 +shop_multiplier = 4.5 + +[Brionac] +grind = 15 +atp_min = 150 +atp_max = 182 +shop_multiplier = 4.5 + +[Vjaya] +grind = 15 +atp_min = 160 +atp_max = 220 +shop_multiplier = 4.5 + +[GaeBolg] +grind = 30 +atp_min = 215 +atp_max = 220 +shop_multiplier = 4.5 + +[AsteronBelt] +grind = 9 +atp_min = 380 +atp_max = 400 +shop_multiplier = 4.5 + +[Slicer] +grind = 20 +atp_min = 5 +atp_max = 15 +shop_multiplier = 3.75 + +[Spinner] +grind = 20 +atp_min = 10 +atp_max = 30 +shop_multiplier = 3.75 + +[Cutter] +grind = 15 +atp_min = 35 +atp_max = 55 +shop_multiplier = 3.75 + +[Sawcer] +grind = 15 +atp_min = 60 +atp_max = 80 +shop_multiplier = 3.75 + +[Diska] +grind = 10 +atp_min = 85 +atp_max = 105 +shop_multiplier = 3.75 + +[SlicerOfAssassin] +grind = 12 +atp_min = 120 +atp_max = 125 +shop_multiplier = 3.75 + +[DiskaOfLiberator] +grind = 9 +atp_min = 120 +atp_max = 146 +shop_multiplier = 3.75 + +[DiskaOfBraveman] +grind = 9 +atp_min = 150 +atp_max = 167 +shop_multiplier = 3.75 + +[Izmaela] +grind = 0 +atp_min = 250 +atp_max = 250 +shop_multiplier = 3.75 + +[Handgun] +grind = 75 +atp_min = 20 +atp_max = 30 +shop_multiplier = 6.29999971 + +[Autogun] +grind = 50 +atp_min = 45 +atp_max = 65 +shop_multiplier = 6.29999971 + +[Lockgun] +grind = 35 +atp_min = 80 +atp_max = 100 +shop_multiplier = 6.29999971 + +[Railgun] +grind = 25 +atp_min = 120 +atp_max = 140 +shop_multiplier = 6.29999971 + +[Raygun] +grind = 15 +atp_min = 150 +atp_max = 180 +shop_multiplier = 6.29999971 + +[Varista] +grind = 25 +atp_min = 155 +atp_max = 210 +shop_multiplier = 6.29999971 + +[CustomRayVerOo] +grind = 20 +atp_min = 165 +atp_max = 195 +shop_multiplier = 6.29999971 + +[Bravace] +grind = 30 +atp_min = 190 +atp_max = 230 +shop_multiplier = 6.29999971 + +[TensionBlaster] +grind = 0 +atp_min = 280 +atp_max = 310 +shop_multiplier = 6.29999971 + +[Rifle] +grind = 65 +atp_min = 10 +atp_max = 50 +shop_multiplier = 9.0 + +[Sniper] +grind = 55 +atp_min = 50 +atp_max = 90 +shop_multiplier = 9.0 + +[Blaster] +grind = 45 +atp_min = 100 +atp_max = 130 +shop_multiplier = 9.0 + +[Beam] +grind = 35 +atp_min = 140 +atp_max = 170 +shop_multiplier = 9.0 + +[Laser] +grind = 25 +atp_min = 200 +atp_max = 210 +shop_multiplier = 9.0 + +[Visk235W] +grind = 15 +atp_min = 220 +atp_max = 250 +shop_multiplier = 9.0 + +[WalsMk2] +grind = 9 +atp_min = 260 +atp_max = 280 +shop_multiplier = 9.0 + +[Justy23St] +grind = 15 +atp_min = 290 +atp_max = 320 +shop_multiplier = 9.0 + +[Rianov303snr] +grind = 60 +atp_min = 300 +atp_max = 300 +shop_multiplier = 9.0 + +[Rianov303snr1] +grind = 50 +atp_min = 350 +atp_max = 400 +shop_multiplier = 9.0 + +[Rianov303snr2] +grind = 25 +atp_min = 150 +atp_max = 400 +shop_multiplier = 9.0 + +[Rianov303snr3] +grind = 15 +atp_min = 500 +atp_max = 500 +shop_multiplier = 9.0 + +[Rianov303snr4] +grind = 60 +atp_min = 350 +atp_max = 450 +shop_multiplier = 9.0 + +[Rianov303snr5] +grind = 0 +atp_min = 550 +atp_max = 550 +shop_multiplier = 9.0 + +[Mechgun] +grind = 9 +atp_min = 2 +atp_max = 4 +shop_multiplier = 0.12 + +[Assault] +grind = 9 +atp_min = 5 +atp_max = 8 +shop_multiplier = 0.12 + +[Repeater] +grind = 9 +atp_min = 5 +atp_max = 12 +shop_multiplier = 0.12 + +[Gatling] +grind = 9 +atp_min = 5 +atp_max = 16 +shop_multiplier = 0.12 + +[Vulcan] +grind = 9 +atp_min = 5 +atp_max = 20 +shop_multiplier = 0.12 + +[MA60Vise] +grind = 9 +atp_min = 15 +atp_max = 25 +shop_multiplier = 0.12 + +[HS25Justice] +grind = 9 +atp_min = 15 +atp_max = 30 +shop_multiplier = 0.12 + +[LK14Combat] +grind = 20 +atp_min = 15 +atp_max = 30 +shop_multiplier = 0.12 + +[Shot] +grind = 20 +atp_min = 20 +atp_max = 25 +shop_multiplier = 2.69999981 + +[Spread] +grind = 20 +atp_min = 30 +atp_max = 50 +shop_multiplier = 2.69999981 + +[Cannon] +grind = 15 +atp_min = 40 +atp_max = 80 +shop_multiplier = 2.69999981 + +[Launcher] +grind = 15 +atp_min = 50 +atp_max = 110 +shop_multiplier = 2.69999981 + +[Arms] +grind = 10 +atp_min = 60 +atp_max = 140 +shop_multiplier = 2.69999981 + +[CrushBullet] +grind = 25 +atp_min = 85 +atp_max = 133 +shop_multiplier = 2.69999981 + +[MeteorSmash] +grind = 25 +atp_min = 80 +atp_max = 160 +shop_multiplier = 2.69999981 + +[FinalImpact] +grind = 30 +atp_min = 95 +atp_max = 170 +shop_multiplier = 2.69999981 + +[Cane] +grind = 55 +atp_min = 25 +atp_max = 30 +shop_multiplier = 6.0 + +[Stick] +grind = 40 +atp_min = 50 +atp_max = 60 +shop_multiplier = 6.0 + +[Mace] +grind = 25 +atp_min = 90 +atp_max = 90 +shop_multiplier = 6.0 + +[Club] +grind = 10 +atp_min = 110 +atp_max = 120 +shop_multiplier = 6.0 + +[ClubOfLaconium] +grind = 9 +atp_min = 140 +atp_max = 150 +shop_multiplier = 6.0 + +[MaceOfAdaman] +grind = 9 +atp_min = 170 +atp_max = 170 +shop_multiplier = 6.0 + +[ClubOfZumiuran] +grind = 9 +atp_min = 178 +atp_max = 180 +shop_multiplier = 6.0 + +[Lollipop] +grind = 12 +atp_min = 150 +atp_max = 200 +shop_multiplier = 6.0 + +[Rod] +grind = 75 +atp_min = 25 +atp_max = 45 +shop_multiplier = 7.5 + +[Pole] +grind = 50 +atp_min = 55 +atp_max = 80 +shop_multiplier = 7.5 + +[Pillar] +grind = 30 +atp_min = 85 +atp_max = 115 +shop_multiplier = 7.5 + +[Striker] +grind = 20 +atp_min = 100 +atp_max = 150 +shop_multiplier = 7.5 + +[BattleVerge] +grind = 15 +atp_min = 130 +atp_max = 185 +shop_multiplier = 7.5 + +[BraveHammer] +grind = 15 +atp_min = 170 +atp_max = 220 +shop_multiplier = 7.5 + +[AliveAqhu] +grind = 15 +atp_min = 210 +atp_max = 230 +shop_multiplier = 7.5 + +[Valkyrie] +grind = 33 +atp_min = 600 +atp_max = 600 +shop_multiplier = 7.5 + +[Wand] +grind = 15 +atp_min = 3 +atp_max = 10 +shop_multiplier = 2.25 + +[Staff] +grind = 15 +atp_min = 10 +atp_max = 30 +shop_multiplier = 2.25 + +[Baton] +grind = 10 +atp_min = 35 +atp_max = 50 +shop_multiplier = 2.25 + +[Scepter] +grind = 10 +atp_min = 55 +atp_max = 75 +shop_multiplier = 2.25 + +[FireScepterAgni] +grind = 9 +atp_min = 70 +atp_max = 95 +shop_multiplier = 2.25 + +[IceStaffDagon] +grind = 9 +atp_min = 73 +atp_max = 105 +shop_multiplier = 2.25 + +[StormWandIndra] +grind = 9 +atp_min = 105 +atp_max = 120 +shop_multiplier = 2.25 + +[EarthWandBrownie] +grind = 20 +atp_min = 370 +atp_max = 670 +shop_multiplier = 2.25 + +[PhotonClaw] +grind = 20 +atp_min = 230 +atp_max = 300 +shop_multiplier = 5.0 + +[SilenceClaw] +grind = 15 +atp_min = 335 +atp_max = 345 +shop_multiplier = 5.0 + +[NeisClaw] +grind = 0 +atp_min = 756 +atp_max = 756 +shop_multiplier = 1.0 + +[PhoenixClaw] +grind = 15 +atp_min = 540 +atp_max = 570 +shop_multiplier = 5.0 + +[DoubleSaber] +grind = 35 +atp_min = 150 +atp_max = 152 +shop_multiplier = 3.0 + +[StagCutlery] +grind = 30 +atp_min = 230 +atp_max = 235 +shop_multiplier = 3.0 + +[TwinBrand] +grind = 60 +atp_min = 235 +atp_max = 240 +shop_multiplier = 3.0 + +[BraveKnuckle] +grind = 30 +atp_min = 380 +atp_max = 460 +shop_multiplier = 5.0 + +[AngryFist] +grind = 50 +atp_min = 460 +atp_max = 560 +shop_multiplier = 5.0 + +[GodHand] +grind = 30 +atp_min = 580 +atp_max = 700 +shop_multiplier = 5.0 + +[SonicKnuckle] +grind = 0 +atp_min = 250 +atp_max = 300 +shop_multiplier = 5.0 + +[Login] +grind = 0 +atp_min = 5 +atp_max = 5 +shop_multiplier = 10.0 + +[Orotiagito] +grind = 0 +atp_min = 750 +atp_max = 800 +shop_multiplier = 8.0 + +[Agito1975] +grind = 0 +atp_min = 460 +atp_max = 480 +shop_multiplier = 8.0 + +[Agito1983] +grind = 45 +atp_min = 200 +atp_max = 500 +shop_multiplier = 8.0 + +[Agito2001] +grind = 9 +atp_min = 400 +atp_max = 430 +shop_multiplier = 8.0 + +[Agito1991] +grind = 9 +atp_min = 400 +atp_max = 410 +shop_multiplier = 8.0 + +[Agito1977] +grind = 50 +atp_min = 450 +atp_max = 460 +shop_multiplier = 8.0 + +[Agito1980] +grind = 40 +atp_min = 455 +atp_max = 460 +shop_multiplier = 8.0 + +[Raikiri] +grind = 0 +atp_min = 560 +atp_max = 570 +shop_multiplier = 8.0 + +[SoulEater] +grind = 9 +atp_min = 180 +atp_max = 185 +shop_multiplier = 20.0 + +[SoulBanish] +grind = 9 +atp_min = 350 +atp_max = 370 +shop_multiplier = 20.0 + +[SpreadNeedle] +grind = 40 +atp_min = 1 +atp_max = 110 +shop_multiplier = 2.0 + +[HolyRay] +grind = 40 +atp_min = 290 +atp_max = 300 +shop_multiplier = 5.0 + +[InfernoBazooka] +grind = 9 +atp_min = 230 +atp_max = 410 +shop_multiplier = 4.0 + +[RamblingMay] +grind = 0 +atp_min = 360 +atp_max = 450 +shop_multiplier = 4.0 + +[LK38Combat] +grind = 25 +atp_min = 150 +atp_max = 250 +shop_multiplier = 4.0 + +[FlameVisit] +grind = 9 +atp_min = 300 +atp_max = 450 +shop_multiplier = 5.0 + +[AkikosFryingPan] +grind = 0 +atp_min = 230 +atp_max = 250 +shop_multiplier = 100.0 + +[SorcerersCane] +grind = 0 +atp_min = 360 +atp_max = 360 +shop_multiplier = 2.0 + +[SBeatsBlade] +grind = 15 +atp_min = 210 +atp_max = 220 +shop_multiplier = 0.7 + +[PArmssBlade] +grind = 25 +atp_min = 250 +atp_max = 270 +shop_multiplier = 1.5 + +[DelsabersBuster] +grind = 9 +atp_min = 340 +atp_max = 350 +shop_multiplier = 6.0 + +[BringersRifle] +grind = 9 +atp_min = 330 +atp_max = 370 +shop_multiplier = 3.5 + +[EggBlaster] +grind = 0 +atp_min = 300 +atp_max = 330 +shop_multiplier = 100.0 + +[PsychoWand] +grind = 0 +atp_min = 395 +atp_max = 400 +shop_multiplier = 1.8 + +[HeavenPunisher] +grind = 0 +atp_min = 300 +atp_max = 330 +shop_multiplier = 0.7 + +[LavisCannon] +grind = 0 +atp_min = 730 +atp_max = 750 +shop_multiplier = 2.89999986 + +[VictorAxe] +grind = 20 +atp_min = 300 +atp_max = 420 +shop_multiplier = 2.1 + +[LaconiumAxe] +grind = 25 +atp_min = 700 +atp_max = 750 +shop_multiplier = 2.1 + +[ChainSawd] +grind = 15 +atp_min = 500 +atp_max = 525 +shop_multiplier = 2.8 + +[Caduceus] +grind = 0 +atp_min = 360 +atp_max = 360 +shop_multiplier = 1.19999993 + +[MercuriusRod] +grind = 0 +atp_min = 390 +atp_max = 400 +shop_multiplier = 1.19999993 + +[StingTip] +grind = 30 +atp_min = 170 +atp_max = 170 +shop_multiplier = 1.8 + +[MagicalPiece] +grind = 0 +atp_min = 240 +atp_max = 240 +shop_multiplier = 1.19999993 + +[TechnicalCrozier] +grind = 0 +atp_min = 130 +atp_max = 135 +shop_multiplier = 2.0 + +[SuppressedGun] +grind = 9 +atp_min = 260 +atp_max = 270 +shop_multiplier = 0.9 + +[AncientSaber] +grind = 9 +atp_min = 531 +atp_max = 544 +shop_multiplier = 3.3 + +[HarisenBattleFan] +grind = 0 +atp_min = 310 +atp_max = 280 +shop_multiplier = 3.3 + +[Yamigarasu] +grind = 0 +atp_min = 580 +atp_max = 650 +shop_multiplier = 2.89999986 + +[AkikosWok] +grind = 0 +atp_min = 210 +atp_max = 250 +shop_multiplier = 3.19999981 + +[ToyHammer] +grind = 0 +atp_min = 1 +atp_max = 400 +shop_multiplier = 3.19999981 + +[Elysion] +grind = 9 +atp_min = 360 +atp_max = 368 +shop_multiplier = 3.19999981 + +[RedSaber] +grind = 78 +atp_min = 450 +atp_max = 489 +shop_multiplier = 3.3 + +[MeteorCudgel] +grind = 15 +atp_min = 300 +atp_max = 560 +shop_multiplier = 3.19999981 + +[MonkeyKingBar] +grind = 25 +atp_min = 380 +atp_max = 390 +shop_multiplier = 3.19999981 + +[BlackKingBar] +grind = 80 +atp_min = 590 +atp_max = 600 +shop_multiplier = 3.19999981 + +[DoubleCannon] +grind = 0 +atp_min = 620 +atp_max = 650 +shop_multiplier = 2.8 + +[Girasole] +grind = 0 +atp_min = 500 +atp_max = 550 +shop_multiplier = 2.8 + +[HugeBattleFan] +grind = 0 +atp_min = 10 +atp_max = 255 +shop_multiplier = 3.19999981 + +[TsumikiriJSword] +grind = 50 +atp_min = 700 +atp_max = 756 +shop_multiplier = 2.8 + +[SealedJSword] +grind = 0 +atp_min = 400 +atp_max = 525 +shop_multiplier = 3.3 + +[RedSword] +grind = 52 +atp_min = 400 +atp_max = 611 +shop_multiplier = 3.3 + +[CrazyTune] +grind = 0 +atp_min = 200 +atp_max = 255 +shop_multiplier = 3.19999981 + +[TwinChakram] +grind = 20 +atp_min = 245 +atp_max = 250 +shop_multiplier = 3.19999981 + +[WokOfAkikosShop] +grind = 0 +atp_min = 170 +atp_max = 160 +shop_multiplier = 3.19999981 + +[LavisBlade] +grind = 0 +atp_min = 380 +atp_max = 450 +shop_multiplier = 3.19999981 + +[RedDagger] +grind = 65 +atp_min = 245 +atp_max = 280 +shop_multiplier = 3.3 + +[MadamsParasol] +grind = 0 +atp_min = 215 +atp_max = 220 +shop_multiplier = 2.8 + +[MadamsUmbrella] +grind = 0 +atp_min = 210 +atp_max = 280 +shop_multiplier = 3.19999981 + +[ImperialPick] +grind = 9 +atp_min = 280 +atp_max = 300 +shop_multiplier = 3.19999981 + +[Berdysh] +grind = 25 +atp_min = 270 +atp_max = 290 +shop_multiplier = 3.19999981 + +[RedPartisan] +grind = 40 +atp_min = 290 +atp_max = 295 +shop_multiplier = 3.3 + +[FlightCutter] +grind = 9 +atp_min = 250 +atp_max = 260 +shop_multiplier = 3.19999981 + +[FlightFan] +grind = 15 +atp_min = 185 +atp_max = 200 +shop_multiplier = 3.19999981 + +[RedSlicer] +grind = 45 +atp_min = 190 +atp_max = 200 +shop_multiplier = 3.3 + +[HandgunGuld] +grind = 9 +atp_min = 370 +atp_max = 400 +shop_multiplier = 0.9 + +[MasterRaven] +grind = 9 +atp_min = 350 +atp_max = 380 +shop_multiplier = 0.9 + +[HandgunMilla] +grind = 9 +atp_min = 350 +atp_max = 360 +shop_multiplier = 0.9 + +[LastSwan] +grind = 9 +atp_min = 80 +atp_max = 90 +shop_multiplier = 0.9 + +[RedHandgun] +grind = 50 +atp_min = 300 +atp_max = 300 +shop_multiplier = 0.9 + +[FrozenShooter] +grind = 9 +atp_min = 240 +atp_max = 250 +shop_multiplier = 0.9 + +[AntiAndroidRifle] +grind = 9 +atp_min = 330 +atp_max = 350 +shop_multiplier = 0.9 + +[RocketPunch] +grind = 50 +atp_min = 50 +atp_max = 300 +shop_multiplier = 3.19999981 + +[SambaMaracas] +grind = 0 +atp_min = 5 +atp_max = 10 +shop_multiplier = 3.19999981 + +[TwinPsychogun] +grind = 0 +atp_min = 35 +atp_max = 40 +shop_multiplier = 0.9 + +[DrillLauncher] +grind = 0 +atp_min = 180 +atp_max = 200 +shop_multiplier = 0.9 + +[GuldMilla] +grind = 9 +atp_min = 180 +atp_max = 200 +shop_multiplier = 0.599999964 + +[DualBird] +grind = 21 +atp_min = 200 +atp_max = 210 +shop_multiplier = 0.599999964 + +[RedMechgun] +grind = 30 +atp_min = 50 +atp_max = 50 +shop_multiplier = 0.9 + +[BelraCannon] +grind = 20 +atp_min = 400 +atp_max = 500 +shop_multiplier = 0.9 + +[PanzerFaust] +grind = 9 +atp_min = 350 +atp_max = 500 +shop_multiplier = 0.9 + +[SummitMoon] +grind = 9 +atp_min = 270 +atp_max = 280 +shop_multiplier = 1.8 + +[Windmill] +grind = 9 +atp_min = 300 +atp_max = 310 +shop_multiplier = 1.8 + +[EvilCurst] +grind = 0 +atp_min = 444 +atp_max = 666 +shop_multiplier = 1.5999999 + +[FlowerCane] +grind = 0 +atp_min = 168 +atp_max = 180 +shop_multiplier = 1.8 + +[HildebearsCane] +grind = 9 +atp_min = 220 +atp_max = 230 +shop_multiplier = 1.8 + +[HildebluesCane] +grind = 9 +atp_min = 290 +atp_max = 300 +shop_multiplier = 1.5 + +[RabbitWand] +grind = 0 +atp_min = 120 +atp_max = 230 +shop_multiplier = 1.8 + +[PlantainLeaf] +grind = 0 +atp_min = 219 +atp_max = 280 +shop_multiplier = 30.0 + +[Fatsia] +grind = 0 +atp_min = 219 +atp_max = 280 +shop_multiplier = 30.0 + +[DemonicFork] +grind = 0 +atp_min = 325 +atp_max = 340 +shop_multiplier = 1.8 + +[StrikerOfChao] +grind = 0 +atp_min = 300 +atp_max = 325 +shop_multiplier = 1.3 + +[Broom] +grind = 0 +atp_min = 90 +atp_max = 230 +shop_multiplier = 1.8 + +[ProphetsOfMotav] +grind = 0 +atp_min = 90 +atp_max = 250 +shop_multiplier = 1.8 + +[TheSighOfAGod] +grind = 0 +atp_min = 175 +atp_max = 180 +shop_multiplier = 1.8 + +[TwinkleStar] +grind = 0 +atp_min = 175 +atp_max = 175 +shop_multiplier = 1.8 + +[PlantainFan] +grind = 40 +atp_min = 95 +atp_max = 150 +shop_multiplier = 1.8 + +[TwinBlaze] +grind = 9 +atp_min = 300 +atp_max = 520 +shop_multiplier = 3.3 + +[MarinasBag] +grind = 0 +atp_min = 10 +atp_max = 180 +shop_multiplier = 1.8 + +[DragonsClaw] +grind = 35 +atp_min = 550 +atp_max = 580 +shop_multiplier = 3.3 + +[PanthersClaw] +grind = 0 +atp_min = 180 +atp_max = 280 +shop_multiplier = 3.3 + +[SRedsBlade] +grind = 15 +atp_min = 340 +atp_max = 350 +shop_multiplier = 3.3 + +[PlantainHugeFan] +grind = 9 +atp_min = 265 +atp_max = 300 +shop_multiplier = 1.8 + +[ChameleonScythe] +grind = 0 +atp_min = 80 +atp_max = 180 +shop_multiplier = 3.3 + +[Yasminkov3000R] +grind = 60 +atp_min = 370 +atp_max = 400 +shop_multiplier = 0.9 + +[AnoRifle] +grind = 15 +atp_min = 350 +atp_max = 380 +shop_multiplier = 0.9 + +[BaranzLauncher] +grind = 30 +atp_min = 230 +atp_max = 240 +shop_multiplier = 0.9 + +[BranchOfPakupaku] +grind = 0 +atp_min = 240 +atp_max = 267 +shop_multiplier = 30.0 + +[HeartOfPoumn] +grind = 0 +atp_min = 680 +atp_max = 700 +shop_multiplier = 3.3 + +[Yasminkov2000H] +grind = 10 +atp_min = 340 +atp_max = 340 +shop_multiplier = 0.9 + +[Yasminkov7000V] +grind = 25 +atp_min = 370 +atp_max = 450 +shop_multiplier = 0.9 + +[Yasminkov9000M] +grind = 10 +atp_min = 40 +atp_max = 80 +shop_multiplier = 0.9 + +[MaserBeam] +grind = 20 +atp_min = 230 +atp_max = 230 +shop_multiplier = 0.9 + +[FlowerBouquet] +grind = 0 +atp_min = 1 +atp_max = 1 +shop_multiplier = 10.0 + +[Musashi] +grind = 40 +atp_min = 330 +atp_max = 350 +shop_multiplier = 1.0 + +[Yamato] +grind = 60 +atp_min = 380 +atp_max = 390 +shop_multiplier = 1.0 + +[Asuka] +grind = 30 +atp_min = 560 +atp_max = 570 +shop_multiplier = 1.0 + +[SangeYasha] +grind = 30 +atp_min = 640 +atp_max = 650 +shop_multiplier = 1.0 + +[Sange] +grind = 0 +atp_min = 500 +atp_max = 550 +shop_multiplier = 1.0 + +[Yasha] +grind = 0 +atp_min = 500 +atp_max = 550 +shop_multiplier = 1.0 + +[Kamui] +grind = 0 +atp_min = 650 +atp_max = 650 +shop_multiplier = 1.0 + +[PhotonLauncher] +grind = 9 +atp_min = 210 +atp_max = 220 +shop_multiplier = 1.0 + +[GuiltyLight] +grind = 18 +atp_min = 240 +atp_max = 250 +shop_multiplier = 1.0 + +[RedScorpio] +grind = 50 +atp_min = 280 +atp_max = 300 +shop_multiplier = 1.0 + +[PhononMaser] +grind = 36 +atp_min = 350 +atp_max = 360 +shop_multiplier = 1.0 + +[Talis] +grind = 9 +atp_min = 120 +atp_max = 180 +shop_multiplier = 1.0 + +[Mahu] +grind = 9 +atp_min = 120 +atp_max = 200 +shop_multiplier = 1.0 + +[Hitogata] +grind = 9 +atp_min = 150 +atp_max = 230 +shop_multiplier = 1.0 + +[DancingHitogata] +grind = 0 +atp_min = 350 +atp_max = 354 +shop_multiplier = 1.0 + +[Kunai] +grind = 0 +atp_min = 95 +atp_max = 175 +shop_multiplier = 1.0 + +[Nug2000Bazooka] +grind = 32 +atp_min = 400 +atp_max = 660 +shop_multiplier = 1.0 + +[SBerillsHands0] +grind = 35 +atp_min = 158 +atp_max = 197 +shop_multiplier = 1.0 + +[SBerillsHands1] +grind = 15 +atp_min = 320 +atp_max = 321 +shop_multiplier = 1.0 + +[FlowensSword3060] +grind = 12 +atp_min = 135 +atp_max = 243 +shop_multiplier = 1.0 + +[FlowensSword3064] +grind = 16 +atp_min = 164 +atp_max = 248 +shop_multiplier = 1.0 + +[FlowensSword3067] +grind = 21 +atp_min = 200 +atp_max = 256 +shop_multiplier = 1.0 + +[FlowensSword3073] +grind = 34 +atp_min = 197 +atp_max = 262 +shop_multiplier = 1.0 + +[FlowensSword3077] +grind = 32 +atp_min = 121 +atp_max = 255 +shop_multiplier = 1.0 + +[FlowensSword3082] +grind = 12 +atp_min = 211 +atp_max = 273 +shop_multiplier = 1.0 + +[FlowensSword3083] +grind = 11 +atp_min = 261 +atp_max = 283 +shop_multiplier = 1.0 + +[FlowensSword3084] +grind = 85 +atp_min = 300 +atp_max = 320 +shop_multiplier = 1.0 + +[FlowensSword3079] +grind = 9 +atp_min = 290 +atp_max = 300 +shop_multiplier = 1.0 + +[GiGueBazooka] +grind = 0 +atp_min = 520 +atp_max = 620 +shop_multiplier = 1.0 + +[Guardianna] +grind = 9 +atp_min = 200 +atp_max = 280 +shop_multiplier = 1.0 + +[MorningGlory] +grind = 0 +atp_min = 450 +atp_max = 500 +shop_multiplier = 1.0 + +[PartisanOfLightning] +grind = 60 +atp_min = 370 +atp_max = 410 +shop_multiplier = 1.0 + +[GalWind] +grind = 15 +atp_min = 270 +atp_max = 310 +shop_multiplier = 1.0 + +[Zanba] +grind = 38 +atp_min = 310 +atp_max = 438 +shop_multiplier = 1.0 + +[RikasClaw] +grind = 35 +atp_min = 590 +atp_max = 670 +shop_multiplier = 1.0 + +[AngelHarp] +grind = 0 +atp_min = 300 +atp_max = 320 +shop_multiplier = 1.0 + +[DemolitionComet] +grind = 25 +atp_min = 530 +atp_max = 530 +shop_multiplier = 1.0 + +[RainbowBaton] +grind = 24 +atp_min = 300 +atp_max = 320 +shop_multiplier = 1.0 + +[DarkFlow] +grind = 0 +atp_min = 756 +atp_max = 900 +shop_multiplier = 1.0 + +[DarkMeteor] +grind = 25 +atp_min = 150 +atp_max = 280 +shop_multiplier = 1.0 + +[DarkBridge] +grind = 0 +atp_min = 185 +atp_max = 400 +shop_multiplier = 1.0 + +[GAssassinsSabers] +grind = 25 +atp_min = 350 +atp_max = 360 +shop_multiplier = 1.0 + +[RappysFan] +grind = 32 +atp_min = 140 +atp_max = 146 +shop_multiplier = 1.0 + +[BoomasClaw] +grind = 15 +atp_min = 300 +atp_max = 315 +shop_multiplier = 1.0 + +[GoboomasClaw] +grind = 35 +atp_min = 330 +atp_max = 345 +shop_multiplier = 1.0 + +[GigoboomasClaw] +grind = 55 +atp_min = 450 +atp_max = 500 +shop_multiplier = 1.0 + +[RubyBullet] +grind = 0 +atp_min = 350 +atp_max = 350 +shop_multiplier = 1.0 + +[AmoreRose] +grind = 0 +atp_min = 5 +atp_max = 7 +shop_multiplier = 1.0 + +[SlicerOfFanatic] +grind = 30 +atp_min = 340 +atp_max = 360 +shop_multiplier = 1.0 + +[LameDArgent] +grind = 35 +atp_min = 430 +atp_max = 465 +shop_multiplier = 1.0 + +[Excalibur] +grind = 0 +atp_min = 900 +atp_max = 950 +shop_multiplier = 1.0 + +[RageDeFeu] +grind = 9 +atp_min = 175 +atp_max = 185 +shop_multiplier = 1.0 + +[DaisyChain] +grind = 0 +atp_min = 350 +atp_max = 410 +shop_multiplier = 1.0 + +[OphelieSeize] +grind = 9 +atp_min = 390 +atp_max = 420 +shop_multiplier = 1.0 + +[MilleMarteaux] +grind = 12 +atp_min = 200 +atp_max = 220 +shop_multiplier = 1.0 + +[LeCogneur] +grind = 0 +atp_min = 310 +atp_max = 330 +shop_multiplier = 1.0 + +[CommanderBlade] +grind = 0 +atp_min = 560 +atp_max = 585 +shop_multiplier = 1.0 + +[Vivienne] +grind = 50 +atp_min = 575 +atp_max = 590 +shop_multiplier = 1.0 + +[Kusanagi] +grind = 32 +atp_min = 560 +atp_max = 575 +shop_multiplier = 1.0 + +[SacredDuster] +grind = 25 +atp_min = 660 +atp_max = 730 +shop_multiplier = 1.0 + +[Guren] +grind = 0 +atp_min = 790 +atp_max = 840 +shop_multiplier = 1.0 + +[Shouren] +grind = 0 +atp_min = 820 +atp_max = 870 +shop_multiplier = 1.0 + +[Jizai] +grind = 40 +atp_min = 800 +atp_max = 810 +shop_multiplier = 1.0 + +[Flamberge] +grind = 30 +atp_min = 575 +atp_max = 590 +shop_multiplier = 1.0 + +[Yunchang] +grind = 25 +atp_min = 300 +atp_max = 350 +shop_multiplier = 1.0 + +[SnakeSpire] +grind = 15 +atp_min = 290 +atp_max = 310 +shop_multiplier = 1.0 + +[FlapjackFlapper] +grind = 25 +atp_min = 350 +atp_max = 400 +shop_multiplier = 1.0 + +[Getsugasan] +grind = 0 +atp_min = 190 +atp_max = 230 +shop_multiplier = 1.0 + +[Maguwa] +grind = 15 +atp_min = 230 +atp_max = 250 +shop_multiplier = 1.0 + +[HeavenStriker] +grind = 20 +atp_min = 550 +atp_max = 660 +shop_multiplier = 1.0 + +[CannonRouge] +grind = 30 +atp_min = 600 +atp_max = 750 +shop_multiplier = 1.0 + +[MeteorRouge] +grind = 0 +atp_min = 265 +atp_max = 315 +shop_multiplier = 1.0 + +[Solferino] +grind = 0 +atp_min = 250 +atp_max = 300 +shop_multiplier = 1.0 + +[Clio] +grind = 0 +atp_min = 660 +atp_max = 690 +shop_multiplier = 1.0 + +[SirenGlassHammer] +grind = 0 +atp_min = 390 +atp_max = 450 +shop_multiplier = 1.0 + +[GlideDivine] +grind = 0 +atp_min = 185 +atp_max = 400 +shop_multiplier = 1.0 + +[Shichishito] +grind = 0 +atp_min = 500 +atp_max = 560 +shop_multiplier = 1.0 + +[Murasame] +grind = 0 +atp_min = 420 +atp_max = 435 +shop_multiplier = 1.0 + +[DaylightScar] +grind = 25 +atp_min = 500 +atp_max = 550 +shop_multiplier = 1.0 + +[Decalog] +grind = 0 +atp_min = 150 +atp_max = 200 +shop_multiplier = 1.0 + +[TyrellsParasol] +grind = 0 +atp_min = 250 +atp_max = 300 +shop_multiplier = 1.0 + +[AkikosCleaver] +grind = 0 +atp_min = 1 +atp_max = 200 +shop_multiplier = 1.0 + +[Tanegashima] +grind = 0 +atp_min = 320 +atp_max = 410 +shop_multiplier = 1.0 + +[TreeClippers] +grind = 0 +atp_min = 1 +atp_max = 200 +shop_multiplier = 1.0 + +[NiceShot] +grind = 0 +atp_min = 180 +atp_max = 200 +shop_multiplier = 1.0 + +[Unknown3] +grind = 0 +atp_min = 200 +atp_max = 200 +shop_multiplier = 1.0 + +[Unknown4] +grind = 0 +atp_min = 200 +atp_max = 200 +shop_multiplier = 1.0 + +[AnoBazooka] +grind = 15 +atp_min = 350 +atp_max = 370 +shop_multiplier = 1.0 + +[Synthesizer] +grind = 0 +atp_min = 1 +atp_max = 1 +shop_multiplier = 1.0 + +[BambooSpear] +grind = 0 +atp_min = 2 +atp_max = 255 +shop_multiplier = 1.0 + +[KaneiTsuho] +grind = 0 +atp_min = 1 +atp_max = 1 +shop_multiplier = 1.0 + +[Jitte] +grind = 0 +atp_min = 100 +atp_max = 123 +shop_multiplier = 1.0 + +[ButterflyNet] +grind = 0 +atp_min = 1 +atp_max = 1 +shop_multiplier = 1.0 + +[Syringe] +grind = 0 +atp_min = 95 +atp_max = 175 +shop_multiplier = 1.0 + +[Battledore] +grind = 0 +atp_min = 1 +atp_max = 1 +shop_multiplier = 1.0 + +[Racket] +grind = 0 +atp_min = 1 +atp_max = 1 +shop_multiplier = 1.0 + +[Hammer] +grind = 0 +atp_min = 120 +atp_max = 185 +shop_multiplier = 1.0 + +[GreatBouquet] +grind = 0 +atp_min = 1 +atp_max = 1 +shop_multiplier = 1.0 + +[TypesaSaber] +grind = 125 +atp_min = 120 +atp_max = 120 +shop_multiplier = 1.0 + +[TypeslSaber] +grind = 125 +atp_min = 100 +atp_max = 130 +shop_multiplier = 1.0 + +[TypeslSlicer] +grind = 125 +atp_min = 140 +atp_max = 140 +shop_multiplier = 1.0 + +[TypeslClaw] +grind = 125 +atp_min = 100 +atp_max = 150 +shop_multiplier = 1.0 + +[TypeslKatana] +grind = 125 +atp_min = 100 +atp_max = 140 +shop_multiplier = 1.0 + +[TypejsSaber] +grind = 125 +atp_min = 100 +atp_max = 140 +shop_multiplier = 1.0 + +[TypejsSlicer] +grind = 125 +atp_min = 100 +atp_max = 130 +shop_multiplier = 1.0 + +[TypejsJSword] +grind = 125 +atp_min = 130 +atp_max = 130 +shop_multiplier = 1.0 + +[TypeswSword] +grind = 125 +atp_min = 150 +atp_max = 150 +shop_multiplier = 1.0 + +[TypeswSlicer] +grind = 125 +atp_min = 100 +atp_max = 140 +shop_multiplier = 1.0 + +[TypeswJSword] +grind = 125 +atp_min = 100 +atp_max = 150 +shop_multiplier = 1.0 + +[TyperoSword] +grind = 100 +atp_min = 10 +atp_max = 100 +shop_multiplier = 1.0 + +[TyperoHalbert] +grind = 100 +atp_min = 10 +atp_max = 80 +shop_multiplier = 1.0 + +[TyperoRod] +grind = 90 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypeblBlade] +grind = 90 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypeknBlade] +grind = 125 +atp_min = 180 +atp_max = 200 +shop_multiplier = 1.0 + +[TypeknClaw] +grind = 125 +atp_min = 180 +atp_max = 220 +shop_multiplier = 1.0 + +[TypehaHalbert] +grind = 90 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypehaRod] +grind = 80 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypedsDSaber] +grind = 125 +atp_min = 30 +atp_max = 30 +shop_multiplier = 1.0 + +[TypedsRod] +grind = 125 +atp_min = 10 +atp_max = 30 +shop_multiplier = 1.0 + +[Typeds] +grind = 125 +atp_min = 10 +atp_max = 30 +shop_multiplier = 1.0 + +[TypeclClaw] +grind = 125 +atp_min = 170 +atp_max = 170 +shop_multiplier = 1.0 + +[TypessSw] +grind = 125 +atp_min = 150 +atp_max = 150 +shop_multiplier = 1.0 + +[TypeguHand] +grind = 95 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypeguMechgun] +grind = 90 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TyperiRifle] +grind = 100 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypemeMechgun] +grind = 30 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypeshShot] +grind = 60 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 + +[TypewaWand] +grind = 60 +atp_min = 10 +atp_max = 10 +shop_multiplier = 1.0 diff --git a/src/ship/item_stats.rs b/src/ship/item_stats.rs index 998ff70..be39a90 100644 --- a/src/ship/item_stats.rs +++ b/src/ship/item_stats.rs @@ -4,6 +4,7 @@ use serde::{Serialize, Deserialize}; use std::fs::File; use std::io::Read; +use crate::entity::item::weapon::WeaponType; use crate::entity::item::armor::ArmorType; use crate::entity::item::shield::ShieldType; use crate::entity::item::unit::UnitType; @@ -11,6 +12,11 @@ use crate::entity::item::mag::MagType; use crate::entity::item::tool::ToolType; +lazy_static::lazy_static! { + pub static ref WEAPON_STATS: HashMap = weapon_stats(); +} + + fn load_data_file(path: &str) -> T { let mut f = File::open(path).unwrap(); let mut s = String::new(); @@ -20,8 +26,12 @@ fn load_data_file(path: &str) -> T { } -struct WeaponStats { - +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub struct WeaponStats { + pub grind: usize, + pub atp_min: usize, + pub atp_max: usize, + pub shop_multiplier: f32, } #[derive(Debug, Copy, Clone, Serialize, Deserialize)] @@ -86,6 +96,15 @@ pub struct MagFeedTable(HashMap); #[derive(Debug)] pub struct MagFeedTables(Vec); +pub fn weapon_stats() -> HashMap { + let weapon_stats: HashMap = load_data_file("data/item_stats/weapon_stats.toml"); + weapon_stats.iter() + .inspect(|k| println!("{:?}", k)) + .map(|(name, stats)| { + (name.parse().unwrap(), *stats) + }).collect() +} + pub fn armor_stats() -> HashMap { let armor_stats: HashMap = load_data_file("data/item_stats/armor_stats.toml"); armor_stats.iter() @@ -135,6 +154,12 @@ pub fn mag_feed_tables() -> MagFeedTables { mod test { use super::*; + #[test] + fn test_weapon_stats() { + let wstat = weapon_stats(); + assert!(wstat.get(&WeaponType::MadamsUmbrella).unwrap().atp_max == 280); + } + #[test] fn test_armor_stats() { let astat = armor_stats(); From 52d4fe8495143972d65d8f9183c9aff251acc674 Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 23 Sep 2020 19:14:11 -0600 Subject: [PATCH 06/15] weapon shop prices --- src/ship/shops/mod.rs | 4 +++ src/ship/shops/weapon.rs | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs index e8753d1..bfff30d 100644 --- a/src/ship/shops/mod.rs +++ b/src/ship/shops/mod.rs @@ -1,3 +1,7 @@ pub mod weapon; pub mod tool; pub mod armor; + +pub trait ShopItem { + fn price(&self) -> usize; +} diff --git a/src/ship/shops/weapon.rs b/src/ship/shops/weapon.rs index f2aead2..f108e12 100644 --- a/src/ship/shops/weapon.rs +++ b/src/ship/shops/weapon.rs @@ -9,6 +9,8 @@ use rand::seq::{SliceRandom, IteratorRandom}; use crate::entity::character::SectionID; use crate::ship::room::Difficulty; use crate::entity::item::weapon::{WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; +use crate::ship::shops::ShopItem; +use crate::ship::item_stats::WEAPON_STATS; const TIER1_SPECIAL: [WeaponSpecial; 8] = [WeaponSpecial::Draw, WeaponSpecial::Heart, WeaponSpecial::Ice, WeaponSpecial::Bind, @@ -26,6 +28,80 @@ pub struct ShopWeapon { } +fn special_stars(special: &WeaponSpecial) -> usize { + match special { + WeaponSpecial::Draw => 1, + WeaponSpecial::Drain => 2, + WeaponSpecial::Fill => 3, + WeaponSpecial::Gush => 4, + WeaponSpecial::Heart => 1, + WeaponSpecial::Mind => 2, + WeaponSpecial::Soul => 3, + WeaponSpecial::Geist => 4, + WeaponSpecial::Masters => 2, + WeaponSpecial::Lords => 3, + WeaponSpecial::Kings => 4, + WeaponSpecial::Charge => 2, + WeaponSpecial::Spirit => 3, + WeaponSpecial::Berserk => 4, + WeaponSpecial::Ice => 1, + WeaponSpecial::Frost => 2, + WeaponSpecial::Freeze => 3, + WeaponSpecial::Blizzard => 4, + WeaponSpecial::Bind => 1, + WeaponSpecial::Hold => 2, + WeaponSpecial::Seize => 3, + WeaponSpecial::Arrest => 4, + WeaponSpecial::Heat => 1, + WeaponSpecial::Fire => 2, + WeaponSpecial::Flame => 3, + WeaponSpecial::Burning => 4, + WeaponSpecial::Shock => 1, + WeaponSpecial::Thunder => 2, + WeaponSpecial::Storm => 3, + WeaponSpecial::Tempest => 4, + WeaponSpecial::Dim => 1, + WeaponSpecial::Shadow => 2, + WeaponSpecial::Dark => 3, + WeaponSpecial::Hell => 4, + WeaponSpecial::Panic => 1, + WeaponSpecial::Riot => 2, + WeaponSpecial::Havoc => 3, + WeaponSpecial::Chaos => 4, + WeaponSpecial::Devils => 3, + WeaponSpecial::Demons => 4, + } + +} + +impl ShopItem for ShopWeapon { + fn price(&self) -> usize { + WEAPON_STATS.get(&self.weapon) + .map(|weapon_stat| { + let mut price = weapon_stat.atp_max as f32; + price += self.grind as f32; + price = (price * (price * 3.0)) / weapon_stat.shop_multiplier; + + let percent = self.attributes.iter() + .fold(0.0, |acc, attr| { + acc + attr.map(|a| a.value).unwrap_or(0) as f32 + }); + + price = price + ((price / 300.0) * percent); + + let special = self.special.map(|special| { + special_stars(&special) as f32 + }).unwrap_or(0.0); + + price += special * special * 1000.0; + + price as usize + }) + .unwrap_or(0xFFFF) + } +} + + #[derive(Debug, Deserialize)] struct WeaponTableTierEntry { weapon: WeaponType, From 8a9ced09ea0a53ca45159048e2b50a8d0be3ce22 Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 23 Sep 2020 20:54:39 -0600 Subject: [PATCH 07/15] armor shop pricing --- src/ship/item_stats.rs | 3 +++ src/ship/shops/armor.rs | 44 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/ship/item_stats.rs b/src/ship/item_stats.rs index be39a90..953ecce 100644 --- a/src/ship/item_stats.rs +++ b/src/ship/item_stats.rs @@ -14,6 +14,9 @@ use crate::entity::item::tool::ToolType; lazy_static::lazy_static! { pub static ref WEAPON_STATS: HashMap = weapon_stats(); + pub static ref ARMOR_STATS: HashMap = armor_stats(); + pub static ref SHIELD_STATS: HashMap = shield_stats(); + pub static ref UNIT_STATS: BTreeMap = unit_stats(); } diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index 8944350..07e115b 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -11,14 +11,56 @@ use crate::ship::room::Difficulty; use crate::entity::item::armor::ArmorType; use crate::entity::item::shield::ShieldType; use crate::entity::item::unit::UnitType; +use crate::ship::shops::ShopItem; +use crate::ship::item_stats::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; - +#[derive(Debug)] enum ShopArmor { Frame(ArmorType, usize), Barrier(ShieldType), Unit(UnitType), } +const ARMOR_MULTIPLIER: f32 = 0.799999952; +const SHIELD_MULTIPLIER: f32 = 1.5; +const UNIT_MULTIPLIER: f32 = 1000.0; + +impl ShopItem for ShopArmor { + fn price(&self) -> usize { + match self { + ShopArmor::Frame(frame, slot) => { + ARMOR_STATS.get(&frame) + .map(|frame_stats| { + let mut price = (frame_stats.dfp + frame_stats.evp) as f32; + price *= price; + price /= ARMOR_MULTIPLIER; + price += 70.0 * frame_stats.level_req as f32; + price += 70.0 * frame_stats.level_req as f32 * *slot as f32; + price as usize + }) + .unwrap_or(0) + }, + ShopArmor::Barrier(barrier) => { + SHIELD_STATS.get(&barrier) + .map(|barrier_stats| { + let mut price = (barrier_stats.dfp + barrier_stats.evp) as f32; + price *= price; + price /= SHIELD_MULTIPLIER; + price += 70.0 * barrier_stats.level_req as f32; + price as usize + }) + .unwrap_or(0) + }, + ShopArmor::Unit(unit) => { + UNIT_STATS.get(&unit) + .map(|unit_stats| { + (unit_stats.stars as f32 * UNIT_MULTIPLIER) as usize + }) + .unwrap_or(0) + } + } + } +} #[derive(Debug, Deserialize, Clone)] From 1e18d5729b02f26ee211758e544e96972743d977 Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 23 Sep 2020 21:41:15 -0600 Subject: [PATCH 08/15] default to high price rather than zero --- src/ship/shops/armor.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index 07e115b..79dade5 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -38,7 +38,7 @@ impl ShopItem for ShopArmor { price += 70.0 * frame_stats.level_req as f32 * *slot as f32; price as usize }) - .unwrap_or(0) + .unwrap_or(0xFFFF) }, ShopArmor::Barrier(barrier) => { SHIELD_STATS.get(&barrier) @@ -49,14 +49,14 @@ impl ShopItem for ShopArmor { price += 70.0 * barrier_stats.level_req as f32; price as usize }) - .unwrap_or(0) + .unwrap_or(0xFFFF) }, ShopArmor::Unit(unit) => { UNIT_STATS.get(&unit) .map(|unit_stats| { (unit_stats.stars as f32 * UNIT_MULTIPLIER) as usize }) - .unwrap_or(0) + .unwrap_or(0xFFFF) } } } From b94dcb62d0f995f097507d89ea7894090355bbd7 Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 23 Sep 2020 21:49:33 -0600 Subject: [PATCH 09/15] tool shop pricing --- data/item_stats/tech_stats.toml | 56 ++++++++++++++++++++ data/item_stats/tool_stats.toml | 92 +++++++++++++++++++++++++++++++++ src/ship/item_stats.rs | 43 ++++++++++++++- src/ship/shops/tool.rs | 24 +++++++++ 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 data/item_stats/tech_stats.toml create mode 100644 data/item_stats/tool_stats.toml diff --git a/data/item_stats/tech_stats.toml b/data/item_stats/tech_stats.toml new file mode 100644 index 0000000..959a8d5 --- /dev/null +++ b/data/item_stats/tech_stats.toml @@ -0,0 +1,56 @@ +[Foie] +price = 100 + +[Gifoie] +price = 300 + +[Rafoie] +price = 450 + +[Zonde] +price = 100 + +[Gizonde] +price = 300 + +[Razonde] +price = 450 + +[Barta] +price = 100 + +[Gibarta] +price = 300 + +[Rabarta] +price = 450 + +[Grants] +price = 500 + +[Deband] +price = 100 + +[Jellen] +price = 100 + +[Zalure] +price = 100 + +[Shifta] +price = 100 + +[Ryuker] +price = 5000 + +[Resta] +price = 300 + +[Anti] +price = 100 + +[Reverser] +price = 5000 + +[Megid] +price = 500 diff --git a/data/item_stats/tool_stats.toml b/data/item_stats/tool_stats.toml new file mode 100644 index 0000000..1d69fcd --- /dev/null +++ b/data/item_stats/tool_stats.toml @@ -0,0 +1,92 @@ +[Monomate] +price = 50 + +[Dimate] +price = 300 + +[Trimate] +price = 2000 + +[Monofluid] +price = 100 + +[Difluid] +price = 500 + +[Trifluid] +price = 3600 + +[SolAtomizer] +price = 300 + +[MoonAtomizer] +price = 500 + +[StarAtomizer] +price = 5000 + +[Antidote] +price = 60 + +[Antiparalysis] +price = 60 + +[Telepipe] +price = 350 + +[TrapVision] +price = 100 + +[ScapeDoll] +price = 10000 + +[Monogrinder] +price = 5000 + +[Digrinder] +price = 10000 + +[Trigrinder] +price = 15000 + +[PowerMaterial] +price = 2400 + +[MindMaterial] +price = 2400 + +[EvadeMaterial] +price = 2400 + +[HpMaterial] +price = 2400 + +[TpMaterial] +price = 2400 + +[DefMaterial] +price = 2400 + +[LuckMaterial] +price = 2400 + +[PhotonDrop] +price = 8000 + +[PhotonSphere] +price = 16000 + +[PhotonCrystal] +price = 24000 + +[TeamPoints500] +price = 500 + +[TeamPoints1000] +price = 1000 + +[TeamPoints5000] +price = 5000 + +[TeamPoints10000] +price = 10000 diff --git a/src/ship/item_stats.rs b/src/ship/item_stats.rs index 953ecce..c2b72b3 100644 --- a/src/ship/item_stats.rs +++ b/src/ship/item_stats.rs @@ -10,6 +10,7 @@ use crate::entity::item::shield::ShieldType; use crate::entity::item::unit::UnitType; use crate::entity::item::mag::MagType; use crate::entity::item::tool::ToolType; +use crate::entity::item::tech::Technique; lazy_static::lazy_static! { @@ -17,6 +18,8 @@ lazy_static::lazy_static! { pub static ref ARMOR_STATS: HashMap = armor_stats(); pub static ref SHIELD_STATS: HashMap = shield_stats(); pub static ref UNIT_STATS: BTreeMap = unit_stats(); + pub static ref TOOL_STATS: HashMap = tool_stats(); + pub static ref TECH_STATS: HashMap = tech_stats(); } @@ -78,6 +81,17 @@ pub struct UnitStats { pub modifier: u32, } + +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub struct ToolStats { + pub price: usize, +} + +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub struct TechStats { + pub price: usize, +} + #[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub struct MagStats { pub feed_table: u32, @@ -102,7 +116,6 @@ pub struct MagFeedTables(Vec); pub fn weapon_stats() -> HashMap { let weapon_stats: HashMap = load_data_file("data/item_stats/weapon_stats.toml"); weapon_stats.iter() - .inspect(|k| println!("{:?}", k)) .map(|(name, stats)| { (name.parse().unwrap(), *stats) }).collect() @@ -132,6 +145,22 @@ pub fn unit_stats() -> BTreeMap { }).collect() } +pub fn tool_stats() -> HashMap { + let tool_stats: HashMap = load_data_file("data/item_stats/tool_stats.toml"); + tool_stats.iter() + .map(|(name, stats)| { + (name.parse().unwrap(), *stats) + }).collect() +} + +pub fn tech_stats() -> HashMap { + let tech_stats: HashMap = load_data_file("data/item_stats/tech_stats.toml"); + tech_stats.iter() + .map(|(name, stats)| { + (name.parse().unwrap(), *stats) + }).collect() +} + pub fn mag_stats() -> HashMap { let mag_stats: BTreeMap = load_data_file("data/item_stats/mag_stats.toml"); mag_stats.iter() @@ -181,6 +210,18 @@ mod test { assert!(ustat.get(&UnitType::ElfArm).unwrap().stars == 5); } + #[test] + fn test_tool_stats() { + let tstat = tool_stats(); + assert!(tstat.get(&ToolType::Monomate).unwrap().price == 50); + } + + #[test] + fn test_tech_stats() { + let tstat = tech_stats(); + assert!(tstat.get(&Technique::Reverser).unwrap().price == 5000); + } + #[test] fn test_mag_stats() { let mstats = mag_stats(); diff --git a/src/ship/shops/tool.rs b/src/ship/shops/tool.rs index 1b3df5d..dbabc11 100644 --- a/src/ship/shops/tool.rs +++ b/src/ship/shops/tool.rs @@ -10,6 +10,8 @@ use crate::entity::character::SectionID; use crate::ship::room::Difficulty; use crate::entity::item::tool::{Tool, ToolType}; use crate::entity::item::tech::{Technique, TechniqueDisk}; +use crate::ship::shops::ShopItem; +use crate::ship::item_stats::{TOOL_STATS, TECH_STATS}; #[derive(Debug, PartialEq, Eq)] @@ -48,6 +50,28 @@ impl PartialOrd for ShopTool { } } +impl ShopItem for ShopTool { + fn price(&self) -> usize { + match self { + ShopTool::Tool(tool) => { + TOOL_STATS.get(&tool) + .map(|tool_stats| { + tool_stats.price + }) + .unwrap_or(0xFFFF) + }, + ShopTool::Tech(tech) => { + TECH_STATS.get(&tech.tech) + .map(|tech_stats| { + tech_stats.price * tech.level as usize + }) + .unwrap_or(0xFFFF) + } + } + } +} + + #[derive(Debug, Deserialize)] struct ToolTable(Vec); From e387bfafbac8872d13c2f4a45c10a5813eb0055a Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 25 Sep 2020 18:16:08 -0600 Subject: [PATCH 10/15] looks like the shop item list length still exists --- data/shops/tools.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shops/tools.toml b/data/shops/tools.toml index d0731bb..be1cb07 100644 --- a/data/shops/tools.toml +++ b/data/shops/tools.toml @@ -1 +1 @@ -tools = [ "Monomate", "Dimate", "Trimate", "Monofluid", "Difluid", "Trifluid", "Antidote", "Antiparalysis", "SolAtomizer", "MoonAtomizer", "StarAtomizer", "Telepipe",] +tools = [ "Monomate", "Dimate", "Trimate", "Monofluid", "Difluid", "Trifluid", "Antidote", "Antiparalysis", "SolAtomizer", "MoonAtomizer", "Telepipe",] From 32d30d38ec51284a50b1c1c36c7b4f71ccca5c81 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 27 Sep 2020 17:47:21 -0600 Subject: [PATCH 11/15] off by one errors sure are nice the item gets added to the vec before len is calculated, and since its 0-indexed we want to subtract 1 --- src/ship/items/inventory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 89d1c9e..0e5ef61 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -494,7 +494,7 @@ impl CharacterInventory { self.items.push(new_stacked_item); if let Some(InventoryItem::Stacked(new_item)) = self.items.last() { - Some((new_item, InventorySlot(self.count()))) + Some((new_item, InventorySlot(self.count()-1))) } else { None From 64040d55a21a08207f0831d01c370b276e2e16fd Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 27 Sep 2020 18:05:23 -0600 Subject: [PATCH 12/15] and another! --- src/ship/items/inventory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 0e5ef61..e1519e6 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -452,7 +452,7 @@ impl CharacterInventory { })); if let Some(InventoryItem::Individual(new_item)) = self.items.last() { - Some((new_item, InventorySlot(self.count()))) + Some((new_item, InventorySlot(self.count()-1))) } else { None From 7028f911870ea8b9fabbc7ead73368e4d5d4052e Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 27 Sep 2020 18:09:03 -0600 Subject: [PATCH 13/15] latest nightly works again --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4991eb9..a7bb401 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # setup * get http://rustup.rs -* get a specific nightly version `rustup override set nightly-2020-02-27`. for some reason newer versions give internal compiler errors and I'm not sure if it is my fault or the compilers. +* get nightly version `rustup install nightly`. +* set nightly `rustup override set nightly`. * grab elseware * `cargo test` to run tests From d08db622e23d6dda269291586fb9e8601f213b00 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 27 Sep 2020 18:16:27 -0600 Subject: [PATCH 14/15] shops! --- src/entity/item/mod.rs | 3 +- src/ship/items/manager.rs | 107 ++++++ src/ship/packet/builder/message.rs | 23 ++ src/ship/packet/handler/direct_message.rs | 96 ++++- src/ship/room.rs | 2 +- src/ship/ship.rs | 46 ++- src/ship/shops/armor.rs | 71 +++- src/ship/shops/mod.rs | 20 +- src/ship/shops/tool.rs | 74 ++-- src/ship/shops/weapon.rs | 53 ++- tests/common.rs | 7 +- tests/test_shops.rs | 449 ++++++++++++++++++++++ 12 files changed, 894 insertions(+), 57 deletions(-) create mode 100644 tests/test_shops.rs diff --git a/src/entity/item/mod.rs b/src/entity/item/mod.rs index a594d3a..165f207 100644 --- a/src/entity/item/mod.rs +++ b/src/entity/item/mod.rs @@ -46,7 +46,8 @@ pub enum ItemLocation { Consumed, FedToMag { mag: ItemEntityId, - } + }, + Shop, /*Destroyed { // marks an item that has been consumed in some way }, diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 27ab699..4aa5a40 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -10,6 +10,7 @@ use crate::ship::map::MapArea; use crate::ship::ship::ItemDropLocation; use crate::ship::drops::{ItemDrop, ItemDropType}; use crate::ship::location::{AreaClient, RoomId}; +use crate::ship::shops::ShopItem; use crate::ship::items::bank::*; use crate::ship::items::floor::*; @@ -39,6 +40,9 @@ pub enum ItemManagerError { BankFull, WrongItemType(ClientItemId), UseItemError(#[from] use_tool::UseItemError), + CouldNotBuyItem, + CouldNotAddBoughtItemToInventory, + ItemIdNotInInventory(ClientItemId) } pub struct ItemManager { @@ -752,4 +756,107 @@ impl ItemManager { } Ok(()) } + + pub async fn player_buys_item(&mut self, + entity_gateway: &mut EG, + character: &CharacterEntity, + shop_item: &(dyn ShopItem + Send + Sync), + item_id: ClientItemId, + amount: usize) + -> Result<(&InventoryItem), ItemManagerError> { + let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; + + let item_detail = shop_item.as_item(); + let inventory_item = match item_detail { + ItemDetail::Tool(tool) => { + if tool.is_stackable() { + let mut item_entities = Vec::new(); + for _ in 0..amount { + item_entities.push(entity_gateway.create_item(NewItemEntity { + location: ItemLocation::Shop, + item: ItemDetail::Tool(tool), + }).await.ok_or(ItemManagerError::EntityGatewayError)?); + } + let floor_item = StackedFloorItem { + entity_ids: item_entities.into_iter().map(|i| i.id).collect(), + item_id: item_id, + tool: tool, + // TODO: this is gonna choke if I ever require the item being near the player for pickup + map_area: MapArea::Pioneer2Ep1, + x: 0.0, + y: 0.0, + z: 0.0, + }; + let item_id = { + let (picked_up_item, slot) = inventory.pick_up_stacked_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; + for entity_id in &picked_up_item.entity_ids { + entity_gateway.change_item_location(entity_id, + ItemLocation::Inventory { + character_id: character.id, + slot: slot.0, + equipped: false, + }).await;//.ok_or(ItemManagerError::EntityGatewayError)?; + } + picked_up_item.item_id + }; + inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? + } + else { + let item_entity = entity_gateway.create_item(NewItemEntity { + location: ItemLocation::Shop, + item: ItemDetail::Tool(tool), + }).await.ok_or(ItemManagerError::EntityGatewayError)?; + let floor_item = IndividualFloorItem { + entity_id: item_entity.id, + item_id: item_id, + item: ItemDetail::Tool(tool), + // TODO: this is gonna choke if I ever require the item being near the player for pickup + map_area: MapArea::Pioneer2Ep1, + x: 0.0, + y: 0.0, + z: 0.0, + }; + let item_id = { + let (picked_up_item, slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; + entity_gateway.change_item_location(&picked_up_item.entity_id, + ItemLocation::Inventory { + character_id: character.id, + slot: slot.0, + equipped: false, + }).await;//.ok_or(ItemManagerError::EntityGatewayError)?; + picked_up_item.item_id + }; + inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? + } + }, + item_detail @ _ => { + let item_entity = entity_gateway.create_item(NewItemEntity { + location: ItemLocation::Shop, + item: item_detail.clone(), + }).await.ok_or(ItemManagerError::EntityGatewayError)?; + let floor_item = IndividualFloorItem { + entity_id: item_entity.id, + item_id: item_id, + item: item_detail, + // TODO: this is gonna choke if I ever require the item being near the player for pickup + map_area: MapArea::Pioneer2Ep1, + x: 0.0, + y: 0.0, + z: 0.0, + }; + let item_id = { + let (picked_up_item, slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; + entity_gateway.change_item_location(&picked_up_item.entity_id, + ItemLocation::Inventory { + character_id: character.id, + slot: slot.0, + equipped: false, + }).await;//.ok_or(ItemManagerError::EntityGatewayError)?; + picked_up_item.item_id + }; + inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? + }, + }; + Ok(inventory_item) + } } diff --git a/src/ship/packet/builder/message.rs b/src/ship/packet/builder/message.rs index 69ad26c..d7bfe75 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/ship/packet/builder/message.rs @@ -5,6 +5,7 @@ use crate::ship::ship::{ShipError}; use crate::ship::items::{ClientItemId, InventoryItem, StackedFloorItem, FloorItem, CharacterBank}; use crate::ship::location::AreaClient; use std::convert::TryInto; +use crate::ship::shops::ShopItem; pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result { @@ -139,3 +140,25 @@ pub fn player_no_longer_has_item(area_client: AreaClient, item_id: ClientItemId, amount: amount, } } + +pub fn shop_list(shop_type: u8, items: &Vec) -> ShopList { + let items = items.into_iter() + .enumerate() + .map(|(i, item)| { + ShopListItem { + item_bytes: item.as_bytes(), + unknown: i as u32 + 23, + price: item.price() as u32, + } + }) + .collect(); + + ShopList { + client: 0, + target: 0, + shop_type: shop_type, + num_items: 0, + unused: 0, + items: items, + } +} diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 18edad8..8c2dd21 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -1,17 +1,24 @@ use log::warn; use libpso::packet::ship::*; use libpso::packet::messages::*; +use crate::common::leveltable::CharacterLevelTable; use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms}; +use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops}; use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::drops::ItemDrop; use crate::ship::items::{ItemManager, ClientItemId, TriggerCreateItem, FloorItem}; use crate::entity::gateway::EntityGateway; use libpso::utf8_to_utf16_array; use crate::ship::packet::builder; +use crate::ship::shops::ShopItem; const BANK_ACTION_DEPOSIT: u8 = 0; const BANK_ACTION_WITHDRAW: u8 = 1; + +const SHOP_OPTION_TOOL: u8 = 0; +const SHOP_OPTION_WEAPON: u8 = 1; +const SHOP_OPTION_ARMOR: u8 = 2; + //const BANK_ACTION_: u8 = 1; fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation) @@ -269,3 +276,90 @@ where .flatten() )) } + +pub async fn shop_request(id: ClientId, + shop_request: &ShopRequest, + client_location: &ClientLocation, + clients: &mut Clients, + rooms: &Rooms, + level_table: &CharacterLevelTable, + shops: &mut ItemShops) + -> Result + Send>, ShipError> +{ + let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get(room_id.0) + .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? + .as_ref() + .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?; + let level = level_table.get_level_from_exp(client.character.char_class, client.character.exp) as usize; + let shop_list = match shop_request.shop_type { + SHOP_OPTION_WEAPON => { + client.weapon_shop = shops.weapon_shop.get_mut(&(room.mode.difficulty(), client.character.section_id)) + .ok_or(ShipError::ShopError)? + .generate_weapon_list(level); + builder::message::shop_list(shop_request.shop_type, &client.weapon_shop) + }, + SHOP_OPTION_TOOL => { + client.tool_shop = shops.tool_shop.generate_tool_list(level); + builder::message::shop_list(shop_request.shop_type, &client.tool_shop) + }, + SHOP_OPTION_ARMOR => { + client.armor_shop = shops.armor_shop.generate_armor_list(level); + builder::message::shop_list(shop_request.shop_type, &client.armor_shop) + }, + _ => { + return Err(ShipError::ShopError) + } + }; + + Ok(Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::ShopList(shop_list))))].into_iter())) +} + + +pub async fn buy_item(id: ClientId, + buy_item: &BuyItem, + entity_gateway: &mut EG, + client_location: &ClientLocation, + clients: &mut Clients, + item_manager: &mut ItemManager) + -> Result + Send>, ShipError> +where + EG: EntityGateway +{ + let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + + let item: &(dyn ShopItem + Send + Sync) = match buy_item.shop_type { + SHOP_OPTION_WEAPON => { + client.weapon_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)? + }, + SHOP_OPTION_TOOL => { + client.tool_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)? + }, + SHOP_OPTION_ARMOR => { + client.armor_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)? + }, + _ => { + return Err(ShipError::ShopError) + } + }; + + if client.character.meseta < item.price() as u32{ + return Err(ShipError::ShopError) + } + + client.character.meseta -= item.price() as u32; + entity_gateway.save_character(&client.character).await; + + let inventory_item = item_manager.player_buys_item(entity_gateway, &client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as usize).await?; + + let create = builder::message::create_withdrawn_inventory_item(area_client, inventory_item)?; + + let other_clients_in_area = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?; + Ok(Box::new(other_clients_in_area.into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create.clone())))) + }))) + +} diff --git a/src/ship/room.rs b/src/ship/room.rs index 7ab224f..c2d1c8a 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -60,7 +60,7 @@ impl Episode { } } -#[derive(Debug, Copy, Clone, derive_more::Display)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] pub enum Difficulty { Normal, Hard, diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 643d662..e654bc3 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -20,7 +20,7 @@ use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, Lo use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; -use crate::entity::character::CharacterEntity; +use crate::entity::character::{CharacterEntity, SectionID}; use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError}; @@ -29,6 +29,7 @@ use crate::ship::room; use crate::ship::quests; use crate::ship::map::{MapsError, MapAreaError, MapArea}; use crate::ship::packet::handler; +use crate::ship::shops::{ShopType, WeaponShop, ToolShop, ArmorShop, WeaponShopItem, ToolShopItem, ArmorShopItem}; pub const SHIP_PORT: u16 = 23423; pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; @@ -60,6 +61,7 @@ pub enum ShipError { InvalidQuestFilename(String), IoError(#[from] std::io::Error), NotEnoughMeseta(ClientId, u32), + ShopError, } #[derive(Debug)] @@ -228,6 +230,9 @@ pub struct ClientState { pub x: f32, pub y: f32, pub z: f32, + pub weapon_shop: Vec, + pub tool_shop: Vec, + pub armor_shop: Vec, } impl ClientState { @@ -244,10 +249,41 @@ impl ClientState { x: 0.0, y: 0.0, z: 0.0, + weapon_shop: Vec::new(), + tool_shop: Vec::new(), + armor_shop: Vec::new(), } } } +pub struct ItemShops { + pub weapon_shop: HashMap<(room::Difficulty, SectionID), WeaponShop>, + pub tool_shop: ToolShop, + pub armor_shop: ArmorShop, +} + +impl ItemShops { + pub fn new() -> ItemShops { + let difficulty = [room::Difficulty::Normal, room::Difficulty::Hard, room::Difficulty::VeryHard, room::Difficulty::Ultimate]; + let section_id = [SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum, + SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill]; + + let mut weapon_shop = HashMap::new(); + for d in difficulty.iter() { + for id in section_id.iter() { + weapon_shop.insert((*d, *id), WeaponShop::new(*d, *id)); + } + } + + ItemShops { + weapon_shop: weapon_shop, + tool_shop: ToolShop::new(), + armor_shop: ArmorShop::new(), + } + } +} + + pub struct ShipServerStateBuilder { entity_gateway: Option, name: Option, @@ -297,6 +333,7 @@ impl ShipServerStateBuilder { quests: quests::load_quests("data/quests.toml".into()).unwrap(), ip: self.ip.unwrap_or(Ipv4Addr::new(127,0,0,1)), port: self.port.unwrap_or(SHIP_PORT), + shops: Box::new(ItemShops::new()), } } } @@ -312,6 +349,7 @@ pub struct ShipServerState { quests: quests::QuestList, ip: Ipv4Addr, port: u16, + shops: Box, } impl ShipServerState { @@ -382,6 +420,12 @@ impl ShipServerState { GameMessage::BankInteraction(bank_interaction) => { handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.item_manager).await }, + GameMessage::ShopRequest(shop_request) => { + handler::direct_message::shop_request(id, shop_request, &self.client_location, &mut self.clients, &self.rooms, &self.level_table, &mut self.shops).await + }, + GameMessage::BuyItem(buy_item) => { + handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.item_manager).await + }, _ => { let cmsg = msg.clone(); Ok(Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter() diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index 79dade5..657b732 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -2,20 +2,22 @@ use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::path::PathBuf; +use std::convert::TryInto; use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; use rand::seq::{SliceRandom, IteratorRandom}; use crate::entity::character::SectionID; use crate::ship::room::Difficulty; -use crate::entity::item::armor::ArmorType; -use crate::entity::item::shield::ShieldType; -use crate::entity::item::unit::UnitType; +use crate::entity::item::ItemDetail; +use crate::entity::item::armor::{Armor, ArmorType}; +use crate::entity::item::shield::{Shield, ShieldType}; +use crate::entity::item::unit::{Unit, UnitType}; use crate::ship::shops::ShopItem; use crate::ship::item_stats::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; #[derive(Debug)] -enum ShopArmor { +pub enum ArmorShopItem { Frame(ArmorType, usize), Barrier(ShieldType), Unit(UnitType), @@ -25,10 +27,10 @@ const ARMOR_MULTIPLIER: f32 = 0.799999952; const SHIELD_MULTIPLIER: f32 = 1.5; const UNIT_MULTIPLIER: f32 = 1000.0; -impl ShopItem for ShopArmor { +impl ShopItem for ArmorShopItem { fn price(&self) -> usize { match self { - ShopArmor::Frame(frame, slot) => { + ArmorShopItem::Frame(frame, slot) => { ARMOR_STATS.get(&frame) .map(|frame_stats| { let mut price = (frame_stats.dfp + frame_stats.evp) as f32; @@ -40,7 +42,7 @@ impl ShopItem for ShopArmor { }) .unwrap_or(0xFFFF) }, - ShopArmor::Barrier(barrier) => { + ArmorShopItem::Barrier(barrier) => { SHIELD_STATS.get(&barrier) .map(|barrier_stats| { let mut price = (barrier_stats.dfp + barrier_stats.evp) as f32; @@ -51,7 +53,7 @@ impl ShopItem for ShopArmor { }) .unwrap_or(0xFFFF) }, - ShopArmor::Unit(unit) => { + ArmorShopItem::Unit(unit) => { UNIT_STATS.get(&unit) .map(|unit_stats| { (unit_stats.stars as f32 * UNIT_MULTIPLIER) as usize @@ -60,6 +62,37 @@ impl ShopItem for ShopArmor { } } } + + fn as_bytes(&self) -> [u8; 12] { + self.as_item().as_client_bytes()[0..12].try_into().unwrap() + } + + fn as_item(&self) -> ItemDetail { + match self { + ArmorShopItem::Frame(frame, slot) => { + ItemDetail::Armor(Armor { + armor: *frame, + dfp: 0, + evp: 0, + slots: *slot as u8, + modifiers: Vec::new() + }) + }, + ArmorShopItem::Barrier(barrier) => { + ItemDetail::Shield(Shield { + shield: *barrier, + dfp: 0, + evp: 0, + }) + }, + ArmorShopItem::Unit(unit) => { + ItemDetail::Unit(Unit { + unit: *unit, + modifier: None, + }) + }, + } + } } @@ -201,7 +234,7 @@ fn number_of_units_to_generate(character_level: usize) -> usize { } #[derive(Debug)] -struct ArmorShop { +pub struct ArmorShop { frame: FrameTable, barrier: BarrierTable, unit: UnitTable, @@ -218,7 +251,7 @@ impl ArmorShop { } } - fn generate_frame_list(&mut self, character_level: usize) -> Vec { + fn generate_frame_list(&mut self, character_level: usize) -> Vec { let tier = self.frame.frame.iter() .filter(|t| t.level <= character_level) .last() @@ -231,13 +264,13 @@ impl ArmorShop { .map(|_| { let frame_detail = tier.item.get(frame_choice.sample(&mut self.rng)).unwrap(); let slot = self.frame.slot_rate.get(slot_choice.sample(&mut self.rng)).unwrap(); - - ShopArmor::Frame(frame_detail.item, slot.slot) + + ArmorShopItem::Frame(frame_detail.item, slot.slot) }) .collect() } - fn generate_barrier_list(&mut self, character_level: usize) -> Vec { + fn generate_barrier_list(&mut self, character_level: usize) -> Vec { let tier = self.barrier.barrier.iter() .filter(|t| t.level <= character_level) .last() @@ -248,13 +281,13 @@ impl ArmorShop { (0..number_of_barriers_to_generate(character_level)) .map(|_| { let barrier_detail = tier.item.get(barrier_choice.sample(&mut self.rng)).unwrap(); - - ShopArmor::Barrier(barrier_detail.item) + + ArmorShopItem::Barrier(barrier_detail.item) }) .collect() } - fn generate_unit_list(&mut self, character_level: usize) -> Vec { + fn generate_unit_list(&mut self, character_level: usize) -> Vec { self.unit.unit.iter() .filter(|t| t.level <= character_level) .last() @@ -264,15 +297,15 @@ impl ArmorShop { (0..number_of_units_to_generate(character_level)) .map(|_| { let unit_detail = tier.item.get(unit_choice.sample(&mut self.rng)).unwrap(); - - ShopArmor::Unit(unit_detail.item) + + ArmorShopItem::Unit(unit_detail.item) }) .collect() }) .unwrap_or(Vec::new()) } - pub fn generate_armor_list(&mut self, character_level: usize) -> Vec { + pub fn generate_armor_list(&mut self, character_level: usize) -> Vec { self.generate_frame_list(character_level).into_iter() .chain(self.generate_barrier_list(character_level).into_iter()) .chain(self.generate_unit_list(character_level).into_iter()) diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs index bfff30d..573b667 100644 --- a/src/ship/shops/mod.rs +++ b/src/ship/shops/mod.rs @@ -1,7 +1,21 @@ -pub mod weapon; -pub mod tool; -pub mod armor; +mod weapon; +mod tool; +mod armor; + +use crate::entity::item::ItemDetail; pub trait ShopItem { fn price(&self) -> usize; + fn as_bytes(&self) -> [u8; 12]; + fn as_item(&self) -> ItemDetail; +} + +pub enum ShopType { + Weapon, + Tool, + Armor } + +pub use weapon::{WeaponShop, WeaponShopItem}; +pub use tool::{ToolShop, ToolShopItem}; +pub use armor::{ArmorShop, ArmorShopItem}; diff --git a/src/ship/shops/tool.rs b/src/ship/shops/tool.rs index dbabc11..c3ecaa9 100644 --- a/src/ship/shops/tool.rs +++ b/src/ship/shops/tool.rs @@ -2,12 +2,14 @@ use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::path::PathBuf; +use std::convert::TryInto; use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; use rand::seq::{SliceRandom, IteratorRandom}; use crate::entity::character::SectionID; use crate::ship::room::Difficulty; +use crate::entity::item::ItemDetail; use crate::entity::item::tool::{Tool, ToolType}; use crate::entity::item::tech::{Technique, TechniqueDisk}; use crate::ship::shops::ShopItem; @@ -15,52 +17,52 @@ use crate::ship::item_stats::{TOOL_STATS, TECH_STATS}; #[derive(Debug, PartialEq, Eq)] -pub enum ShopTool { +pub enum ToolShopItem { Tool(ToolType), Tech(TechniqueDisk), } -impl Ord for ShopTool { - fn cmp(&self, other: &ShopTool) -> std::cmp::Ordering { +impl Ord for ToolShopItem { + fn cmp(&self, other: &ToolShopItem) -> std::cmp::Ordering { let a = match self { - ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ShopTool::Tech(t) => t.as_bytes(), + ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ToolShopItem::Tech(t) => t.as_bytes(), }; let b = match other { - ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ShopTool::Tech(t) => t.as_bytes(), + ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ToolShopItem::Tech(t) => t.as_bytes(), }; a.cmp(&b) } } -impl PartialOrd for ShopTool { - fn partial_cmp(&self, other: &ShopTool) -> Option { +impl PartialOrd for ToolShopItem { + fn partial_cmp(&self, other: &ToolShopItem) -> Option { let a = match self { - ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ShopTool::Tech(t) => t.as_bytes(), + ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ToolShopItem::Tech(t) => t.as_bytes(), }; let b = match other { - ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ShopTool::Tech(t) => t.as_bytes(), + ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), + ToolShopItem::Tech(t) => t.as_bytes(), }; a.partial_cmp(&b) } } -impl ShopItem for ShopTool { +impl ShopItem for ToolShopItem { fn price(&self) -> usize { match self { - ShopTool::Tool(tool) => { + ToolShopItem::Tool(tool) => { TOOL_STATS.get(&tool) .map(|tool_stats| { tool_stats.price }) .unwrap_or(0xFFFF) }, - ShopTool::Tech(tech) => { + ToolShopItem::Tech(tech) => { TECH_STATS.get(&tech.tech) .map(|tech_stats| { tech_stats.price * tech.level as usize @@ -69,6 +71,32 @@ impl ShopItem for ShopTool { } } } + + fn as_bytes(&self) -> [u8; 12] { + match self { + ToolShopItem::Tool(tool) => { + Tool { + tool: *tool + }.as_individual_bytes()[0..12].try_into().unwrap() + }, + ToolShopItem::Tech(tech) => { + tech.as_bytes()[0..12].try_into().unwrap() + }, + } + } + + fn as_item(&self) -> ItemDetail { + match self { + ToolShopItem::Tool(tool) => { + ItemDetail::Tool(Tool { + tool: *tool + }) + }, + ToolShopItem::Tech(tech) => { + ItemDetail::TechniqueDisk(*tech) + }, + } + } } @@ -163,7 +191,7 @@ fn number_of_techs_to_generate(character_level: usize) -> usize { #[derive(Debug)] -struct ToolShop { +pub struct ToolShop { tools: ToolTable, techs: TechTable, rng: R, @@ -178,7 +206,7 @@ impl ToolShop { } } - fn generate_tech(&mut self, character_level: usize) -> ShopTool { + fn generate_tech(&mut self, character_level: usize) -> ToolShopItem { let tier = self.techs.0.iter() .filter(|t| t.level <= character_level) .last() @@ -198,7 +226,7 @@ impl ToolShop { TechLevel::Range{min, max} => self.rng.gen_range(min, max+1), }; - ShopTool::Tech( + ToolShopItem::Tech( TechniqueDisk { tech: *tech_detail.0, level: tech_level as u32, @@ -245,7 +273,7 @@ impl ToolShop { } - fn generate_techs(&mut self, character_level: usize) -> Vec { + fn generate_techs(&mut self, character_level: usize) -> Vec { let tier = self.techs.0.iter() .filter(|t| t.level <= character_level) .last() @@ -262,7 +290,7 @@ impl ToolShop { TechLevel::Range{min, max} => self.rng.gen_range(min, max+1), }; - ShopTool::Tech(TechniqueDisk { + ToolShopItem::Tech(TechniqueDisk { tech: tech, level: level as u32, }) @@ -270,9 +298,9 @@ impl ToolShop { .collect() } - pub fn generate_tool_list(&mut self, character_level: usize) -> Vec { + pub fn generate_tool_list(&mut self, character_level: usize) -> Vec { let mut tools = Vec::new().into_iter() - .chain(self.tools.0.clone().into_iter().map(|t| ShopTool::Tool(t))) + .chain(self.tools.0.clone().into_iter().map(|t| ToolShopItem::Tool(t))) .chain(self.generate_techs(character_level).into_iter()) .collect::>(); tools.sort(); diff --git a/src/ship/shops/weapon.rs b/src/ship/shops/weapon.rs index f108e12..877ce52 100644 --- a/src/ship/shops/weapon.rs +++ b/src/ship/shops/weapon.rs @@ -2,13 +2,15 @@ use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::path::PathBuf; +use std::convert::TryInto; use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; use rand::seq::{SliceRandom, IteratorRandom}; use crate::entity::character::SectionID; use crate::ship::room::Difficulty; -use crate::entity::item::weapon::{WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; +use crate::entity::item::ItemDetail; +use crate::entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; use crate::ship::shops::ShopItem; use crate::ship::item_stats::WEAPON_STATS; @@ -20,7 +22,7 @@ const TIER2_SPECIAL: [WeaponSpecial; 10] = [WeaponSpecial::Drain, WeaponSpecial: WeaponSpecial::Hold, WeaponSpecial::Fire, WeaponSpecial::Thunder, WeaponSpecial::Shadow, WeaponSpecial::Riot]; #[derive(Debug)] -pub struct ShopWeapon { +pub struct WeaponShopItem { weapon: WeaponType, special: Option, grind: usize, @@ -74,7 +76,7 @@ fn special_stars(special: &WeaponSpecial) -> usize { } -impl ShopItem for ShopWeapon { +impl ShopItem for WeaponShopItem { fn price(&self) -> usize { WEAPON_STATS.get(&self.weapon) .map(|weapon_stat| { @@ -99,6 +101,23 @@ impl ShopItem for ShopWeapon { }) .unwrap_or(0xFFFF) } + + fn as_bytes(&self) -> [u8; 12] { + self.as_item().as_client_bytes()[0..12].try_into().unwrap() + } + + fn as_item(&self) -> ItemDetail { + ItemDetail::Weapon( + Weapon { + weapon: self.weapon, + special: self.special, + grind: self.grind as u8, + attrs: [self.attributes[0], self.attributes[1], None], + tekked: true, + modifiers: Vec::new(), + } + ) + } } @@ -259,8 +278,20 @@ fn load_attribute2_table() -> AttributeTable { AttributeTable(table.remove("attributes".into()).unwrap()) } +fn number_of_weapons_to_generate(character_level: usize) -> usize { + if character_level <= 10 { + 10 + } + else if character_level <= 42 { + 12 + } + else { + 16 + } +} + #[derive(Debug)] -struct WeaponShop { +pub struct WeaponShop { difficulty: Difficulty, section_id: SectionID, weapon: WeaponTable, @@ -429,7 +460,7 @@ impl WeaponShop { } } - pub fn generate_weapon(&mut self, level: usize) -> ShopWeapon { + fn generate_weapon(&mut self, level: usize) -> WeaponShopItem { let weapon = self.generate_type(level); let grind = if self.is_alt_grind(&weapon) { self.generate_alt_grind(level) @@ -460,13 +491,21 @@ impl WeaponShop { } }; - ShopWeapon { + WeaponShopItem { weapon: weapon, grind: grind, special: special, attributes: [attr1, attr2], } } + + pub fn generate_weapon_list(&mut self, level: usize) -> Vec { + (0..number_of_weapons_to_generate(level)) + .map(|_| { + self.generate_weapon(level) + }) + .collect() + } } #[cfg(test)] @@ -481,7 +520,7 @@ mod test { fn test_generating_some_weapons() { let mut ws = WeaponShop::::new(Difficulty::Ultimate, SectionID::Pinkal); for i in 0..200 { - ws.generate_weapon(i); + ws.generate_weapon_list(i); } } } diff --git a/tests/common.rs b/tests/common.rs index 693f1f8..bce80d7 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -6,6 +6,7 @@ use elseware::entity::gateway::EntityGateway; use elseware::entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; use elseware::entity::character::{CharacterEntity, NewCharacterEntity}; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::ship::room::Difficulty; use libpso::packet::ship::*; use libpso::packet::login::{Login, Session}; @@ -58,11 +59,15 @@ pub async fn join_lobby(ship: &mut ShipServerState, id: C } pub async fn create_room(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str) { + create_room_with_difficulty(ship, id, name, password, Difficulty::Normal).await; +} + +pub async fn create_room_with_difficulty(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str, difficulty: Difficulty) { ship.handle(id, &RecvShipPacket::CreateRoom(CreateRoom { unknown: [0; 2], name: utf8_to_utf16_array!(name, 16), password: utf8_to_utf16_array!(password, 16), - difficulty: 0, + difficulty: difficulty.into(), battle: 0, challenge: 0, episode: 1, diff --git a/tests/test_shops.rs b/tests/test_shops.rs new file mode 100644 index 0000000..4044607 --- /dev/null +++ b/tests/test_shops.rs @@ -0,0 +1,449 @@ +use elseware::common::serverstate::{ClientId, ServerState}; +use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use elseware::entity::item; +use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use elseware::ship::room::Difficulty; + +use libpso::packet::ship::*; +use libpso::packet::messages::*; + +#[path = "common.rs"] +mod common; +use common::*; + +#[async_std::test] +async fn test_player_opens_weapon_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 1 + })))).await.unwrap().collect::>(); + + assert_eq!(packets.len(), 1); + match &packets[0].1 { + SendShipPacket::Message(Message {msg: GameMessage::ShopList(shop_list)}) => { + assert_eq!(shop_list.items.len(), 16) + } + _ => panic!("") + } +} + +#[async_std::test] +async fn test_player_opens_tool_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 0 + })))).await.unwrap().collect::>(); + + assert_eq!(packets.len(), 1); + match &packets[0].1 { + SendShipPacket::Message(Message {msg: GameMessage::ShopList(shop_list)}) => { + assert_eq!(shop_list.items.len(), 18) + } + _ => panic!("") + } +} + +#[async_std::test] +async fn test_player_opens_armor_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 2 + })))).await.unwrap().collect::>(); + + assert_eq!(packets.len(), 1); + match &packets[0].1 { + SendShipPacket::Message(Message {msg: GameMessage::ShopList(shop_list)}) => { + assert_eq!(shop_list.items.len(), 21) + } + _ => panic!("") + } +} + +#[async_std::test] +async fn test_player_buys_from_weapon_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 1 + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 1, + shop_index: 0, + amount: 1, + unknown1: 0, + })))).await.unwrap().for_each(drop); + + let characters1 = entity_gateway.get_characters_by_user(&user1).await; + let c1 = characters1.get(0).as_ref().unwrap().as_ref().unwrap(); + assert!(c1.meseta < 999999); + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert_eq!(p1_items.len(), 1); +} + +#[async_std::test] +async fn test_player_buys_from_tool_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 0, + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 0, + shop_index: 0, + amount: 1, + unknown1: 0, + })))).await.unwrap().for_each(drop); + + let characters1 = entity_gateway.get_characters_by_user(&user1).await; + let c1 = characters1.get(0).as_ref().unwrap().as_ref().unwrap(); + assert!(c1.meseta < 999999); + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert_eq!(p1_items.len(), 1); +} + +#[async_std::test] +async fn test_player_buys_multiple_from_tool_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 0, + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 0, + shop_index: 0, + amount: 5, + unknown1: 0, + })))).await.unwrap().for_each(drop); + + let characters1 = entity_gateway.get_characters_by_user(&user1).await; + let c1 = characters1.get(0).as_ref().unwrap().as_ref().unwrap(); + assert!(c1.meseta < 999999); + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert_eq!(p1_items.len(), 5); +} + +#[async_std::test] +async fn test_player_buys_from_armor_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 2 + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 2, + shop_index: 0, + amount: 1, + unknown1: 0, + })))).await.unwrap().for_each(drop); + + let characters1 = entity_gateway.get_characters_by_user(&user1).await; + let c1 = characters1.get(0).as_ref().unwrap().as_ref().unwrap(); + assert!(c1.meseta < 999999); + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert_eq!(p1_items.len(), 1); +} + +#[async_std::test] +async fn test_player_sells_to_shop() { +} + +#[async_std::test] +async fn test_other_clients_see_purchase() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + log_in_char(&mut ship, ClientId(2), "a2", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + join_lobby(&mut ship, ClientId(2)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + join_room(&mut ship, ClientId(2), 0).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 1 + })))).await.unwrap().for_each(drop); + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 1, + shop_index: 0, + amount: 1, + unknown1: 0, + })))).await.unwrap().collect::>(); + + assert_eq!(packets.len(), 1); + assert_eq!(packets[0].0, ClientId(2)); + match &packets[0].1 { + SendShipPacket::Message(Message{msg: GameMessage::CreateItem(_)}) => {}, + _ => panic!(""), + } +} + +#[async_std::test] +async fn test_other_clients_see_stacked_purchase() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Tool( + item::tool::Tool { + tool: item::tool::ToolType::Monomate + } + ), + location: item::ItemLocation::Inventory { + character_id: char1.id, + slot: 0, + equipped: false, + } + }).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + log_in_char(&mut ship, ClientId(2), "a2", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + join_lobby(&mut ship, ClientId(2)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + join_room(&mut ship, ClientId(2), 0).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 1 + })))).await.unwrap().for_each(drop); + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 1, + shop_index: 0, + amount: 1, + unknown1: 0, + })))).await.unwrap().collect::>(); + + assert_eq!(packets.len(), 1); + assert_eq!(packets[0].0, ClientId(2)); + match &packets[0].1 { + SendShipPacket::Message(Message{msg: GameMessage::CreateItem(_)}) => {}, + _ => panic!(""), + } +} + +#[async_std::test] +async fn test_buying_item_without_enough_mseseta() { + let mut entity_gateway = InMemoryGateway::new(); + + let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 1 + })))).await.unwrap().for_each(drop); + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 1, + shop_index: 0, + amount: 1, + unknown1: 0, + })))).await; + + assert!(packets.is_err()); + let characters1 = entity_gateway.get_characters_by_user(&user1).await; + let c1 = characters1.get(0).as_ref().unwrap().as_ref().unwrap(); + assert_eq!(c1.meseta, 0); + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert_eq!(p1_items.len(), 0); +} + +#[async_std::test] +async fn test_player_double_buys_from_tool_shop() { + let mut entity_gateway = InMemoryGateway::new(); + + let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 0, + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 0, + shop_index: 0, + amount: 3, + unknown1: 0, + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10001, + shop_type: 0, + shop_index: 1, + amount: 2, + unknown1: 0, + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10002, + shop_type: 0, + shop_index: 0, + amount: 4, + unknown1: 0, + })))).await.unwrap().for_each(drop); + + let characters1 = entity_gateway.get_characters_by_user(&user1).await; + let c1 = characters1.get(0).as_ref().unwrap().as_ref().unwrap(); + assert!(c1.meseta < 999999); + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert_eq!(p1_items.len(), 10); +} From cebb6a5f31ee3c388959c0cb7e5ec0e058c16ff4 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 27 Sep 2020 20:30:37 -0600 Subject: [PATCH 15/15] handle case where items are removed from shop after buying --- src/ship/items/manager.rs | 2 +- src/ship/packet/handler/direct_message.rs | 36 +++++-- tests/test_shops.rs | 119 +++++++++++++++++++++- 3 files changed, 147 insertions(+), 10 deletions(-) diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 4aa5a40..ace390b 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -763,7 +763,7 @@ impl ItemManager { shop_item: &(dyn ShopItem + Send + Sync), item_id: ClientItemId, amount: usize) - -> Result<(&InventoryItem), ItemManagerError> { + -> Result<&InventoryItem, ItemManagerError> { let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let item_detail = shop_item.as_item(); diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 8c2dd21..5ed7751 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -10,7 +10,7 @@ use crate::ship::items::{ItemManager, ClientItemId, TriggerCreateItem, FloorItem use crate::entity::gateway::EntityGateway; use libpso::utf8_to_utf16_array; use crate::ship::packet::builder; -use crate::ship::shops::ShopItem; +use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem}; const BANK_ACTION_DEPOSIT: u8 = 0; const BANK_ACTION_WITHDRAW: u8 = 1; @@ -330,22 +330,33 @@ where let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let item: &(dyn ShopItem + Send + Sync) = match buy_item.shop_type { + + let (item, remove): (&(dyn ShopItem + Send + Sync), bool) = match buy_item.shop_type { SHOP_OPTION_WEAPON => { - client.weapon_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)? + (client.weapon_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?, false) }, SHOP_OPTION_TOOL => { - client.tool_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)? + let item = client.tool_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; + let remove = match item { + ToolShopItem::Tech(_) => true, + _ => false, + }; + (item, remove) }, SHOP_OPTION_ARMOR => { - client.armor_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)? + let item = client.armor_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; + let remove = match item { + ArmorShopItem::Unit(_) => true, + _ => false, + }; + (item, remove) }, _ => { return Err(ShipError::ShopError) } }; - if client.character.meseta < item.price() as u32{ + if client.character.meseta < item.price() as u32 { return Err(ShipError::ShopError) } @@ -353,9 +364,20 @@ where entity_gateway.save_character(&client.character).await; let inventory_item = item_manager.player_buys_item(entity_gateway, &client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as usize).await?; - let create = builder::message::create_withdrawn_inventory_item(area_client, inventory_item)?; + if remove { + match buy_item.shop_type { + SHOP_OPTION_TOOL => { + client.tool_shop.remove(buy_item.shop_index as usize); + }, + SHOP_OPTION_ARMOR => { + client.armor_shop.remove(buy_item.shop_index as usize); + }, + _ => {} + } + } + let other_clients_in_area = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?; Ok(Box::new(other_clients_in_area.into_iter() .map(move |c| { diff --git a/tests/test_shops.rs b/tests/test_shops.rs index 4044607..f1c292c 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -360,7 +360,7 @@ async fn test_other_clients_see_stacked_purchase() { async fn test_buying_item_without_enough_mseseta() { let mut entity_gateway = InMemoryGateway::new(); - let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut ship = ShipServerState::builder() .gateway(entity_gateway.clone()) @@ -445,5 +445,120 @@ async fn test_player_double_buys_from_tool_shop() { let c1 = characters1.get(0).as_ref().unwrap().as_ref().unwrap(); assert!(c1.meseta < 999999); let p1_items = entity_gateway.get_items_by_character(&char1).await; - assert_eq!(p1_items.len(), 10); + assert_eq!(p1_items.len(), 9); +} + + +#[async_std::test] +async fn test_techs_disappear_from_shop_when_bought() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 0, + })))).await.unwrap().collect::>(); + + let first_tech = match &packets[0].1 { + SendShipPacket::Message(Message {msg: GameMessage::ShopList(shop_list)}) => { + shop_list.items.iter() + .enumerate() + .filter(|(_, item)| { + item.item_bytes[0] == 3 && item.item_bytes[1] == 2 + }) + .nth(0).unwrap().0 + }, + _ => panic!(""), + }; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 0, + shop_index: first_tech as u8, + amount: 1, + unknown1: 0, + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10001, + shop_type: 0, + shop_index: first_tech as u8, + amount: 1, + unknown1: 0, + })))).await.unwrap().for_each(drop); + + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert!(p1_items[0].item != p1_items[1].item); +} + +#[async_std::test] +async fn test_units_disappear_from_shop_when_bought() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + char1.exp = 80000000; + char1.meseta = 999999; + entity_gateway.save_character(&char1).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + client: 255, + target: 255, + shop_type: 2, + })))).await.unwrap().collect::>(); + + let first_unit = match &packets[0].1 { + SendShipPacket::Message(Message {msg: GameMessage::ShopList(shop_list)}) => { + shop_list.items.iter() + .enumerate() + .filter(|(_, item)| { + item.item_bytes[0] == 1 && item.item_bytes[1] == 3 + }) + .nth(0).unwrap().0 + }, + _ => panic!(""), + }; + + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10000, + shop_type: 2, + shop_index: first_unit as u8, + amount: 1, + unknown1: 0, + })))).await.unwrap().for_each(drop); + ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + client: 255, + target: 255, + item_id: 0x10001, + shop_type: 2, + shop_index: first_unit as u8, + amount: 1, + unknown1: 0, + })))).await.unwrap().for_each(drop); + + let p1_items = entity_gateway.get_items_by_character(&char1).await; + assert!(p1_items[0].item != p1_items[1].item); }