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

Solved Dutchman Quest Revisions (Test Game Download Included)

Logs from Latest Run, computer crashed two times due to that new change... Here:
 

Attachments

  • compile.log
    11.1 KB · Views: 222
  • error.log
    3.6 KB · Views: 243
  • system.log
    10.7 KB · Views: 209
At the minimum, we would expect that the boarding_enemy would have had that charge_max and I wonder if that is why the gun is never used. Should have been set so let's see what's happening during char setup. Find these files/functions and add traces:

characters\CharacterUtilite.c
Code:
void EquipCharacterByItem(ref chref, string itemID)
{
   aref arItm;
trace("EquipCharacterByItem " + itemID);
   if( !CheckCharacterItem(chref, itemID) ) return;
   if( Items_FindItem(itemID, &arItm)<0 )   return;
   if( !CheckAttribute(arItm, "groupID") ) return;

   string groupName = arItm.groupID;
   string oldItemID = GetCharacterEquipByGroup(chref, groupName);
   if(oldItemID==itemID) return;
   chref.equip.(groupName) = itemID;

   if(IsEntity(chref))
   {   trace("calling SetEquipedItemToCharacter " + itemID);
        SetEquipedItemToCharacter(chref, groupName, itemID);
   }
   if(groupName==GUN_ITEM_TYPE && sti(chref.index)==GetMainCharacterIndex())
   {   LAi_GunSetUnload(chref);
   }
   if(groupName==SABERGUN_ITEM_TYPE && sti(chref.index)==GetMainCharacterIndex())
   {   LAi_GunSetUnload(chref);
   }
}

void SetEquipedItemToCharacter(ref chref, string groupID, string itemID)
{
   object emptyItm;
   aref arItm;
   string modelName = "";
   makearef(arItm,emptyItm);
   if(itemID!="")
   {
       if( !CheckCharacterItem(chref,itemID) ) return;
       Items_FindItem(itemID,&arItm);
   }

   switch(groupID)
   {
   case SPYGLASS_ITEM_TYPE:
       if(CheckAttribute(arItm,"id"))
       {
           setTelescopeInitParameters(arItm);
       }
   break;

   case GUN_ITEM_TYPE:
       trace("GUN_ITEM_TYPE " + itemID);
       if(CheckAttribute(arItm,"model"))   {modelName = arItm.model;}
       SendMessage(chref,"ls",MSG_CHARACTER_SETGUN,modelName);
       if(CheckAttribute(arItm,"chargeQ"))
       {
           trace("calling LAi_GunSetChargeQuant " + arItm.chargeQ);
           LAi_GunSetChargeQuant(chref,sti(arItm.chargeQ));
       } else
       {   LAi_GunSetChargeQuant(chref,0);
       }
       if(CheckAttribute(arItm,"chargespeed") && stf(arItm.chargespeed)>0.0)
       {   LAi_GunSetChargeSpeed(chref,1.0/stf(arItm.chargespeed));
       } else
       {   LAi_GunSetChargeSpeed(chref,0.0);
       }
       if(CheckAttribute(arItm,"dmg_min"))
       {   LAi_GunSetDamageMin(chref,stf(arItm.dmg_min));
       } else
       {   LAi_GunSetDamageMin(chref,0.0);
       }
       if(CheckAttribute(arItm,"dmg_max"))
       {   LAi_GunSetDamageMax(chref,stf(arItm.dmg_max));
       } else
       {   LAi_GunSetDamageMax(chref,0.0);
       }
       if(CheckAttribute(arItm,"accuracy"))
       {   LAi_GunSetAccuracy(chref,stf(arItm.accuracy)*0.01);
       } else
       {   LAi_GunSetAccuracy(chref,0.0);
       }
   break;

   case BLADE_ITEM_TYPE:
       float liveTime = 0.1;
       int colors = argb(64, 64, 64, 64);
       int colore = argb(0, 32, 32, 32);
       if(CheckAttribute(arItm,"model"))   {modelName = arItm.model;}
       if(CheckAttribute(arItm, "blade.time"))   {liveTime = stf(arItm.blade.time);}
       if(CheckAttribute(arItm, "blade.colorstart"))   {colors = sti(arItm.blade.colorstart);}
       if(CheckAttribute(arItm, "blade.colorend"))   {colore = sti(arItm.blade.colorend);}
       SendMessage(chref, "llsfll", MSG_CHARACTER_SETBLADE, 0, modelName, liveTime, colors, colore);
       if(CheckAttribute(arItm,"dmg_min"))
       {   LAi_BladeSetDamageMin(chref,stf(arItm.dmg_min));
       } else
       {   LAi_BladeSetDamageMin(chref,0.0);
       }
       if(CheckAttribute(arItm,"dmg_max"))
       {   LAi_BladeSetDamageMax(chref,stf(arItm.dmg_max));
       } else
       {   LAi_BladeSetDamageMax(chref,0.0);
       }
       if(CheckAttribute(arItm,"piercing"))
       {   LAi_BladeSetPiercing(chref,stf(arItm.piercing)*0.01);
       } else
       {   LAi_BladeSetPiercing(chref,0.0);
       }
       if(CheckAttribute(arItm,"block"))
       {   LAi_BladeSetBlock(chref,stf(arItm.block)*0.01);
       } else
       {   LAi_BladeSetBlock(chref,0.0);
       }
   break;

   case SABERGUN_ITEM_TYPE:
       float liveTime2 = 0.1;
       int colors2 = argb(64, 64, 64, 64);
       int colore2 = argb(0, 32, 32, 32);
       if(CheckAttribute(arItm,"model"))   {modelName = arItm.model;}
       if(CheckAttribute(arItm, "blade.time"))   {liveTime2 = stf(arItm.blade.time);}
       if(CheckAttribute(arItm, "blade.colorstart"))   {colors2 = sti(arItm.blade.colorstart);}
       if(CheckAttribute(arItm, "blade.colorend"))   {colore2 = sti(arItm.blade.colorend);}
       SendMessage(chref, "llsfll", MSG_CHARACTER_SETBLADE, 1, modelName, liveTime2, colors2, colore2);
       if(CheckAttribute(arItm,"dmg_min"))
       {   LAi_BladeSetDamageMin(chref,stf(arItm.dmg_min));
       } else
       {   LAi_BladeSetDamageMin(chref,0.0);
       }
       if(CheckAttribute(arItm,"dmg_max"))
       {   LAi_BladeSetDamageMax(chref,stf(arItm.dmg_max));
       } else
       {   LAi_BladeSetDamageMax(chref,0.0);
       }
       if(CheckAttribute(arItm,"piercing"))
       {   LAi_BladeSetPiercing(chref,stf(arItm.piercing)*0.01);
       } else
       {   LAi_BladeSetPiercing(chref,0.0);
       }
       if(CheckAttribute(arItm,"block"))
       {   LAi_BladeSetBlock(chref,stf(arItm.block)*0.01);
       } else
       {   LAi_BladeSetBlock(chref,0.0);
       }
   break;
   }
}

loc_ai\LAi_character.c

Code:
void LAi_GunSetChargeQuant(aref chr, int quant)
{
    trace("LAi_GunSetChargeQuant " + quant);
   if(quant < 0) quant = 0;
   if(quant > 4) quant = 4;
   trace("setting charge_max " + quant);
   chr.chr_ai.charge_max = quant;
   chr.chr_ai.charge = quant;
   chr.chr_ai.chargeprc = "1";
}
 
The Logs As Requested:
 

Attachments

  • compile.log
    20.9 KB · Views: 212
  • error.log
    314 bytes · Views: 220
  • system.log
    4 KB · Views: 227
That gun6 equip is not getting anywhere toward setting the charges for Davy. Let's add some more to see what the hangup might be in CharacterUtilite.c:

Code:
void EquipCharacterByItem(ref chref, string itemID)
{
    aref arItm;
trace("EquipCharacterByItem " + itemID);
    if( !CheckCharacterItem(chref, itemID) ) return;
trace("checked " + itemID);
    if( Items_FindItem(itemID, &arItm)<0 )    return;
    if( !CheckAttribute(arItm, "groupID") ) return;

    string groupName = arItm.groupID;
    string oldItemID = GetCharacterEquipByGroup(chref, groupName);
trace("oldItemID " + oldItemID);
    if(oldItemID==itemID) return;
    chref.equip.(groupName) = itemID;
trace("IsEntity(chref) " + IsEntity(chref));
    if(IsEntity(chref))
    {    trace("calling SetEquipedItemToCharacter " + chref.id + ", " + itemID);
        SetEquipedItemToCharacter(chref, groupName, itemID);
    }
    if(groupName==GUN_ITEM_TYPE && sti(chref.index)==GetMainCharacterIndex())
    {    LAi_GunSetUnload(chref);
    }
    if(groupName==SABERGUN_ITEM_TYPE && sti(chref.index)==GetMainCharacterIndex())
    {    LAi_GunSetUnload(chref);
    }
}
 
Logs based on above traces:
 

Attachments

  • compile.log
    35.2 KB · Views: 217
  • error.log
    8 KB · Views: 231
  • system.log
    4.3 KB · Views: 213
Google drive is being a royal pain uploading the latest version so I have created a mega account to try and have a more reliable file host...
 
The reason the max_charge is not being set is due to IsEntity returning negative. I see now that GenerateCharacter does not actually send a message to create an entity, yet CreateFantom character does. Hence the need to copy stuff...but it does not copy the chr_ai attributes associated with gun charge...I think this will do it:

Change these lines in ChangeAttributesFromCharacter

Code:
if (CheckAttribute(PastChref, "equip.blade"))
    {
       //CopyChref.equip.blade =   PastChref.equip.blade;
       EquipCharacterByItem(CopyChref, PastChref.equip.blade);
   }
   if (CheckAttribute(PastChref, "equip.gun"))
    {
       //CopyChref.equip.gun   =   PastChref.equip.gun;
       EquipCharacterByItem(CopyChref, PastChref.equip.gun);
   }
 
Last edited:
I have been having trouble uploading to file hosts recently. Expect a reply this coming Sunday or Monday as my home machine's client has not been updated.
 
The character is still not shooting at me.... Logs:
 

Attachments

  • compile.log
    56.3 KB · Views: 221
  • error.log
    1.2 KB · Views: 227
  • system.log
    16 KB · Views: 222
Well, the good news is that the last change was correct, the standin char is a valid entity, and the gun charge attributes are now being set correctly:

LoadLocation(ref loc) CaptainCabine
GUN_ITEM_TYPE gun1
calling LAi_GunSetChargeQuant 1
LAi_GunSetChargeQuant 1
setting charge_max 1
EquipCharacterByItem blade1
checked blade1
oldItemID
IsEntity(chref) 0
Special Character
EquipCharacterByItem blade19
checked blade19
oldItemID blade1
IsEntity(chref) 1
calling SetEquipedItemToCharacter Location fantom character <0>, blade19
EquipCharacterByItem gun6
checked gun6
oldItemID
IsEntity(chref) 1
calling SetEquipedItemToCharacter Location fantom character <0>, gun6
GUN_ITEM_TYPE gun6
calling LAi_GunSetChargeQuant 4
LAi_GunSetChargeQuant 4
setting charge_max 4
Standin capt .model (attr funct)= pirate_5
Standin capt .equip.gun (attr funct)= gun6
Standin capt .equip.blade (attr funct)= blade19
Standin capt .location (attr funct)= CaptainCabine
Standin capt .model = pirate_5
Standin capt .equip.gun = gun6
Standin capt .equip.blade = blade19
Standin capt .location = CaptainCabine
charge max 4
charge curr 4

As for the actual character not using the gun, seems a peculiarity with CT, of which I am not yet sure about the cause. I thought it was those gun attributes, but we can see from the log they are now being set properly, so it remains a mystery why the NPC refuses to actually use the gun.
 
OK, I made a console.c, with the same methods to replicate this character scenario, but instead on the pier so I could debug why the character never pulls a pistol. It of course did as you describe, no matter how long I evaded just out of reach, the NPC never fired. But, I eventually figured it all out. Some if is errors in the .ani files, and also a bug fixed in later versions, along with one piece missing to help initiate a call in the engine to kick off the correct event to enable NPC firing. Let me clean up my files and package this up, as it requires modification of .ani files, LAi_events.c, LAi_utils.c, characters.c.
 
Pick it up here: MEGA

GunFix.zip

Also, in void LAi_SetBoardingCaptain, add two lines before LAi_CreateFantomCharacterEx:

Code:
    TempFightChar.skill.fencing = boarding_enemy.skill.fencing;
    TempFightChar.skill.gun = boarding_enemy.skill.gun;
    chr = LAi_CreateFantomCharacterEx(model, ani, "rld", sLoc);
 
Pick it up here: MEGA

GunFix.zip

Also, in void LAi_SetBoardingCaptain, add two lines before LAi_CreateFantomCharacterEx:

Code:
    TempFightChar.skill.fencing = boarding_enemy.skill.fencing;
    TempFightChar.skill.gun = boarding_enemy.skill.gun;
    chr = LAi_CreateFantomCharacterEx(model, ani, "rld", sLoc);
The gun fix has made the boarding defenders more trigger happy, but the commander still refuses to return fire...Logs:
 

Attachments

  • compile.log
    41.4 KB · Views: 216
  • error.log
    157 bytes · Views: 232
  • system.log
    9.5 KB · Views: 220
Here is what I used to test it while standing on the pier in town. It matches the code in the boarding captain logic and works, if you keep your distance long enough:

Code:
void ExecuteConsole()
{
    ref pchar = GetMainCharacter();

    int limit = SpawnDutchman();
    ref chr;
    string ani;
    ref boarding_enemy = &characters[limit];
    string model = LAi_GetBoardingModel(boarding_enemy, &ani);
    string sLoc = "reload1";
    TempFightChar.skill.fencing = boarding_enemy.skill.fencing;
    TempFightChar.skill.gun = boarding_enemy.skill.gun;
    chr = LAi_CreateFantomCharacterEx(model, ani, "reload", sLoc);
    if(CheckAttribute(boarding_enemy, "copyme") && sti(boarding_enemy.copyme) == 1) {
        trace("Special Character");
        ChangeAttributesFromCharacter(chr, boarding_enemy, false);
    }

    SetNewModelToChar(chr);

    LAi_group_MoveCharacter(chr, LAI_GROUP_BRDENEMY);
    LAi_group_FightGroupsEx(LAI_GROUP_PLAYER, LAI_GROUP_BRDENEMY, true, nMainCharacterIndex, -1, false, false);
    LAi_group_SetCheckEvent(LAI_GROUP_BRDENEMY);
    Log_SetStringToLog("Executed Console");

}

If it doesn't work in the cabin, I don't know why that would occur.
 
Well it's no great loss if the captain doesn't do that... At least the boarding defenders are shooting correctly now... :p... Next on the list is the win conditions. They are not working at all...
 
In void ChangeAttributesFromCharacter, add:

Code:
if (CheckAttribute(PastChref, "SuperShooter"))
    {
       CopyChref.SuperShooter         = PastChref.SuperShooter;
   }

In SpawnDutchman(), add:

characters[qChar].SuperShooter = true;

In LAi_fightparams.c, float LAi_NPC_GetFireActive(), change:
Code:
float LAi_NPC_GetFireActive()
{
    float MOD_SKILL_ENEMY_RATE = 3.0;

   aref chr = GetEventData();
   float level = LAi_GetCharacterGunLevel(chr);
   npc_return_tmp = 0.001 + level*0.06;
   // boal íàøè îôèöåðû ïóëÿò èç âñåõ ñòâîëîâ -->
   if (chr.chr_ai.group == LAI_GROUP_PLAYER)
   {
        npc_return_tmp = 0.38 + npc_return_tmp;
   }
   else
   {
   // boal íàøè îôèöåðû ïóëÿò èç âñåõ ñòâîëîâ <--
       if (CheckAttribute(chr, "SuperShooter"))
       {
           npc_return_tmp = npc_return_tmp + 0.4 * MOD_SKILL_ENEMY_RATE / 10.0;
       }
       else
       {
           npc_return_tmp = npc_return_tmp + 0.1 * MOD_SKILL_ENEMY_RATE / 10.0;
       }
   }
   //if (npc_return_tmp > 0.5) npc_return_tmp = 0.5;

   if(!iArcadeFencingAI)
   {
       npc_return_tmp = npc_return_tmp  +  0.03;
       //if (npc_return_tmp > 0.5) npc_return_tmp = 0.5;
   }

   return npc_return_tmp;
}

To debug win conditions, in interface\ransack_main.c:
Code:
void ProcessCancelExit()

if(n<0) {
       trace("ransack n is zero " + refEnepchararacter.id);
       ShipDead(sti(refEnepchararacter.index),KILL_BY_ABORDAGE,sti(pchar.index));
   } else {
       trace("ransack n is other " + refEnepchararacter.id);
....

quests_check.c

Code:
case "NPC_Death":
   trace("NPC_Death " + refcharacter.id);
       return CharacterIsDead(refCharacter);
   break;
 
Latest Run Logs:
 

Attachments

  • compile.log
    61.5 KB · Views: 207
  • error.log
    1.3 KB · Views: 234
  • system.log
    8.1 KB · Views: 233
I kind of suspected it would be here...should have probably had you do this to begin with. Slight addition and change in the ransack_main, swap the order and add hp:

ShipDead(...
trace("ransack n is zero " + refEnepchararacter.id + ", " + refEnepchararacter.chr_ai.hp);

I suspect we will not see a zero for hp.
 
We do see a Zero..
Logs for Changed code:
 

Attachments

  • compile.log
    54.1 KB · Views: 224
  • error.log
    157 bytes · Views: 219
  • system.log
    4.2 KB · Views: 202
Yep. Turns out my suspicion was not even close. It's because OnQuestComplete is called, and it's missing your Dutch Encounter. This should get everything...find and change the following to add DutchEncounterQuestComplete:

battle_interface/utils.c

Code:
void procTimerTimeOut()
{
   QuestComplete(objTimerInterface.questtype, objTimerInterface.questname);
   StoryLineQuestComplete(objTimerInterface.questtype, objTimerInterface.questname);
   DutchEncounterQuestComplete(objTimerInterface.questtype, objTimerInterface.questname);
}

quests_check.c

Code:
void OnQuestComplete(aref quest, string sQuestname)
{
   if(!CheckAttribute(quest,"over") && CheckAttribute(quest,"win_condition"))
   {
       quest.over = "yes";
       QuestComplete(quest.win_condition, sQuestName);
       StoryLineQuestComplete(quest.win_condition, sQuestName);
       DutchEncounterQuestComplete(quest.win_condition, sQuestName);
   }
}

void OnQuestFailed(aref quest, string sQuestName)
{
   if(CheckAttribute(quest,"fail_condition"))
   {
       quest.over = "yes";
       QuestComplete(quest.fail_condition, sQuestName);
       StoryLineQuestComplete(quest.fail_condition, sQuestName);
       DutchEncounterQuestComplete(quest.fail_condition, sQuestName);
   }
}
 
Back
Top