-
Posts
940 -
Joined
-
Last visited
Content Type
Forums
Events
Downloads
Gallery
Mods
News
Store
Posts posted by Lauriel
-
-
4 hours ago, CoraMoose said:
Then installed EET to BG2EE,
At the beginning of the EET install, when asked for the BG1 folder, did you give it the BG1 folder where you have DS installed?
-
1 hour ago, jastey said:
Did you experience this ingame? Because there is a !AreaCheck("bd6200") in there to prevent that.
Yeah, in a custom area...but I don't think I'll be doing it that way in the future. So it's probably ok, and if it's not I'll just add the bd_plot check myself if it's required. S'ok.
-
Current bug - from Github:
SpoilerQuote/* join-up after leaving the group */ IF WEIGHT #-1 ~!AreaCheck("bd6200") !InParty(Myself) Global("bd_joined","locals",0) GlobalGT("bd_plot","GLOBAL",54)~ THEN join_again <=====NEED TO PUT AN UPPER LIMIT ON THIS LIKE 590 or something SAY #%63958% /* ~Heya, how are things going?~ */ ++ #%16414% /* ~Sorry to have kept you waiting. Let's get going.~ */ + kickout_4 ++ #%16413% /* ~Sorry, kiddo, but I don't need your company just yet.~ */ + kickout_3 END
Because there's no upper limit on bd_plot when Imoen begins a dialogue when not in the group, she will muck up the ending of SoD ... when the PC meets her after leaving the sewer
-
I like your idea of upping the cost of the ship to Spellhold. What I've done for mods that add a lot of expensive loot in BG1 is to just not sell it even if I'll not use it or not even pick it up in that case. I'd not have thought of upping prices, but that's a really good idea.
-
I just found this. Sounds great! I'll definitely check it out after I'm finished with this modding/testing run.
-
9 hours ago, jastey said:
@Lauriel and EE_End taggs it with "Global("EndofBG1","GLOBAL",0)" in addition:
There seems to be something off in your install.
Only an old version again. I've been working with this install for quire a while it seems
-
Just now, jastey said:
But I will disable all of them, maybe there will be more mods to carry over NPCs into SoD in the future.
That would definitely be the safer route.
-
5 minutes ago, jastey said:
THis is fixed in the current 7.2.
Ooops! My bad. I'm using v5 pre. Well darn it anyway!
-
Just now, jastey said:
In EET it gets unified so there we have the problem.
Yes. And I imagine it would affect all PIDs.
-
1 minute ago, jastey said:
in an EET game. BG:SoD is no problem because the NPCs use different dlgs in that case. Thanks for the report.
No, they don't. This is the SoD campaign in EET.
-
While browsing BD1000.BCS in NI, I discovered an invalid dialogue file name.
Code Block:
SpoilerIF Global("C#IM_ImoenRejoinsbd1000","GLOBAL",4) !Dead("IMOEN2") // Imoen !InPartyAllowDead("IMOEN2") // Imoen THEN RESPONSE #100 SetGlobal("C#IM_ImoenRejoinsbd1000","GLOBAL",5) MoveGlobal("bd1000","IMOEN2",[470.3737]) // Imoen ActionOverride("IMOEN2",Face(N)) ReallyForceSpellDeadRES("bdrejuve","IMOEN2") // No such index ChangeEnemyAlly("IMOEN2",NEUTRAL) // Imoen ChangeSpecifics("IMOEN2",ALLIES) // Imoen ActionOverride("IMOEN2",SetGlobal("bd_joined","locals",0)) ActionOverride("IMOEN2",SetGlobal("bd_retreat","locals",0)) ActionOverride("IMOEN2",SaveObjectLocation("LOCALS","bd_default_loc",Myself)) ActionOverride("IMOEN2",ChangeAIScript("BDIMOENS",OVERRIDE)) ActionOverride("IMOEN2",ChangeAIScript("bdasc3",CLASS)) ActionOverride("IMOEN2",ChangeAIScript("BDSHOUT",RACE)) ActionOverride("IMOEN2",ChangeAIScript("",GENERAL)) ActionOverride("IMOEN2",ChangeAIScript("",DEFAULT)) ActionOverride("IMOEN2",SetDialog("BDIMOENP")) <================bad file name Continue() END
-
I did install it after EET core this time instead of in with BG1. But it said it was EET compatible now. Its trigger includes a check to make sure EndOfBG1 < 2, so it appears to purposely also work in SoD. That would probably be the only fix needed.
-
The same thing happens to Edwin. After looking at their dialogue files, pretty much no dialogue other than their PID will fire except for those with weights.
-
Dynaheir gets stuck in a dialogue loop in SoD if Edwin joins the group. She wants to get to the state which says "Thou invite this snake to join us, <CHARNAME>? Hast thou taken leave of thy senses?" but is sidetracked by the state which says "*You find Dynaheir on her own and in a quiet mood; for once, she is not sorting her scrolls or discussing things in a low voice with one of your companions. Perhaps it would be wise to take advantage of the situation and chat with the mysterious Wychlaran.*"
I think a weight on the former's trigger is in order.
-
Close ... sorta ... I wrote one to add a door (with polygons) to an existing area. It won't get you all the way there, but it might help a little.
-
I see. So the entire file structure gets embedded into those areas. Gotcha. I'd have never guessed that from the docs, to be honest ... well ... obviously since I had to ask. LOL
Thank you all!
-
56 minutes ago, kjeron said:
Not sure what you mean, they are all defined.
Really? Where?
-
Just now, kjeron said:
there just isn't much reason to do so.
And because no one uses them, we just haven't bothered to define them?
-
There are a number of offsets listed in the ARE file that point to undefined sections. For example, "Offset to CRE structure (for embedded CRE files)" in the ACTORS sections.
Are these offsets to sections in the ARE file or is it understood that these sections are to be found in other files? I really hope the latter isn't the case... Are they defined but under a different name?
List of undefined sections reference by offsets in the ARE file:
ACTORS => 0x0088 => Offset to CRE structure (for embedded CRE files)
TILED OBJECTS => 0x002c => Offset to open search squares
TILED OBJECTS => 0x0038 => Offset to closed search squares
PROJECTILE TRAPS (BG2) => 0x0008 => Effect block offsetEDIT: Are these only used by save games?
-
I did a function that adds a door. It's not generic, but it's a start. It should help folks get over some hurdles at least.
It's a lot of code...feel free to rip into it. Everything can always be better.
Spoiler//////////////////////////////////////////////////// // ADD A DOOR TO AN AREA AND ITS ASSOCIATED FILES // // PVRz are compressed graphic files // // TIS are a series of indices pointing to // // sections (tiles) in the PVRz files // // An area can have two TIS/WED files associated // // with it. One for day, one for night. // // If the area has a day and night version, then // // this will need to be called twice - once // // for each TIS/WED // // // // THIS IS NOT A GENERIC FUNCTION // // IT WAS BUILT FOR A VERY SPECIFIC CASE // // MUCH WORK WOULD NEED TO BE DONE TO MAKE IT // // FIT ALL USE CASES // //////////////////////////////////////////////////// // To get the x/y of the open and closed tiles (g_closed_... and g_open_...) use: // COPY_EXISTING ~<your source tis file>.tis~ ~override~ // LPF ps_tileset_info INT_VAR Verbose = 2 Log = 1 END // Log verbose output of PVRz-based tileset to file // BUT_ONLY // Then open up the log file it generates, search for your tile #s and it'll list and the X/Ys needed to use in his other functions // I could probably automate that process...but I don't feel much inclined to do so DEFINE_ACTION_FUNCTION ADD_DOOR INT_VAR is_day = 0 g_closed_x1 = 0 // X,Y coordinates of the graphic within the source PVRz file (use ps_tileset_info to determine) g_closed_x2 = 0 g_closed_y1 = 0 g_closed_y2 = 0 g_open_x1 = 0 g_open_x2 = 0 g_open_y1 = 0 g_open_y2 = 0 t_open_pos1 = 0 // The tile # in the target TIS to be replaced (closed are added to the end of the file, not replaced) t_open_pos2 = 0 t_open_pos3 = 0 t_open_pos4 = 0 v_closed_x0 = 0 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_closed_y0 = 0 // Must be given in clockwise order starting with the one furthest to the right v_closed_x1 = 0 // If 2 tie for rightmost - use the lower of the two v_closed_y1 = 0 v_closed_x2 = 0 v_closed_y2 = 0 v_closed_x3 = 0 v_closed_y3 = 0 v_open_x0 = 0 v_open_y0 = 0 v_open_x1 = 0 v_open_y1 = 0 v_open_x2 = 0 v_open_y2 = 0 v_open_x3 = 0 v_open_y3 = 0 STR_VAR source_open_pvrz = "" source_closed_pvrz = "" target_tis = "" target_wed = "" target_are = "" door_name = "" door_id = "" RET open_pvrz closed_pvrz BEGIN // There are 2 versions of the door, opened and closed // Copy their respective PVRZ (source graphic) files to the override folder using // names that can be associated with the target TIS file (if necessary) LAF COPY_PVRZ_FILE_TO_OVERRIDE STR_VAR tis_file = EVAL ~%target_tis%~ source_pvrz = EVAL ~%source_open_pvrz%~ RET open_pvrz = pvrz_file open_pvrz_page = pvrz_suffix END ACTION_IF (~%source_closed_pvrz%~ STRING_EQUAL ~%source_open_pvrz%~) = 1 BEGIN // Open and closed day sources are the same file OUTER_SPRINT closed_pvrz ~%open_pvrz%~ OUTER_SPRINT closed_pvrz_page ~%open_pvrz_page%~ END ELSE BEGIN LAF COPY_PVRZ_FILE_TO_OVERRIDE STR_VAR tis_file = EVAL ~%target_tis%~ source_pvrz = EVAL ~%source_closed_pvrz%~ RET closed_pvrz = pvrz_file closed_pvrz_page = pvrz_suffix END END // Update the target TIS file COPY_EXISTING ~%target_tis%.tis~ ~override~ // Will need to know where the closed tiles were added in order to update the WED READ_LONG 0x0008 new_closed_tile // The count of the current tiles will be the index to the new one PATCH_IF (STRING_LENGTH ~%closed_pvrz%~ > 1) BEGIN // Add closed door tiles to end of TIS first LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x1%" PVRz_Y = "%g_closed_y1%" STR_VAR Method = "Push" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x2%" PVRz_Y = "%g_closed_y1%" STR_VAR Method = "Push" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x1%" PVRz_Y = "%g_closed_y2%" STR_VAR Method = "Push" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x2%" PVRz_Y = "%g_closed_y2%" STR_VAR Method = "Push" RET Count END END PATCH_IF (STRING_LENGTH ~%open_pvrz%~ > 1) BEGIN // These replace tiles currently in the file LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos1%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x1%" PVRz_Y = "%g_open_y1%" STR_VAR Method = "Replace" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos2%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x2%" PVRz_Y = "%g_open_y1%" STR_VAR Method = "Replace" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos3%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x1%" PVRz_Y = "%g_open_y2%" STR_VAR Method = "Replace" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos4%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x2%" PVRz_Y = "%g_open_y2%" STR_VAR Method = "Replace" RET Count END END BUT_ONLY_IF_IT_CHANGES // WED file changes COPY_EXISTING ~%target_wed%.WED~ ~override~ LPF ADD_WED_DOOR INT_VAR v_open_x0 = %v_open_x0% // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_open_y0 = %v_open_y0% // Must be given in clockwise order starting with the one furthest to the right v_open_x1 = %v_open_x1% // Start with the lowest if two are tied for the rightmost v_open_y1 = %v_open_y1% v_open_x2 = %v_open_x2% v_open_y2 = %v_open_y2% v_open_x3 = %v_open_x3% v_open_y3 = %v_open_y3% v_closed_x0 = %v_closed_x0% v_closed_y0 = %v_closed_y0% v_closed_x1 = %v_closed_x1% v_closed_y1 = %v_closed_y1% v_closed_x2 = %v_closed_x2% v_closed_y2 = %v_closed_y2% v_closed_x3 = %v_closed_x3% v_closed_y3 = %v_closed_y3% t_open_pos1 = %t_open_pos1% // The tile # in the target TIS that was replaced t_open_pos2 = %t_open_pos2% t_open_pos3 = %t_open_pos3% t_open_pos4 = %t_open_pos4% t_closed_pos1 = %new_closed_tile% // The tile # of the first new closed graphic that was added to the target TIS ... rest are sequential STR_VAR door_id = EVAL ~%door_id%~ // Called name in NI, but it's the ID used in the ARE file END BUT_ONLY_IF_IT_CHANGES // I'm just putting it in to connect it to the WED // Any details like scripts, flags, travel regions, keys, etc will have to be done elsewhere ACTION_IF is_day = 1 BEGIN COPY_EXISTING ~%target_are%.ARE~ ~override~ // Set defaults SET door_cursor = 30 // Calculate the min/max x/y for both open/closed LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_open_x0% v_y0 = %v_open_y0% v_x1 = %v_open_x1% v_y1 = %v_open_y1% v_x2 = %v_open_x2% v_y2 = %v_open_y2% v_x3 = %v_open_x3% v_y3 = %v_open_y3% RET min_open_x = min_x max_open_x = max_x min_open_y = min_y max_open_y = max_y END LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_closed_x0% v_y0 = %v_closed_y0% v_x1 = %v_closed_x1% v_y1 = %v_closed_y1% v_x2 = %v_closed_x2% v_y2 = %v_closed_y2% v_x3 = %v_closed_x3% v_y3 = %v_closed_y3% RET min_closed_x = min_x max_closed_x = max_x min_closed_y = min_y max_closed_y = max_y END LPF fj_are_structure INT_VAR fj_open_box_left = min_open_x fj_open_box_top = min_open_y fj_open_box_right = max_open_x fj_open_box_bottom = max_open_y fj_closed_box_left = min_closed_x fj_closed_box_top = min_closed_y fj_closed_box_right = max_closed_x fj_closed_box_bottom = max_closed_y fj_cursor_idx = door_cursor fj_door_open_vert_0 = v_open_x0 + (v_open_y0 << 16) fj_door_open_vert_1 = v_open_x1 + (v_open_y1 << 16) fj_door_open_vert_2 = v_open_x2 + (v_open_y2 << 16) fj_door_open_vert_3 = v_open_x3 + (v_open_y3 << 16) fj_door_closed_vert_0 = v_closed_x0 + (v_closed_y0 << 16) fj_door_closed_vert_1 = v_closed_x1 + (v_closed_y1 << 16) fj_door_closed_vert_2 = v_closed_x2 + (v_closed_y2 << 16) fj_door_closed_vert_3 = v_closed_x3 + (v_closed_y3 << 16) STR_VAR fj_structure_type = ~door~ fj_name = EVAL ~%door_name%~ fj_door_wed_id = EVAL ~%door_id%~ END BUT_ONLY_IF_IT_CHANGES END END //////////////////////////////////////////////////// // Gets the name of the PVRz file and copies it // // to the override folder if it's new // // Returns the name of the PVRz file as well // // as it's associated parts (prefix and suffix) // // The PVRz file name is the TIS file name // // with the 2nd letter of the file name dropped // // and then a sequential number added as a suffix // //////////////////////////////////////////////////// DEFINE_ACTION_FUNCTION COPY_PVRZ_FILE_TO_OVERRIDE STR_VAR tis_file = ~~ // target tis file name without the extension source_pvrz = ~~ // source of the graphic without the extension RET pvrz_file pvrz_prefix pvrz_suffix BEGIN // Set default return values OUTER_SPRINT pvrz_file ~~ OUTER_SPRINT pvrz_prefix ~~ OUTER_SPRINT pvrz_suffix ~~ ACTION_IF (STRING_LENGTH ~%tis_file%~ > 1) BEGIN OUTER_INNER_PATCH_SAVE pvrz_prefix ~%tis_file%~ BEGIN DELETE_BYTES 1 1 END ACTION_IF ((~%source_pvrz%~ STRING_CONTAINS_REGEXP ~%pvrz_prefix%~) = 0) AND ((STRING_LENGTH ~%pvrz_prefix%~) = ((STRING_LENGTH ~%source_pvrz%~) - 2)) BEGIN // The source of the graphic is already one of the TIS file's PVRz files OUTER_INNER_PATCH_SAVE pvrz_suffix ~%source_pvrz%~ BEGIN DELETE_BYTES 0 ((STRING_LENGTH ~%source_pvrz%~) - 2) END OUTER_SPRINT pvrz_file ~%source_pvrz%~ END ELSE BEGIN // The source of the graphic will need to be copied to a new PVRz that can be associated with the TIS OUTER_SPRINT pvrz_suffix ~-1~ OUTER_SET file_ok = 0 OUTER_SET strt_idx = 0 ACTION_IF GAME_IS ~eet~ THEN BEGIN OUTER_SET strt_idx = 50 END OUTER_FOR (idx = strt_idx; idx < 99 && file_ok = 0; idx = idx + 1) BEGIN ACTION_IF idx < 10 THEN BEGIN OUTER_SPRINT pvrz_suffix ~0%idx%~ END ELSE BEGIN OUTER_SPRINT pvrz_suffix ~%idx%~ END ACTION_IF NOT FILE_EXISTS_IN_GAME ~%pvrz_prefix%%pvrz_suffix%.pvrz~ THEN BEGIN OUTER_SET file_ok = 1 OUTER_SPRINT pvrz_file ~%pvrz_prefix%%pvrz_suffix%~ COPY_EXISTING ~%source_pvrz%.PVRZ~ ~override\%pvrz_file%.pvrz~ END END END END END ///////////////////////////////////////////////////// // Determine the bounding box for polygon vertices // // Expects there to be four // ///////////////////////////////////////////////////// DEFINE_PATCH_FUNCTION GET_BOUNDING_BOX INT_VAR v_x0 = 0 v_y0 = 0 v_x1 = 0 v_y1 = 0 v_x2 = 0 v_y2 = 0 v_x3 = 0 v_y3 = 0 RET min_x max_x min_y max_y BEGIN SET min_x = v_x0 SET max_x = v_x0 SET min_y = v_y0 SET max_y = v_y0 // Calculate the min/max x/y PATCH_IF v_x1 < min_x BEGIN SET min_x = v_x1 END PATCH_IF v_x2 < min_x BEGIN SET min_x = v_x2 END PATCH_IF v_x3 < min_x BEGIN SET min_x = v_x3 END PATCH_IF v_x1 > max_x BEGIN SET max_x = v_x1 END PATCH_IF v_x2 > max_x BEGIN SET max_x = v_x2 END PATCH_IF v_x3 > max_x BEGIN SET max_x = v_x3 END PATCH_IF v_y1 < min_y BEGIN SET min_y = v_y1 END PATCH_IF v_y2 < min_y BEGIN SET min_y = v_y2 END PATCH_IF v_y3 < min_y BEGIN SET min_y = v_y3 END PATCH_IF v_y1 > max_y BEGIN SET max_y = v_y1 END PATCH_IF v_y2 > max_y BEGIN SET max_y = v_y2 END PATCH_IF v_y3 > max_y BEGIN SET max_y = v_y3 END END ////////////////////////////////////////// // ADD A DOOR TO THE WED FILE // // It'll be easier to insert bytes at // // the proper places starting from // // the bottom of the file, recalc all // // the offsets, then add objects that // // reference those offsets. // // Those sections that don't reference // // offsets can be written right away. // ////////////////////////////////////////// DEFINE_PATCH_FUNCTION ADD_WED_DOOR INT_VAR v_open_x0 = 0 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_open_y0 = 0 // Must be given in clockwise order starting with the one furthest to the right v_open_x1 = 0 // Start with the lowest if two are tied for the rightmost v_open_y1 = 0 v_open_x2 = 0 v_open_y2 = 0 v_open_x3 = 0 v_open_y3 = 0 v_closed_x0 = 0 v_closed_y0 = 0 v_closed_x1 = 0 v_closed_y1 = 0 v_closed_x2 = 0 v_closed_y2 = 0 v_closed_x3 = 0 v_closed_y3 = 0 t_open_pos1 = 0 // The tile # in the target TIS that was replaced (closed were added to the end of the file, not replaced) t_open_pos2 = 0 t_open_pos3 = 0 t_open_pos4 = 0 t_closed_pos1 = 0 // The tile # of the first new closed graphic that was added to the target TIS ... rest are sequential STR_VAR door_id = "" // Called name in NI, but it's the ID used in the ARE file BEGIN /////////////////////////////////////////// // Read in offsets and counts from the headers /////////////////////////////////////////// READ_LONG 0x0008 num_overlays READ_LONG 0x000c num_doors READ_LONG 0x0010 offset_overlays READ_LONG 0x0014 offset_header2 READ_LONG 0x0018 offset_doors READ_LONG 0x001c offset_door_tile_cells READ_LONG (offset_header2) num_polygons READ_LONG (offset_header2 + 0x0004) offset_polygons READ_LONG (offset_header2 + 0x0008) offset_vertices READ_LONG (offset_header2 + 0x000c) offset_wallgroups READ_LONG (offset_header2 + 0x0010) offset_polygon_indices READ_LONG (offset_overlays + 0x0010) offset_overlay_tilemap // if it's not the first overlay - this will need to change /////////////////////////////////////////// // Set up the size of objects /////////////////////////////////////////// SET size_overlay = 0x0018 SET size_door = 0x001a SET size_tilemap = 0x000a SET size_door_tile_cell = 0x0002 SET size_polygon = 0x0012 SET size_index = 0x0002 SET size_vertex = 0x0004 // X,Y ////////////////////////////////// // // // ******** VERTICES ******** // // // ////////////////////////////////// // Only allowing for 8 new vertices, 4 for the open door and 4 for the closed SET new_vertices_open = 4 SET new_vertices_closed = 4 // New vertices can just be added at the end of the file (hopefully) // We'll add the open ones first then the closed ones SET new_open_vertices_offset = SOURCE_SIZE SET new_closed_vertices_offset = new_open_vertices_offset + (new_vertices_open * size_vertex) // Insert bytes at the end of the file for our new vertices INSERT_BYTES new_open_vertices_offset (size_vertex * (new_vertices_open + new_vertices_closed)) // Add the vertices to our new vertices section // These define the door polygons WRITE_SHORT new_open_vertices_offset %v_open_x0% WRITE_SHORT (new_open_vertices_offset + 0x0002) %v_open_y0% WRITE_SHORT (new_open_vertices_offset + 0x0004) %v_open_x1% WRITE_SHORT (new_open_vertices_offset + 0x0006) %v_open_y1% WRITE_SHORT (new_open_vertices_offset + 0x0008) %v_open_x2% WRITE_SHORT (new_open_vertices_offset + 0x000a) %v_open_y2% WRITE_SHORT (new_open_vertices_offset + 0x000c) %v_open_x3% WRITE_SHORT (new_open_vertices_offset + 0x000e) %v_open_y3% WRITE_SHORT new_closed_vertices_offset %v_closed_x0% WRITE_SHORT (new_closed_vertices_offset + 0x0002) %v_closed_y0% WRITE_SHORT (new_closed_vertices_offset + 0x0004) %v_closed_x1% WRITE_SHORT (new_closed_vertices_offset + 0x0006) %v_closed_y1% WRITE_SHORT (new_closed_vertices_offset + 0x0008) %v_closed_x2% WRITE_SHORT (new_closed_vertices_offset + 0x000a) %v_closed_y2% WRITE_SHORT (new_closed_vertices_offset + 0x000c) %v_closed_x3% WRITE_SHORT (new_closed_vertices_offset + 0x000e) %v_closed_y3% //////////////////////////////////////////////////// // // // ******** POLYGON INDEX LOOKUP TABLE ******** // // // //////////////////////////////////////////////////// // I think this is only used for walls - not doors ////////////////////////////////// // // // ******** POLYGONS ******** // // // ////////////////////////////////// // Need to add polygons for both open and closed doors in the polygon section // the offset to and count of these will be added to the door object // only allowing for 1 open and 1 closed polygon at the moment SET new_polygons_open = 1 SET new_polygons_closed = 1 SET new_open_polygon_flags = 129 // Shade wall + door SET new_closed_polygon_flags = 129 // New entries will go at the bottom of the current section SET new_polygons_open_offset = offset_polygons + (num_polygons * size_polygon) SET new_polygons_closed_offset = new_polygons_open_offset + (new_polygons_open * size_polygon) // Determine the next vertex index to use READ_LONG (offset_polygons + ((num_polygons - 1) * size_polygon)) last_vertex_index READ_LONG (offset_polygons + ((num_polygons - 1) * size_polygon) + 0x0004) num_last_vertices_used SET new_vertex_index = last_vertex_index + num_last_vertices_used // Calculate the min/max x/y for both open/closed LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_open_x0% v_y0 = %v_open_y0% v_x1 = %v_open_x1% v_y1 = %v_open_y1% v_x2 = %v_open_x2% v_y2 = %v_open_y2% v_x3 = %v_open_x3% v_y3 = %v_open_y3% RET min_open_x = min_x max_open_x = max_x min_open_y = min_y max_open_y = max_y END LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_closed_x0% v_y0 = %v_closed_y0% v_x1 = %v_closed_x1% v_y1 = %v_closed_y1% v_x2 = %v_closed_x2% v_y2 = %v_closed_y2% v_x3 = %v_closed_x3% v_y3 = %v_closed_y3% RET min_closed_x = min_x max_closed_x = max_x min_closed_y = min_y max_closed_y = max_y END // Insert bytes at the end of the current section for our new polygons INSERT_BYTES new_polygons_open_offset (size_polygon * (new_polygons_open + new_polygons_closed)) // Can add polygons now since they only reference indices, not offsets WRITE_LONG new_polygons_open_offset %new_vertex_index% WRITE_LONG (new_polygons_open_offset + 0x0004) %new_vertices_open% WRITE_BYTE (new_polygons_open_offset + 0x0008) %new_open_polygon_flags% WRITE_BYTE (new_polygons_open_offset + 0x0009) 0xff WRITE_SHORT (new_polygons_open_offset + 0x000a) %min_open_x% WRITE_SHORT (new_polygons_open_offset + 0x000c) %max_open_x% WRITE_SHORT (new_polygons_open_offset + 0x000e) %min_open_y% WRITE_SHORT (new_polygons_open_offset + 0x0010) %max_open_y% WRITE_LONG new_polygons_closed_offset (%new_vertex_index% + %new_vertices_open%) WRITE_LONG (new_polygons_closed_offset + 0x0004) %new_vertices_closed% WRITE_BYTE (new_polygons_closed_offset + 0x0008) %new_closed_polygon_flags% WRITE_BYTE (new_polygons_closed_offset + 0x0009) 0xff WRITE_SHORT (new_polygons_closed_offset + 0x000a) %min_closed_x% WRITE_SHORT (new_polygons_closed_offset + 0x000c) %max_closed_x% WRITE_SHORT (new_polygons_closed_offset + 0x000e) %min_closed_y% WRITE_SHORT (new_polygons_closed_offset + 0x0010) %max_closed_y% ///////////////////////////////////// // // // ******** WALL GROUPS ******** // // // ///////////////////////////////////// // I don't think I need to do anything here ///////////////////////////////////////////////// // // // ******** TILE INDEX LOOKUP TABLE ******** // // // ///////////////////////////////////////////////// // I don't think I need to do anything with these ///////////////////////////////////////// // // // ******** DOOR TILE CELLS ******** // // // ///////////////////////////////////////// // Need to add 4 entries into this table for the 4 graphic tiles used by the open door // It'll point to tiles defined in the Tile Map Structure and will also associate them with their closed graphics SET new_door_tile_cells = 4 // Find the last tilemap index to calculate the next and determine the offset to the next SET last_door_tile_index = 0 SET last_door_tile_count = 0 PATCH_IF num_doors > 0 BEGIN SET last_door_offset = offset_doors + ((num_doors - 1) * size_door) READ_SHORT (last_door_offset + 0x000a) last_door_tile_index READ_SHORT (last_door_offset + 0x000c) last_door_tile_count END SET new_door_tile_index = (last_door_tile_index + last_door_tile_count) // Calculate where the new door tile cells are inserted SET new_door_tile_cell_offset = offset_door_tile_cells + (new_door_tile_index * size_door_tile_cell) // Insert bytes at the end of the current section for our new door tile cells INSERT_BYTES new_door_tile_cell_offset (size_door_tile_cell * new_door_tile_cells) // Door tile cells only reference indices, not offsets, so we can add them right away WRITE_SHORT new_door_tile_cell_offset %t_open_pos1% WRITE_SHORT (new_door_tile_cell_offset + size_door_tile_cell) %t_open_pos2% WRITE_SHORT (new_door_tile_cell_offset + (2 * size_door_tile_cell)) %t_open_pos3% WRITE_SHORT (new_door_tile_cell_offset + (3 * size_door_tile_cell)) %t_open_pos4% ///////////////////////////////////////////// // // // ******** TILE MAP STRUCTURES ******** // // // ///////////////////////////////////////////// // Need to find and update the tiles associated with the open door // and update their secondary values to point to the new closed door graphics WRITE_SHORT (offset_overlay_tilemap + (t_open_pos1 * size_tilemap) + 0x0004) %t_closed_pos1% WRITE_SHORT (offset_overlay_tilemap + (t_open_pos2 * size_tilemap) + 0x0004) (%t_closed_pos1% + 1) WRITE_SHORT (offset_overlay_tilemap + (t_open_pos3 * size_tilemap) + 0x0004) (%t_closed_pos1% + 2) WRITE_SHORT (offset_overlay_tilemap + (t_open_pos4 * size_tilemap) + 0x0004) (%t_closed_pos1% + 3) /////////////////////////////// // // // ******** DOORS ******** // // // /////////////////////////////// // Calculate the start of our new door object SET new_door_offset = offset_doors + (num_doors * size_door) // Only allowing for 4 door tiles (per state) at the moment // Only the open ones need to be linked to the door structure SET new_tilemap_tiles = 4 // Insert bytes at the start of our new door section INSERT_BYTES new_door_offset size_door // Write the door section after all offsets are updated ///////////////////////////////////////////// // // // ******** RECALCULATE OFFSETS ******** // // // ///////////////////////////////////////////// SET add_size = size_door SET offset_door_tile_cells = offset_door_tile_cells + add_size SET add_size = add_size + (size_door_tile_cell * new_door_tile_cells) SET offset_wallgroups = offset_wallgroups + add_size SET offset_polygons = offset_polygons + add_size SET new_polygons_open_offset = new_polygons_open_offset + add_size SET new_polygons_closed_offset = new_polygons_open_offset + (size_polygon * new_polygons_open) SET add_size = add_size + (size_polygon * (new_polygons_open + new_polygons_closed)) SET offset_polygon_indices = offset_polygon_indices + add_size SET offset_vertices = offset_vertices + add_size SET new_open_vertices_offset = new_open_vertices_offset + add_size SET new_closed_vertices_offset = new_closed_vertices_offset + add_size /////////////////////////////////////////////////////////////// // // // ******** WRITE TO SECTIONS REFERENCING OFFSETS ******** // // // /////////////////////////////////////////////////////////////// // VERTICES - already written // POLYGON INDEX LOOKUP TABLE - no changes // POLYGONS - already written // WALL GROUPS - no changes // TILE INDEX LOOKUP TABLE - no changes // DOOR TILE CELLS - already written // TILE MAP STRUCTURES - already written // DOORS WRITE_ASCIIE new_door_offset ~%door_id%~ (8) WRITE_SHORT (new_door_offset + 0x0008) 1 // Is door? WRITE_SHORT (new_door_offset + 0x000a) %new_door_tile_index% WRITE_SHORT (new_door_offset + 0x000c) %new_tilemap_tiles% WRITE_SHORT (new_door_offset + 0x000e) %new_polygons_open% WRITE_SHORT (new_door_offset + 0x0010) %new_polygons_closed% WRITE_LONG (new_door_offset + 0x0012) %new_polygons_open_offset% WRITE_LONG (new_door_offset + 0x0016) %new_polygons_closed_offset% // SECONDARY HEADER WRITE_LONG (offset_header2) (num_polygons + new_polygons_open + new_polygons_closed) WRITE_LONG (offset_header2 + 0x0004) %offset_polygons% WRITE_LONG (offset_header2 + 0x0008) %offset_vertices% WRITE_LONG (offset_header2 + 0x000c) %offset_wallgroups% WRITE_LONG (offset_header2 + 0x0010) %offset_polygon_indices% // OVERLAYS - offset to this section doesn't change // Update offsets to tilemaps and tile index lookups referenced by the overlays FOR (idx = 0; idx < num_overlays; idx = idx + 1) BEGIN READ_LONG (offset_overlays + (idx * size_overlay) + 0x0010) offset_overlay_tilemap READ_LONG (offset_overlays + (idx * size_overlay) + 0x0014) offset_overlay_tile_lookup SET add_size = size_door SET new_offset_overlay_tilemap = offset_overlay_tilemap + add_size SET add_size = add_size + (new_door_tile_cells * size_door_tile_cell) SET new_offset_overlay_tile_lookup = offset_overlay_tile_lookup + add_size WRITE_LONG (offset_overlays + (idx * size_overlay) + 0x0010) %new_offset_overlay_tilemap% WRITE_LONG (offset_overlays + (idx * size_overlay) + 0x0014) %new_offset_overlay_tile_lookup% END // HEADER // Update the header section with new number of doors and offset to door tile cell indices WRITE_LONG (0x000c) (num_doors + 1) WRITE_LONG (0x001c) %offset_door_tile_cells% END
It's called like this:
Spoiler// Add a door to the PC's residence in the SoD areas // Will take the graphic for the open door from the BG1 area PVRz files // There are 4 versions of every exterior door - open and closed during the day and night OUTER_SPRINT open_source_day "A020008" OUTER_SPRINT open_source_night "A0200N08" OUTER_SPRINT closed_source_day "B001000" OUTER_SPRINT closed_source_night "B0010N00" ACTION_IF GAME_IS ~eet~ THEN BEGIN OUTER_SPRINT open_source_day "B020008" OUTER_SPRINT open_source_night "B0200N08" OUTER_SPRINT closed_source_day "B001050" OUTER_SPRINT closed_source_night "B0010N50" END // Daytime door LAF ADD_DOOR INT_VAR is_day = 1 g_closed_x1 = 0 // X,Y coordinates from within the source PVRz file g_closed_x2 = 64 g_closed_y1 = 448 g_closed_y2 = 512 g_open_x1 = 128 g_open_x2 = 192 g_open_y1 = 704 g_open_y2 = 768 t_open_pos1 = 140 // The tile # in the target TIS to be replaced t_open_pos2 = 141 t_open_pos3 = 160 t_open_pos4 = 161 v_closed_x0 = 39 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_closed_y0 = 524 // Must be given in clockwise order starting with the one furthest to the right v_closed_x1 = 87 // If 2 tie for rightmost - use the lower of the two v_closed_y1 = 535 v_closed_x2 = 87 v_closed_y2 = 469 v_closed_x3 = 39 v_closed_y3 = 457 v_open_x0 = 16 v_open_y0 = 553 v_open_x1 = 39 v_open_y1 = 552 v_open_x2 = 39 v_open_y2 = 455 v_open_x3 = 16 v_open_y3 = 484 STR_VAR source_open_pvrz = EVAL "%open_source_day%" source_closed_pvrz = EVAL "%closed_source_day%" target_tis = ~BD0010~ target_wed = ~BD0010~ target_are = ~BD0010~ door_name = "Port0006" door_id = "door0006" RET pvrzOpenDay = open_pvrz pvrzClosedDay = closed_pvrz END // Nighttime door LAF ADD_DOOR INT_VAR is_day = 0 g_closed_x1 = 0 // X,Y coordinates from within the source PVRz file (use DLTCEP to determine) g_closed_x2 = 64 g_closed_y1 = 448 g_closed_y2 = 512 g_open_x1 = 128 g_open_x2 = 192 g_open_y1 = 704 g_open_y2 = 768 t_open_pos1 = 140 // The tile # in the target TIS to be replaced t_open_pos2 = 141 t_open_pos3 = 160 t_open_pos4 = 161 v_closed_x0 = 39 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_closed_y0 = 524 // Must be given in clockwise order starting with the one furthest to the right v_closed_x1 = 87 // If 2 tie for rightmost - use the lower of the two v_closed_y1 = 535 v_closed_x2 = 87 v_closed_y2 = 469 v_closed_x3 = 39 v_closed_y3 = 457 v_open_x0 = 16 v_open_y0 = 553 v_open_x1 = 39 v_open_y1 = 552 v_open_x2 = 39 v_open_y2 = 455 v_open_x3 = 16 v_open_y3 = 484 STR_VAR source_open_pvrz = EVAL "%open_source_night%" source_closed_pvrz = EVAL "%closed_source_night%" target_tis = ~BD0010N~ target_wed = ~BD0010N~ target_are = ~BD0010~ door_name = "Port0006" door_id = "door0006" RET pvrzOpenNight = open_pvrz pvrzClosedNight = closed_pvrz END
-
-
I did a function that adds a door. It's not generic, but it's a start. It should help folks get over some hurdles at least.
It's a lot of code...feel free to rip into it. Everything can always be better.
Spoiler//////////////////////////////////////////////////// // ADD A DOOR TO AN AREA AND ITS ASSOCIATED FILES // // PVRz are compressed graphic files // // TIS are a series of indices pointing to // // sections (tiles) in the PVRz files // // An area can have two TIS/WED files associated // // with it. One for day, one for night. // // If the area has a day and night version, then // // this will need to be called twice - once // // for each TIS/WED // // // // THIS IS NOT A GENERIC FUNCTION // // IT WAS BUILT FOR A VERY SPECIFIC CASE // // MUCH WORK WOULD NEED TO BE DONE TO MAKE IT // // FIT ALL USE CASES // //////////////////////////////////////////////////// // To get the x/y of the open and closed tiles (g_closed_... and g_open_...) use: // COPY_EXISTING ~<your source tis file>.tis~ ~override~ // LPF ps_tileset_info INT_VAR Verbose = 2 Log = 1 END // Log verbose output of PVRz-based tileset to file // BUT_ONLY // Then open up the log file it generates, search for your tile #s and it'll list and the X/Ys needed to use in his other functions // I could probably automate that process...but I don't feel much inclined to do so DEFINE_ACTION_FUNCTION ADD_DOOR INT_VAR is_day = 0 g_closed_x1 = 0 // X,Y coordinates of the graphic within the source PVRz file (use ps_tileset_info to determine) g_closed_x2 = 0 g_closed_y1 = 0 g_closed_y2 = 0 g_open_x1 = 0 g_open_x2 = 0 g_open_y1 = 0 g_open_y2 = 0 t_open_pos1 = 0 // The tile # in the target TIS to be replaced (closed are added to the end of the file, not replaced) t_open_pos2 = 0 t_open_pos3 = 0 t_open_pos4 = 0 v_closed_x0 = 0 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_closed_y0 = 0 // Must be given in clockwise order starting with the one furthest to the right v_closed_x1 = 0 // If 2 tie for rightmost - use the lower of the two v_closed_y1 = 0 v_closed_x2 = 0 v_closed_y2 = 0 v_closed_x3 = 0 v_closed_y3 = 0 v_open_x0 = 0 v_open_y0 = 0 v_open_x1 = 0 v_open_y1 = 0 v_open_x2 = 0 v_open_y2 = 0 v_open_x3 = 0 v_open_y3 = 0 STR_VAR source_open_pvrz = "" source_closed_pvrz = "" target_tis = "" target_wed = "" target_are = "" door_name = "" door_id = "" RET open_pvrz closed_pvrz BEGIN // There are 2 versions of the door, opened and closed // Copy their respective PVRZ (source graphic) files to the override folder using // names that can be associated with the target TIS file (if necessary) LAF COPY_PVRZ_FILE_TO_OVERRIDE STR_VAR tis_file = EVAL ~%target_tis%~ source_pvrz = EVAL ~%source_open_pvrz%~ RET open_pvrz = pvrz_file open_pvrz_page = pvrz_suffix END ACTION_IF (~%source_closed_pvrz%~ STRING_EQUAL ~%source_open_pvrz%~) = 1 BEGIN // Open and closed day sources are the same file OUTER_SPRINT closed_pvrz ~%open_pvrz%~ OUTER_SPRINT closed_pvrz_page ~%open_pvrz_page%~ END ELSE BEGIN LAF COPY_PVRZ_FILE_TO_OVERRIDE STR_VAR tis_file = EVAL ~%target_tis%~ source_pvrz = EVAL ~%source_closed_pvrz%~ RET closed_pvrz = pvrz_file closed_pvrz_page = pvrz_suffix END END // Update the target TIS file COPY_EXISTING ~%target_tis%.tis~ ~override~ // Will need to know where the closed tiles were added in order to update the WED READ_LONG 0x0008 new_closed_tile // The count of the current tiles will be the index to the new one PATCH_IF (STRING_LENGTH ~%closed_pvrz%~ > 1) BEGIN // Add closed door tiles to end of TIS first LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x1%" PVRz_Y = "%g_closed_y1%" STR_VAR Method = "Push" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x2%" PVRz_Y = "%g_closed_y1%" STR_VAR Method = "Push" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x1%" PVRz_Y = "%g_closed_y2%" STR_VAR Method = "Push" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 PVRz_Page = "%closed_pvrz_page%" PVRz_X = "%g_closed_x2%" PVRz_Y = "%g_closed_y2%" STR_VAR Method = "Push" RET Count END END PATCH_IF (STRING_LENGTH ~%open_pvrz%~ > 1) BEGIN // These replace tiles currently in the file LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos1%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x1%" PVRz_Y = "%g_open_y1%" STR_VAR Method = "Replace" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos2%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x2%" PVRz_Y = "%g_open_y1%" STR_VAR Method = "Replace" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos3%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x1%" PVRz_Y = "%g_open_y2%" STR_VAR Method = "Replace" RET Count END LPF ps_tileset_add_tiles INT_VAR MaxCount = 1 Pos = "%t_open_pos4%" PVRz_Page = "%open_pvrz_page%" PVRz_X = "%g_open_x2%" PVRz_Y = "%g_open_y2%" STR_VAR Method = "Replace" RET Count END END BUT_ONLY_IF_IT_CHANGES // WED file changes COPY_EXISTING ~%target_wed%.WED~ ~override~ LPF ADD_WED_DOOR INT_VAR v_open_x0 = %v_open_x0% // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_open_y0 = %v_open_y0% // Must be given in clockwise order starting with the one furthest to the right v_open_x1 = %v_open_x1% // Start with the lowest if two are tied for the rightmost v_open_y1 = %v_open_y1% v_open_x2 = %v_open_x2% v_open_y2 = %v_open_y2% v_open_x3 = %v_open_x3% v_open_y3 = %v_open_y3% v_closed_x0 = %v_closed_x0% v_closed_y0 = %v_closed_y0% v_closed_x1 = %v_closed_x1% v_closed_y1 = %v_closed_y1% v_closed_x2 = %v_closed_x2% v_closed_y2 = %v_closed_y2% v_closed_x3 = %v_closed_x3% v_closed_y3 = %v_closed_y3% t_open_pos1 = %t_open_pos1% // The tile # in the target TIS that was replaced t_open_pos2 = %t_open_pos2% t_open_pos3 = %t_open_pos3% t_open_pos4 = %t_open_pos4% t_closed_pos1 = %new_closed_tile% // The tile # of the first new closed graphic that was added to the target TIS ... rest are sequential STR_VAR door_id = EVAL ~%door_id%~ // Called name in NI, but it's the ID used in the ARE file END BUT_ONLY_IF_IT_CHANGES // I'm just putting it in to connect it to the WED // Any details like scripts, flags, travel regions, keys, etc will have to be done elsewhere ACTION_IF is_day = 1 BEGIN COPY_EXISTING ~%target_are%.ARE~ ~override~ // Set defaults SET door_cursor = 30 // Calculate the min/max x/y for both open/closed LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_open_x0% v_y0 = %v_open_y0% v_x1 = %v_open_x1% v_y1 = %v_open_y1% v_x2 = %v_open_x2% v_y2 = %v_open_y2% v_x3 = %v_open_x3% v_y3 = %v_open_y3% RET min_open_x = min_x max_open_x = max_x min_open_y = min_y max_open_y = max_y END LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_closed_x0% v_y0 = %v_closed_y0% v_x1 = %v_closed_x1% v_y1 = %v_closed_y1% v_x2 = %v_closed_x2% v_y2 = %v_closed_y2% v_x3 = %v_closed_x3% v_y3 = %v_closed_y3% RET min_closed_x = min_x max_closed_x = max_x min_closed_y = min_y max_closed_y = max_y END LPF fj_are_structure INT_VAR fj_open_box_left = min_open_x fj_open_box_top = min_open_y fj_open_box_right = max_open_x fj_open_box_bottom = max_open_y fj_closed_box_left = min_closed_x fj_closed_box_top = min_closed_y fj_closed_box_right = max_closed_x fj_closed_box_bottom = max_closed_y fj_cursor_idx = door_cursor fj_door_open_vert_0 = v_open_x0 + (v_open_y0 << 16) fj_door_open_vert_1 = v_open_x1 + (v_open_y1 << 16) fj_door_open_vert_2 = v_open_x2 + (v_open_y2 << 16) fj_door_open_vert_3 = v_open_x3 + (v_open_y3 << 16) fj_door_closed_vert_0 = v_closed_x0 + (v_closed_y0 << 16) fj_door_closed_vert_1 = v_closed_x1 + (v_closed_y1 << 16) fj_door_closed_vert_2 = v_closed_x2 + (v_closed_y2 << 16) fj_door_closed_vert_3 = v_closed_x3 + (v_closed_y3 << 16) STR_VAR fj_structure_type = ~door~ fj_name = EVAL ~%door_name%~ fj_door_wed_id = EVAL ~%door_id%~ END BUT_ONLY_IF_IT_CHANGES END END //////////////////////////////////////////////////// // Gets the name of the PVRz file and copies it // // to the override folder if it's new // // Returns the name of the PVRz file as well // // as it's associated parts (prefix and suffix) // // The PVRz file name is the TIS file name // // with the 2nd letter of the file name dropped // // and then a sequential number added as a suffix // //////////////////////////////////////////////////// DEFINE_ACTION_FUNCTION COPY_PVRZ_FILE_TO_OVERRIDE STR_VAR tis_file = ~~ // target tis file name without the extension source_pvrz = ~~ // source of the graphic without the extension RET pvrz_file pvrz_prefix pvrz_suffix BEGIN // Set default return values OUTER_SPRINT pvrz_file ~~ OUTER_SPRINT pvrz_prefix ~~ OUTER_SPRINT pvrz_suffix ~~ ACTION_IF (STRING_LENGTH ~%tis_file%~ > 1) BEGIN OUTER_INNER_PATCH_SAVE pvrz_prefix ~%tis_file%~ BEGIN DELETE_BYTES 1 1 END ACTION_IF ((~%source_pvrz%~ STRING_CONTAINS_REGEXP ~%pvrz_prefix%~) = 0) AND ((STRING_LENGTH ~%pvrz_prefix%~) = ((STRING_LENGTH ~%source_pvrz%~) - 2)) BEGIN // The source of the graphic is already one of the TIS file's PVRz files OUTER_INNER_PATCH_SAVE pvrz_suffix ~%source_pvrz%~ BEGIN DELETE_BYTES 0 ((STRING_LENGTH ~%source_pvrz%~) - 2) END OUTER_SPRINT pvrz_file ~%source_pvrz%~ END ELSE BEGIN // The source of the graphic will need to be copied to a new PVRz that can be associated with the TIS OUTER_SPRINT pvrz_suffix ~-1~ OUTER_SET file_ok = 0 OUTER_SET strt_idx = 0 ACTION_IF GAME_IS ~eet~ THEN BEGIN OUTER_SET strt_idx = 50 END OUTER_FOR (idx = strt_idx; idx < 99 && file_ok = 0; idx = idx + 1) BEGIN ACTION_IF idx < 10 THEN BEGIN OUTER_SPRINT pvrz_suffix ~0%idx%~ END ELSE BEGIN OUTER_SPRINT pvrz_suffix ~%idx%~ END ACTION_IF NOT FILE_EXISTS_IN_GAME ~%pvrz_prefix%%pvrz_suffix%.pvrz~ THEN BEGIN OUTER_SET file_ok = 1 OUTER_SPRINT pvrz_file ~%pvrz_prefix%%pvrz_suffix%~ COPY_EXISTING ~%source_pvrz%.PVRZ~ ~override\%pvrz_file%.pvrz~ END END END END END ///////////////////////////////////////////////////// // Determine the bounding box for polygon vertices // // Expects there to be four // ///////////////////////////////////////////////////// DEFINE_PATCH_FUNCTION GET_BOUNDING_BOX INT_VAR v_x0 = 0 v_y0 = 0 v_x1 = 0 v_y1 = 0 v_x2 = 0 v_y2 = 0 v_x3 = 0 v_y3 = 0 RET min_x max_x min_y max_y BEGIN SET min_x = v_x0 SET max_x = v_x0 SET min_y = v_y0 SET max_y = v_y0 // Calculate the min/max x/y PATCH_IF v_x1 < min_x BEGIN SET min_x = v_x1 END PATCH_IF v_x2 < min_x BEGIN SET min_x = v_x2 END PATCH_IF v_x3 < min_x BEGIN SET min_x = v_x3 END PATCH_IF v_x1 > max_x BEGIN SET max_x = v_x1 END PATCH_IF v_x2 > max_x BEGIN SET max_x = v_x2 END PATCH_IF v_x3 > max_x BEGIN SET max_x = v_x3 END PATCH_IF v_y1 < min_y BEGIN SET min_y = v_y1 END PATCH_IF v_y2 < min_y BEGIN SET min_y = v_y2 END PATCH_IF v_y3 < min_y BEGIN SET min_y = v_y3 END PATCH_IF v_y1 > max_y BEGIN SET max_y = v_y1 END PATCH_IF v_y2 > max_y BEGIN SET max_y = v_y2 END PATCH_IF v_y3 > max_y BEGIN SET max_y = v_y3 END END ////////////////////////////////////////// // ADD A DOOR TO THE WED FILE // // It'll be easier to insert bytes at // // the proper places starting from // // the bottom of the file, recalc all // // the offsets, then add objects that // // reference those offsets. // // Those sections that don't reference // // offsets can be written right away. // ////////////////////////////////////////// DEFINE_PATCH_FUNCTION ADD_WED_DOOR INT_VAR v_open_x0 = 0 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_open_y0 = 0 // Must be given in clockwise order starting with the one furthest to the right v_open_x1 = 0 // Start with the lowest if two are tied for the rightmost v_open_y1 = 0 v_open_x2 = 0 v_open_y2 = 0 v_open_x3 = 0 v_open_y3 = 0 v_closed_x0 = 0 v_closed_y0 = 0 v_closed_x1 = 0 v_closed_y1 = 0 v_closed_x2 = 0 v_closed_y2 = 0 v_closed_x3 = 0 v_closed_y3 = 0 t_open_pos1 = 0 // The tile # in the target TIS that was replaced (closed were added to the end of the file, not replaced) t_open_pos2 = 0 t_open_pos3 = 0 t_open_pos4 = 0 t_closed_pos1 = 0 // The tile # of the first new closed graphic that was added to the target TIS ... rest are sequential STR_VAR door_id = "" // Called name in NI, but it's the ID used in the ARE file BEGIN /////////////////////////////////////////// // Read in offsets and counts from the headers /////////////////////////////////////////// READ_LONG 0x0008 num_overlays READ_LONG 0x000c num_doors READ_LONG 0x0010 offset_overlays READ_LONG 0x0014 offset_header2 READ_LONG 0x0018 offset_doors READ_LONG 0x001c offset_door_tile_cells READ_LONG (offset_header2) num_polygons READ_LONG (offset_header2 + 0x0004) offset_polygons READ_LONG (offset_header2 + 0x0008) offset_vertices READ_LONG (offset_header2 + 0x000c) offset_wallgroups READ_LONG (offset_header2 + 0x0010) offset_polygon_indices READ_LONG (offset_overlays + 0x0010) offset_overlay_tilemap // if it's not the first overlay - this will need to change /////////////////////////////////////////// // Set up the size of objects /////////////////////////////////////////// SET size_overlay = 0x0018 SET size_door = 0x001a SET size_tilemap = 0x000a SET size_door_tile_cell = 0x0002 SET size_polygon = 0x0012 SET size_index = 0x0002 SET size_vertex = 0x0004 // X,Y ////////////////////////////////// // // // ******** VERTICES ******** // // // ////////////////////////////////// // Only allowing for 8 new vertices, 4 for the open door and 4 for the closed SET new_vertices_open = 4 SET new_vertices_closed = 4 // New vertices can just be added at the end of the file (hopefully) // We'll add the open ones first then the closed ones SET new_open_vertices_offset = SOURCE_SIZE SET new_closed_vertices_offset = new_open_vertices_offset + (new_vertices_open * size_vertex) // Insert bytes at the end of the file for our new vertices INSERT_BYTES new_open_vertices_offset (size_vertex * (new_vertices_open + new_vertices_closed)) // Add the vertices to our new vertices section // These define the door polygons WRITE_SHORT new_open_vertices_offset %v_open_x0% WRITE_SHORT (new_open_vertices_offset + 0x0002) %v_open_y0% WRITE_SHORT (new_open_vertices_offset + 0x0004) %v_open_x1% WRITE_SHORT (new_open_vertices_offset + 0x0006) %v_open_y1% WRITE_SHORT (new_open_vertices_offset + 0x0008) %v_open_x2% WRITE_SHORT (new_open_vertices_offset + 0x000a) %v_open_y2% WRITE_SHORT (new_open_vertices_offset + 0x000c) %v_open_x3% WRITE_SHORT (new_open_vertices_offset + 0x000e) %v_open_y3% WRITE_SHORT new_closed_vertices_offset %v_closed_x0% WRITE_SHORT (new_closed_vertices_offset + 0x0002) %v_closed_y0% WRITE_SHORT (new_closed_vertices_offset + 0x0004) %v_closed_x1% WRITE_SHORT (new_closed_vertices_offset + 0x0006) %v_closed_y1% WRITE_SHORT (new_closed_vertices_offset + 0x0008) %v_closed_x2% WRITE_SHORT (new_closed_vertices_offset + 0x000a) %v_closed_y2% WRITE_SHORT (new_closed_vertices_offset + 0x000c) %v_closed_x3% WRITE_SHORT (new_closed_vertices_offset + 0x000e) %v_closed_y3% //////////////////////////////////////////////////// // // // ******** POLYGON INDEX LOOKUP TABLE ******** // // // //////////////////////////////////////////////////// // I think this is only used for walls - not doors ////////////////////////////////// // // // ******** POLYGONS ******** // // // ////////////////////////////////// // Need to add polygons for both open and closed doors in the polygon section // the offset to and count of these will be added to the door object // only allowing for 1 open and 1 closed polygon at the moment SET new_polygons_open = 1 SET new_polygons_closed = 1 SET new_open_polygon_flags = 129 // Shade wall + door SET new_closed_polygon_flags = 129 // New entries will go at the bottom of the current section SET new_polygons_open_offset = offset_polygons + (num_polygons * size_polygon) SET new_polygons_closed_offset = new_polygons_open_offset + (new_polygons_open * size_polygon) // Determine the next vertex index to use READ_LONG (offset_polygons + ((num_polygons - 1) * size_polygon)) last_vertex_index READ_LONG (offset_polygons + ((num_polygons - 1) * size_polygon) + 0x0004) num_last_vertices_used SET new_vertex_index = last_vertex_index + num_last_vertices_used // Calculate the min/max x/y for both open/closed LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_open_x0% v_y0 = %v_open_y0% v_x1 = %v_open_x1% v_y1 = %v_open_y1% v_x2 = %v_open_x2% v_y2 = %v_open_y2% v_x3 = %v_open_x3% v_y3 = %v_open_y3% RET min_open_x = min_x max_open_x = max_x min_open_y = min_y max_open_y = max_y END LPF GET_BOUNDING_BOX INT_VAR v_x0 = %v_closed_x0% v_y0 = %v_closed_y0% v_x1 = %v_closed_x1% v_y1 = %v_closed_y1% v_x2 = %v_closed_x2% v_y2 = %v_closed_y2% v_x3 = %v_closed_x3% v_y3 = %v_closed_y3% RET min_closed_x = min_x max_closed_x = max_x min_closed_y = min_y max_closed_y = max_y END // Insert bytes at the end of the current section for our new polygons INSERT_BYTES new_polygons_open_offset (size_polygon * (new_polygons_open + new_polygons_closed)) // Can add polygons now since they only reference indices, not offsets WRITE_LONG new_polygons_open_offset %new_vertex_index% WRITE_LONG (new_polygons_open_offset + 0x0004) %new_vertices_open% WRITE_BYTE (new_polygons_open_offset + 0x0008) %new_open_polygon_flags% WRITE_BYTE (new_polygons_open_offset + 0x0009) 0xff WRITE_SHORT (new_polygons_open_offset + 0x000a) %min_open_x% WRITE_SHORT (new_polygons_open_offset + 0x000c) %max_open_x% WRITE_SHORT (new_polygons_open_offset + 0x000e) %min_open_y% WRITE_SHORT (new_polygons_open_offset + 0x0010) %max_open_y% WRITE_LONG new_polygons_closed_offset (%new_vertex_index% + %new_vertices_open%) WRITE_LONG (new_polygons_closed_offset + 0x0004) %new_vertices_closed% WRITE_BYTE (new_polygons_closed_offset + 0x0008) %new_closed_polygon_flags% WRITE_BYTE (new_polygons_closed_offset + 0x0009) 0xff WRITE_SHORT (new_polygons_closed_offset + 0x000a) %min_closed_x% WRITE_SHORT (new_polygons_closed_offset + 0x000c) %max_closed_x% WRITE_SHORT (new_polygons_closed_offset + 0x000e) %min_closed_y% WRITE_SHORT (new_polygons_closed_offset + 0x0010) %max_closed_y% ///////////////////////////////////// // // // ******** WALL GROUPS ******** // // // ///////////////////////////////////// // I don't think I need to do anything here ///////////////////////////////////////////////// // // // ******** TILE INDEX LOOKUP TABLE ******** // // // ///////////////////////////////////////////////// // I don't think I need to do anything with these ///////////////////////////////////////// // // // ******** DOOR TILE CELLS ******** // // // ///////////////////////////////////////// // Need to add 4 entries into this table for the 4 graphic tiles used by the open door // It'll point to tiles defined in the Tile Map Structure and will also associate them with their closed graphics SET new_door_tile_cells = 4 // Find the last tilemap index to calculate the next and determine the offset to the next SET last_door_tile_index = 0 SET last_door_tile_count = 0 PATCH_IF num_doors > 0 BEGIN SET last_door_offset = offset_doors + ((num_doors - 1) * size_door) READ_SHORT (last_door_offset + 0x000a) last_door_tile_index READ_SHORT (last_door_offset + 0x000c) last_door_tile_count END SET new_door_tile_index = (last_door_tile_index + last_door_tile_count) // Calculate where the new door tile cells are inserted SET new_door_tile_cell_offset = offset_door_tile_cells + (new_door_tile_index * size_door_tile_cell) // Insert bytes at the end of the current section for our new door tile cells INSERT_BYTES new_door_tile_cell_offset (size_door_tile_cell * new_door_tile_cells) // Door tile cells only reference indices, not offsets, so we can add them right away WRITE_SHORT new_door_tile_cell_offset %t_open_pos1% WRITE_SHORT (new_door_tile_cell_offset + size_door_tile_cell) %t_open_pos2% WRITE_SHORT (new_door_tile_cell_offset + (2 * size_door_tile_cell)) %t_open_pos3% WRITE_SHORT (new_door_tile_cell_offset + (3 * size_door_tile_cell)) %t_open_pos4% ///////////////////////////////////////////// // // // ******** TILE MAP STRUCTURES ******** // // // ///////////////////////////////////////////// // Need to find and update the tiles associated with the open door // and update their secondary values to point to the new closed door graphics WRITE_SHORT (offset_overlay_tilemap + (t_open_pos1 * size_tilemap) + 0x0004) %t_closed_pos1% WRITE_SHORT (offset_overlay_tilemap + (t_open_pos2 * size_tilemap) + 0x0004) (%t_closed_pos1% + 1) WRITE_SHORT (offset_overlay_tilemap + (t_open_pos3 * size_tilemap) + 0x0004) (%t_closed_pos1% + 2) WRITE_SHORT (offset_overlay_tilemap + (t_open_pos4 * size_tilemap) + 0x0004) (%t_closed_pos1% + 3) /////////////////////////////// // // // ******** DOORS ******** // // // /////////////////////////////// // Calculate the start of our new door object SET new_door_offset = offset_doors + (num_doors * size_door) // Only allowing for 4 door tiles (per state) at the moment // Only the open ones need to be linked to the door structure SET new_tilemap_tiles = 4 // Insert bytes at the start of our new door section INSERT_BYTES new_door_offset size_door // Write the door section after all offsets are updated ///////////////////////////////////////////// // // // ******** RECALCULATE OFFSETS ******** // // // ///////////////////////////////////////////// SET add_size = size_door SET offset_door_tile_cells = offset_door_tile_cells + add_size SET add_size = add_size + (size_door_tile_cell * new_door_tile_cells) SET offset_wallgroups = offset_wallgroups + add_size SET offset_polygons = offset_polygons + add_size SET new_polygons_open_offset = new_polygons_open_offset + add_size SET new_polygons_closed_offset = new_polygons_open_offset + (size_polygon * new_polygons_open) SET add_size = add_size + (size_polygon * (new_polygons_open + new_polygons_closed)) SET offset_polygon_indices = offset_polygon_indices + add_size SET offset_vertices = offset_vertices + add_size SET new_open_vertices_offset = new_open_vertices_offset + add_size SET new_closed_vertices_offset = new_closed_vertices_offset + add_size /////////////////////////////////////////////////////////////// // // // ******** WRITE TO SECTIONS REFERENCING OFFSETS ******** // // // /////////////////////////////////////////////////////////////// // VERTICES - already written // POLYGON INDEX LOOKUP TABLE - no changes // POLYGONS - already written // WALL GROUPS - no changes // TILE INDEX LOOKUP TABLE - no changes // DOOR TILE CELLS - already written // TILE MAP STRUCTURES - already written // DOORS WRITE_ASCIIE new_door_offset ~%door_id%~ (8) WRITE_SHORT (new_door_offset + 0x0008) 1 // Is door? WRITE_SHORT (new_door_offset + 0x000a) %new_door_tile_index% WRITE_SHORT (new_door_offset + 0x000c) %new_tilemap_tiles% WRITE_SHORT (new_door_offset + 0x000e) %new_polygons_open% WRITE_SHORT (new_door_offset + 0x0010) %new_polygons_closed% WRITE_LONG (new_door_offset + 0x0012) %new_polygons_open_offset% WRITE_LONG (new_door_offset + 0x0016) %new_polygons_closed_offset% // SECONDARY HEADER WRITE_LONG (offset_header2) (num_polygons + new_polygons_open + new_polygons_closed) WRITE_LONG (offset_header2 + 0x0004) %offset_polygons% WRITE_LONG (offset_header2 + 0x0008) %offset_vertices% WRITE_LONG (offset_header2 + 0x000c) %offset_wallgroups% WRITE_LONG (offset_header2 + 0x0010) %offset_polygon_indices% // OVERLAYS - offset to this section doesn't change // Update offsets to tilemaps and tile index lookups referenced by the overlays FOR (idx = 0; idx < num_overlays; idx = idx + 1) BEGIN READ_LONG (offset_overlays + (idx * size_overlay) + 0x0010) offset_overlay_tilemap READ_LONG (offset_overlays + (idx * size_overlay) + 0x0014) offset_overlay_tile_lookup SET add_size = size_door SET new_offset_overlay_tilemap = offset_overlay_tilemap + add_size SET add_size = add_size + (new_door_tile_cells * size_door_tile_cell) SET new_offset_overlay_tile_lookup = offset_overlay_tile_lookup + add_size WRITE_LONG (offset_overlays + (idx * size_overlay) + 0x0010) %new_offset_overlay_tilemap% WRITE_LONG (offset_overlays + (idx * size_overlay) + 0x0014) %new_offset_overlay_tile_lookup% END // HEADER // Update the header section with new number of doors and offset to door tile cell indices WRITE_LONG (0x000c) (num_doors + 1) WRITE_LONG (0x001c) %offset_door_tile_cells% END
It's called like this:
Spoiler// Add a door to the PC's residence in the SoD areas // Will take the graphic for the open door from the BG1 area PVRz files // There are 4 versions of every exterior door - open and closed during the day and night OUTER_SPRINT open_source_day "A020008" OUTER_SPRINT open_source_night "A0200N08" OUTER_SPRINT closed_source_day "B001000" OUTER_SPRINT closed_source_night "B0010N00" ACTION_IF GAME_IS ~eet~ THEN BEGIN OUTER_SPRINT open_source_day "B020008" OUTER_SPRINT open_source_night "B0200N08" OUTER_SPRINT closed_source_day "B001050" OUTER_SPRINT closed_source_night "B0010N50" END // Daytime door LAF ADD_DOOR INT_VAR is_day = 1 g_closed_x1 = 0 // X,Y coordinates from within the source PVRz file g_closed_x2 = 64 g_closed_y1 = 448 g_closed_y2 = 512 g_open_x1 = 128 g_open_x2 = 192 g_open_y1 = 704 g_open_y2 = 768 t_open_pos1 = 140 // The tile # in the target TIS to be replaced t_open_pos2 = 141 t_open_pos3 = 160 t_open_pos4 = 161 v_closed_x0 = 39 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_closed_y0 = 524 // Must be given in clockwise order starting with the one furthest to the right v_closed_x1 = 87 // If 2 tie for rightmost - use the lower of the two v_closed_y1 = 535 v_closed_x2 = 87 v_closed_y2 = 469 v_closed_x3 = 39 v_closed_y3 = 457 v_open_x0 = 16 v_open_y0 = 553 v_open_x1 = 39 v_open_y1 = 552 v_open_x2 = 39 v_open_y2 = 455 v_open_x3 = 16 v_open_y3 = 484 STR_VAR source_open_pvrz = EVAL "%open_source_day%" source_closed_pvrz = EVAL "%closed_source_day%" target_tis = ~BD0010~ target_wed = ~BD0010~ target_are = ~BD0010~ door_name = "Port0006" door_id = "door0006" RET pvrzOpenDay = open_pvrz pvrzClosedDay = closed_pvrz END // Nighttime door LAF ADD_DOOR INT_VAR is_day = 0 g_closed_x1 = 0 // X,Y coordinates from within the source PVRz file (use DLTCEP to determine) g_closed_x2 = 64 g_closed_y1 = 448 g_closed_y2 = 512 g_open_x1 = 128 g_open_x2 = 192 g_open_y1 = 704 g_open_y2 = 768 t_open_pos1 = 140 // The tile # in the target TIS to be replaced t_open_pos2 = 141 t_open_pos3 = 160 t_open_pos4 = 161 v_closed_x0 = 39 // X/Y pairs (vertices) of the actual door object - only allowing 4 per door state v_closed_y0 = 524 // Must be given in clockwise order starting with the one furthest to the right v_closed_x1 = 87 // If 2 tie for rightmost - use the lower of the two v_closed_y1 = 535 v_closed_x2 = 87 v_closed_y2 = 469 v_closed_x3 = 39 v_closed_y3 = 457 v_open_x0 = 16 v_open_y0 = 553 v_open_x1 = 39 v_open_y1 = 552 v_open_x2 = 39 v_open_y2 = 455 v_open_x3 = 16 v_open_y3 = 484 STR_VAR source_open_pvrz = EVAL "%open_source_night%" source_closed_pvrz = EVAL "%closed_source_night%" target_tis = ~BD0010N~ target_wed = ~BD0010N~ target_are = ~BD0010~ door_name = "Port0006" door_id = "door0006" RET pvrzOpenNight = open_pvrz pvrzClosedNight = closed_pvrz END
-
From the IESDP for this section:
QuoteThe 'tile map' structures reference indices into this table. The 'tile counts' in the tilemap table are counts of indices in this table. This maps tile indices from the WED tile indices into the appropriate tile indices for the particular tileset file which the overlay in question references. Each element in this array is a little-endian 16-bit word.I've never used little-endians. Do I have to muck about with the order of bits to write the correct value or is there notation (like hex) to say - put this in little-
fellaendian notation. Or ... what?Or is this some sort of (start, count) pair of ... something.
EDIT: Never mind - I don't think I need to add to this table when adding a door.
-
Oh, I've seen this...something you installed mucked about with the trigger table so now those triggers are no longer valid when they should be.
To quote @tipun from another thread...On 9/5/2021 at 7:10 PM, tipun said:I think there is a mod ... that has poor EE compatibility (or not compatibility at all). And it replaces the trigger.ids file. Therefore, EET_end cannot find the triggers it needs.
Tweaks Anthology v9 Released
in Tweaks Anthology Forum
Posted
You are beautiful! Thank you so much.