• New Horizons on Maelstrom
    Maelstrom New Horizons


    Visit our website www.piratehorizons.com to quickly find download links for the newest versions of our New Horizons mods Beyond New Horizons and Maelstrom New Horizons!

Tips and Tricks for modding

Thomas the Terror

Mad Pirate
Storm Modder
Pirate Legend
The topic for modders to place their tips and tricks about modding. <img src="http://www.piratesahoy.com/forum/style_emoticons/<#EMO_DIR#>/doff.gif" style="vertical-align:middle" emoid=":doff" border="0" alt="doff.gif" />
 
From the wiki's Unsorted Info page.

NK:
This is just a temporary dump of stuff I've found out while modding. Hope it's useful. When I remeber, I'll try to add to this. :]

Ship_CheckSituation called once every _three_ seconds if not mainchar's ship.

In order to change character animations, i.e. to reset run/walk properties after toggling alwaysrun, one must do this sequence:
BeginChangeCharacterActions(pchar);
SetDefaultNormWalk(pchar); //or any anim-changing function
SetDefaultFight(pchar); //ditto
EndChangeCharacterActions(pchar);

Changes will not apply without Begin Change? and End Change?.

Pchar.seaAI.update has a tree of all forts and ships active when at sea. They are *.ships.l0 (L0) through ln and forts.l0 through ln.
They have neat properties: char idx commanding the ship, distance to pchar, etc.
You can thus for example if you need to debug stuff, set up a quick loop to find all loaded ships, check their relation to pchar, and then sink them if hostile.

Sea AI? is a neat attribute in itself; for the AI, it has seaAI.task which is the current task, and if attack or something else that has a target (defend, sail to), seaAI.task.target is the idx of the char who is the target. If move, it's seaAI.task.pos.x and y as the xy coords that are the target.

To explore you can “page through” the different attributes an object has with the following simple for loop:
for(int j = 0; j < GetAttributesNum(some.aref); j++)
{
LogIt(GetAttributeName(GetAttributeN(some.aref,j)));
}

Where some.aref is the attribute tree you want to page through.

Mehrunes: ship cannon reload status stored in:
char.ship.Cannons.Borts.cannonX.chargeratio as a float 0.0 to 1.0.
where X is L, R, F, or B.

NK again:
Ship's fallen (and not fallen) masts are stored in char.ship.masts, the scorch marks in *.blots, and saildamage in *.sails. (I _think_. Haven't looked deeply)

In order to add a new location that has a shore, and thus foam, you must make a new ini file in the resource\foam\whatever_model folder with the same name as the location ID. You may have to make it reference a new texture of the same name and copy and rename the tga.zap to that name.
 
Pepillo Lazaro doesn't exist.

LAi_CharacterPlaySound() is the function, called by a lai type's characterupdate usually, that plays those soundclips in locations.
It passes a string which is converted to a soundfile via an entry in sound_aliases.ini

There's a sendmessage for characters, SetFightWOWeapon. It's false for everyone but monkeys (who have no weapons). Pieter, you might find it useful.

There's RDTSC support, but it seems not to work from a few of my tests. Maybe they turned off engine-side support for it (it's a native call).
Here's how it should work:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//    int iRDTSC = RDTSC_B();
//    trace("TIME!!! PerkLoad() = " + RDTSC_E(iRDTSC));

in Seadogs.c add:
int onesec_ticks; // global
// then in main()
int iRDTSC = RDTSC_B();
SystemDelay(1000);
onesec = RDTSC_E(iRDTSC);

Then, wherever you need to measure:
// start with this:
int iRDTSC = RDTSC_B();
// and then after code, add this
trace("time in seconds: " + makefloat(RDTSC_E(iRDTSC)) / makefloat(onesec));<!--c2--></div><!--ec2-->

native void SystemDelay(int millsec); will pause execution for that many ms.

It seems there is a way to add impulse after all, so heeling may be possible:
SendMessage(&arShipObjects, "llffffff", MSG_SHIP_ADD_MOVE_IMPULSE, false, x * fLen, 0.0, z * fLen, 0.0, 0.0, 0.0);

What determines speed decrease from sail holes is:
GetSpeedPercentDecreased() and the top of BI\Utils.c
What determines native-side speed based on sail types is:
native float funcGetSailSpeed(int holeQ,int holeMax,float sailPow);
(Which way back in 03 I reverse-engineered, not knowing it existed--better to have it return 1.0 when in realistic mode and not have to divide by a guessed value.)

object Boarding[MAX_BOARDING] seems never to be used (likewise MAX_BOARDING).
#define BOARDING_CHARACTERS seems never to be used.

For ranged controls
// my scale
//CI_CreateAndSetControls( "", "TmpScaleOn", CI_GetKeyCode("KEY_R"), 0, false );
//CI_CreateAndSetControls( "", "TmpScaleOff", CI_GetKeyCode("KEY_R"), INVERSE_CONTROL, false );

That seems to be a way to handle the difference between keypress and key release.

Bottom of fightparams control attack/block/etc for NPCs!
I have made fighting much harder for b12.x (in the pack), and we probably should ease back up some based on diff level.

EURO's \CheckDlgLoad.c has directory reads!
This way you can load all code files in a directory, blind.

LAi_CharacterColThreshold() has something to do with collision.
 
Finally wrote this up today:
<b>extern function prototypes: (<i>i.e. extern void inititems(); </i>)</b>
POTC is somewhat "forgetful" of externs. Sometimes you need to have the extern at the top of the _current file_, even if it's also prototyped somewhere else. For prototypes with no arguments, that's fine. But for some reason, each time you extern-prototype a function -with arguments-, the number of arguments for that function that POTC thinks are needed will increase. So if you define extern void initmodels(bool isstart); twice, then it will think it takes two arguments and calling it will _never_ work. The only way I can think of to get around this is to make a special handler function, and do the extern prototype in the same file (and only there), and when you want to call the extern, call the handler instead.
 
<!--QuoteBegin-NathanKell+Jul 21 2005, 09:38 PM--><div class='quotetop'>QUOTE(NathanKell @ Jul 21 2005, 09:38 PM)</div><div class='quotemain'><!--QuoteEBegin-->But for some reason, each time you extern-prototype a function -with arguments-, the number of arguments for that function that POTC thinks are needed will increase.<!--QuoteEnd--></div><!--QuoteEEnd-->
What's worse is this seems also to happen if the file with the extern declaration is loaded more than once.

The workaround I use (because I don't understand this stuff about the handler function <img src="http://www.piratesahoy.com/forum/style_emoticons/<#EMO_DIR#>/modding.gif" style="vertical-align:middle" emoid=":modding" border="0" alt="modding.gif" /> ) is to write the function without parameters and attach the information I need to pass to the function as an attribute to PChar (found that in another piece of your code <img src="http://www.piratesahoy.com/forum/style_emoticons/<#EMO_DIR#>/icon_mrgreen1.gif" style="vertical-align:middle" emoid=":cheeky" border="0" alt="icon_mrgreen1.gif" /> ).
 
What I mean is, for say locs init.
In locs init, have function DoAllLocInits() which calls the extern'd function.
And have extern with param at the top of locs init.
Then in reinit, call DoAllLocsInits() rather than directly calling the extern'd function.
 
Back
Top