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 <--
}