-
Posts
2,793 -
Joined
-
Last visited
Content Type
Forums
Events
Downloads
Gallery
Mods
News
Store
Posts posted by Ardanis
-
-
Try wrapping it into ~SetInterrupt(FALSE) /* ... */ SetInterrupt(TRUE)~. I don't remember if it works on actors only or from area/global scripts as well, but uninterruptible actions prevent saving until they're complete.
-
See my post edit, NCPLEVEL.2DA may be an automatic solution for your problem. May be, I don't know for a fact.
PS SoD's versions of those tables are NPCLVLDS and BDDIALOG, vanilla are NPCLEVEL, NPCLVL25 and PDIALOG. Consider using only vanilla files to test the code
-
BIO strref means nothing, really.
Check if creature's script name exists in PDIALOG.2DA, iirc this is how they're normally detected as valid party members.
What Kathos said about SoD also applies, there maybe special cases when a character is supposed to be high enough level for plot purpose, either as ally or as enemy.
PS Have a look at NPCLEVEL.2DA, should be possible to replace all level 2+ CREs with level 1 version, so even if you face an NPC as a high level boss, when they JoinParty() they'll drop to level 1 (I think it works this way). EE v2.0 has actually done exactly that, basically killing the entire purpose of that table and replacing the level growth with scripted XP adjustment, so you may need to fix that if it blocks your design.
-
It's possible to separate them if you really want to. IIRC this works - kick both out, tell the first NPC to go to camp, and accept the second character back. The only "hardcoded" rule is that Edwin and Minsc/Dyna refuse to be together in party.
-
This is most likely due to the missing MakeGlobalOverride() for Minsc/Dyna in Three Kegs, which may result in duplicate copies of them in the .GAM save file if you recruit them. This will be fixed in the official SoD patch.
-
Oh FFS. Had known sooner I wouldn't have wasted any time on this.Temnix/Chimeric is against modder prefixes.
https://forums.beamdog.com/discussion/comment/795932/#Comment_795932
Ignorance is bliss
-
- Goddamn Cromwell shouldn't goddamn take a whole goddamn day to goddamn forge his goddamn stuff.
COPY_EXISTING cromwell.bcs override DECOMPILE_AND_PATCH BEGIN REPLACE_TEXTUALLY ~RestParty\(Ex\)?(.*)[%WNL%%LNL%%MNL%%TAB% ]+AdvanceTime(.+)~ ~~ END BUT_ONLY ACTION_IF FILE_EXISTS_IN_GAME cutskip2.bcs BEGIN // if pre-EE v2.0 COPY_EXISTING cutskip2.bcs override DECOMPILE_AND_PATCH BEGIN REPLACE_TEXTUALLY ~ActionOverride("wsmith01",Face(\(SE\|14\)))[%WNL%%LNL%%MNL%%TAB% ]+RestParty\(Ex\)?(.*)[%WNL%%LNL%%MNL%%TAB% ]+AdvanceTime(.+)~ ~ActionOverride("wsmith01",Face(SE))~ END BUT_ONLY END
-
Loading the item file in DLTCEP and saving it should be enough, it auto-corrects the offset structure.
-
My version was like:
Preliminary:
- Scan all official areas for triggers, doors and containers that are trapped & detectable & have difficulty !=100.
- Manually review all the scripts on the obtained list and write appropriate "trap type is X" new string for each script. A few will need to be excluded, because even while they're set up as traps and detected as such by the check routine, they still aren't a trap.
- Now you have a list of trap scripts and a list of detected type strings, match them up via associative array or something.
Prepare the script extension (top):
IF Range([PC],15) !GlobalTimerNotExpired("%script_name%","myarea") Global("%script_name%_detected","myarea",0) Global("%script_name%_disarmed","myarea",0) THEN RESPONSE #100 SetGlobalTimer("%script_name%","myarea",6) DisplayStringHead(Myself,~Trap Detected~) END IF Range([PC],15) !GlobalTimerNotExpired("%script_name%","myarea") Global("%script_name%_detected","myarea",1) Global("%script_name%_disarmed","myarea",0) THEN RESPONSE #100 SetGlobalTimer("%script_name%","myarea",6) DisplayStringHead(Myself,~trap_type_string_that_matches_the_scriptname~) END IF Detected() Global("%script_name%_detected","myarea",0) Global("%script_name%_disarmed","myarea",0) THEN RESPONSE #100 SetGlobal("%script_name%_detected","myarea",1) SetGlobalTimer("%script_name%","myarea",6) DisplayStringHead(Myself,~trap_type_string_that_matches_the_scriptname~) END IF Disarmed() Global("%script_name%_disarmed","myarea",0) THEN RESPONSE #100 SetGlobal("%script_name%_disarmed","myarea",1) END IF OR() Entered() Opened() AndProbablyThereWasAnotherTrigger() THEN RESPONSE #100 SetGlobal("%script_name%_disarmed","myarea",1) Continue() END IF Reset() THEN RESPONSE #100 SetGlobal("%script_name%_disarmed","myarea",0) Continue() END
I think it was kinda like that... Forgot if Continue()'s are correct, better test it.Area patching:
- Scan all areas for the scripts on the list. There will be multiple instances of the same script used in different trigger regions. For each duplicate copy the original script under unique new name, extend it and eval (those %script_name% vars), and write new script entry into the trigger.
- Keep a track of each trap type's max number of duplicates in a single area (I used arrays), so that if you run into another area with duplicates of that type then you can just use existing copies of the trap script created for previously processed areas.
-
Restore original NPCLEVEL.2DA and disable the scripted XP matching to that of Player1.
Seing Ardanis at the announcement topic reminded me of his Trap Detection mod.
I've lost the code long ago, though it's possible to remake.
-
Dead Player1 also breaks most of cutscenes, as they typically use him as CutsceneID (and sometimes it *must* be player1, e.g. for LeaveAreaLUA).
If i win a fight which will immediate trigger a cut scene, it's possible to break the game?
Dead actor usually can run the cutscene, but they're unable to Wait(). Area transitions also require to be run by Player1 (especially in multiplayer), and I think a couple times I've had issues with complex StartCutsceneMode() + CutsceneLite(TRUE) + breakable cutscene combinations if they weren't done by Player1 as well. Waiting was also required for some area transitions (e.g. dreams) to not fall apart in multiplayer mode.
So, as a rule of thumb, consider the possibility of playing with dead Charname to be a bug that must be rectified ASAP via resurrection, not a stable feature you can rely upon.
-
Dead Player1 also breaks most of cutscenes, as they typically use him as CutsceneID (and sometimes it *must* be player1, e.g. for LeaveAreaLUA).
-
Instead of adding your door image to the tileset, make it a BAM file and place in the area as ambient animation. Positioning can be calculated based on the tile size and tile offset.
You can set time of day when animation is active, so one for day version and another for night will work fine. Dusk and dawn are problematic, however, because of dynamic lighting adjustment. I've seen it almost working for dusk with day animation's light source flagged off, but not for dawn.
-
If you need it for a mod, just ship the updated tileset. I don't even think there was at least one that added new tiles to existing area? That, and since doors themselves are among the most complex structures for random people to bother, you aren't gonna run into compatibility issues.
PS You can also kind of fake the door with a bam overlay, without touching the tileset itself, but it doesn't work too well for day/night areas (namely during dawn/dusk transitions) and would need scripting activate/deactivate, so you can't really use it as a "normal" door that player can interact with.
-
Adding new tooltips for the items in a few quick strokes. Usage example is inside the link
https://github.com/Gibberlings3/ItemRevisions/blob/master/item_rev/lib/tooltip_macro.tpa
-
ADD_SPELL_HEADER
ADD_ITEM_HEADER
CREATE_EFFECT
Also CREATE_SPELL, but it's probably not a thing many would care about.
Parameters should be self-explanatory. Can also copy an existing one.
I had this for items as well, but I don't think I've got the code anywhere in close vicinity.
EDIT Here it is https://github.com/Gibberlings3/ItemRevisions/blob/master/item_rev/lib/macros.tpa
DEFINE_PATCH_FUNCTION ~ADD_SPELL_HEADER~ INT_VAR type=1 location=4 target=1 target_count=0 range=0 required_level=1 speed=0 projectile=1 copy_header=0 insert_point=~-1~ STR_VAR icon=~~ RET insert_point BEGIN LPF ~FJ_SPL_ITM_REINDEX~ END hs=0x28 READ_LONG 0x64 ho READ_SHORT 0x68 hc READ_LONG 0x6a eo insert_point = (insert_point>hc || insert_point<0) ? hc : insert_point copy_header = (copy_header<0) ? 0 : copy_header PATCH_IF copy_header>hc BEGIN PATCH_WARN ~Unable to copy %copy_header%th header, %SOURCE_FILE% contains only %hc% headers!~ END ELSE BEGIN INSERT_BYTES ho+insert_point*hs hs hc+=1 eo+=hs PATCH_IF copy_header BEGIN READ_SHORT ho+(copy_header - 1)*hs+0x1e ec READ_SHORT ho+(copy_header - 1)*hs+0x20 ei READ_ASCII eo+ei*0x30 effs (ec*0x30) READ_ASCII ho+(copy_header - 1)*hs copy (hs) WRITE_ASCIIE ho+insert_point*hs ~%copy%~ (hs) END WRITE_SHORT 0x68 hc WRITE_LONG 0x6a eo READ_SHORT 0x70 ei // technically, it is a counter FOR (i=ho;i<ho+hc*hs;i+=hs) BEGIN READ_SHORT i+0x1e ec WRITE_SHORT i+0x20 ei ei+=ec END PATCH_IF copy_header BEGIN READ_SHORT ho+insert_point*hs+0x1e ec READ_SHORT ho+insert_point*hs+0x20 ei INSERT_BYTES eo+ei*0x30 ec*0x30 WRITE_ASCIIE eo+ei*0x30 ~%effs%~ (ec*0x30) END ELSE BEGIN off=ho+insert_point*hs WRITE_BYTE off type WRITE_BYTE off+0x2 location WRITE_ASCIIE off+0x4 ~%icon%~ (8) WRITE_BYTE off+0xc target WRITE_BYTE off+0xd target_count WRITE_SHORT off+0xe range WRITE_SHORT off+0x10 required_level WRITE_LONG off+0x12 speed WRITE_SHORT off+0x26 projectile END END END
update_item_descriptions_to_bgee
Updates vanilla item descriptions to EE format, i.e. stripping Usable By section, so that you don't have to provide two strings for vanilla and EE descriptions.
https://github.com/Gibberlings3/ItemRevisions/blob/master/item_rev/lib/usability_description.tpa#L77
// make sure to add these two to your TRA files, adjust the numbers if needed //OUTER_SPRINT usab @900000 // ~Usable[ %tab%]+[Bb]y[ %tab%]*:~ //OUTER_SPRINT unus @900001 // ~\(Not[ %tab%]+\|Un\)[Uu]sable[ %tab%]+[Bb]y[ %tab%]*:~ OUTER_SPRINT usab ~Usable[ %tab%]+[Bb]y[ %tab%]*:~ OUTER_SPRINT unus ~\(Not[ %tab%]+\|Un\)[Uu]sable[ %tab%]+[Bb]y[ %tab%]*:~ DEFINE_PATCH_FUNCTION ~update_item_descriptions_to_bgee~ BEGIN PATCH_IF (ENGINE_IS ~bgee bg2ee~) BEGIN FOR (index = 0x54 ; index >= 0x50 ; index -= 4) BEGIN // loop through descriptions READ_LONG index strref PATCH_IF (strref < 2147483646 && strref >= 0) BEGIN // verify description is valid READ_STRREF index description INNER_PATCH_SAVE new_desc ~%description%~ BEGIN REPLACE_TEXTUALLY ~\(\([%LNL%%MNL%%WNL%][ %TAB%]*\(%usab%\|%unus%\)[ %TAB%]*\)\(\([%LNL%%MNL%%WNL%].*\)*\)?\)~ ~~ END SAY_EVALUATED index ~%new_desc%~ END END END END
Example usage 1, by item:
COPY_EXISTING ~mymod/myitem.itm~ override SAY_DESC ~Whatever~ LPF update_item_descriptions_to_bgee END
Example usage 2, batch update (caution, only really useful if you've got a simple content mod and don't do any level 80 patching:
// run this after all items have been copied into the game, i.e. near the end of tp2 ACTION_IF (ENGINE_IS ~bgee bg2ee~) BEGIN ACTION_FOR_EACH directory IN items itm any_other_subfolder_that_contains_installable_items BEGIN ACTION_BASH_FOR ~MyModFolder/%directory%~ ~.*\.itm~ BEGIN // get a list of .itm files in the mod directory ACTION_IF FILE_EXISTS_IN_GAME ~%BASH_FOR_FILE%~ BEGIN // if those files have been copied into override COPY_EXISTING ~%BASH_FOR_FILE%~ override // load those files from override, i.e. with descriptions already SAY'ed LPF update_item_descriptions_to_bgee END // patch the description BUT_ONLY END END END END
-
I'd be very happy for a "Dungeon-B-gone" type mod for SoD that skips through first dungeon, with an optional component that skips through whole BG city and puts you in the first wilderness area in SoD.
Add SetPrivateProfileString('Script','QAMODE','1') line to baldur.lua, then in-game select Player1 and press B key. Only works in SoD chapters, though.
-
The problematic names are:
bdneoawe
This is neothelid's psionics, I don't think it should be affected by Deflection?
-
I think the only place where it really counts is at the beginning of castle assault, and only to ensure that enough allies will run through the gates before crusaders can bottleneck it.I hope he will include some other tweaks as well; if for nothing than for SoD AI to work properly (mages use Haste to speed up entire armies, but with SR they fail with it...). -
So this is like IncrementGlobal but able to use a GLOBAL variable instead of an integer?
Yes.
-
About Dead() and NumDead(), are those found in the creatures ai scripts? or is it something that have logic behind it and the developers put it in some known script for such things?
Can be found in any script or dialog, so it's better to compile a list of quest actors first, then refer to it.
-
I am not checking for quest items, cause i think it doesn't matter if you've got 2 quest items. Do you think it can cause a problem down the line? if so i'll fix it.
There may be death variable checks, that can interfere with SoD's scripting if the actors get duplicated. I think most should get filtered out by the checks you mentioned, though... If you want to be on a safe side, then read scripts/dialogs for a list of Dead(), NumDead**(), Global**("SPRITE_IS_DEADxxxx",) etc. names and exclude actors with DVs from the list. Also note that embedded actors may have their scripting name/DV overriden by the bit 3 flag, so it's usually a good idea to not clone those either.
-
I need to interpret the BCS file and duplicate CreateCreature on specific conditions.
What are the conditions, btw? It's the most interesting part that you've omitted
Because I can't really imagine an automated bullet-proof way to separate quest-related actors from others.
-
I agree, but I don't really fiddle with cast'n'attack stuff - best I could do is remove this spell from liches which would make them try to attack melee (they're awfully slow-moving and it would be horrible).
I made the passive attack routine for SoD mages - they'll attack if target is within range or if they're out of spells, otherwise they stay rooted.
///////////////////////////////////////////////////////////////////////// if in melee range, equip melee and attack nearest// if have ranged equipped, attack nearest// attack with ranged weapon if more than 1 round has passed since the last time i've used a spell// otherwise just equip ranged without attackingIFSee(NearestEnemyOf(Myself))Range(LastSeenBy(Myself),5)THEN RESPONSE #100EquipMostDamagingMelee()AttackReevaluate(NearestEnemyOf(Myself),30)ENDIFSee(NearestEnemyOf(Myself))IsWeaponRanged(Myself)THEN RESPONSE #100AttackReevaluate(NearestEnemyOf(Myself),30)ENDIFSee(NearestEnemyOf(Myself))!GlobalTimerNotExpired("bd_cast","locals")THEN RESPONSE #100EquipRanged()AttackReevaluate(NearestEnemyOf(Myself),30)ENDIFSee(NearestEnemyOf(Myself))Delay(2)THEN RESPONSE #100EquipRanged()END
Enemies do double damage on Core Rules
in General Mod Discussion
Posted
Melee attacks against targets without melee weapon equipped receive +4 thaco/damage bonus.
If I were to hazard a guess, you're playing as monk and for some reason his fists don't function as melee weapons. Honestly, I don't remember if it was supposed to be like that in vanilla.