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

Fixed Crewmen who die from gangrene are actually healed

jsv

Freebooter
Storm Modder
After a brief fight with pirates my hoy has a crew of 18: 16 are fit for duty and 2 are wounded. At least, that's what the ship dialog shows: 16/2. Then I'm told the poor wounded souls have both died from gangrene, so I expect to have 16 sailors left. But I have 18. It's either a bug or a holy necromantic miracle!

I thought I've made a quicksave just before the midnight, but no such luck.

I took a brief look at related code and at first glance nothing looks broken... but something probably is, so I'm leaving a report here. One more thing to keep an eye on... :)
 
That is weird indeed. Worth keeping an eye on.
Pretty sure that worked fine before and the code should not have changed. :shock
 
I'll keep an eye out for this. Me and the buys keep getting into battles, so i should get some confirmation soon.
 
I'm not sure if i can confirm this bug just yet, but i did see that crewmembers said to have healed actually died. Maybe it's simply reversed?
 
I'm not sure if i can confirm this bug just yet, but i did see that crewmembers said to have healed actually died. Maybe it's simply reversed?
It doesn't look that way from the code. The report itself is correct:

Code:
    if (wounded_total > 0 || healed_total > 0 || killed_total > 0) {
        LogIt(wounded_total + " wounded crewmembers: " + healed_total + " healed and " + killed_total + " died from gangrene.");
    }
and the code that precedes it doesn't look broken either.
Well, we have a confirmation that something is not right here. I'll try to investigate this once I'm done with that payments stuff.
 
Could you post the other related code by any chance? I can't look it up myself right now and haven't looked at that since I did some correcting work on it many years back.
 
Here is the relevant part of DailyCrewUpdate:
Code:
// KK & PB -->
    int wounded_total = 0;
    int healed_total = 0;
    int killed_total = 0;
    for (i = 0; i < 4; i++)
    {
        cn = GetCompanionIndex(pchar, i);
        if (cn < 0) continue;
        chref = GetCharacter(cn);
        int wounded_qty = GetWoundedCrewQuantity(chref);
        if (wounded_qty > 0) {
            int healed_qty = GetWoundedHealedPerDay(chref);
            if(healed_qty > wounded_qty) healed_qty = wounded_qty;
            AddCharacterCrew(chref, healed_qty);
            RemoveCharacterWoundedCrew(chref, healed_qty);

            wounded_qty = GetWoundedCrewQuantity(chref);
            int killed_qty = GetWoundedKilledPerDay(chref);
            if(killed_qty > wounded_qty) killed_qty = wounded_qty;
            RemoveCharacterWoundedCrew(chref, killed_qty);

            if (GetCargoGoods(chref, GOOD_TREATMENT) > 0) RemoveCharacterGoods(chref, GOOD_TREATMENT, 1);

            wounded_total = wounded_total + GetWoundedCrewQuantity(chref);
            healed_total  = healed_total  + healed_qty;
            killed_total  = killed_total  + killed_qty;
        }
    }
    if (wounded_total > 0 || healed_total > 0 || killed_total > 0) {
        LogIt(wounded_total + " wounded crewmembers: " + healed_total + " healed and " + killed_total + " died from gangrene.");
    }
// KK & PB <--

Functions from CharacterUtilite:

Code:
// KK -->
int GetWoundedCrewQuantity(ref _refCharacter)
{
    if (!CheckAttribute(_refCharacter, "Ship.Crew.Wounded.Quantity")) return 0;
    return sti(_refCharacter.Ship.Crew.Wounded.Quantity);
}

bool SetWoundedCrewQuantity(ref _refCharacter, int num)
{
    if (num < 0) return;
    int crew = GetTotalCrewQuantity(_refCharacter);
    if (num == 0) {
        if (CheckAttribute(_refCharacter, "Ship.Crew.Wounded")) {
            AddCharacterCrew(_refCharacter, GetWoundedCrewQuantity(_refCharacter));
            DeleteAttribute(_refCharacter, "Ship.Crew.Wounded");
        }
        return true;
    }
    if (num > crew) num = crew;
    SetCrewQuantity(_refCharacter, crew - num);
    _refCharacter.Ship.Crew.Wounded.Quantity = num;
    return true;
}

void ResetSquadronWoundedCrew()
{
    ref pchar = GetMainCharacter();
    for (int i = 0; i < 4; i++)
    {
        int cn = GetCompanionIndex(pchar, i);
        if (cn < 0) continue;
        ref rCharacter = GetCharacter(cn);
        SetWoundedCrewQuantity(rCharacter, 0);
    }
}

bool AddCharacterWoundedCrew(ref _refCharacter, int num)
{
    if (num == 0) return false;
    return SetWoundedCrewQuantity(_refCharacter, GetWoundedCrewQuantity(_refCharacter) + num);
}

bool RemoveCharacterWoundedCrew(ref _refCharacter, int num)
{
    int woundedCrew = GetWoundedCrewQuantity(_refCharacter);
    if (num > woundedCrew) num = woundedCrew;
    return SetWoundedCrewQuantity(_refCharacter, woundedCrew - num);
}

int GetTotalCrewQuantity(ref _refCharacter)
{
    return GetCrewQuantity(_refCharacter) + GetWoundedCrewQuantity(_refCharacter);
}

string GetCharacterOfficerType(ref _refCharacter)
{
    if (!CheckAttribute(_refCharacter, "quest.officertype")) return "";
    return _refCharacter.quest.officertype;
}
// <-- KK

// PB -->
int GetWoundedHealedPerDay(ref _refCharacter)
{
    int healing_rate = HEALED_PER_DAY;
    if(CharacterHasOfficerType(_refCharacter, OFFIC_TYPE_DOCTOR))
        healing_rate = healing_rate + CharacterGetOfficerSkill(_refCharacter, OFFIC_TYPE_DOCTOR, "defence");
    if(GetCargoGoods(_refCharacter, GOOD_TREATMENT) > 0)
        healing_rate = healing_rate + HEALED_WITH_MEDS;
    return makeint(0.5 * healing_rate + rand(healing_rate));
}

int GetWoundedKilledPerDay(ref _refCharacter)
{
    int death_rate = KILLED_PER_DAY;
    if(CharacterHasOfficerType(_refCharacter, OFFIC_TYPE_DOCTOR))
        death_rate = death_rate - CharacterGetOfficerSkill(_refCharacter, OFFIC_TYPE_DOCTOR, "defence");
    if(GetCargoGoods(_refCharacter, GOOD_TREATMENT) > 0)
        death_rate = death_rate - HEALED_WITH_MEDS;
    return makeint(0.5 * death_rate + rand(death_rate));
}

Tell me if you want the code that assigns casualties in battle or anything else.
 
Code:
string GetCharacterOfficerType(ref _refCharacter)
{
  if (!CheckAttribute(_refCharacter, "quest.officertype")) return "";
  return _refCharacter.quest.officertype;
}
@Levis: Do you think maybe we should start using that in various places instead of just reading that attribute?
I think using functions would be preferred....

Tell me if you want the code that assigns casualties in battle or anything else.
Unless that creates negative values, I don't see where that could go wrong.

But maybe the section from PROGRAM\INTERFACE\ship.c that displays the numbers could help?

I'm also not quite clear yet on the actual problem.
The on-screen log message from post #6 above shows that a certain amount of crew have been healed and died.
So that one IS correct? But the F2>Ship>Crew interface subsequently does not update in the way you'd expect?

I do spot one bit of potential weirdness: The use of Medications seems a little odd.
It is one Medication per ship for whatever number of wounded/healed per day.
No sharing between the fleet, by the looks of it. But that just "simple" and not technically wrong.

Also curious that it takes away one medication good only if you have them.
But that probably goes OK since if you don't have them, you don't get the bonus from them either.
 
In my game, it was like that: I check F2>Ship>Crew, it shows 16/2. Then on daily update I have 2 died from gangrene, then F2>Ship>Crew shows 18.

But maybe the section from PROGRAM\INTERFACE\ship.c that displays the numbers could help?

I doubt that :)
Code:
// PB -->
                if (GetWoundedCrewQuantity(otherCh) > 0)
                    GameInterface.strings.Crew = GetCrewQuantity(otherCh) + "/" + GetWoundedCrewQuantity(otherCh);
                else
                    GameInterface.strings.Crew = GetCrewQuantity(otherCh);
 
In my game, it was like that: I check F2>Ship>Crew, it shows 16/2. Then on daily update I have 2 died from gangrene, then F2>Ship>Crew shows 18.
It didn't say "0 wounded crewmembers: 2 healed and 2 died from gangrene." by any chance, did it?
It could be that there is nothing in place to prevent that, but that would of course be conjuring free crewmembers out of thin air. :confused:
 
I think it was "0 healed and 2 died", but I can't be sure. At the moment I had no reason to pay very close attention to that message.
 
It could be that there is nothing in place to prevent that
The total amount of wounded is reduced by the amount of healed before it gets to any killing. And there are checks to prevent more wounded than you actually have from dying/healing.
So that scenario with 2 died 2 healed should not be happening. Probably. :)
 
The total amount of wounded is reduced by the amount of healed before it gets to any killing. And there are checks to prevent more wounded than you actually have from dying/healing.
So that scenario with 2 died 2 healed should not be happening. Probably. :)
True that. I do seem to remember I gave it some proper thought back when I actually messed around with that.
As far as I recall, it worked at the time. So I'm a bit surprised that you guys are noting such weirdness now. :confused:
 
As far as I recall, it worked at the time. So I'm a bit surprised that you guys are noting such weirdness now. :confused:
It's certainly is puzzling. If not for @morgan terror 's confirmation, I'd be wondering whether I had imagined the entire episode. Not that I'm much given to such flights of imagination, but still... Well, I guess when I have a free evening, I'll try calling SetWoundedCrewQuantity from the console to see if I can collect more info on this.
 
It didn't say "0 wounded crewmembers: 2 healed and 2 died from gangrene." by any chance, did it?
It could be that there is nothing in place to prevent that, but that would of course be conjuring free crewmembers out of thin air. :confused:

From what i've seen, the problem is that the messages you recieve are the inverse of the actual result. I'm wondering what would happen if you don't have any medications on board. If it works properly when you don't, we might be able to narrow down the source of the problem. I'll continue to keep an eye on this.
 
Ok, I was able to reproduce it and I think I see where the problem is... to be continued... :)
 
Yep, i can confirm this. 83/1 before the hour change, message of 1 healed, 0 died, and had 83 healthy crew after. Same result after 5 tries. Tossing the medicaments overboard first made the crewmember die from gangrene (sometimes, as intentional), and also resulted in 83 healthy crew. The only thing left to test now is seeing what happens when i've got medicaments on board, but the crewmember dies anyway. I haven't been able to make that happen again since i made my first post in this topic, but i'd like to test it some more.
 
Medications do not matter, it's simpler that that. The problem is that RemoveCharacterWoundedCrew actually adds ex-wounded crewmembers back to active service. There seems to be no method for sending them to the Davy Jones' Locker instead, short of updating the attribute directly.

Was the functionality of RemoveCharacterWoundedCrew/SetWoundedCrewQuantity altered at some point in not so remote past? It's hard to imagine this went for a decade unnoticed... :confused:
 
Changing the code in DailyCrewUpdate like this:

Code:
if (wounded_qty > 0) {
            int healed_qty = GetWoundedHealedPerDay(chref);
            if(healed_qty > wounded_qty) healed_qty = wounded_qty;
            // AddCharacterCrew(chref, healed_qty);
            RemoveCharacterWoundedCrew(chref, healed_qty);

            wounded_qty = GetWoundedCrewQuantity(chref);
            int killed_qty = GetWoundedKilledPerDay(chref);
            if(killed_qty > wounded_qty) killed_qty = wounded_qty;
            RemoveCharacterWoundedCrew(chref, killed_qty);
            SetCrewQuantity(chref, GetCrewQuantity(chref) -  killed_qty);

            if (GetCargoGoods(chref, GOOD_TREATMENT) > 0) RemoveCharacterGoods(chref, GOOD_TREATMENT, 1);

            wounded_total = wounded_total + GetWoundedCrewQuantity(chref);
            healed_total  = healed_total  + healed_qty;
            killed_total  = killed_total  + killed_qty;
        }
solves the problem for me. That's not a proper fix, of course. The proper fix would be to add a function called PleaseKillThatDamnedWoundedCrewPermanently to CharacterUtilite.
 
@Pieter Boelen: I propose to rename RemoveCharacterWoundedCrew to HealCharacterWoundedCrew, because that's what it does. It's used elsewhere only once, so that's not a laborious task.
Then add a proper RemoveCharacterWoundedCrew (or maybe KillCharacterWoundedCrew?) and use it here in DailyCrewUpdate. I can do that tomorrow unless you have some better ideas.
 
Back
Top