Skip to content

Commit feffd4f

Browse files
committed
Work on "ultra rando" mode
Initial work on ultra randomize mode Player stats, spell learning, enemy zones, and enemy patterns can now be randomized in an "anything goes" fashion Changed --enemies to --zones Some minor tweaks to enemy zone randomization in normal mode
1 parent 5b96681 commit feffd4f

File tree

2 files changed

+131
-73
lines changed

2 files changed

+131
-73
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@ See below for other command line options.
114114
-c, --chests Do not randomize chest contents.
115115
-f, --force Skip checksums and force randomization. This may
116116
produce an invalid ROM if the incorrect file is used.
117-
-e, --enemies Do not randomize enemy zones.
118117
-l, --repel Do not move repel to level 8.
119118
-p, --patterns Do not randomize enemy attack patterns.
120119
-s SEED, --seed SEED Specify a seed to be used for randomization.
121120
-t, --towns Do not randomize towns.
122121
-w, --shops Do not randomize weapon shops.
122+
-z, --zones Do not randomize enemy zones.
123123

124124
## Special Thanks
125125

dwrandomizer.py

Lines changed: 130 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def non_charlock_chest(self):
123123
chest = chest + 1 if (chest > 23) else chest
124124
return chest
125125

126-
def randomize_attack_patterns(self):
126+
def randomize_attack_patterns(self, ultra=False):
127127
"""
128128
Randomizes attack patterns of enemies (whether or not they use spells/fire
129129
breath).
@@ -135,18 +135,21 @@ def randomize_attack_patterns(self):
135135
if random.randint(0,1): # 50/50 chance
136136
resist = random.randint(0,round(i/5))
137137
new_ss_resist[i] &= (0xf0 | resist)
138-
if i <= 20:
139-
# heal, sleep, stopspell, hurt
140-
new_patterns.append((random.randint(0,11) << 4) | random.randint(0,3))
141-
elif i < 30:
142-
# healmore, heal, sleep, stopspell, fire breath, hurtmore
143-
new_patterns.append((random.randint(0,15) << 4) | random.randint(4, 11))
138+
if ultra:
139+
new_patterns.append((random.randint(0,255)))
144140
else:
145-
# healmore, sleep, stopspell, strong fire breath, fire breath, hurtmore
146-
#we'll be nice and not give Axe Knight Dragonlord's breath.
147-
slot2 = random.randint(4, 11) if i == 33 else random.randint(4, 15)
148-
new_patterns.append((random.choice((0, 1, 3)) << 6) |
149-
(random.randint(0, 3) << 4) | slot2)
141+
if i <= 20:
142+
# heal, sleep, stopspell, hurt
143+
new_patterns.append((random.randint(0,11) << 4) | random.randint(0,3))
144+
elif i < 30:
145+
# healmore, heal, sleep, stopspell, fire breath, hurtmore
146+
new_patterns.append((random.randint(0,15) << 4) | random.randint(4, 11))
147+
else:
148+
# healmore, sleep, stopspell, strong fire breath, fire breath, hurtmore
149+
#we'll be nice and not give Axe Knight Dragonlord's breath.
150+
slot2 = random.randint(4, 11) if i == 33 else random.randint(4, 15)
151+
new_patterns.append((random.choice((0, 1, 3)) << 6) |
152+
(random.randint(0, 3) << 4) | slot2)
150153
else:
151154
new_patterns.append(0)
152155
new_patterns.append(87) #Dragonlord form 1
@@ -170,7 +173,8 @@ def shuffle_towns(self):
170173
# this could happen if it ends up in southern shrine position or
171174
# behind a locked door when rimuldar is in it's normal location.
172175
while (caves[3][0] == 21 or
173-
(towns[3][0] == 11 and 21 in (caves[5][0], caves[6][0]))):
176+
(towns[3][0] == 11 and 21 in (caves[5][0], caves[6][0])) or
177+
(towns[3][0] == 9 and caves[6][0] == 21)):
174178
random.shuffle(caves)
175179
warp_data[153:156] = towns[0]
176180
warp_data[159:162] = towns[1]
@@ -191,39 +195,46 @@ def shuffle_towns(self):
191195
warp_data[174:177],warp_data[189:192] = warp_data[189:192],warp_data[174:177]
192196
self.rom_data[self.warps_slice] = warp_data
193197

194-
def randomize_zones(self):
198+
def randomize_zones(self, ultra=False):
195199
"""
196200
Randomizes which enemies are present in each zone.
197201
"""
198202
new_zones = list()
199-
#zone 0
200-
for j in range(5):
201-
new_zones.append(int(random.randint(0, 4)/2))
202-
203-
# zones 1-13 (overworld)
204-
for i in range(1, 14):
205-
for j in range(5):
206-
enemy = random.randint(max(0, i * 2 - 2), (max(2,round(i*2.5))))
207-
while enemy == 24: # don't add golem
208-
enemy = random.randint(i * 2 - 2, round(i*2.5))
209-
new_zones.append(enemy)
210-
211-
#zone 14 - garin's grave?
212-
for j in range(5):
213-
new_zones.append(random.randint(7, 17))
214-
215-
#zone 15 - lower garin's grave
216-
for j in range(5):
217-
new_zones.append(random.randint(15, 23))
218-
219-
# zone 16-18 - Charlock
220-
for i in range(16, 19):
203+
if ultra:
204+
#zone 0-1
205+
for i in range(0,10):
206+
new_zones.append(random.randint(0, 6))
207+
for i in range(0,90):
208+
new_zones.append(random.randint(0, 37))
209+
else:
210+
#zones 2-19
211+
for j in range(5):
212+
new_zones.append(int(random.randint(0, 6)/2))
213+
214+
# zones 1-13 (Overworld)
215+
for i in range(1, 14):
216+
for j in range(5):
217+
enemy = random.randint(i * 2 - 2, min(37,round(i*3)))
218+
while enemy == 24: # don't add golem
219+
enemy = random.randint(i * 2 - 2, min(37,round(i*3)))
220+
new_zones.append(enemy)
221+
222+
#zone 14 - Garin's Grave?
223+
for j in range(5):
224+
new_zones.append(random.randint(7, 17))
225+
226+
#zone 15 - Lower Garin's Grave
227+
for j in range(5):
228+
new_zones.append(random.randint(15, 23))
229+
230+
# zone 16-18 - Charlock
231+
for i in range(16, 19):
232+
for j in range(5):
233+
new_zones.append(random.randint(13+i, 37))
234+
235+
# zone 19 - Rimuldar Tunnel
221236
for j in range(5):
222-
new_zones.append(random.randint(13+i, 37))
223-
224-
# zone 19 rimuldar tunnel
225-
for j in range(5):
226-
new_zones.append(random.randint(3, 11))
237+
new_zones.append(random.randint(3, 11))
227238
self.rom_data[self.zones_slice] = new_zones
228239

229240
def randomize_shops(self):
@@ -269,22 +280,32 @@ def shuffle_searchables(self):
269280
self.rom_data[self.flute_slice] = searchables[1]
270281
self.rom_data[self.armor_slice] = searchables[2]
271282

272-
def randomize_growth(self):
283+
def randomize_growth(self, ultra=False):
273284
player_stat_data = self.rom_data[self.player_stats_slice]
274285

275286
player_str = list(player_stat_data[0:180:6])
276287
player_agi = list(player_stat_data[1:180:6])
277288
player_hp = list(player_stat_data[2:180:6])
278289
player_mp = list(player_stat_data[3:180:6])
279290

280-
for i in range(len(player_str)):
281-
player_str[i] = round(player_str[i] * random.uniform(0.8, 1.2))
282-
for i in range(len(player_agi)):
283-
player_agi[i] = round(player_agi[i] * random.uniform(0.8, 1.2))
284-
for i in range(len(player_hp)):
285-
player_hp[i] = round(player_hp[i] * random.uniform(0.8, 1.2))
286-
for i in range(len(player_mp)):
287-
player_mp[i] = round(player_mp[i] * random.uniform(0.8, 1.2))
291+
if ultra:
292+
for i in range(len(player_str)):
293+
player_str[i] = round(player_str[i] * random.uniform(0.8, 1.2))
294+
for i in range(len(player_agi)):
295+
player_agi[i] = round(player_agi[i] * random.uniform(0.8, 1.2))
296+
for i in range(len(player_hp)):
297+
player_hp[i] = round(player_hp[i] * random.uniform(0.8, 1.2))
298+
for i in range(len(player_mp)):
299+
player_mp[i] = round(player_mp[i] * random.uniform(0.8, 1.2))
300+
else:
301+
for i in range(len(player_str)):
302+
player_str[i] = random.randint(4,200)
303+
for i in range(len(player_agi)):
304+
player_agi[i] = random.randint(4,200)
305+
for i in range(len(player_hp)):
306+
player_hp[i] = random.randint(10,255)
307+
for i in range(len(player_mp)):
308+
player_mp[i] = random.randint(0,255)
288309

289310
player_str.sort()
290311
player_agi.sort()
@@ -297,14 +318,18 @@ def randomize_growth(self):
297318
player_stat_data[3:180:6] = player_mp
298319
self.rom_data[self.player_stats_slice] = player_stat_data
299320

300-
def randomize_spell_learning(self):
321+
def randomize_spell_learning(self, ultra=False):
301322
self.move_repel() # in case this hasn't been called yet.
302323
levels = self.rom_data[self.new_spell_slice]
303324
player_mp = self.rom_data[self.player_mp_slice]
304325
new_masks = []
305326
# choose the levels for new spells
306-
for i in range(len(levels)):
307-
levels[i] = levels[i] + random.randint(-2, 2)
327+
if ultra:
328+
for i in range(len(levels)):
329+
levels[i] = random.randint(0, 20)
330+
else:
331+
for i in range(len(levels)):
332+
levels[i] = levels[i] + random.randint(-2, 2)
308333
#adjust the spell masks to fit the new levels
309334
for i in range(30):
310335
mask = 0
@@ -342,12 +367,15 @@ def update_drops(self):
342367
enemy_stats[7::16] = bytearray(remake_gold)
343368
self.rom_data[self.enemy_stats_slice] = enemy_stats
344369

345-
def update_mp_reqs(self):
370+
def update_mp_reqs(self, ultra=False):
346371
"""
347372
Lowers the MP requirements of spells to that of the remake
348373
"""
349374
#magic required for each spell, in order
350375
remake_mp = [3, 2, 2, 2, 2, 6, 8, 2, 8, 5]
376+
if ultra:
377+
for i in range(10):
378+
remake_mp[i] = random.randint(1, 8)
351379
self.rom_data[self.mp_req_slice] = remake_mp
352380

353381
def update_enemy_hp(self):
@@ -411,26 +439,36 @@ def main():
411439
parser.add_argument("-f","--force", action="store_false",
412440
help="Skip checksums and force randomization. This may produce an invalid"
413441
" ROM if the incorrect file is used.")
414-
parser.add_argument("-e","--enemies", action="store_false",
415-
help="Do not randomize enemy zones.")
416442
parser.add_argument("-i","--searchitems", action="store_false",
417443
help="Do not randomize the locations of searchable items (Fairy Flute, "
418444
"Erdrick's Armor, Erdrick's Token).")
419445
parser.add_argument("-g","--growth", action="store_false",
420446
help="Do not randomize player stat growth.")
447+
parser.add_argument("-G","--ultra-growth", action="store_true",
448+
help="Enable ultra randomization of player stat growth.")
421449
parser.add_argument("-l","--repel", action="store_false",
422450
help="Do not move repel to level 8.")
423451
parser.add_argument("-m","--spells", action="store_false",
424452
help="Do not randomize the level spells are learned.")
453+
parser.add_argument("-M","--ultra-spells", action="store_true",
454+
help="Enable ultra randomization of the level spells are learned.")
425455
parser.add_argument("-p","--patterns", action="store_false",
426456
help="Do not randomize enemy attack patterns.")
457+
parser.add_argument("-P","--ultra-patterns", action="store_true",
458+
help="Enable ultra randomization of enemy attack patterns.")
427459
parser.add_argument("-s","--seed", type=int,
428460
help="Specify a seed to be used for randomization.")
429461
parser.add_argument("-t","--towns", action="store_false",
430462
help="Do not randomize towns.")
431463
parser.add_argument("-w","--shops", action="store_false",
432464
help="Do not randomize weapon shops.")
465+
parser.add_argument("-U","--ultra", action="store_true",
466+
help="Enable all '--ultra' options.")
433467
# parser.add_argument('--version', action='version', version='%(prog) %s'%VERSION)
468+
parser.add_argument("-z","--zones", action="store_false",
469+
help="Do not randomize enemy zones.")
470+
parser.add_argument("-Z","--ultra-zones", action="store_true",
471+
help="Enable ultra randomization of enemy zones.")
434472
parser.add_argument("filename", help="The rom file to use for input")
435473
args = parser.parse_args()
436474
randomize(args)
@@ -442,7 +480,7 @@ def randomize(args):
442480
print("Randomizing %s using random seed %d..." % (args.filename, args.seed))
443481
random.seed(args.seed)
444482
flags = ""
445-
prg = "PRG_"
483+
prg = ""
446484

447485
rom = Rom(args.filename)
448486

@@ -455,7 +493,7 @@ def randomize(args):
455493
sys.exit(-1)
456494
else:
457495
print("Processing Dragon Warrior PRG%d ROM..." % result)
458-
prg = "PRG%d" % result
496+
prg = "PRG%d." % result
459497

460498
else:
461499
print("Skipping checksum...")
@@ -484,25 +522,40 @@ def randomize(args):
484522
flags += "t"
485523
rom.shuffle_towns()
486524

487-
if args.enemies:
488-
print("Randomizing enemy zones...")
489-
flags += "e"
490-
rom.randomize_zones()
525+
if args.zones:
526+
if args.ultra or args.ultra_zones:
527+
print("Ultra randomizing enemy zones...")
528+
flags += "Z"
529+
rom.randomize_zones(True)
530+
else:
531+
print("Randomizing enemy zones...")
532+
flags += "z"
533+
rom.randomize_zones()
491534

492535
if args.patterns:
493-
print("Randomizing enemy attack patterns...")
494-
flags += "p"
495-
rom.randomize_attack_patterns()
536+
if args.ultra or args.ultra_patterns:
537+
print("Ultra randomizing enemy attack patterns...")
538+
flags += "P"
539+
rom.randomize_attack_patterns(True)
540+
else:
541+
print("Randomizing enemy attack patterns...")
542+
flags += "p"
543+
rom.randomize_attack_patterns()
496544

497545
if args.shops:
498546
print("Randomizing weapon shops...")
499547
flags += "w"
500548
rom.randomize_shops()
501549

502550
if args.growth:
503-
print("Randomizing player stat growth...")
504-
flags += "g"
505-
rom.randomize_growth()
551+
if args.ultra or args.ultra_growth:
552+
print("Ultra randomizing player stat growth...")
553+
flags += "G"
554+
rom.randomize_growth(True)
555+
else:
556+
print("Randomizing player stat growth...")
557+
flags += "g"
558+
rom.randomize_growth()
506559

507560
if args.remake:
508561
print("Increasing XP/Gold drops to remake levels...")
@@ -519,11 +572,16 @@ def randomize(args):
519572
rom.move_repel()
520573

521574
if args.spells:
522-
print("Randomizing level spells are learned...")
523-
flags += "m"
524-
rom.randomize_spell_learning()
575+
if args.ultra or args.ultra_spells:
576+
print("Ultra randomizing level spells are learned...")
577+
flags += "M"
578+
rom.randomize_spell_learning(True)
579+
else:
580+
print("Randomizing level spells are learned...")
581+
flags += "m"
582+
rom.randomize_spell_learning()
525583

526-
output_filename = "DWRandomizer.%d.%s.%s.nes" % (args.seed, flags, prg)
584+
output_filename = "DWRando.%s.%d.%snes" % (flags, args.seed, prg)
527585
print("Writing output file %s..." % output_filename)
528586
rom.write(output_filename)
529587
print ("New ROM Checksum: %s" % rom.sha1())

0 commit comments

Comments
 (0)