• 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!

WIP Improvements to Smuggling.

btw something which came to mind.
If the officer returns from scouting, does this officer also receive experience for this scouting? If not than I think this should be added, could be another reason why you send the officer for scouting ;).
Sounds sensible and easy enough to add. :onya
 
btw something which came to mind.
If the officer returns from scouting, does this officer also receive experience for this scouting? If not than I think this should be added, could be another reason why you send the officer for scouting ;).
dunno if thats the case rn, but thats a great idea! xD
 
would randnorm(10,2) give something similar? would it have the same problem with small numbers as the normal rand system?

Your 6 sided dice should be just fine. No real need to use a "50 sided dice" for that. If nothing else, you're rolling 3 dice so differences would average out over time.

Pseudo-random numbers are what the computer produces. Any given seed will always produce the same sequence of random numbers. You can use this to your advantage if you can set a specific seed. For the purposes of a game, it doesn't matter if they aren't actually *random* but a pseudo-random sequence.

For what it's worth, every test I've ever done with random number generators has produced results within expected limits. Generating a number between 1 and 3 will produce approximately 1/3 of each number if a sufficiently high number of numbers are generated. It only appears to be off because of too few numbers tested. No matter what you do, you won't get exactly 1/3 each time; this is why they call it a random number generator.

OK... RandNorm(10,2) will produce numbers from 4 to 16, with very few at the extremes. 99% of the numbers will be 6 to 14. Three 6 sided dice will produce 3 to 18 with one each of 3, 4, 17 and 18, two each of 5, 6, 15 and 16, and three each of the other 8 numbers: basically very flat but tapering at the extremes. If you wanted more of a bell curve you'd have to roll a lot more dice.

RandNorm does not require you to use every number. If you wanted just 6 to 14 with no possibility of going lower or higher, simply discard the numbers out of range. This will produce a slightly flatter curve and give more numbers at the extremes.

Here's an example of possible code:

Code:
int r = 0;
while (r < 6 || r > 14)
    r = RandNorm(10,2);

You could do something similar to cluster the numbers higher or lower.

Hook
 
could you look into it?
sure, getting on it tonight:onya

Your 6 sided dice should be just fine. No real need to use a "50 sided dice" for that. If nothing else, you're rolling 3 dice so differences would average out over time.

Pseudo-random numbers are what the computer produces. Any given seed will always produce the same sequence of random numbers. You can use this to your advantage if you can set a specific seed. For the purposes of a game, it doesn't matter if they aren't actually *random* but a pseudo-random sequence.

For what it's worth, every test I've ever done with random number generators has produced results within expected limits. Generating a number between 1 and 3 will produce approximately 1/3 of each number if a sufficiently high number of numbers are generated. It only appears to be off because of too few numbers tested. No matter what you do, you won't get exactly 1/3 each time; this is why they call it a random number generator.

OK... RandNorm(10,2) will produce numbers from 4 to 16, with very few at the extremes. 99% of the numbers will be 6 to 14. Three 6 sided dice will produce 3 to 18 with one each of 3, 4, 17 and 18, two each of 5, 6, 15 and 16, and three each of the other 8 numbers: basically very flat but tapering at the extremes. If you wanted more of a bell curve you'd have to roll a lot more dice.

RandNorm does not require you to use every number. If you wanted just 6 to 14 with no possibility of going lower or higher, simply discard the numbers out of range. This will produce a slightly flatter curve and give more numbers at the extremes.

Here's an example of possible code:

Code:
int r = 0;
while (r < 6 || r > 14)
    r = RandNorm(10,2);

You could do something similar to cluster the numbers higher or lower.

Hook
superinteresting stuff! xD thanks, gonna keep it in mind going forward
 
Hm, I believe RandNorm produces a float. You might need to round it if you need an int, because if you just assign it to an int it will truncate it. I usually do something like "int r = RandNorm(10,2) + 0.5;"

Three 6 sided dice will produce an average of 10.5, not 10. (high - low) / 2 + low.

Hook
 
Hm, I believe RandNorm produces a float. You might need to round it if you need an int, because if you just assign it to an int it will truncate it. I usually do something like "int r = RandNorm(10,2) + 0.5;"

Three 6 sided dice will produce an average of 10.5, not 10. (high - low) / 2 + low.

Hook
oh well, so much for me rolling lots of dice, getting the probabilities wrong anyway :p there is a round() function that I guess rounds up or down depending on if the float decimal is above or below .5 too?

also, @Levis , it seems the officer does indeed get exp! xD
Code:
case "Send Officer has time":
            if(DEBUG_SMUGGLING>0) trace("SMUGGLING officer "+PChar.quest.Contraband.officerID+" appears in tavern");
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            ChangeCharacterAddressGroup(NPChar, Pchar.quest.Contraband.tavern, "reload", "reload1");
            LAi_SetActorType(NPChar);
            NPChar.dialog.currentnode = "Patrolschedule_got";
            LAi_ActorDialog(NPChar,Pchar,"",10.0,1.0); // PB: was "Send Officer back in slot"
            AddPartyExpChar(NPChar, SKILL_SNEAK, 500);
        break;

I have no idea how much 500 actually is in balance terms tho. does it sound alright?
 
I have no idea how much 500 actually is in balance terms tho. does it sound alright?

Please change it to:

Code:
AddXP(NPChar, SKILL_SNEAK, 850, XP_GROUP_PLAYER);
AddXP(NPChar, "", 150, XP_GROUP_OFFIC);

This should add 850 XP for luck to the officer itself and 150 general XP (which will divided over the different skills) too all officers and the player.
 
Please change it to:

Code:
AddXP(NPChar, SKILL_SNEAK, 850, XP_GROUP_PLAYER);
AddXP(NPChar, "", 150, XP_GROUP_OFFIC);

This should add 850 XP for luck to the officer itself and 150 general XP (which will divided over the different skills) too all officers and the player.
sure :onya gonna fix when I get home

just remembered another bug, when sending the officer to scout, they run to an exit locator but they dont actually disappear, they just run there and then turn back and continue following you until you transition to another area
 
sure :onya gonna fix when I get home

just remembered another bug, when sending the officer to scout, they run to an exit locator but they dont actually disappear, they just run there and then turn back and continue following you until you transition to another area

Looking at my code (don't know how old it is)
this should take care of it, the ChangeCharacterAddressGroup should make it dissapair.
Code:
case "Send Officer Gone":
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            LAi_SetOfficerType(NPChar);
            ChangeCharacterAddressGroup(NPChar,"none","",""); //We don't have to see him anymore
            if(DEBUG_SMUGGLING>2)trace("SMUGGLING removed "+NPChar.id+" from location");
            PChar.quest.Contraband_Scouting.win_condition.l1 = "Timer";
            PChar.quest.Contraband_Scouting.win_condition.l1.date.day = GetAddingDataDay(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.month = GetAddingDataMonth(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.year = GetAddingDataYear(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition = "Send Officer time expired";
            if(DEBUG_SMUGGLING>0)trace("SMUGGLING timer set 1 day later ");
        break;

But this is called by:

Code:
LAi_ActorRunToLocator(NPChar,"reload","reload1","Send Officer Gone",40);

maybe this 40 is the problem, I believe that's the delay, i don't remember completly how it works again, but it should call the Send Officer Gone once the officer arived at the locator.
@Jack Rackham or @Grey Roger can probably tell how it should be from the top of their head.
 
In my experience, 'LAi_ActorRunToLocator' is used if you don't want the character to disappear, e.g. if he's running into a fight. 'LAi_ActorRunToLocation' makes the character disappear:
Code:
LAi_ActorRunToLocation(characterFromID(NPChar,"reload","reload1", "none", "", "", "Send Officer Gone",40.0);
Also, you probably don't want 'LAi_SetOfficerType(NPChar);' as that is indeed the command to make a character follow you around, at least until you leave the area.

The number is a time limit. Whether 'LAi_ActorRunToLocator' or 'LAi_ActorRunToLocation', the character has that many seconds to get to the locator by running. If he can't make it in time, either because it's too far away or because too many other characters are blocking the route, when the time limit expires he just teleports there. The problem with putting an excessively long time limit is that if you go to another location and then return, he may still be there trying to continue his movement.

Moreover, if you leave the area before he's finished moving, the quest name given in the command won't happen. You may be better to trigger "Send Officer Gone" like this:
Code:
PChar.quest.Send Officer Gone.win_condition.l1 = "ExitFromLocation";
PChar.quest.Send Officer Gone.win_condition.l1.location = PChar.location;
PChar.quest.Send Officer Gone.win_condition = "Send Officer Gone";
That triggers "Send Officer Gone" when you leave the area. If he's still on the move, it shouldn't matter, so long as "Send Officer Gone" makes sure to remove him completely so that he's not still trying to move if you go back.
 
In my experience, 'LAi_ActorRunToLocator' is used if you don't want the character to disappear, e.g. if he's running into a fight. 'LAi_ActorRunToLocation' makes the character disappear:
Code:
LAi_ActorRunToLocation(characterFromID(NPChar,"reload","reload1", "none", "", "", "Send Officer Gone",40.0);
that looks okay to me :)

Also, you probably don't want 'LAi_SetOfficerType(NPChar);' as that is indeed the command to make a character follow you around, at least until you leave the area.
It's called in the Officer Gone case which is called after the officer is gone.


The number is a time limit. Whether 'LAi_ActorRunToLocator' or 'LAi_ActorRunToLocation', the character has that many seconds to get to the locator by running. If he can't make it in time, either because it's too far away or because too many other characters are blocking the route, when the time limit expires he just teleports there. The problem with putting an excessively long time limit is that if you go to another location and then return, he may still be there trying to continue his movement.

Moreover, if you leave the area before he's finished moving, the quest name given in the command won't happen. You may be better to trigger "Send Officer Gone" like this:
Code:
PChar.quest.Send Officer Gone.win_condition.l1 = "ExitFromLocation";
PChar.quest.Send Officer Gone.win_condition.l1.location = PChar.location;
PChar.quest.Send Officer Gone.win_condition = "Send Officer Gone";
That triggers "Send Officer Gone" when you leave the area. If he's still on the move, it shouldn't matter, so long as "Send Officer Gone" makes sure to remove him completely so that he's not still trying to move if you go back.
Sounds like a good idea. Why not do both just to be sure.
 
alright, I havent had much time to experiment with quests coding yet, so Im not 100% sure where all the things go. does this look alright?
Code:
case "Send Officer to scout":
            //Levis add smuggling questbook
            Preprocessor_AddQuestData("location",locations[FindLocation(Pchar.quest.contraband.CurrentPlace)].name);
            questbookname = "smuggle&number="+Pchar.amount_smuggleruns; //Set a questname
            AddQuestRecord(questbookname, 11);
            Preprocessor_Remove("location");
            Pchar.quest.Contraband.scout.done = true;
            //In 1 day he has to return
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            RemovePassenger(PChar, NPChar);
            NPChar.StoredFellow = True;
            if(DEBUG_SMUGGLING>2)trace("SMUGGLING removed "+NPChar.id+" as officer");
            LAi_SetActorType(NPChar);
            LAi_ActorRunToLocation(characterFromID(NPChar,"reload","reload1", "none", "", "", "Send Officer Gone",40.0);
            PChar.quest.Send Officer Gone.win_condition.l1 = "ExitFromLocation";
            PChar.quest.Send Officer Gone.win_condition.l1.location = PChar.location;
            PChar.quest.Send Officer Gone.win_condition = "Send Officer Gone";
        break;

        case "Send Officer Gone":
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            LAi_SetOfficerType(NPChar);
            ChangeCharacterAddressGroup(NPChar,"none","",""); //We don't have to see him anymore
            if(DEBUG_SMUGGLING>2)trace("SMUGGLING removed "+NPChar.id+" from location");
            PChar.quest.Contraband_Scouting.win_condition.l1 = "Timer";
            PChar.quest.Contraband_Scouting.win_condition.l1.date.day = GetAddingDataDay(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.month = GetAddingDataMonth(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.year = GetAddingDataYear(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition = "Send Officer time expired";
            if(DEBUG_SMUGGLING>0)trace("SMUGGLING timer set 1 day later ");
        break;
stuff todo and places to be tonite so wont be able to test it out rigorously today, but Ill be back at it when I have time if theres trouble :p
 
I'd be inclined to remove "Send Officer Gone" from the 'LAi_ActorRunToLocation' line. If you get to the door before the officer, those "PChar.quest.Send Officer Gone" lines will trigger, the officer should be removed as soon as you leave, and so should not be there if you go back in. If the officer gets to the door first then "Send Officer Gone" will be triggered twice, once by him and once by you when you leave. So, either way, it's triggered by you leaving; the only question is whether you want another, redundant run of "Send Officer Gone".

There's no great rush now. I've already uploaded the update with what's already done, and unless someone reports a problem, I don't plan to do another one before next month. After the dash to get it finished by the end of this week, we can relax a bit now. xD
 
sweet xD
Code:
        case "Send Officer to scout":
            //Levis add smuggling questbook
            Preprocessor_AddQuestData("location",locations[FindLocation(Pchar.quest.contraband.CurrentPlace)].name);
            questbookname = "smuggle&number="+Pchar.amount_smuggleruns; //Set a questname
            AddQuestRecord(questbookname, 11);
            Preprocessor_Remove("location");
            Pchar.quest.Contraband.scout.done = true;
            //In 1 day he has to return
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            RemovePassenger(PChar, NPChar);
            NPChar.StoredFellow = True;
            if(DEBUG_SMUGGLING>2)trace("SMUGGLING removed "+NPChar.id+" as officer");
            LAi_SetActorType(NPChar);
            LAi_ActorRunToLocation(characterFromID(NPChar,"reload","reload1", "none", "", "", "",40.0);
            PChar.quest.Send Officer Gone.win_condition.l1 = "ExitFromLocation";
            PChar.quest.Send Officer Gone.win_condition.l1.location = PChar.location;
            PChar.quest.Send Officer Gone.win_condition = "Send Officer Gone";
        break;

        case "Send Officer Gone":
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            ChangeCharacterAddressGroup(NPChar,"none","",""); //We don't have to see him anymore
            LAi_SetOfficerType(NPChar);
            if(DEBUG_SMUGGLING>2)trace("SMUGGLING removed "+NPChar.id+" from location");
            PChar.quest.Contraband_Scouting.win_condition.l1 = "Timer";
            PChar.quest.Contraband_Scouting.win_condition.l1.date.day = GetAddingDataDay(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.month = GetAddingDataMonth(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.year = GetAddingDataYear(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition = "Send Officer time expired";
            if(DEBUG_SMUGGLING>0)trace("SMUGGLING timer set 1 day later ");
        break;

I havent tried it out yet, will probly have time later today, but does this look alright?

EDIT: doesnt work, sadly. first crashed on startup and got undeclared identifier Officer error from
Code:
PChar.quest.Send Officer Gone.win_condition.l1 = "ExitFromLocation"
I added quotes around Send Officer Gone since I guess spaces were the problem. then I got invalid syntax from
Code:
LAi_ActorRunToLocation(characterFromID(NPChar,"reload","reload1", "none", "", "", "",40.0);
I removed characterFromID since it didnt have a closing paranthesis and NPChar was already defined above. she then ran to the door and stopped there but didnt disappear. it didnt trace any errors tho.

I tried keeping characterFromID and adding a paranthesis behind NPChar too, but then she didnt run at all and I got these errors in the log
Code:
RUNTIME ERROR - file: quests\quests.c; line: 471
Invalid conversation
RUNTIME ERROR - file: globals.c; line: 271
function 'NativeFindCharacter' stack error
RUNTIME ERROR - file: globals.c; line: 271
integer function return reference value
RUNTIME ERROR - file: quests\quests.c; line: 472
Array conversation not supported
RUNTIME ERROR - file: quests\quests.c; line: 472
Missed array index
RUNTIME ERROR - file: globals.c; line: 271
function 'NativeFindCharacter' stack error
RUNTIME ERROR - file: globals.c; line: 271
integer function return reference value
RUNTIME ERROR - file: quests\quests.c; line: 478
Missed array index
 
Last edited:
This will also cause problems.
If the character decides to stay in the tavern and just wait there by using the inkeeper dialog to wait for one day the "Send Officer Gone" never will triger (right)?
Could you test this?
 
This will also cause problems.
If the character decides to stay in the tavern and just wait there by using the inkeeper dialog to wait for one day the "Send Officer Gone" never will triger (right)?
Could you test this?
yes, edited my post while you posted! :p
 
sweet xD
EDIT: doesnt work, sadly. first crashed on startup and got undeclared identifier Officer error from
Code:
PChar.quest.Send Officer Gone.win_condition.l1 = "ExitFromLocation"
I added quotes around Send Officer Gone since I guess spaces were the problem. then I got invalid syntax from
Code:
LAi_ActorRunToLocation(characterFromID(NPChar,"reload","reload1", "none", "", "", "",40.0);
I removed characterFromID since it didnt have a closing paranthesis and NPChar was already defined above. she then ran to the door and stopped there but didnt disappear. it didnt trace any errors tho.
change it to PChar.quest.Send_Officer_Gone.win_condition [..etc]
The name here doesn't matter, it looks at the name which is defined for the win_condition attribute. But you can't used spaces in attribute names so you need to replaces them for underscores.

I tried keeping characterFromID and adding a paranthesis behind NPChar too, but then she didnt run at all and I got these errors in the log
Code:
RUNTIME ERROR - file: quests\quests.c; line: 471
Invalid conversation
RUNTIME ERROR - file: globals.c; line: 271
function 'NativeFindCharacter' stack error
RUNTIME ERROR - file: globals.c; line: 271
integer function return reference value
RUNTIME ERROR - file: quests\quests.c; line: 472
Array conversation not supported
RUNTIME ERROR - file: quests\quests.c; line: 472
Missed array index
RUNTIME ERROR - file: globals.c; line: 271
function 'NativeFindCharacter' stack error
RUNTIME ERROR - file: globals.c; line: 271
integer function return reference value
RUNTIME ERROR - file: quests\quests.c; line: 478
Missed array index

You still need to define the character again because maybe since then another questcase has triggered (and other reasons which are to complex to tell now :p ).
 
change it to PChar.quest.Send_Officer_Gone.win_condition [..etc]
The name here doesn't matter, it looks at the name which is defined for the win_condition attribute. But you can't used spaces in attribute names so you need to replaces them for underscores.



You still need to define the character again because maybe since then another questcase has triggered (and other reasons which are to complex to tell now :p ).
Code:
        case "Send Officer to scout":
            //Levis add smuggling questbook
            Preprocessor_AddQuestData("location",locations[FindLocation(Pchar.quest.contraband.CurrentPlace)].name);
            questbookname = "smuggle&number="+Pchar.amount_smuggleruns; //Set a questname
            AddQuestRecord(questbookname, 11);
            Preprocessor_Remove("location");
            Pchar.quest.Contraband.scout.done = true;
            //In 1 day he has to return
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            RemovePassenger(PChar, NPChar);
            NPChar.StoredFellow = True;
            if(DEBUG_SMUGGLING>2)trace("SMUGGLING removed "+NPChar.id+" as officer");
            LAi_SetActorType(NPChar);
            LAi_ActorRunToLocation(characterFromID(PChar.quest.Contraband.officerID),"reload","reload1", "none", "", "", "",40.0);
            PChar.quest.Send_Officer_Gone.win_condition.l1 = "ExitFromLocation";
            PChar.quest.Send_Officer_Gone.win_condition.l1.location = PChar.location;
            PChar.quest.Send_Officer_Gone.win_condition = "Send Officer Gone";
        break;

        case "Send Officer Gone":
            NPChar = characterFromID(PChar.quest.Contraband.officerID);
            ChangeCharacterAddressGroup(NPChar,"none","",""); //We don't have to see him anymore
            LAi_SetOfficerType(NPChar);
            if(DEBUG_SMUGGLING>2)trace("SMUGGLING removed "+NPChar.id+" from location");
            PChar.quest.Contraband_Scouting.win_condition.l1 = "Timer";
            PChar.quest.Contraband_Scouting.win_condition.l1.date.day = GetAddingDataDay(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.month = GetAddingDataMonth(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition.l1.date.year = GetAddingDataYear(0, 0, 1);
            PChar.quest.Contraband_Scouting.win_condition = "Send Officer time expired";
            if(DEBUG_SMUGGLING>0)trace("SMUGGLING timer set 1 day later ");
        break;
still runs to the exit but doesnt disappear. just stands there, inert, cant be talked to
 
@DeathDaisy cant test it myself now but could you try this?
call this trough the console:
Code:
 NPChar = characterFromID(PChar.quest.Contraband.officerID);
           ChangeCharacterAddressGroup(NPChar,"none","",""); //We don't have to see him anymore

does that make the character dissapair?
 
Back
Top