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

Allow the Thief Lockpicking to be granted by a Blursing #978

Closed
Closed
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
4 changes: 2 additions & 2 deletions FF1Blazorizer/Tabs/ClassesTab.razor
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<CheckBox UpdateToolTip="@UpdateToolTipID" IsEnabled="@(Flags.Transmooglifier == false)" Id="fixHitChanceCapCheckBox" @bind-Value="Flags.FixHitChanceCap">Raise Hit % Cap</CheckBox>
<EnumDropDown UpdateToolTip="@UpdateToolTipID" IsEnabled="@(Flags.Transmooglifier == false)" Id="MDefModeDropDown" TItem="MDEFGrowthMode" @bind-Value="Flags.MDefMode">MDEF Growth:</EnumDropDown>
<CheckBox UpdateToolTip="@UpdateToolTipID" IsEnabled="@(Flags.Transmooglifier == false)" Id="WhiteMageHarmEveryoneCheckBox" @bind-Value="Flags.WhiteMageHarmEveryone">Improved HARM for White Mage</CheckBox>
<TriStateCheckBox UpdateToolTip="@UpdateToolTipID" IsEnabled="@(Flags.Transmooglifier == false)" Id="Lockpicking" @bind-Value="Flags.Lockpicking">Thief Lockpicking</TriStateCheckBox>
<IntSlider Indent Min="1" Max="50" Step="1" DisableTooltip UpdateToolTip="@UpdateToolTipID" IsEnabled="Flags.Lockpicking" Id="LockpickingLevelRequirement" @bind-Value="@Flags.LockpickingLevelRequirement">Lockpicking Level Requirement:</IntSlider>
<EnumDropDown UpdateToolTip="@UpdateToolTipID" IsEnabled="@(Flags.Transmooglifier == false)" Id="Lockpicking" @bind-Value="Flags.Lockpicking">Thief Lockpicking</EnumDropDown>
<IntSlider Indent Min="1" Max="50" Step="1" DisableTooltip UpdateToolTip="@UpdateToolTipID" IsEnabled="Flags.Lockpicking != Lockpicking.None" Id="LockpickingLevelRequirement" @bind-Value="@Flags.LockpickingLevelRequirement">Lockpicking Level Requirement:</IntSlider>
<TriStateCheckBox UpdateToolTip="@UpdateToolTipID" Id="ReducedLuckCheckBox" @bind-Value="Flags.ReducedLuck">Reduced Luck</TriStateCheckBox>

<div class="checkbox-cell"></div>
Expand Down
2 changes: 1 addition & 1 deletion FF1Blazorizer/wwwroot/tooltips/tooltips.json
Original file line number Diff line number Diff line change
Expand Up @@ -2158,7 +2158,7 @@
"Id": "Lockpicking",
"title": "Thief Lockpicking",
"screenshot": "Lockpicking.png",
"description": "Having a thief in the party, when they reach the required level, allows players to open all locked doors. (Selecting level 1 will allow the thief to always unlock doors.)\n\n Enabling this flag also adds a -10 level requirement bonus and a +10 level requirement malus to blursed classes."
"description": "Having a thief in the party, when they reach the required level, allows players to open all locked doors. (Selecting level 1 will allow the thief to always unlock doors.)\n\n Enabling this flag also adds a -10 level requirement bonus and a +10 level requirement malus to blursed classes.\n\nThis can be enabled for all Thieves or only for Thieves that receive the 'Lockpicking' class blessing (which will only show up when this option is set to blessed classes)."
},
{
"Id": "ReducedLuckCheckBox",
Expand Down
53 changes: 41 additions & 12 deletions FF1Lib/Classes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ public enum MpGainOnMaxGain
Blursed
}

public enum Lockpicking
{
[Description("None")]
None = 0,
[Description("Thief")]
Thief,
[Description("Blessed Thief Only")]
Blursed
}

public class GameClasses
{
private List<ClassData> _classes;
Expand Down Expand Up @@ -124,7 +134,8 @@ public enum BonusMalusAction
Sleepy,
Sick,
StartWithKI,
InnateSpells
InnateSpells,
Lockpicking
}

public class BonusMalus
Expand Down Expand Up @@ -726,6 +737,15 @@ public List<string> DoRandomizeClassNormalMode(MT19337 rng, List<string> olditem
//new BonusMalus(BonusMalusAction.Sleepy, "Sleepy"),
};

// Add lockpicking bonus
if (flags.Lockpicking == Lockpicking.Thief) {
// Give Thief and Ninja the effect of the bonus without adding a blursing
_classes[(int)Classes.Thief].Lockpicking = true;
_classes[(int)Classes.Ninja].Lockpicking = true;
} else if (flags.Lockpicking == Lockpicking.Blursed) {
bonusNormal.Add(new BonusMalus(BonusMalusAction.Lockpicking, "Lockpicking", Classes: new List<Classes> { Classes.Thief }));
}

// Negative amounts are processed separately in ProcessStartWithRoutines, because they affect the Assembly code
// If changing the Malus gold labels below, change those as well to alter the actual number used
if (flags.StartingGold == StartingGold.None) {
Expand Down Expand Up @@ -813,14 +833,15 @@ public List<string> DoRandomizeClassNormalMode(MT19337 rng, List<string> olditem
}

// Add Lockpicking Bonus/Malus
if ((bool)flags.Lockpicking && flags.LockpickingLevelRequirement < 50)
{
malusNormal.Add(new BonusMalus(BonusMalusAction.LockpickingLevel, "LateLockpik", mod: 10, Classes: new List<Classes> { Classes.Thief }));
}

if ((bool)flags.Lockpicking && flags.LockpickingLevelRequirement > 1)
{
bonusNormal.Add(new BonusMalus(BonusMalusAction.LockpickingLevel, "EarlyLokpik", mod: -10, Classes: new List<Classes> { Classes.Thief }));
if (flags.Lockpicking != Lockpicking.None){
if (flags.LockpickingLevelRequirement < 50)
{
malusNormal.Add(new BonusMalus(BonusMalusAction.LockpickingLevel, "LateLockpik", mod: 10, Classes: new List<Classes> { Classes.Thief }));
}
if (flags.LockpickingLevelRequirement > 1)
{
bonusNormal.Add(new BonusMalus(BonusMalusAction.LockpickingLevel, "EarlyLokpik", mod: -10, Classes: new List<Classes> { Classes.Thief }));
}
}

// Add Natural Resist Bonuses
Expand Down Expand Up @@ -1094,7 +1115,7 @@ public List<string> DoRandomizeClassNormalMode(MT19337 rng, List<string> olditem
break;
case BonusMalusAction.LockpickingLevel:
int newLockPickingLevel = flags.LockpickingLevelRequirement + bonusmalus.StatMod;
if ((bool)flags.Lockpicking)
if (flags.Lockpicking != Lockpicking.None)
{
//constrain lp level to 1-50
newLockPickingLevel = Math.Max(1, newLockPickingLevel);
Expand Down Expand Up @@ -1175,6 +1196,10 @@ public List<string> DoRandomizeClassNormalMode(MT19337 rng, List<string> olditem
_classes[i].InnateSpells = bonusmalus.SpellsMod.ToList();
_classes[i + 6].InnateSpells = bonusmalus.SpellsMod.ToList();
break;
case BonusMalusAction.Lockpicking:
_classes[i].Lockpicking = true;
_classes[i + 6].Lockpicking = true;
break;
}
}
}
Expand Down Expand Up @@ -2142,6 +2167,7 @@ public void ProcessStartWithRoutines(Flags flags, List<int> blursesValues, FF1Ro
Blob lut_Sick = _classes.Select(x => (byte)(x.Sick ? 0x01 : 0x00)).ToArray();
Blob lut_SteelArmor = _classes.Select(x => (byte)(x.SteelLord ? 0x01 : 0x00)).ToArray();
Blob lut_WoodArmors = _classes.Select(x => (byte)(x.WoodAdept ? 0x01 : 0x00)).ToArray();
Blob lut_Lockpicking = _classes.Select(x => (byte)(x.Lockpicking ? 0x01 : 0x00)).ToArray();

rom.PutInBank(0x1B, 0xB200, lut_Blackbelts + new byte[] { 0x00 } +
lut_CatClaws + new byte[] { 0x00 } +
Expand All @@ -2150,7 +2176,8 @@ public void ProcessStartWithRoutines(Flags flags, List<int> blursesValues, FF1Ro
lut_Sleepy + new byte[] { 0x00 } +
lut_Sick + new byte[] { 0x00 } +
lut_SteelArmor + new byte[] { 0x00 } +
lut_WoodArmors + new byte[] { 0x00 });
lut_WoodArmors + new byte[] { 0x00 } +
lut_Lockpicking + new byte[] { 0x00 });

// Recruit Mode Switcher
rom.PutInBank(0x1B, 0xB600, Blob.FromHex("A5108513A8B913B6A8202EB3A51385104CAA87004080C0"));
Expand Down Expand Up @@ -2184,7 +2211,7 @@ private List<BonusMalus> StartWithKeyItems(Flags flags, MT19337 rng, List<string
kiBlursings.Add(new BonusMalus(BonusMalusAction.StartWithKI, "+" + olditemnames[(int)Item.Tail], mod: (int)Item.Tail));
}

if (!(bool)flags.Lockpicking)
if (flags.Lockpicking != Lockpicking.None)
{
kiBlursings.Add(new BonusMalus(BonusMalusAction.StartWithKI, "+" + olditemnames[(int)Item.Key], mod: (int)Item.Key));
}
Expand Down Expand Up @@ -2247,6 +2274,7 @@ public class ClassData
public bool Sick { get; set; }
public bool WoodAdept { get; set; }
public bool SteelLord { get; set; }
public bool Lockpicking { get; set; }
public List<SpellSlotInfo> InnateSpells { get; set; }
public Item StartingKeyItem { get; set; }

Expand Down Expand Up @@ -2279,6 +2307,7 @@ public ClassData(byte classid, byte[] startingStats, byte[] levelUpStats, byte h
Sick = false;
WoodAdept = false;
SteelLord = false;
Lockpicking = false;
StartingKeyItem = Item.None;
InnateSpells = new() { new SpellSlotInfo(), new SpellSlotInfo(), new SpellSlotInfo() };
}
Expand Down
2 changes: 1 addition & 1 deletion FF1Lib/FF1Rom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,7 @@ public async Task Randomize(Blob seed, Flags flags, Preferences preferences)
MDefChanges(flags.MDefMode);
}

if ((bool)flags.Lockpicking)
if (flags.Lockpicking != Lockpicking.None)
{
EnableLockpicking();
SetLockpickingLevel(flags.LockpickingLevelRequirement);
Expand Down
2 changes: 1 addition & 1 deletion FF1Lib/Flags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ public class Flags : IIncentiveFlags, IMapEditFlags, IScaleFlags, IFloorShuffleF

public bool? TouchIncludeBosses { get; set; } = false;

public bool? Lockpicking { get; set; } = false;
public Lockpicking Lockpicking { get; set; } = Lockpicking.None;

public bool? ReducedLuck { get; set; } = false;

Expand Down
5 changes: 3 additions & 2 deletions FF1Lib/FlagsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4870,13 +4870,14 @@ public SpellNameMadness SpellNameMadness
}
}

public bool? Lockpicking

public Lockpicking Lockpicking
{
get => Flags.Lockpicking;
set
{
Flags.Lockpicking = value;
RaisePropertyChanged();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Lockpicking"));
}
}

Expand Down
7 changes: 2 additions & 5 deletions FF1Lib/Lockpicking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public void EnableLockpicking()
{
//put in the base hack: see 1B_9300_LockpickDoors.asm for more info
PutInBank(0x1F, 0xCE53, Blob.FromHex("AA9848A91B2003FE200093C00168A88AB0ED"));
PutInBank(0x1B, 0x9300, Blob.FromHex("8A4A2903C902D059A2008645AE2560D050AE2661E009900BAE0061E001F042E007F03EAE6661E009900BAE4061E001F030E007F02CAEA661E009900BAE8061E001F01EE007F01AAEE661E009900BAEC061E001F00CE007F008A001AAA90E4C03FEA000AAA90E4C03FE"));
PutInBank(0x1B, 0x9300, Blob.FromHex("8A4A2903C902D03AA2008645AE2560D03148A90048A96885EDA9B285EEA000204C93D00ABE2661E009B0174C2E9318686940B005A8484C1F93A00168AAA90E4C03FEA0006868AAA90E4C03FEB90061C90C9002A90C8410A8B1EDC90108A4102860"));
}

public void SetLockpickingLevel(int requiredLevel)
Expand All @@ -15,10 +15,7 @@ public void SetLockpickingLevel(int requiredLevel)
if (requiredLevel > 0 && requiredLevel <= 50)
{
//level is stored zero based
PutInBank(0x1B, 0x9315, new byte[] { (byte)(requiredLevel - 1) });
PutInBank(0x1B, 0x9327, new byte[] { (byte)(requiredLevel - 1) });
PutInBank(0x1B, 0x9339, new byte[] { (byte)(requiredLevel - 1) });
PutInBank(0x1B, 0x934B, new byte[] { (byte)(requiredLevel - 1) });
PutInBank(0x1B, 0x9328, new byte[] { (byte)(requiredLevel - 1) });
}
}
}
Expand Down
104 changes: 60 additions & 44 deletions FF1Lib/asm/1B_9300_LockpickDoors.asm
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
.include "Constants.inc"
.include "Constants.inc"
.include "variables.inc"

SwapPRG = $FE03
SMMove_Norm_RTS = $CE52

class_lut_a = $ED
class_lut_b = $EE

;currently in the MENU_BANK
;this replacement could be a lot less bytes if we use a temporary memory to store A
;A gets overwriten by the bank swap method and we cant grab it from the stack without some heavy stack manipulation
;A gets overwritten by the bank swap method and we cant grab it from the stack without some heavy stack manipulation
;so we store it in X to carry through bank swaps
.org $CE53
TAX
Expand All @@ -24,6 +27,13 @@ BCS SMMove_Norm_RTS ;save a byte by just branching to a nearby rts instead of ha
;exact change replacing 18 bytes at CE53
;AA 98 48 A9 1B 20 03 FE 20 00 93 C0 01 68 A8 8A B0 ED


.ORG $B268 ; for reference
lut_Lockpicking:
.BYTE $00, $00, $00, $00, $00, $00
.BYTE $00, $00, $00, $00, $00, $00
.BYTE $00

;bank 1b
.ORG $9300
CheckDoorLocked:
Expand All @@ -37,58 +47,64 @@ CheckDoorLocked:
STX tileprop+1 ; erase the secondary attribute byte (prevent it from being a locked shop)
LDX item_mystickey ; check to see if the player has the key
BNE DoorUnlocked ; if they do, open the door
;all of this checking is rom space ineffecient but I don't know if we have available temp memory to do an index
;all of this checking is rom space inefficient but I don't know if we have available temp memory to do an index
;check to see if they have a thief/ninja in the party, and they're at or above level 10, the class and level are randomizable at rom creation
LDX ch_level
CPX #$09
BCC Slot1UnderLeveled
LDX ch_class
CPX #$01
BEQ DoorUnlocked
CPX #$07
BEQ DoorUnlocked

Slot1UnderLeveled:
LDX ch_level+$40
CPX #$09
BCC Slot2UnderLeveled
LDX ch_class+$40
CPX #$01
BEQ DoorUnlocked
CPX #$07
BEQ DoorUnlocked

Slot2UnderLeveled:
LDX ch_level+$80
CPX #$09
BCC Slot3UnderLeveled
LDX ch_class+$80
CPX #$01
BEQ DoorUnlocked
CPX #$07
BEQ DoorUnlocked

Slot3UnderLeveled:
LDX ch_level+$C0
CPX #$09
BCC Slot4UnderLeveled
LDX ch_class+$C0
CPX #$01
BEQ DoorUnlocked
CPX #$07
BEQ DoorUnlocked
PHA
LDA #$00
PHA
LDA #<lut_Lockpicking
STA class_lut_a
LDA #>lut_Lockpicking
STA class_lut_b
LDY #$00
CheckLockpicking:
; check to see if they have the Lockpicking bonus
JSR CheckIfClass
BNE NextClass
CheckLevel:
LDX ch_level,Y
CPX #$09
BCS DoorUnlocked
JMP NextClass
NextClass:
CLC
PLA
ADC #$40
BCS UnderLeveled
TAY
PHA
JMP CheckLockpicking

Slot4UnderLeveled:
UnderLeveled:
LDY #$01
PLA
TAX
LDA #BANK_MENUS
JMP SwapPRG

DoorUnlocked:
LDY #$00
PLA
PLA
TAX
LDA #BANK_MENUS
JMP SwapPRG

;105 bytes
;8A 4A 29 03 C9 02 D0 59 A2 00 86 45 AE 25 60 D0 50 AE 26 61 E0 09 90 0B AE 00 61 E0 01 F0 42 E0 07 F0 3E AE 66 61 E0 09 90 0B AE 40 61 E0 01 F0 30 E0 07 F0 2C AE A6 61 E0 09 90 0B AE 80 61 E0 01 F0 1E E0 07 F0 1A AE E6 61 E0 09 90 0B AE C0 61 E0 01 F0 0C E0 07 F0 08 A0 01 AA A9 0E 4C 03 FE A0 00 AA A9 0E 4C 03 FE
CheckIfClass:
LDA ch_class, Y
CMP #$0C
BCC NotANone
LDA #$0C

NotANone:
STY tmp
TAY
LDA (class_lut_a), Y
CMP #$01
PHP
LDY tmp
PLP
RTS

;97 bytes
;8A4A2903C902D03AA2008645AE2560D03148A90048A96885EDA9B285EEA000204C93D00ABE2661E009B0174C2E9318686940B005A8484C1F93A00168AAA90E4C03FEA0006868AAA90E4C03FEB90061C90C9002A90C8410A8B1EDC90108A4102860
5 changes: 5 additions & 0 deletions FF1Lib/asm/1B_B000_StartWithRoutines.asm
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,11 @@ lut_WoodArmors:
.BYTE $00, $00, $00, $00, $00, $00
.BYTE $FF

lut_Lockpicking:
.BYTE $00, $00, $00, $00, $00, $00
.BYTE $00, $00, $00, $00, $00, $00
.BYTE $00

.ORG $B300

ApplyStartOfGame:
Expand Down