Jump to content


Photo

Area Modding Tool & Tutorial by Qwinn


  • Please log in to reply
164 replies to this topic

#21 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 01:28 PM

EDIT: Never mind, I think I see what you're getting at. Response below.

Qwinn

Edited by Qwinn, 28 May 2009 - 03:18 PM.


#22 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 02:48 PM

Okay, I took a longer look at what you linked to, and I think I see what you're getting at. You basically mean standardize an include for each section type that contains writes for every offset, with every single field laid out.

Sure, that'll work. I guess I didn't feel the need cause if you take the writes out of my component .tph, there's hardly anything left.

For example, in the candlestick.tph example that I've been giving, doing what you're suggesting, this is all that'd be left of candlestick.tph:

COPY_EXISTING ~AR0109.ARE~ ~override~
LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
SET "Q_New_Actor" = 1
SET "Q_New_Trigg" = 2
SET "Q_New_Vertx" = 10
LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

[b][The includes that you're suggesting here][/b]

BUT_ONLY_IF_IT_CHANGES

Why make the modder go through the trouble to dig that include up in order to read it? I figure it reads easier seeing the macro call and variable sets right along with the writes. I'd rather cut and paste that whole thing in one piece when I need to reuse it, modifying those bits as well.

If I -were- to do the whole thing as an include, I'd probably include the macro call in the include as well, cause, why not? And at that point, my new include looks a whole lot like my existing candlestick.tph.

At any rate, the purpose of the macros is not to deal with the writes. The writes are the really easy part, as far as I'm concerned, and which really can't be dealt with programatically - every use is going to require specific unique attention to what to write to each field. Best you can do, really, is cut and paste and then modify the values (or, alternatively as you suggest, copy a file, modify it, and include it... not all that different I think). What my macros sought to do was eliminate the huge overhead of inserting the bytes, and adjusting the offsets and counts. It then provides the modder with variables containing offsets with the implied instructions "start your writes here". Everything after that is up to the modder. Your solution of what to do at that point looks perfectly valid to me.

EDIT: Upon even further review, what you're doing is solid for your version of the macros, but I don't think it works for mine. My macros do the inserting, offsets, counts as a separate function, and they don't care about the specifics of what lies within each section - the method of inserting bytes and resetting offsets is the same regardless of the section in question being added. Your method does the inserting, offsets, counts and writes all in one piece, and therefore -has- to have code exclusive to each section type (meaning, one function for triggers, another for actors, another for doors, etc.). I wanted an all-in-one utility that can handle the insert-offset-count overhead no matter what section I was adding.

Qwinn

Edited by Qwinn, 28 May 2009 - 03:17 PM.


#23 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 03:03 PM

I have a correction to make. From my little walkthrough up there:

PATCH_FOR_EACH "S1" IN
~Actor~ ~Trigg~ ~Spawn~ ~Entra~ ~Conta~ ~Items~ ~Ambie~ ~Varia~ ~Doors~
~Tiled~ ~Vertx~ ~Explo~ ~Anima~ ~Songs~ ~RestS~

...runs 15 times. The first pass through the loop, %S1% equals ~Actor~. The second pass, %S1% equals ~Trigg~. The third time, %S1% equals ~Spawn~. In this way, I have the loop run once for each type of section that can be added to an area. First thing it does:

SET "Q_NewSect" = $Q_New("%S1%")


I said that $Q_New("%S1%") would resolve to $Q_NewActor.

Except, it doesn't. I actually set the new records I want to Q_New_Actor. The difference is that second underscore.

Where is that second underscore coming from? It must be getting automatically inserted by Weidu. Don't ask me how the hell I figured that out, it's been a long time. Either it's documented somewhere in the weidu readme and I forgot that, or I figured it out through lots of DEBUG statements.

At any rate, did my explanation of PATCH_FOR_EACH help you understand what I was doing there at all?

Qwinn

Edited by Qwinn, 28 May 2009 - 03:09 PM.


#24 Mike1072

Mike1072
  • Member
  • 536 posts

Posted 28 May 2009 - 03:12 PM

I said that $Q_New("%S1%") would resolve to $Q_NewActor.

Except, it doesn't. I actually set the new records I want to Q_New_Actor. The difference is that second underscore.

Where is that second underscore coming from? It must be getting automatically inserted by Weidu. Don't ask me how the hell I figured that out, it's been a long time. Either it's documented somewhere in the weidu readme and I forgot that, or I figured it out through lots of DEBUG statements.

Qwinn

It is documented, sort of: "$variable(modifier list) ... is equivalent to saying ~variable_%modifier1%_%modifier2%_etc.~". I can use most of WeiDU's different array commands ($, DEFINE_ARRAY, and DEFINE_ASSOCIATIVE_ARRAY) separately, but it would be nice if there was more information available for how to combine them and see about using PHP_EACH with them, as I was testing something the other day and think the two DEFINE_ array commands end up spitting out something behind the scenes very much like the array construct.

#25 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 03:21 PM

Thaaaaat's right, thank you, yeah. Basically, I'm -simulating- an array, though you'll notice I never actually create one. (I never DEFINE_ARRAY or anything like that.) I basically just create discrete variables, and just using the array logic to let me evaluate them dynamically.

Why do it that way? Well, the alternative would've been to create arrays like CountOffset_1 through CountOffset_15, and another called CountOffsetOffset_1 through CountOffsetOffset_15, etc. etc. Then somewhere I'd refer to a table that told me 1=Actor, 2=Trigger, 3=Entrance, etc. Way I do it, I don't need to worry about that kinda reference, the actual strings "Actor", "Trigg" etc is effectively my 1-15 element reference.

Qwinn

Edited by Qwinn, 28 May 2009 - 03:27 PM.


#26 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 03:48 PM

Sasha,

Another reason your method wouldn't work very well with my macros, I think, is because my macros can add, say, 3 triggers at once. Your method would require setting all the variables, include, reset, include, reset, include. And the include would have to be smart enough to realize "this first set of variables gets written to my starting location, second set gets written to my starting location + the size of one trigger record, third set gets written to my starting location + the size of two trigger records".

I think it's easier to just copy paste my writes for the three triggers being added, increment the 0 in ("Q_Siz_Trigg" * 0) for each additional trigger being added, edit the values being written, and whala, done.

If you dislike my writes because you don't feel it's clear what field is being written to by each one, that's what the comment at the end of each write is supposed to inform you of. If you don't feel that the comment I put there was descriptive enough, I'd say just edit the comment to be whatever name you would've called your variables, so you're comfortable knowing what field each write is dealing with. That serves the same purpose, no?

Qwinn

Edited by Qwinn, 28 May 2009 - 03:57 PM.


#27 Thanatos.

Thanatos.
  • Member
  • 474 posts

Posted 28 May 2009 - 03:59 PM

My brain hurts.

#28 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 04:00 PM

thread is red 2 u?

int buff plz

:D

(I seriously love that LOTR/WoW gif)

Qwinn

Edited by Qwinn, 28 May 2009 - 04:01 PM.


#29 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 04:11 PM

Look, in this post, I'll make the purpose and use of these macros really REALLY simple. As simple as can be.

Say you want to add something to an area file. A door, a trigger, an actor, a container, whatever. The purpose of this macro is to take care of all the necessary overhead regarding inserting bytes, adjusting all the offsets, and adjusting the counts. The only thing left up to you is actually writing your new records.

In your code, you put an include defining my macros. Just cut and paste 'em into a file, stick that somewhere, and include it into your code.

Then add this, editing only the name of your .ARE file:

COPY_EXISTING ~ARyourareaname.ARE~ ~override~
LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~

Then you need to tell the macro how many of each kind of area section you're adding. If you want, just copy and paste the following.

SET "Q_New_Actor" = 0 // Number of New Actors
SET "Q_New_Trigg" = 0 // Number of New Triggers
SET "Q_New_Spawn" = 0 // Number of New Spawn Points
SET "Q_New_Entra" = 0 // Number of New Entrances
SET "Q_New_Conta" = 0 // Number of New Containers
SET "Q_New_Items" = 0 // Number of New Items
SET "Q_New_Ambie" = 0 // Number of New Ambients
SET "Q_New_Varia" = 0 // Number of New Variables
SET "Q_New_Doors" = 0 // Number of New Doors
SET "Q_New_Tiled" = 0 // Number of New Tiled Objects
SET "Q_New_Vertx" = 0 // Number of New Vertexes
SET "Q_New_Explo" = 0 // Number of New Explored Bitmap
SET "Q_New_Anima" = 0 // Number of New Animations

You don't really need to set any to 0, they will always be initialized for you at this point, but this lists the variable names you need to use for each section. So if you wanted to create 1 new empty actor section, 2 triggers, and 10 vertexes, you just say:

SET "Q_New_Actor" = 1 // Number of New Actors
SET "Q_New_Trigg" = 2 // Number of New Triggers
SET "Q_New_Vertx" = 10 // Number of New Vertexes

Then you run the macro:

LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

Whala. All bytes you need have been inserted. All offsets have been adjusted. All counts have been updated. The only thing you need to do now, is your writes. Where do you write them to? The offset where you should start your writes for each section type just created is contained in these variables:

"Q_NewOffset_Actor" // Begin writing your new actors here.
"Q_NewOffset_Trigg" // Begin writing your new triggers here.
"Q_NewOffset_Spawn" // Etc.
"Q_NewOffset_Entra"
"Q_NewOffset_Conta"
"Q_NewOffset_Items"
"Q_NewOffset_Ambie"
"Q_NewOffset_Varia"
"Q_NewOffset_Doors"
"Q_NewOffset_Tiled"
"Q_NewOffset_Vertx"
"Q_NewOffset_Explo"
"Q_NewOffset_Anima"


How you write them is up to you. The only time this should be a pain is the first time you do it for each section. Near Infinity and IESDP will be handy. After the first time, you can just cut and paste your first effort for subsequent attempts and tweak as needed. Examples of how I wrote to actor, trigger and vertex records are in post #4 of this thread. Sorry I don't have examples for any other sections, I've never needed to add any other records. (Well, actually, I did containers and items at some point, lemme know if anyone wants examples of those.) Also, my examples are for PS:T... BG1 and BG2 and IWD and IWD2 may need other fields set that are unnecessary in PS:T, so verify with IESDP/NI, but they are fairly similar.

And then you add
BUT_ONLY_IF_IT_CHANGES

That's it. That's all you really need to know. If you want to -delete- sections, you can do that too, but that's a little different. If someone needs a walkthrough on that, just ask.

Qwinn

Edited by Qwinn, 28 May 2009 - 06:18 PM.


#30 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 28 May 2009 - 05:13 PM

As far as the patch for each...

will set the string1 variable to each value in string list and process each patch.

Does that mean that string1 becomes the value from the current string in the list OR that the current string in the list becomes the value of string1?

Its used in the offset updates so the guess is that string1 becomes the value of the current string being read within the list. I'm just thinking out loud in code here... Correct me if I'm wrong...

If I take some pointers from your code even though I've read the comments but don't remember what everything is supposed to mean...
I'll use long form for now so that you can read and I can understand what I'm typing...

SET offset_of_actor_offset 0x54	//assign the offset to a variable because we need it later to do the patch for each
SET offset_of_spawn_offset 0x60  //assign the offset to a variable because we need it later to do the patch for each
etc...
READ_LONG %offset_of_actor_offset% ~actor_offset~ //get the actual current/starting offset
READ_LONG %offset_of_spawn_offset% ~spawn_offset~ //get the actual current/starting offset
etc..
PATCH_FOR_EACH string1 IN
~actor~ ~spawn~ etc..
BEGIN
 SPRINT offset_of_offset ~offset_of_%string1%_offset~  //assign a generic variable with the combined value of text and string1 which equaled a previous defined offset
 SET new_offset = EVALUATE_BUFFER (%%string1%_offset%+%new_bytes%) //set the new offset using string1 and text to equal the starting offset + new bytes
 WRITE_LONG %offset_of_offset% %new_offset% //update the starting offset (see sprint above for definition) by new bytes
END
That would update each offset by that amount of new_bytes which would be previously determined by whatever was being added. That sprint and evaluate_buffer thing was a trick showed to me I think by Mike1072 over at ppg in the weidu thread. He said I could otherwise do an array which is what you basically do. I understand this method arrays not so much...

Perhaps not as detailed as you have done, but if that was correct in form and function then I'm one step closer to understanding what is going on in these macros... hands on learning is how I do it...

BTW have you thought about those extra BG2 offsets to be updated? When I get to the point that I understand what this does (and can use the code ideas in other things), I could possibly use it in any IE game except PST. That's the only one I don't have now.

I know ADD_MAP_NOTE (or something like that) is already in weidu for use with BG2 files. As I understand your code so far if it's used on an existing BG2 area and then someone else comes along and adds a map note there could be problems...
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm

#31 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 05:32 PM

Your little snippet of code there basically does what the inner loop in my macro does, the S2 loop. But yes, I think you have the right idea now.

Songs and Rest Areas: As far as I can tell, in all IE games, every area has exactly 1 of each section. You can't have more than one. So adjusting the offsets, I already do, but count and offset of count don't seem to be relevant. Removing the bit from my tutorial that suggests you can create "new" sections of these.

Map Notes: Yeah, this is meaningless in PS:T (they're generated "automatically", IESDP says, and they don't exist in any base .ARE files, probably only in save games). So I might as well just add them in to work for other IE games. Will do that tonight, thanks for pointing it out.

Qwinn

Edited by Qwinn, 28 May 2009 - 06:18 PM.


#32 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 28 May 2009 - 05:51 PM

As far as the patch for each...

I think it can be described as

FOR (i=0;i<index;i+=1)

except that [0;index) aren't integers, but strings.

Retired from modding.


#33 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 06:09 PM

Okay, I'm adjusting my macro for non-PST games. People who want to mod PS:T are better served downloading my mods and grabbing 'em in any of their utils directories.

I noticed what you'd think was a significant error in my macros but that has had no impact on my mods. I was reading and writing every "Count" variable as a short, when a good number of them are longs. This is easy to fix on the reads, but it's a real problem for the writes. I'll try to come up with something to deal with it.

I'm adding in the map note stuff, but projectile traps... is that just BG2? IESDP suggests it exists in everything except PS:T in one section, but only in BG2 in another. If it's BG2 only, ugh, making it work's gonna take some doing.

Qwinn

Edited by Qwinn, 28 May 2009 - 06:12 PM.


#34 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 28 May 2009 - 06:23 PM

Look, in this post, I'll make the purpose and use of these macros really REALLY simple. As simple as can be.

I understand the simplicity of it. That's not the issue. I know that the macro would simplify a lot of the code. I didn't really understand why the offsets were always as variables and as such wasn't sure where things were going. I'm beginning to understand what you've done as far as putting the initial offset values that would eventually need to be updated into variable names. It helps with the update process that you've developed for an insert of multiple sections. I just had to get my hands dirty and try to do what you were doing to see why you were doing what you were doing. Does that make sense?

I still like my idea of having the user do sets instead of the writes. By having them do the writes, it can lead to potential errors if they make a mistake. I've got an idea that would allow for multiple passes of each section code without having to update in between. I'll work on it. When done, I'll let you look at it and see if you think that it would work.

Now that I can see somewhat more of what you are doing, I may be able to get the hang of this thing yet...
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm

#35 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 06:50 PM

Okay, but be aware I'm doing a LOT of work on it right now to get it to work with any IE game.

For one thing, I have to do up another 15 or so variables indicating whether the Count of each section is stored as a short or a long, sigh. I should've done that anyway, tho, that was sloppy of me. Still, it worked perfectly in PS:T.

Also, now, the InitVars section of the macro is first going to set a variable called Q_Game. When you copy the macros, you're going to want to set this variable to whatever game you're modding - PST, BG1, BG2, IWD or IWD2. Hopefully the ton of PATCH_IF's I'm inserting right now will handle the rest.

Qwinn

#36 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 08:05 PM

All right, all set. Updated to take those map notes and projectile traps into account.

Tested it on my mods, and they still seem to work fine for PS:T. As far as I know, these macros haven't been tested on any other IE game (with reason, I now see). I'd be very appreciative if, if and when someone does try it, they report any issues that arise so I can fix 'em :)

EDIT: I take that back. Not -any- other IE game. IWD2 area files are very different. The macros will not work for IWD2. Should work fine for BG1, BG2 or IWD though.

Qwinn

Edited by Qwinn, 28 May 2009 - 08:08 PM.


#37 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 30 May 2009 - 05:54 AM

I'm not that dense, but I was looking for a download link for the macro files. Are we just to copy and paste the code from the post then? If so, that's fine. I just want to make sure that I get the correct version to work with and break down for further offline study...
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm

#38 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 30 May 2009 - 06:16 AM

The macro in the first post is updated, but sure, I can upload it as well. I'll attach it to the first post of the thread.

Probably better to use that, actually, since this is directly pulled from an install that I -know- works for PS:T properly.

Qwinn

Edited by Qwinn, 30 May 2009 - 06:17 AM.


#39 Miloch

Miloch

    Barbarian

  • Modder
  • 6554 posts

Posted 30 May 2009 - 05:51 PM

Maybe one of you can use the macro(s) as a 'proof of concept' on my code here.

Basically, what we're looking to do is read the ambient sounds and if there are no valid ones or any sounds at all, then delete the entire ambient block and update all area offsets accordingly. Right now, I just clear the sound resref if it isn't valid.

If it works and actually seems to help with lag with no ill effects, it might be considered fixpack material, but we'd* probably want to test it pretty thoroughly. I will say that there are probably quite a few of these in BG1 at least, because they carry over into Tutu (unless it is Tutu that screwed up some references).

* By 'we' I mean someone other than me preferably :).

PS: Your goal, plainab, should you choose to accept this mission, will be to accomplish the task with as little code as possible :D.

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#40 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 30 May 2009 - 07:21 PM

PS: Your goal, plainab, should you choose to accept this mission, will be to accomplish the task with as little code as possible :D.

Ha! ROTFL

Okay, I'll get you short code for the fixpack.... :devil:

in fixpack.tph
DEFINE_ACTION_FUNCTION ~install_fixpack_for_bg~ BEGIN
//put everything decided to be a FIX from the fixpack here
END

in the fixpack.tp2
BEGIN ~Install BG Core Fixes~
INCLUDE ~bg_fixpack\tph\fixpack.tph~
LAUNCH_ACTION_FUNCTION ~install_fixpack_for_bg~
That will make the header longer than the mod. Short enough for you....
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm