NPC starting XP adjustments
Sikorsky
Member Posts: 402
Is this a new v2.0 feature? Now when NPC join your party they exp is scaled with CHARNAME but they are on level 1 and you can level them up by yourself. For me it's great for the NPC that you can join only later in game. Now you can spend the proficency points and thieving skills like you want it. What do you think about that?
Post edited by AlexT on
11
Comments
If it is a bug, I hope no-one fixes it.
Very useful indeed!
It's especially important with SoD in mind, when you'll (possibly) start BG2 with higher levels than before, so would want to spend all those shiny proficiencies and abilities on NPCs the way YOU want.
The same happens in BG2, with NPCs startin not of the 1st level.
So, this thing is covered by the new patch, don't worry, with NPCs starting rather not of the 1st level, but of their minimum game level (3 in case of Coran), after which you level them up as you want.
I like it, as otherwise I feel forced to rush over to NPCs I want to make sure the game doesn't give them any weird proficiency and skill slots that I don't want them to have. Now I can just continue the story in the normal flow and encounter them naturally.
Once in a blue moon even Beamdog manages to do something right
N.B.: this is as close as a compliment you'll get from me
@Erg I'm quoting this so you can never take it back.
For the dual-classed characters you start with their minimum BG2 version, when they have already dual-classed, i.e. you can't change anything in their first class, but can still develop their second class.
For example,
Imoen - Thief 7/Mage 8+XP based on your main character's XP
Anomen - Fighter 7/Cleric 9+XP based on your main character's XP
Nalia - Thief 4/Mage 9+XP based on your main character's XP
Normally, NPCs have two or three different character files, each indicating them at different levels. When you first encounter them, the game picks a file based on your current XP. Say an NPC has two character files, one at level 2, and one at level 6.
Normally, if you rush over to the NPC when you're still low level, you'll get the level 2 version of the NPC, whereas if you first do a bunch of sidequests, and are of higher level, you'll get the level 6 version of the NPC. The level 6 version has already gained additional levels, and placed weapon proficiency and skill points where you don't like them to be.
What this change does is always use the lowest level file, level 2 in the above example, and then give that character an amount of XP based on the PCs current amount of XP, so you can immediately level him up, and then assign the proficiency points yourself.
It still uses one of the pregenerated sheets, it just always uses the lowest level available, so you don't need to rush over to a certain NPC to recruit it, worried that if you wait, a higher level with oddly placed proficienty points is used instead.
The Dualclass characters are already Dualclass in the lowest level file of their character, so they remain Dualclass under this system.
@Thels
not exactly.
I don't know the details of Beamdog implementation, but the "right way to do it" still requires using different files for different levels as before.
The only difference should be that the higher level versions are not fully levelled and their proficiencies, skills, etc are not fully assigned, but they must still differ from the lower level variants in terms of things like equipment, known wizard spells, etc.
I'm confused. What I'm describing is the method used by BG2 Tweaks.
This component will alter all joinable NPCs to join in the same fashion as Throne of Bhaal, where NPCs immediately level-up upon joining, with a caveat: all creature files are moved down to their lowest experience version, so if you pick up an NPC early enough they will not level upon joining. However, later in the game they will, allowing you to select weapon proficiencies, thieving points, and other goodies from the level-up process.
Notice where it says "all creature files are moved down to their lowest experience version". If I understand this correctly, that means it always uses the lowest level version of each character, not?
No.
For example Ajantis has three CRE files (AJANTI.CRE, AJANTI4.CRE, AJANTI6.CRE).
The code in "ToB-Style NPCs" start by overwriting AJANTI4.CRE and AJANTI6.CRE with a copy of AJANTI.CRE (this is indeed the "moving down to their lowest experience version" part), but subsequently the copies are modified so AJANTI4.CRE and AJANTI6.CRE will still have better equipment than AJANTI.CRE (e.g. AJANTI.CRE has a Chain Mail, AJANTI4.CRE has a Splint Mail and AJANTI6.CRE has a Plate Mail).
And it isn't just equipment, also other stuff is modified back to whatever the higher lever version had, like known spells, scripts, etc. For a full list see the code under the spoiler tag:
SET "orig_xp" = 0
INNER_PATCH_FILE ~%DEST_FILE%~ BEGIN // read info from file about to be overwritten
READ_LONG 0x2a0 "orig_known_off"
READ_LONG 0x2a4 "orig_known_num"
READ_LONG 0x2a8 "orig_meminfo_off"
READ_LONG 0x2b0 "orig_memspl_off"
READ_LONG 0x2b4 "orig_memspl_num"
READ_LONG 0x2b8 "orig_slot_off"
READ_LONG 0x2bc "orig_item_off"
READ_LONG 0x2c0 "orig_item_num"
READ_LONG 0x18 "orig_xp"
READ_SHORT 0x28 "orig_anim"
READ_ASCII 0x280 "orig_dv" (18)
READ_ASCII 0x34 "orig_portraits" (16)
READ_ASCII 0x248 "orig_scripts" (40)
READ_ASCII 0x2cc "orig_dialogue" (8)
READ_ASCII "%orig_slot_off%" "orig_slot_info" (78)
READ_ASCII "%orig_meminfo_off%" "orig_meminfo_info" (272)
READ_ASCII "%orig_item_off%" "orig_item_info" (0x14 * "%orig_item_num%")
READ_ASCII "%orig_known_off%" "orig_known_info" (0x0c * "%orig_known_num%")
READ_ASCII "%orig_memspl_off%" "orig_memspl_info" (0x0c * "%orig_memspl_num%")
END
PATCH_IF (("%orig_xp%" != 0) AND (SOURCE_SIZE > 0x2d3)) BEGIN // only true if read from destination file is successful and source exists
WRITE_LONG 0x18 "%orig_xp%"
WRITE_SHORT 0x28 "%orig_anim%"
WRITE_EVALUATED_ASCII 0x34 "%orig_portraits%" #16
WRITE_EVALUATED_ASCII 0x248 "%orig_scripts%" #40
WRITE_EVALUATED_ASCII 0x2cc "%orig_dialogue%" #8
WRITE_EVALUATED_ASCII 0x280 "%orig_dv%" #18
READ_LONG 0x2a0 "known_off"
READ_LONG 0x2a4 "known_num"
READ_LONG 0x2a8 "meminfo_off"
READ_LONG 0x2b0 "memspl_off"
READ_LONG 0x2b4 "memspl_num"
READ_LONG 0x2b8 "slot_off"
READ_LONG 0x2bc "item_off"
READ_LONG 0x2c0 "item_num"
READ_LONG 0x2c4 "fx_off"
WRITE_EVALUATED_ASCII "%slot_off%" "%orig_slot_info%"
WRITE_EVALUATED_ASCII "%meminfo_off%" "%orig_meminfo_info%"
// transfer memorized spells
SET "offset" = (0x0c * ("%orig_memspl_num%" - "%memspl_num%"))
PATCH_IF ("%offset%" > 0) BEGIN
INSERT_BYTES "%memspl_off%" "%offset%"
END ELSE
PATCH_IF ("%offset%" < 0) BEGIN
DELETE_BYTES "%memspl_off%" (0 - "%offset%")
END
WRITE_EVALUATED_ASCII "%memspl_off%" "%orig_memspl_info%"
WRITE_LONG 0x2b4 "%orig_memspl_num%"
PATCH_IF NOT ("%memspl_off%" > "%meminfo_off%") BEGIN
SET "meminfo_off" = "%meminfo_off%" + "%offset%"
END
PATCH_IF NOT ("%memspl_off%" > "%known_off%") BEGIN
SET "known_off" = "%known_off%" + "%offset%"
END
PATCH_IF NOT ("%memspl_off%" > "%slot_off%") BEGIN
SET "slot_off" = "%slot_off%" + "%offset%"
END
PATCH_IF NOT ("%memspl_off%" > "%item_off%") BEGIN
SET "item_off" = "%item_off%" + "%offset%"
END
PATCH_IF NOT ("%memspl_off%" > "%fx_off%") BEGIN
SET "fx_off" = "%fx_off%" + "%offset%"
END
// transfer items
SET "offset" = (0x14 * ("%orig_item_num%" - "%item_num%"))
PATCH_IF ("%offset%" > 0) BEGIN
INSERT_BYTES "%item_off%" "%offset%"
END ELSE
PATCH_IF ("%offset%" < 0) BEGIN
DELETE_BYTES "%item_off%" (0 - "%offset%")
END
WRITE_EVALUATED_ASCII "%item_off%" "%orig_item_info%"
WRITE_LONG 0x2c0 "%orig_item_num%"
PATCH_IF NOT ("%item_off%" > "%known_off%") BEGIN
SET "known_off" = "%known_off%" + "%offset%"
END
PATCH_IF NOT ("%item_off%" > "%meminfo_off%") BEGIN
SET "meminfo_off" = "%meminfo_off%" + "%offset%"
END
PATCH_IF NOT ("%item_off%" > "%memspl_off%") BEGIN
SET "memspl_off" = "%memspl_off%" + "%offset%"
END
PATCH_IF NOT ("%item_off%" > "%slot_off%") BEGIN
SET "slot_off" = "%slot_off%" + "%offset%"
END
PATCH_IF NOT ("%item_off%" > "%fx_off%") BEGIN
SET "fx_off" = "%fx_off%" + "%offset%"
END
// transfer known spells
SET "offset" = (0x0c * ("%orig_known_num%" - "%known_num%"))
PATCH_IF ("%offset%" > 0) BEGIN
INSERT_BYTES "%known_off%" "%offset%"
END ELSE
PATCH_IF ("%offset%" < 0) BEGIN
DELETE_BYTES "%known_off%" (0 - "%offset%")
END
WRITE_EVALUATED_ASCII "%known_off%" "%orig_known_info%"
WRITE_LONG 0x2a4 "%orig_known_num%"
PATCH_IF NOT ("%known_off%" > "%meminfo_off%") BEGIN
SET "meminfo_off" = "%meminfo_off%" + "%offset%"
END
PATCH_IF NOT ("%known_off%" > "%memspl_off%") BEGIN
SET "memspl_off" = "%memspl_off%" + "%offset%"
END
PATCH_IF NOT ("%known_off%" > "%slot_off%") BEGIN
SET "slot_off" = "%slot_off%" + "%offset%"
END
PATCH_IF NOT ("%known_off%" > "%item_off%") BEGIN
SET "item_off" = "%item_off%" + "%offset%"
END
PATCH_IF NOT ("%known_off%" > "%fx_off%") BEGIN
SET "fx_off" = "%fx_off%" + "%offset%"
END
// commit offset changes
WRITE_LONG 0x2a0 "%known_off%"
WRITE_LONG 0x2a8 "%meminfo_off%"
WRITE_LONG 0x2b0 "%memspl_off%"
WRITE_LONG 0x2b8 "%slot_off%"
WRITE_LONG 0x2bc "%item_off%"
WRITE_LONG 0x2c4 "%fx_off%"
END
END
From the looks of it, Ajantis always has a Chain mail, i.e. there's no way to meet Ajantis with a Splint Mail or a Plate Mail now.
So, the beta works differently from the "ToB-Style NPCs" mod component.
Well. That's disappointing and it could get worse.
I wonder how wizards are handled. For example Edwin, at low level, knows only Color Spray and Armor, but at higher level is supposed to know already also Larloch's Minor Drain, Melf's Acid Arrow, Mirror Image, Horror, Haste and Monster Summoning I. Does that mean that in 2.0 Edwin only knows a couple of level 1 spells even when recruited by an high level main char?
I can't check myself because I don't have the beta.
That's correct. But it's something that we can definitely look at addressing (along with the equipment thing mentioned earlier). Probably not for this release, but it's already in our lists.
If you are planning to revise this feature, you should really take a look at the code in "Level 1 NPCs", because it is more advanced than the one in "BG2 Tweaks"/"The Tweaks Anthology" and includes additional handy features like the optional one-time-only rest script.