Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random treasure #34

Merged
merged 4 commits into from
Aug 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion randomize.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from randomizer.keyitemsolver import KeyItemPlacement
from randomizer.spellshuffle import SpellShuffle
from randomizer.treasures import treasure_shuffle
from randomizer.randomtreasure import random_treasures, random_bucketed_treasures
from stream.outputstream import OutputStream

BASE_PATCHES = [
Expand Down Expand Up @@ -57,6 +58,7 @@ def randomize_rom(rom: Rom, flags: Flags, rom_seed: str) -> Rom:
patches_to_load.append("data/RandomDefault.ips")

patched_rom_data = rom.rom_data

for patch_path in patches_to_load:
patch = Patch.load(patch_path)
patched_rom_data = patch.apply(patched_rom_data)
Expand All @@ -71,6 +73,8 @@ def randomize_rom(rom: Rom, flags: Flags, rom_seed: str) -> Rom:

rom = update_xp_requirements(rom, flags.exp_mult)

rom = random_treasures(rom, rng)

if flags.key_item_shuffle is not None:
placement = KeyItemPlacement(rom, rng.randint(0, 0xffffffff))
else:
Expand All @@ -82,7 +86,10 @@ def randomize_rom(rom: Rom, flags: Flags, rom_seed: str) -> Rom:
rom = shuffle_magic.write(rom)

if flags.treasures is not None:
rom = treasure_shuffle(rom, rng)
if flags.treasures == "shuffle":
rom = treasure_shuffle(rom, rng)
else:
rom = random_bucketed_treasures(rom, rng, flags.wealth)

if flags.debug is not None:
class_stats_stream = rom.open_bytestream(0x1E1354, 96)
Expand Down
10 changes: 9 additions & 1 deletion randomizer/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def __init__(self, flags_str: str):
self.exp_mult = 1.0

self.shuffle_formations = None
self.treasures = None
self.wealth = 0

self.debug = None

Expand All @@ -38,6 +40,9 @@ def __init__(self, flags_str: str):
self.magic = "shuffle"
elif flag == "Ts":
self.treasures = "shuffle"
elif flag[:1] == "T":
self.treasures = "wealth"
self.wealth = int(flag[1:])
elif flag == "-who":
self.default_party = "random"
elif flag == "-hax":
Expand All @@ -60,7 +65,10 @@ def text(self, internal=False):
if self.magic is not None:
value += "Ms"
if self.treasures is not None:
value += "Ts"
if self.treasures == "shuffle":
value += "Ts"
if self.treasures == "random":
value += "T" + str(self.wealth)
if self.key_item_shuffle is not None:
value += "K"
if self.exp_mult is not None:
Expand Down
114 changes: 114 additions & 0 deletions randomizer/randomtreasure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Copyright 2019 Nicole Borrelli
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from random import Random

from doslib.maps import TreasureChest, MoneyChest, ItemChest
from doslib.rom import Rom
from stream.outputstream import OutputStream
from randomizer.treasurebuckets import TreasureBuckets

#Pure random - easy enough.
# 0x01 ->
#Armor 0x46
#Weapon 0x40
#Item 0x2B
#We'll keep the same ratio of money to items

def random_treasures(rom: Rom, rng: Random) -> Rom:
chest_stream = rom.open_bytestream(0x217FB4, 0x400)
items = [(0,x + 1) for x in list(range(0x45))]
items = items + [(1,x + 1) for x in list(range(0x3F))]
items = items + [(2,x + 1) for x in list(range(0x2A))]
itemCount = len(items)
print(itemCount)
chests_to_shuffle = []
original_list = []
moneyCount = 0
itemTotal = 0
for index in range(256):
chest = TreasureChest.read(chest_stream)
original_list.append(chest)
if isinstance(chest, ItemChest):
if chest.item_type != 0:
new_item = items[rng.randint(0,itemCount-1)]
chest.item_type = new_item[0]
chest.item_id = new_item[1]
itemTotal += 1
chests_to_shuffle.append(chest)
elif isinstance(chest, MoneyChest):
chest.qty = rng.randint(1, 0xfff) * rng.randint(1,6)
chests_to_shuffle.append(chest)
print(chest.qty)
moneyCount += 1
else:
print("BAD CHEST")
return
rng.shuffle(chests_to_shuffle)

chest_data = OutputStream()
for chest in original_list:
if isinstance(chest, MoneyChest) or chest.item_type != 0:
new_chest = chests_to_shuffle.pop()
new_chest.write(chest_data)
else:
chest.write(chest_data)

return rom.apply_patch(0x217FB4, chest_data.get_buffer())

def random_bucketed_treasures(rom: Rom, rng: Random, wealth_level: int=0) -> Rom:
"""Randomly generates and shuffles treasured based on wealth_level"""
bucket_data = TreasureBuckets()
chest_stream = rom.open_bytestream(0x217FB4, 0x400)
items = [(0,x + 1) for x in list(range(0x45))]
items = items + [(1,x + 1) for x in list(range(0x3F))]
items = items + [(2,x + 1) for x in list(range(0x2A))]
itemCount = len(items)
chests_to_shuffle = []
original_list = []
moneyCount = 0
itemTotal = 0
for index in range(256):
chest = TreasureChest.read(chest_stream)
original_list.append(chest)
if isinstance(chest, ItemChest):
if chest.item_type != 0:
item_bucket = bucket_data.getBucket(chest.item_type, chest.item_id)
if wealth_level == 1:
item_bucket = bucket_data.up_one(item_bucket)
if wealth_level == -1:
item_bucket = bucket_data.down_one(item_bucket)
new_item = bucket_data.pullFromBucket(item_bucket,rng, 1)
chest.item_id = new_item[0]
itemTotal += 1
chests_to_shuffle.append(chest)
elif isinstance(chest, MoneyChest):
chest.qty = rng.randint(1, 0xfff) * rng.randint(1,6)
chests_to_shuffle.append(chest)
moneyCount += 1
else:
print("BAD CHEST")
return
rng.shuffle(chests_to_shuffle)

chest_data = OutputStream()
for chest in original_list:
if isinstance(chest, MoneyChest) or chest.item_type != 0:
new_chest = chests_to_shuffle.pop()
new_chest.write(chest_data)
else:
chest.write(chest_data)

return rom.apply_patch(0x217FB4, chest_data.get_buffer())

108 changes: 108 additions & 0 deletions randomizer/treasurebuckets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Copyright 2019 Nicole Borrelli
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from random import Random

class TreasureBuckets:
def __init__(self):
#For now, we're hard coding it. It's possible to change later
self.buckets = {
"Item_D": [0x01,0x0B,0x0D,0x0E,0x10,0x13],
"Item_C": [0x02,0x04,0x0C,0x18,0x19,0x1A,0x1D],
"Item_B": [0x05,0x09,0x0A,0x11,0x14,0x15,0x16,0x1B,0x20,0x22,0x24,0x25,0x26,0x29,0x2A],
"Item_A": [0x03,0x06,0x07,0x12,0x17,0x1C,0x1E,0x1F,0x21,0x23,0x27,0x28,0x2B],
"Item_S": [0x08,0x0F],
"Weapon_D": [0x01,0x02,0x03,0x05,0x09,0x0A],
"Weapon_C": [0x04,0x06,0x07,0x08,0x0B,0x0C,0x0D,0x0E,0x0F,0x1C],
"Weapon_B": [0x10,0x11,0x12,0x13,0x16,0x17,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x21,0x23,0x24,0x2F,0x31,0x33,0x35,0x3A,0x3B,0x3E],
"Weapon_A": [0x14,0x15,0x18,0x20,0x22,0x25,0x26,0x27,0x2D,0x30,0x32,0x34,0x36,0x37,0x38,0x39,0x3D,0x3F,0x40],
"Weapon_S": [0x28,0x29,0x2A,0x2B,0x2C,0x2E,0x3C],
"Armor_D": [0x01,0x02,0x0B,0x1C,0x2A,0x2B,0x2C,0x3A,0x3B,0x3C],
"Armor_C": [0x03,0x04,0x0C,0x1D,0x1E,0x23,0x2D,0x36,0x3D],
"Armor_B": [0x05,0x06,0x0D,0x1A,0x1F,0x20,0x24,0x28,0x29,0x2E,0x35,0x38,0x3E,0x40,0x41,0x42,0x44,0x46],
"Armor_A": [0x07,0x08,0x09,0x0E,0x10,0x12,0x13,0x14,0x16,0x17,0x21,0x22,0x2F,0x31,0x32,0x33,0x34,0x3F,0x43],
"Armor_S": [0x0A,0x0F,0x11,0x15,0x18,0x19,0x1B,0x25,0x26,0x27,0x30,0x37,0x39,0x45],
}
#Okay but for real we need to set something up here

def getBucket(self, itemType:int, id_val:int):
if itemType == 1:
if id_val in self.buckets["Item_D"]:
return "Item_D"
if id_val in self.buckets["Item_C"]:
return "Item_C"
if id_val in self.buckets["Item_B"]:
return "Item_B"
if id_val in self.buckets["Item_A"]:
return "Item_A"
if id_val in self.buckets["Item_S"]:
return "Item_S"
if itemType == 2:
if id_val in self.buckets["Weapon_D"]:
return "Weapon_D"
if id_val in self.buckets["Weapon_C"]:
return "Weapon_C"
if id_val in self.buckets["Weapon_B"]:
return "Weapon_B"
if id_val in self.buckets["Weapon_A"]:
return "Weapon_A"
if id_val in self.buckets["Weapon_S"]:
return "Weapon_S"
if itemType == 3:
if id_val in self.buckets["Armor_D"]:
return "Armor_D"
if id_val in self.buckets["Armor_C"]:
return "Armor_C"
if id_val in self.buckets["Armor_B"]:
return "Armor_B"
if id_val in self.buckets["Armor_A"]:
return "Armor_A"
if id_val in self.buckets["Armor_S"]:
return "Armor_S"
return None

def up_one(self,tier):
if tier.endswith("D"):
return tier[:-1] + "C"
if tier.endswith("C"):
return tier[:-1] + "B"
if tier.endswith("B"):
return tier[:-1] + "A"
if tier.endswith("A"):
return tier[:-1] + "S"
if tier.endswith("S"):
return tier[:-1] + "S"

def down_one(self,tier):
if tier.endswith("D"):
return tier[:-1] + "D"
if tier.endswith("C"):
return tier[:-1] + "D"
if tier.endswith("B"):
return tier[:-1] + "C"
if tier.endswith("A"):
return tier[:-1] + "B"
if tier.endswith("S"):
return tier[:-1] + "A"

def pullFromBucket(self,bucket,rng,count: int):
"""Generate a list of items from a given bucket"""
return rng.choices(self.buckets[bucket],k=count)

def fullBucketList(self,buckets,rng,counts):
"""Generate a list of items, pulling a specified number from each bucket"""
outList = []
for i in range(len(buckets)):
outList += self.pullFromBucket(buckets[i],counts[i])
return outList
20 changes: 19 additions & 1 deletion static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ <h2>
<label>Encounter toggle: <input id="encounter-toggle" type="checkbox"/></label>
<label>Magic shuffle: <input id="magic-shuffle" type="checkbox"/></label>
<label>Treasure shuffle: <input id="treasure-shuffle" type="checkbox"/></label>
<label>Random Treasures?: <input id="treasure-random" type="checkbox"/></label>
<label>Wealth Level:
<input id="wealth" type="range" min="-1" max="1" value="0" step="1" class="slider">
</label>
<label>Formation shuffle: <input id="formation-shuffle" type="checkbox"/></label>
<label>Exp Scale:
<input id="exp-scale" type="range" min="50" max="500" value="150" step="10" class="slider">
Expand Down Expand Up @@ -227,8 +231,20 @@ <h2>
flags += "Ms "
}
if ($("#treasure-shuffle").prop("checked")) {
flags += "Ts "
if ($("#treasure-random").prop("checked")){
wealth = document.getElementById("wealth");
flags += "T" + parseInt(wealth.value) + " ";
}
else
{
flags += "Ts "
}

}
else if ($("#treasure-random").prop("checked")){
wealth = document.getElementById("wealth");
flags += "T" + parseInt(wealth.value) + " ";
}
if ($("#formation-shuffle").prop("checked")) {
flags += "Fs "
}
Expand All @@ -251,7 +267,9 @@ <h2>
$("#encounter-toggle").change(updateFlags);
$("#magic-shuffle").change(updateFlags);
$("#treasure-shuffle").change(updateFlags);
$("#treasure-random").change(updateFlags);
$("#exp-scale").on("input change", updateFlags);
$("#wealth").on("input change", updateFlags);
});


Expand Down