Jump to content

[code] Code fixes, aka stuff we can't fix


CamDawg

Recommended Posts

OK, a quick test on the simulacrum level thing ... start a L7 fighter, dual to L20 mage. Give them spells to memorize at each level; 5/5/5/5/5/4/3/3/2 spell slots. Cast a simulacrum (from a level 8 slot), check memorization of clone.

I get 5/5/5/5/5/3/3/2/1 slots remaining. Drained to level 18; that's 0.4*7 = 2.8 rounded down to 2 levels drained.

Now, try the same thing with a thief -> mage dual. Start a level 8 thief, dual to a level 20 mage, fill slots in the same way and cast Simulacrum. This time, I get 4/4/4/4/4/1 slots remaining; the mage is drained to level 12. That's 0.4*20 = 8 levels drained.

All right, how about a conventional multiclass? Mage/thief at 8 million XP (level 20/28). Skip any extra spell slot HLAs. Spell slots on the simulacrum? 4/4/4/3/3. Drained to level 11. That's 0.4*((20+28)/2) = 9.6 rounded down to 9 levels drained.

All tests done in BG2EE, with vanilla rules. In both patch 2.5 and 2.6, since I can check that by just loading up the same save in a different instance of the game.

My conclusion? For true multiclass characters, Simulacrum uses average level to determine how many levels to drain. For dual-class characters, it uses the LEVEL stat, which may be either the original class or the second class. Mage/thief combinations will always use their mage level, while fighter/mage combinations will always use their fighter level; it depends on the order the classes are listed in in the multiclass definitions.

In all cases, the level drain is applied in the standard way; dual-class characters only suffer drain to their active (not original) class, while multiclass characters suffer drain to all their classes.

It's possible that older versions of the game had dual-class characters always use the original class, but if this was ever true it isn't in current BG2EE. That doesn't make things right as they are now, of course.

Edited by jmerry
Link to comment
1 hour ago, jmerry said:

OK, a quick test on the simulacrum level thing ... start a L7 fighter, dual to L20 mage. Give them spells to memorize at each level; 5/5/5/5/5/4/3/3/2 spell slots. Cast a simulacrum (from a level 8 slot), check memorization of clone.

I get 5/5/5/5/5/3/3/2/1 slots remaining. Drained to level 18; that's 0.4*7 = 2.8 rounded down to 2 levels drained.

Now, try the same thing with a thief -> mage dual. Start a level 8 thief, dual to a level 20 mage, fill slots in the same way and cast Simulacrum. This time, I get 4/4/4/4/4/1 slots remaining; the mage is drained to level 12. That's 0.4*20 = 8 levels drained.

Check real drain calculation, not spell slots. After generation of simulacrum save game, use NearInfinity on savegame, open baldur.sav, decompress area where simulacrum belong, look it in Actors, find drain effect, see # levels parameter.

Your F->M and T->M must have ((7(8)+20)/2 = 14) * 0.4= 5 or 6 levels drained

Link to comment
12 minutes ago, jmerry said:

Multiclass Thief 28/Mage 20: 9 levels drained.

Thief 8 -> Mage 20: 8 levels drained.

Fighter 7 -> Mage 20: 2 levels drained.

You're wrong. Evidence attached.

Confirm, i was wrong, BG2EE split dualclass to separate classes and uses active class (Mage) as single class to calculate average level. oBG2 doesn't have such split, it was specialy added to bg2ee code, i think when they fixed oBG2 50%(wrong) to 40% levels

Link to comment

Another fun bit on the simulacrum level drain: it's possible for the drain to instantly kill the clone before it can even appear, under certain circumstances. Here's a test you can run to reproduce it:

- Create a fighter in SoA. Level 7. Dual-class to cleric. Level 1. Give them Vhailor's helm, and use the ability. Animation plays, no clone appears.

- Create a ranger in SoA. Level 7. Dual-class to cleric. Level 1. Give them Vhailor's helm, and use the ability. The clone shows up.

What's the difference? The difference is that the two multiclasses are listed in opposite orders; fighter/cleric and cleric/ranger. In the former, fighter is first and is what the drain is based on - floor(7*0.4)=2 levels of drain kills the level 1 cleric. In the latter, cleric is first and is what the drain is based on - floor(1*0.4)=0 levels of drain lets the level 1 cleric survive.

Link to comment

There's a regression issue for wallpolys that appeared in 2.6 in that they do not work as well as they did in earlier patches. See attached image. The horns of the statue do not cover the character to the same extent as they used to.

WallPolyRegression.jpg

Edited by Galactygon
Link to comment
25 minutes ago, Galactygon said:

There's a regression issue for wallpolys that appeared in 2.6 in that they do not work as well as they did in earlier patches. See attached image. The horns of the statue do not cover the character to the same extent as they used to.

Another screenshot from the same area can be found here:

 

Link to comment

LOL we happened to test the same group of wallpolys!

Here's another unrelated issue and it's quite a nuissance: SPLPROT.2da doesn't recognize signed stat values. For example, STAT(RESISTFIRE)>=100 will return true if the creature has negative fire resistance. You'd basically have to use STAT(RESISTFIRE)>=100 && STAT(RESISTFIRE)<127 for the fire resistance check, which is 2 extra lines.

Link to comment

@Bubb

Can you confirm the following two script actions are bugged?

  • SetItemFlags()

    • The I:Flags*Invitem parameter appears to be broken...

  • CreateItemGlobal()

    • Completely broken...?

Example script below

Spoiler
IF
	OnCreation()
THEN
	RESPONSE #100
		SetGlobalRandom("gtcount","LOCALS",1,10)
		GiveItemCreate("arow04",Myself,99,0,0)  // Acid Arrow +1
		SetItemFlags("arow04",IDENTIFIED | NONSTEALABLE | NONDROPABLE,TRUE)  // Acid Arrow +1
		XEquipItem("arow04",Myself,SLOT_AMMO0,EQUIP)  // Acid Arrow +1
		CreateItemGlobal("gtcount","LOCALS","arow04")  // Acid Arrow +1
END

 

 

Link to comment
37 minutes ago, Luke said:

Can you confirm the following two script actions are bugged?

  • SetItemFlags()

    • The I:Flags*Invitem parameter appears to be broken...

It looks like this action doesn't work if two or more instances of the same item exist in the inventory. I haven't noticed any issues with CreateItemGlobal() though.

Link to comment
3 hours ago, argent77 said:

It looks like this action doesn't work if two or more instances of the same item exist in the inventory.

Indeed. It seems it cannot handle stackable items... Needs fix...

3 hours ago, argent77 said:

I haven't noticed any issues with CreateItemGlobal() though.

Could you please provide a minimal working example...?

Using the script block I put above nothing happens 😕...

Link to comment
8 minutes ago, Luke said:
3 hours ago, argent77 said:

I haven't noticed any issues with CreateItemGlobal() though.

Could you please provide a minimal working example...?

Using the script block I put above nothing happens 😕...

I tested with this party script:

IF
  HotKey(D)
THEN
  RESPONSE #100
    SetGlobalRandom("a7count","LOCALS",1,20)
    CreateItemGlobal("a7count","LOCALS","arow04")
    XEquipItem("arow04",Myself,SLOT_AMMO0,EQUIP)
    SetItemFlags("arow04",11,TRUE)  // IDENTIFIED | NONSTEALABLE | NONDROPABLE
END

It did everything I would expect from the script. A random number of arrows are created and placed into the ammo slot where it is identified and made unremovable.

Link to comment
12 minutes ago, Bubb said:

Remember that SetGlobalRandom()'s result is only visible on the next script pass. As it is now the block needs to run twice.

OK, so how do I fix it...?

I want it to run every time the game is loaded / the area in which the actor is present is visited (that is why the OnCreation() trigger...)

Link to comment
45 minutes ago, Bubb said:

Remember that SetGlobalRandom()'s result is only visible on the next script pass. As it is now the block needs to run twice.

For some reason the result of this action was picked up correctly in the same script round in my tests.

 

15 minutes ago, Luke said:

I want it to run every time the game is loaded / the area in which the actor is present is visited (that is why the OnCreation() trigger...)

You could run the actions in two script passes:

IF
  OnCreation()
  !Global("DoIt","MYAREA",1)
THEN
  RESPONSE #100
    SetGlobal("DoIt","MYAREA",1)
    Continue()
END

IF
  Global("DoIt","MYAREA",1)
THEN
  RESPONSE #100
    SetGlobal("DoIt","MYAREA",0)
    // Your actions...
    Continue()
END

*The Continue()s are not strictly needed but recommended for compatibility reasons.

Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...