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

Confirmed Bug Sea Relations: When commander of group surrenders the whole group surrenders

Levis

Find(Rum) = false;
Staff member
Administrator
Creative Support
Programmer
Storm Modder
while looking into something else I stumbled on this piece of code in screwface_functions
Code:
if(CheckAttribute(crgchar,"surrendered") || CharacterIsDead(crgchar)){return;}
This seems to cause the problem we had for a while already
commenting out those lines should fix this problem if I read the code right.
Could someone test this?
 
Last edited:
Did ;) Will test it as soon as my PotC lets me play again (since Idk where to put your code I get abnormal determination errors :D )
 
the code should just replace the other piece of code we added before (talking about the dutchman code), if it still gives errors I probally made a typo and just post the error then.
 
Uhm after outcommetning those two lines I get this:

COMPILE ERROR - file: Screwface_functions.c; line: 398
invalid function argument

COMPILE ERROR - file: Screwface_functions.c; line: 398
Invalid Expression

COMPILE ERROR - file: Screwface_functions.c; line: 398
missed ')'

it refers to this:
Code:
    if(CheckAttribute(crgchar,"fantomtype") && crgchar.fantomtype=="trade")
 
hmmmm sounds like something else is going wrong.
btw I just noticed only 1 line must be commented.
only line 367 (in my version at least)
being
Code:
if(CheckAttribute(crgchar,"surrendered") || CharacterIsDead(crgchar)){return;}

so just add // in front of that line
 
Would admittedly be nice to get this sorted. Several people, including myself, already tried things to do on this one.
But so far, nobody has had any luck. Must be a mod-added problem though, since I think it worked at some point in the past.
 
this should fix it, I hope someone can test it for me :).
 
I commented out the line here

This should do the trick. I haven't had a group surrendering yet, so please include it at least to see if it fixes it unless someone wants to test it more for me.
@DavyJack maybe?
 

Attachments

  • Screwface_functions.c
    17.4 KB · Views: 262
Will include that in the next update; hopefully it works as intended! Would be tremendously nice to have this fixed at last. :woot
 
just had a group surrendering at the same time again so it still doesn't work :'( .
 
Drat! So any clue why that check was originally in there? I suspect there must have been a reason, so I don't know if we really should be removing it....
 
I think the check is in there cause if a ship surendered it shouldn't change state anymore.
might be best to change this back altough I haven't found a problem with it, probally its mostly performance based.

As far as I can see the problem lies in the morale.
This piece of code is causing it now I THINK
Code:
void Ship_CheckMorale(int chridx)
{
//if (chridx && DEBUGINFO) trace("Ship_Checkmorale start, chridx = " + chridx);
    ref rCharacter = GetCharacter(chridx);
//if (chridx && DEBUGINFO) trace("Ship_Checkmorale probe 1");
//if (chridx && DEBUGINFO) trace("Ship_Checkmorale rCharacter.index = " + rCharacter.index);
    if(rCharacter.ship.type == SHIP_FORT_NAME) return; // NK fort check 05-04-20
    if(CheckAttribute(rCharacter,"surrendered")) return; // NK surrender 05-04-20
    int timecheck = CHANGE_MORALE_EVERY / (1 + (chridx != GetMainCharacterIndex())*2); //if not mainchar, divide by 3, since checksit is run once per 3 seconds for other ships.
    int timesincelast = timecheck;
    if(CheckAttribute(rCharacter,"seatime.timesincelast"))
        { timesincelast = sti(rCharacter.seatime.timesincelast); }

    if(timesincelast < timecheck)
        { rCharacter.seatime.timesincelast = timesincelast+1; } //increment one and skip; this is to due this once every CHANGE_MORALE_EVERY seconds
    else
    {
        if(!IsCompanion(&rCharacter) && !CheckAttribute(rCharacter,"live")) // added by MAXIMUS [abordage MOD]
        {
            rCharacter.seatime.timesincelast = 0; //reset counter
            float enemydistance = DIST_NOSHIP;
            int targetidx = FindClosestShipofRel(sti(rCharacter.index), &enemydistance, RELATION_ENEMY); // finds nearest hostile ship
            int currenttime = GetSeaTime();
            int lasthit = -1; if(CheckAttribute(rCharacter,"seatime.lasthit")) lasthit = sti(rCharacter.seatime.lasthit); //last time we were hit
            int lastfired = -1; if(CheckAttribute(rCharacter,"seatime.lastfired")) lastfired = sti(rCharacter.seatime.lastfired); // last time we fired or reloaded
            if(!CheckAttribute(rCharacter,"Ship.Crew.Morale")) { rCharacter.Ship.Crew.Morale = 45; }//MAXIMUS
            float tempmorale = stf(rCharacter.ship.crew.morale); if(CheckAttribute(rCharacter,"seatime.tempmorale")) tempmorale = stf(rCharacter.seatime.tempmorale); //i.e. a float morale
            int CrewQuantity = sti(rCharacter.Ship.Crew.Quantity);
            //Logit("Checking morale for the " + rCharacter.ship.name + ", time is " + currenttime + ", current morale is " + fts(tempmorale,2) + ", lht " + lasthit + ", lft " + lastfired);
            if(CheckAttribute(rCharacter,"seatime.lastcrew")) // i.e. have crewmen been killed?
            {
                tempmorale = tempmorale - (stf(rCharacter.seatime.lastcrew) - makefloat(CrewQuantity)) / stf(rCharacter.seatime.basecrewquantity) / CREW_PCT_FOR_MORALE;
                DeleteAttribute(rCharacter,"seatime.lastcrew");
            }
            float combatlevel = COMBATLEVEL_NONE;
            if(enemydistance <= RANGE_TO_ENEMY) combatlevel = COMBATLEVEL_ENEMYHERE;
            if(lastfired != -1) { if((currenttime - lastfired) < TIME_SINCE_GUNS) combatlevel = COMBATLEVEL_GUNS; }
            if(lasthit != -1) { if((currenttime - lasthit) < TIME_SINCE_HIT) combatlevel = COMBATLEVEL_HIT; }
            if(combatlevel == COMBATLEVEL_NONE)
            {
                // return to baseline when not in combat
                if(CheckAttribute(rCharacter,"seatime.basecrewmorale"))
                {
                    int basemorale = sti(rCharacter.seatime.basecrewmorale);
                    if(makeint(tempmorale) != basemorale)
                    {
                        if(tempmorale > basemorale) tempmorale -= MORALE_AMT_COMEBACK;
                        else tempmorale += MORALE_AMT_COMEBACK;
                    }
                }
                else { rCharacter.seatime.basecrewmorale = makeint(tempmorale); } // NK 04-09-16 bugfix if attr not exist.
            }
            else
            {
                //tempmorale -= combatlevel;
                if(tempmorale > 5.0 / combatlevel) { tempmorale -= retmin(COMBATLEVEL_HIT*CHANGE_MORALE_EVERY, combatlevel*2.5); } // now use floors and scalar. 05-04-20
                //Logit("Current combatlevel is " + combatlevel);
            }
            if(CheckAttribute(rCharacter,"seatime.enemydead"))
            {
                tempmorale += stf(rCharacter.seatime.enemydead);
                DeleteAttribute(rCharacter,"seatime.enemydead"); // 04-09-22 fix
            }
            if(tempmorale > MORALE_MAX) tempmorale = MORALE_MAX;
            if(tempmorale < MORALE_MIN) tempmorale = MORALE_MIN;
            //Logit("Morale for " + rCharacter.ship.name + " is " + makeint(tempmorale) + ", change " + (tempmorale - makefloat(sti(rCharacter.ship.crew.morale))));
            rCharacter.ship.crew.morale = makeint(tempmorale);
            rCharacter.seatime.tempmorale = tempmorale;
            //Logit("new morale is " + tempmorale);


            // start surrender checking 05-04-20
            // below also check nosurrender 05-07-06
            if(SURR_GLOBAL_SCL >0 && !IsCompanion(&rCharacter) && targetidx != -1 && lasthit != -1 && !CheckAttribute(&rCharacter, "nosurrender")) // for now comps can't either. Makes life simpler. Also, must be an enemy nearby, and must have been hit.
            {
                float ftmult = 1.0;
                // LDH was using ship's character index as distance - 07Mar09
//                float fdist = DIST_NOSHIP; fdist = FindClosestShipofRel(chridx, &fdist, RELATION_FRIEND);
                float fdist; if (FindClosestShipofRel(chridx, &fdist, RELATION_FRIEND) == -1) fdist = DIST_NOSHIP;    // LDH 07Mar09
                if (CheckAttribute(rCharacter, "fantomtype")) {
                    switch(rCharacter.fantomtype)
                    {
                        case "trade": ftmult = 2.0; break;
                        case "pirate": ftmult = 0.75; break;
                    }
                }
                float mrlmod = Bring2Range(SURR_MRL_SCL_MAX, SURR_MRL_SCL_MIN, 0.1, 1.4, stf(rCharacter.TmpSkill.Leadership)+ AIShip_isPerksUse(rCharacter.TmpPerks.IronWill, 0.0, 0.4));
                ref pch = GetMainCharacter();
                //if(CheckAttribute(rCharacter,"lastballcharacter")) { if(sti(rCharacter.lastballcharacter) == GetMainCharacterIndex()) { if(CheckAttribute(pch,"surmult")) ftmult = 99999.9; } }
                ref rGroup = Group_FindOrCreateGroup(Ship_GetGroupID(rCharacter));
                float surmorale = SURR_MAX_MORALE * mrlmod * ftmult;
//if (chridx && DEBUGINFO) trace("Ship_Checkmorale probe 2");
                if (tempmorale > surmorale) {
                    // put ship back in group and do group's task.
                    if(CheckAttribute(rGroup,"task") && rGroup.task != AITASK_RUNAWAY && CheckAttribute(rCharacter,"SeaAI.task") && rCharacter.SeaAI.task != rGroup.task) { Ship_SetTaskGroupTask(SECONDARY_TASK, chridx); }
                    return;
                }
// LDH fix for possible divide by zero crash -->
                float surch = 0.01;
                if (surmorale != 0.01) surch = Bring2Range(0.75, 0.01, 0.01, surmorale, tempmorale);    // original code
// LDH <--
                float HP = GetCurrentShipHP(&rCharacter);
                float HPr = HP / makefloat(GetCharacterShipHP(&rCharacter));
                // LDH HPr was tested against 20 in following lines, should have been 0.2, changed to 0.4 - 07Mar09
                if(surch > 0.25 || HPr < 0.4) Ship_SetTaskRunaway(SECONDARY_TASK, chridx);    // LDH HPr 0.2 - 07Mar09
//TraceAndLog("**** Surr: surch = " + surch + ", fdist = " + fdist + ", enemydist = " + enemydistance);    // LDH test 07Mar09
                if(HPr > 0.4 && fdist <= enemydistance) return; // if friend closer than enemy, no surrender.
                if (enemydistance > 1600.0) return;                // LDH don't surrender if enemy not on radar - 24Mar09
                if(HPr < 0.4) surch *= Bring2Range(6.0 * (1.0 + makefloat(fdist+200 < enemydistance)), 1.25 * (0.5 + makefloat(fdist+200 < enemydistance)/2.0), 0.1, sqrt(20), sqrt(HPr)); // should often surrender when low on HP, but not if a friend is nearer (to pick them up).
                //ref echr = GetCharacter(targetidx);
                float strengthrat = sqrt(FindPowerRatio(chridx));
                float SP = GetSailPercent(rCharacter);
                if(strengthrat > 1.0) { // they're stronger
                    if (SP < 40)
                        surch *= Bring2Range(5.0, 0.5, 0.1, sqrt(40), sqrt(SP));
                    else
                        surch *= 0.5;
                }
                surch *= SURR_GLOBAL_SCL; // LDH
                //Trace("SURR: for char " + rCharacter.id + " of ship " + rCharacter.ship.name + " surrender chance is " + round(surch*100.0)+"%");
                if (frnd() < surch) Ship_Surrender(chridx);
            }
        }
    }
    // NK <--
}

My guess is the moral of the ships is actually going down to fast. But it seems there are some toggles for it already.

changing this one in the internal setting to 0 should do it for now:
#define SURR_MAX_MORALE

I think we got the same problem here as we had with escort ships etc where there is no food on board etc so the moral drops very quickly which causes all ships to surender almost at the same time cause theire morale has dropped below something.
I'm not sure yet. going to test it now.
 
Why would the morale drop real quick at the exact time the group commander surrenders?
 
no, the group commander surrenders cause his moral drops and as far as I can see most of the group suffer about the same moral drop.
I dont know for sure but I did some testing just yet and most ships end up under 40 (which is set in the file) pretty quick so they can then surrender.
also in surrender ship I see this
Code:
trace("SURR: done lbc boost, now cycle through ships and forts");
        for(i = 0; i < iNumShips; i++)
        {
            if(ships[i] == -1) continue;
            schr = GetCharacter(ships[i]);
            if(SeaAI_GetRelation(Ships[i], chridx) == RELATION_ENEMY && ships[i] != killidx)
            {
                origed = makefloat(GetCharacterShipClass(&schr)) / makefloat(GetCharacterShipClass(&chr)) * CLASS_SCALAR_FOR_MORALE;
                tmped = 0; if(CheckAttribute(schr,"seatime.enemydead")) tmped = stf(schr.seatime.enemydead);
                tmped += origed * CLASS_SCALAR_FOR_MORALE_ORIG_TO_OTHER + makefloat(GetCharacterShipClass(schr)) / makefloat(GetCharacterShipClass(chr)) * CLASS_SCALAR_FOR_MORALE_OTHER;
                schr.seatime.enemydead = tmped;
            }
            // KK tmpstr = Ships[i];
            // KK charsdone.(tmpstr) = true;
            //trace("did " + schr.id);
        }
which to me looks to imply that when a ship in the group surrenders the others get a moral impact to.
I just had 2 large fights and I had no surrenders while I set it to 0 so it does seem to do something.
I checked the moral of the ships during the fights and I think setting it to 20 would be better. When fighting for a while and when I destroyed 2 ships already the morale of the last 2 ships dropped below 20, 1 at first not but when I gave it some more damage it did. so I think lowering this value a bit might work.

I would like to see others test it too.
 
Well - that the whole group surrenders is not the problem - the problem is, when 1 ship surrenderes, (sometimes) the other ships of the convoy turn to status 'neutral' and can't be removed from this status again.. so e.g.:

I attack a group of merchants
one merchant surrenderes - all other merchants change to neutral for me (as seen as grey ships on the compass) and I am able to get back to the worldmap. I am to 100% sure that they didnt surrendered, because they are moving away like they are trying to escape (so maybe they still see me as an enemy - I dont know)
In this state I can't convince the ships to turn enemy to me again (e.g. by firing at them). This is especially frustrating when you have found a convoy which is carrying goods of value like silk and gold..

EDIT:
I just thought about a possible reason for this problem: Could it be, that if the Flagship surrenderes, another captain just gets the command about the group (makes sense, cause the flagship changes) and then somehow doesn't take the nationality/relation check into account, so they stay just neutral? I don't know, just had this idea..
 
Last edited:
That might be the reason, need to check it.
 
@Pillat could you maybe open globals.c and change the variable TRACELOG to 1 (instead of 0). Then try to find a situation where this happened to you and upload your compile log file.
I will search some more too.
 
thats why I ask you to help. I got the same thing enabled and also hope for such an encounter.
 
Back
Top