[FF8] Editing the contents of Draw points

  • Thread starter Thread starter Callisto
  • Start date Start date
Status
Not open for further replies.
C

Callisto

Guest
With the help of Deling Field editor I found that each Draw point is tied to a different ID, and this ID determines which spell can be drawn from that Draw point. For example, the Draw point near the Balamb Garden entrance is ID#1 and contains Cure. Deling allows swapping these ID's, so if I wanted Blizzaga to be in that Draw point, I could change its ID to 14, which would be the hidden Blizzaga Draw point inside the Timber Maniacs building. Problem is that there would be two Draw points sharing the same ID after that change. If I drew from one, both would be empty, so this solution is rather suboptimal. Sure, I could just put Cure from Balamb Garden into the Timber Maniacs Draw point, but I would rather prefer a complete revamp of the spells found in Draw points, without putting cheap spells elsewhere.

Long story short: Does anyone know of another, more direct way to change the contents of Draw points? I assume there must be a list stored somewhere, which contains the ID's and the spells they are linked to.
 
Ran memory value change for byte based on SETDRAWPOINT
Got three variables for BalambCity:
Code: [Select]
Code:
19ad6341cfec8118f334c
Scanned all of them to find the independent one that carried only draw value and got there:
.text:0052B69C loc_52B69C [FF8.exe 1.0 2000], SETDRAWPOINT value is held on EDX. There are some operations, but still it gets to this point eventually:
Code: [Select]
Code:
.text:0052B6CA                 push    edx.text:0052B6CB                 call    00474790
From here the variable is copied over the static data at .data:01CDC1C2
and used later in .text:004751C0
I'm still searching for array for you.

I have found no array, but... Callisto, are you sure the draw point has an ID? For example changing:
PSHN_L      14
SETDRAWPOINT
makes the draw point hidden, but still thunder.
Furthermore, I noticed that it's not draw ID, but just a bool byte. If:
SETDRAWPOINT(0) the drawpoint is visible, if not, then hidden.
To prove this, here's the check code for this:
Code: [Select]
Code:
.text:004751C0                 cmp     SetSavePoint, 1.text:004751C8                 jnz     short loc_4751E2
However, I was able to edit only the magic by changing:
137:talk:
Code: [Select]
Code:
PSHN_L      <magic>DRAWPOINT
EDIT:
Yes. Sorry, my bad. You've been already writing about the talk script, not default. Let's start again but searching this variable.

Code: [Select]
Code:
 .text:00522632                 mov     eax, [edi+eax*4] ; Holds drawID
eax is pushed to sub_52D090:

&(AND) of 0xFF to variable is performed.
And I found the array[256]:
Code: [Select]
Code:
.data:00B92500 byte_B92500     db 55h, 44h, 99h, 9Bh, 0Dh, 0CCh, 0C7h, 0D5h, 0C1h, 0E9h.data:00B92500                                         ; DATA XREF: sub_52D090+9r.data:00B92500                 db 0E6h, 72h, 55h, 6, 0E3h, 0D8h, 0DEh, 0DDh, 21h, 0A0h.data:00B92500                 db 55h, 4Ah, 48h, 70h, 5Bh, 4Ch, 0C2h, 0EEh, 9, 4Bh, 0C5h.data:00B92500                 db 0E6h, 59h, 0ECh, 0DCh, 17h, 1Fh, 0DDh, 0EFh, 56h, 0E3h.data:00B92500                 db 0DEh, 0DAh, 19h, 93h, 0C9h, 10h, 57h, 44h, 0D1h, 52h.data:00B92500                 db 0E1h, 2Dh, 0Fh, 65h, 65h, 0D8h, 1Fh, 0EBh, 0Eh, 69h.data:00B92500                 db 13h, 67h, 6Ah, 0D0h, 57h, 64h, 57h, 0Fh, 8Eh, 68h, 0E7h.data:00B92500                 db 4Bh, 2Ch, 2Dh, 0C9h, 30h, 20h, 0D3h, 46h, 43h, 0D2h.data:00B92500                 db 0CEh, 56h, 58h, 19h, 5Ch, 5Bh, 0A2h, 13h, 0F1h, 10h.data:00B92500                 db 0E3h, 0E4h, 0D7h, 0D8h, 0E5h, 0DAh, 0E1h, 22h, 0Fh.data:00B92500                 db 57h, 56h, 72h, 5Bh, 64h, 5Ch, 65h, 58h, 0Fh, 20h, 0Eh.data:00B92500                 db 10h, 31h, 13h, 19h, 22h, 81h, 81h, 81h, 81h, 81h, 81h.data:00B92500                 db 81h, 81h, 81h, 81h, 81h, 55h, 5Bh, 47h, 42h, 48h, 45h.data:00B92500                 db 44h, 41h, 55h, 4Ah, 56h, 5Bh, 72h, 5Eh, 63h, 4Bh, 4Ch.data:00B92500                 db 58h, 4Dh, 5Dh, 4Eh, 49h, 65h, 43h, 5Ah, 46h, 67h, 4Fh.data:00B92500                 db 5Ch, 64h, 51h, 57h, 52h, 19h, 5Fh, 20h, 11h, 61h, 6Ah.data:00B92500                 db 10h, 13h, 22h, 67h, 66h, 0D1h, 68h, 69h, 0CFh, 6Bh.data:00B92500                 db 6Ch, 0EDh, 6Eh, 6Fh, 70h, 71h, 93h, 0D2h, 0D1h, 0D0h.data:00B92500                 db 0CEh, 0CFh, 0E0h, 0D3h, 0E2h, 0D9h, 0D2h, 0D1h, 0D0h.data:00B92500                 db 0CEh, 0CFh, 0E0h, 0D3h, 0E2h, 0D9h, 0D2h, 0D1h, 0D0h.data:00B92500                 db 0CEh, 0CFh, 0E0h, 0D3h, 0E2h, 0D9h, 0D3h, 0D0h, 0CEh.data:00B92500                 db 0CFh, 0E0h, 0D3h, 0E2h, 0D9h, 0D0h, 0CEh, 0E2h, 0E0h.data:00B92500                 db 0D3h, 0E2h, 0D9h, 0D0h, 0CEh, 0CFh, 0E0h, 0D3h, 0E2h.data:00B92500                 db 0D9h, 0D0h, 0E2h, 0CFh, 0E0h, 0D3h, 0E2h, 0D9h, 0D0h.data:00B92500                 db 0CEh, 0CFh, 0E0h, 0D3h, 44h, 55h, 0DCh, 0E7h, 10h, 21h.data:00B92500                 db 20h, 0Eh, 0Fh, 13h, 0F2h
Tip!
The ID is ID-1, so with the AND of 0xFF, then if:
PSHN_L      0
then realDrawID from above array is 255


Yep. Just tested. You can edit the magic associated with the draw in realtime:
test.jpg


tl;dr
Array is at 00B92500 and is 256 elements : byte.
Code: [Select]
Code:
TALK:PSHN_L      1DRAWPOINT
where PSHN_L should be subtracted by 1 to get real array index. You can freely overflow the 255 limit. It's coded to deal with such cases.
 
Last edited:
Nice work :).
Any idea if the upper 2 bits do anything?
looking at this list

Cure has a magic ID of 0x15 but it's listed as 0x55 in the table... looking at the binary:
Code: [Select]
Code:
HEX  BIN0x15 000101010x55 01010101
seems like the upper 2 bits are ignored or they're doing something else - might be one of the bits is a boolean that controls if it's refilled or not, see this list
The highest magic ID is 0x38, so it makes sense that it can fit into 6 bits.
 
Last edited:
Hm, not sure if I got that right. Maybe an example would help.

Let's say, I want to put Water instead of Thunder inside the Draw point pictured above. What changes would I have to apply, and where? Without just searching for a Draw point that contains Water and changing the DRAWPOINT value in talk script accordingly (which can cause problems, as I said earlier). Using the Steam Version of FF VIII by the way.

Anyway, thank you for your help so far. Much appreciated.
 
You'd either have to hex edit the exe or edit the values in memory.
In my case the values are at offset 0xB92328 or offset 0x792328 in the exe (I just searched for the bytes in the code that MaKiPL showed).

Say you wanted to edit the draw point of ID 15, you first subtract 1 from it to get the index in the array.
This gives us 14 (0x0E), then you'd add this to the start offset of the array.
This means that you would change the value at 0x792336 in the exe.
 
Last edited:
Here's a list of the draw points as they are in the array using the descriptions from here
I might finish the descriptions off later.

Code: [Select]
Code:
001 0 1 Cure - Balamb Garden courtyard002 0 1 Blizzard - Balamb Garden training center003 1 0 Full-Life - Balamb Garden MD level004 1 0 Esuna - Balamb Garden library next to the book shelf005 0 0 Demi - Balamb Garden cafeteria (only during Garden Riot)006 1 1 Bio - Balamb Garden B2 floor007 1 1 Thunder - Balamb outside junk shop008 1 1 Cure - Balamb harbor009 1 1 Fire - Fire Cavern010 1 1 Silence - Dollet town square011 1 1 Blind - Dollet Communications Tower012 0 1 Scan - Timber Pub Aurora back alley013 0 1 Cure - Timber outside the pub014 0 0 Blizzaga - Timber Maniacs Building left room015 1 1 Haste - Galbadia Garden lobby016 1 1 Life - Galbadia Garden changing rooms017 1 1 Shell - Galbadia Garden courtyard018 1 1 Protect - Galbadia Garden ice rink019 0 0 Double - Galbadia Garden auditorium020 1 0 Aura - Outside Galbadia Garden during Garden war021 0 1 Cure - Timber forests in a Laguna dream022 0 1 Water - Timber forests in a Laguna dream023 0 1 Thundara - Deling City park024 0 1 Zombie - Deling City Sewers025 0 1 Esuna - Deling City Sewers026 0 1 Bio - Deling City Sewers027 1 1 Fira028 1 1 Berserk - D-District Prison Floor 9 - right cell029 0 0 Thundaga - D-District Prison Floor 11 - right cell030 0 1 Aero - Outside D-District Prison031 1 1 Blizzara - Missile Base - control room032 1 1 Blind - Missile Base room with G-Soldiers who ask to deliver a message033 0 1 Full-Life - Missile Base - silo room034 1 1 Drain - Winhill road south from town square035 1 1 Dispel - Winhill town square036 0 0 Curaga - Winhill Laguna's room in the dream037 0 0 Reflect - Winhill east road038 1 1 Protect - Tomb of the Unknown King - outside039 1 1 Float - Tomb of the Unknown King - north room040 0 1 Cura - Tomb of the Unknown King - east room041 1 1 Haste - Fishermans Horizon abandoned train station042 1 1 Shell - Fishermans Horizon junk shop043 1 1 Regen - Fishermans Horizon overlooking the sun panel044 0 0 Full-Life - Fishermans Horizon Master Fisherman's fishing spot045 1 0 Ultima - Fishermans Horizon mayor's house046 1 1 Thundaga - Great Salt Lake past the dinosaur skeleton047 0 0 Meteor - Great Salt Lake dinosaur skeleton048 0 1 Curaga - Esthar city streets near city entrance049 0 1 Blizzard - Esthar outside palace050 1 1 Quake - Esthar outside Odine's Lab051 0 1 Tornado - Esthar shopping mall052 1 1 Double - Esthar Odine's Lab in a Laguna dream053 0 0 Pain054 0 0 Flare - Esthar Odine's Lab in a Laguna dream055 0 1 Stop - Sorceress Memorial056 0 1 Stop057 1 1 Life - Tears' Point entrance058 0 0 Reflect - Tears' Point middle059 1 1 Death - Lunatic Pandora Laboratory in a Laguna dream060 0 0 Holy - Lunatic Pandora near Elevator #1061 0 1 Silence - Lunatic Pandora062 0 0 Ultima - Lunatic Pandora063 0 1 Confuse064 0 1 Break - Lunatic Pandora on the way to fight Adel065 1 1 Meteor - Lunatic Pandora entrance066 0 1 Curaga - Lunatic Pandora elevator room067 0 1 Slow068 0 1 Curaga - Edea's Orphanage069 0 0 Flare070 1 0 Holy071 0 1 Sleep - Centra Excavation Site072 1 1 Confuse - Centra Excavation Site073 0 1 Aero - Centra Ruins right ladder after the lift074 0 0 Drain - Centra Ruins platform after the first staircase075 0 0 Pain - Centra Ruins next to the dome076 1 1 Thundaga - Trabia Garden in front of the statue077 0 0 Zombie - Trabia Garden cemetery078 0 0 Aura - Trabia Garden stage079 1 1 Ultima - Shumi Village - above ground080 0 1 Blizzaga - Shumi Village - outside elder's house081 0 1 Firaga - Shumi Village workshop082 1 1 Tornado083 1 1 Holy - White SeeD Ship084 0 1 Cura - Ragnarok room with a red Propagator085 0 1 Life - Ragnarok hangar upstairs086 0 0 Full-Life - Ragnarok room with save point087 0 1 Dispel - Deep Sea Research Center second level088 0 1 Esuna - Deep Sea Research Center secret room089 1 0 Triple - Deep Sea Research Center third screen on the way to Ultima Weapon's lair090 0 0 Ultima - Deep Sea Research Center fifth screen on the way to Ultima Weapon's lair091 1 1 Meltdown - Lunar Base room before the escape pods092 0 0 Meteor - Lunar Base Ellone's room093 1 1 Haste094 1 1 Slow095 1 1 Curaga096 1 1 Life097 1 1 Stop098 1 1 Regen099 1 1 Double100 0 0 Triple101 0 0 Flare - Ultimecia Castle outside102 0 1 Curaga - Ultimecia Castle storage room103 0 1 Cura - Ultimecia Castle passageway104 0 1 Scan105 0 1 Esuna106 0 1 Slow - Ultimecia Castle courtyard107 0 1 Dispel - Ultimecia Castle chapel108 0 1 Stop - Ultimecia Castle clock tower109 0 1 Life110 0 0 Flare111 0 0 Aura - Ultimecia Castle wine cellar112 0 0 Holy - Ultimecia Castle treasure room113 0 0 Meteor114 0 0 Meltdown - Ultimecia Castle art gallery115 0 0 Ultima - Ultimecia Castle armory116 0 0 Full-Life - Ultimecia Castle prison117 0 0 Triple118 1 0 Fire119 1 0 Fire120 1 0 Fire121 1 0 Fire122 1 0 Fire123 1 0 Fire124 1 0 Fire125 1 0 Fire126 1 0 Fire127 1 0 Fire128 1 0 Fire129 0 1 Cure130 0 1 Esuna131 0 1 Thunder132 0 1 Fira133 0 1 Thundara134 0 1 Blizzara135 0 1 Blizzard136 0 1 Fire137 0 1 Cure138 0 1 Water139 0 1 Cura140 0 1 Esuna141 0 1 Scan142 0 1 Shell143 0 1 Haste144 0 1 Aero145 0 1 Bio146 0 1 Life147 0 1 Demi148 0 1 Protect149 0 1 Holy150 0 1 Thundaga151 0 1 Stop152 0 1 Firaga153 0 1 Regen154 0 1 Blizzaga155 0 1 Confuse156 0 1 Flare157 0 1 Dispel158 0 1 Slow159 0 1 Quake160 0 1 Curaga161 0 1 Tornado162 0 0 Full-Life163 0 1 Reflect164 0 0 Aura165 0 0 Quake166 0 1 Double167 0 1 Break168 0 0 Meteor169 0 0 Ultima170 0 0 Triple171 0 1 Confuse172 0 1 Blind173 1 1 Quake174 0 1 Sleep175 0 1 Silence176 1 1 Flare177 0 1 Death178 0 1 Drain179 1 1 Pain180 0 1 Berserk181 0 1 Float182 0 1 Zombie183 0 1 Meltdown184 1 0 Ultima185 1 1 Tornado186 1 1 Quake187 1 1 Meteor188 1 1 Holy189 1 1 Flare190 1 1 Aura191 1 1 Ultima192 1 1 Triple193 1 1 Full-Life194 1 1 Tornado195 1 1 Quake196 1 1 Meteor197 1 1 Holy198 1 1 Flare199 1 1 Aura200 1 1 Ultima201 1 1 Triple202 1 1 Full-Life203 1 1 Tornado204 1 1 Quake205 1 1 Meteor206 1 1 Holy207 1 1 Flare208 1 1 Aura209 1 1 Ultima210 1 1 Triple211 1 1 Full-Life212 1 1 Ultima213 1 1 Meteor214 1 1 Holy215 1 1 Flare216 1 1 Aura217 1 1 Ultima218 1 1 Triple219 1 1 Full-Life220 1 1 Meteor221 1 1 Holy222 1 1 Triple223 1 1 Aura224 1 1 Ultima225 1 1 Triple226 1 1 Full-Life227 1 1 Meteor228 1 1 Holy229 1 1 Flare230 1 1 Aura231 1 1 Ultima232 1 1 Triple233 1 1 Full-Life234 1 1 Meteor235 1 1 Triple236 1 1 Flare237 1 1 Aura238 1 1 Ultima239 1 1 Triple240 1 1 Full-Life241 1 1 Meteor242 1 1 Holy243 1 1 Flare244 1 1 Aura245 1 1 Ultima246 0 1 Blizzard247 0 1 Cure248 1 1 Dispel249 1 1 Confuse250 0 0 Meteor251 0 0 Double252 0 0 Aura253 0 0 Holy254 0 0 Flare255 0 0 Ultima256 1 1 Scan
The second bit listed controls if the drawpoint is refilled or not (1 = refills, 0 = doesn't refill).
See below post at EDIT2 for full explanation of what the first bit does.

In summary, the bytes in the array are set as follows:
magic_id
OR 0x40 if you can refill it
OR 0x80 to be able to draw more magic

to determine the parameters from the byte in the array you can do the following:
magic_id = byte & 0x3F
refill = (byte >> 6) & 1
extra_magic = byte >> 7
 
Last edited:
it looks like the UNKNOWN16 (0x175) function (as listed in Deling) binds the draw point to a variable since changing the parameter can cause the draw point to be restocked.
Generally this is the same as the draw point id but I'm not sure if this is always the case.
Aha! Found the variable in the save data, each draw point has 2 bits allocated to it starting at savegame + 0xDD4 (field vars 100-164) - 64 bytes are allocated to this.
0 = fully stocked
1 = partially stocked
2 = not stocked (white swirls - restocks)
3 = not stocked (blue swirls - doesn't restock)

the required byte is found by indexing by (drawpoint_id - 1)/4 and then it's shifted by the remainder*2 and then masked by anding with 3.

EDIT: I thought I was incorrect at first but it seems like the last draw point id seen (with 1 already subtracted) is stored in memory at savegame + 0xE52 (field var 226 - note this is what function UNKNOWN16 - 0x175 writes to) and the function for pulling the draw point data from memory (0x52D150) keeps getting called even if there isn't a draw point in the current scene - I mean aside from the restocking code.
I guess this also means that you can only have 1 draw point on a scene.

More on the draw point mechanics:
every 10,240 (0x2800) steps (the counter is reset after this - it's stored as a WORD in savegame + 0xE14 - field var 164), all of the draw points are checked to see if they need to be restocked.
For each draw point, a random number between 0 and 32,767 is calculated, this is then anded with 1 (x86 TEST opcode) to give a 50% chance that the draw point is restocked.
It also seems like there are 2 stages of stocking (the counter is decremented every time it is stocked to a minimum of zero) - might be that 0 means it's more likely to give more magic.

EDIT2:
the amount you can draw is determined as follows - for field draw points:
((rand[0-255] + 128)*draw_var)/512 + 1
draw_var is 20 if the MSB of the draw byte in the array is 1 (i.e. AND 0x80) and 10 otherwise, this is then halved if the draw point is partially stocked.
this gives a range of:
6-15 - fully stocked with bit set
3-8 - if partially stocked with bit set or fully stocked with bit not set
2-4 - if partially stocked with bit not set

For the world map:
((rand[0-255] + 128)*draw_var)/512 + 1
draw_var is 6 if the MSB of the draw byte in the array is 1 (i.e. AND 0x80) and 2 otherwise.
this gives a range of:
2-5 - with bit set
1-2 - with bit not set
 
Last edited:
Status
Not open for further replies.
Back
Top