#define INVALID_SHIP_TYPE			-1

ref Fantom_GetNextFantom()
{
	iNumFantoms++;
	return &Characters[FANTOM_CHARACTERS + iNumFantoms];
}

int Fantom_GenerateEncounter(string sGroupName, object oResult, int iEType, int iNation) // NK
{
	aref	aWar, aMerchant;
	ref		rEnc;
	int		i, iNumMerchantShips, iNumWarShips;
	int		iWarClassMax, iWarClassMin, iMerchantClassMax, iMerchantClassMin;

	ref rCharacter = GetMainCharacter();

	makeref(rEnc, EncountersTypes[iEType]);
	makearef(aWar, rEnc.War);
	makearef(aMerchant, rEnc.Trade);

	iNumMerchantShips = MakeInt(aMerchant.ShipsMin) + rand(MakeInt(aMerchant.ShipsMax) - MakeInt(aMerchant.ShipsMin));
	iNumWarShips = MakeInt(aWar.ShipsMin) + rand(MakeInt(aWar.ShipsMax) - MakeInt(aWar.ShipsMin));

	int iRank = sti(rCharacter.Rank);
	if(GetShipCap()) { { if((8-GetCharacterShipClass(rCharacter)) * 2 < iRank) iRank = (8-GetCharacterShipClass(rCharacter)) * 2; } } // NK
	Encounter_GetClassesFromRank(iEType, iRank, &iMerchantClassMin, &iMerchantClassMax, &iWarClassMin, &iWarClassMax);
	//
	/*iWarClassMax = MakeInt(aWar.ClassMax);
	iWarClassMin = MakeInt(aWar.ClassMin);
	iMerchantClassMax = MakeInt(aMerchant.ClassMax);
	iMerchantClassMin = MakeInt(aMerchant.ClassMin);*/

	//Trace("class max = " + iMerchantClassMax + ", class min = " + iMerchantClassMin);

	int iFantomIndex, iShipType;

	//Trace("iNumMerchants = " + iNumMerchantShips);
	//Trace("iNumWars = " + iNumWarShips);
	
	for (i=0; i<iNumMerchantShips; i++)
	{
		if(iNumShips + i >= MAX_SHIPS_ON_SEA) return i; // NK bugfix
		iShipType = Force_GetShipType(iMerchantClassMax, iMerchantClassMin, "Trade", iNation); // NK change to type trade, fixed to swap min,max 04-09-13. Change to Force
		if (iShipType == INVALID_SHIP_TYPE) continue;
		//Trace("Merchant ship class = " + ShipsTypes[iShipType].Class + ", name = " + ShipsTypes[iShipType].Name);
		Fantom_AddFantomCharacter(sGroupName, iShipType, "trade", iEType, iNation);
	}

	for (i=0; i<iNumWarShips; i++)
	{
		if(iNumShips + iNumMerchantShips + i >= MAX_SHIPS_ON_SEA) return iNumMerchantShips + i; // NK bugfix
		iShipType = Force_GetShipType(iWarClassMax, iWarClassMin, "War", iNation); // NK fixed to swap min,max 04-09-13 Change to Force
		if (iShipType == INVALID_SHIP_TYPE) continue;
		//Trace("War ship class = " + ShipsTypes[iShipType].Class + ", name = " + ShipsTypes[iShipType].Name);
		Fantom_AddFantomCharacter(sGroupName, iShipType, "war", iEType, iNation);
	}

	return iNumWarShips + iNumMerchantShips;
}

int Fantom_GetShipType(int iClassMax, int iClassMin, string sShipType, int iNation) // NK
{
	int iShips[2];		// was 512 - must be careful!!!!
	SetArraySize(&iShips, SHIP_TYPES_QUANTITY*10); // new version of chance
	int i, iShipsNum, iClass;
	for(i = 0; i < SHIP_TYPES_QUANTITY*10; i++) iShips[i] = INVALID_SHIP_TYPE;
	// NK -->
	int shipnation = -1;
	float NatSkipChance;
	ref rShip;
	if(iNation == PIRATE) { NatSkipChance = NOSKIP_CHANCE_WRONGNATION_PIRATE; }
	else { NatSkipChance = NOSKIP_CHANCE_WRONGNATION; }
	if(sShipType == "pirate")
	{
		if(PIRATES_USE_BOTH_TYPES) { sShipType = ""; }
		else { sShipType = "war"; }
	}
	int curyear = GetDataYear();
	iShipsNum = 0;
	// move class clamps things to Force_... 05-05-11
	for (i=0; i<SHIP_TYPES_QUANTITY; i++)
	{
		rShip = GetShipByType(i); // why was this type object? 05-05-11
		iClass = sti(rShip.Class);
		if (iClass > iClassMin) { continue; }
		if (iClass < iClassMax) { continue; }
		if (sti(rShip.CanEncounter) != true) { continue; }
		// PB: Periods -->
// KK -->
		if (iNation >= 0 && iNation < MAX_NATIONS) {
			string sNation = GetNationNameByType(iNation);
			if (CheckAttribute(rShip, sNation) == true && sti(rShip.(sNation)) > FRAND(1.0)) continue;
		}
		string sPeriod = GetCurrentPeriod();
		if (CheckAttribute(rShip, "period."+sPeriod) && sti(rShip.period.(sPeriod)) > FRAND(1.0)) continue;
// <-- KK
		/*switch(iNation)
		{
			case ENGLAND:	if(CheckAttribute(rShip,"england") && sti(rShip.england) > rand(100))	continue; break;
			case HOLLAND:	if(CheckAttribute(rShip,"holland") && sti(rShip.holland) > rand(100))	continue; break;
			case FRANCE:	if(CheckAttribute(rShip,"france") && sti(rShip.france) > rand(100))		continue; break;
			case SPAIN:		if(CheckAttribute(rShip,"spain") && sti(rShip.spain) > rand(100))		continue; break;
			case PORTUGAL:	if(CheckAttribute(rShip,"portugal") && sti(rShip.portugal) > rand(100))	continue; break;
			case PIRATE:	if(CheckAttribute(rShip,"pirate") && sti(rShip.pirate) > rand(100))		continue; break;
		}
		switch(GetCurrentPeriod())
		{
			case PERIOD_EARLY_EXPLORERS:		if(CheckAttribute(rShip,"period0") && sti(rShip.period0) > rand(100)) continue; break;
			case PERIOD_THE_SPANISH_MAIN:		if(CheckAttribute(rShip,"period1") && sti(rShip.period1) > rand(100)) continue; break;
			case PERIOD_GOLDEN_AGE_OF_PIRACY:	if(CheckAttribute(rShip,"period2") && sti(rShip.period2) > rand(100)) continue; break;
			case PERIOD_COLONIAL_POWERS:		if(CheckAttribute(rShip,"period3") && sti(rShip.period3) > rand(100)) continue; break;
			case PERIOD_REVOLUTIONS:			if(CheckAttribute(rShip,"period4") && sti(rShip.period4) > rand(100)) continue; break;
			case PERIOD_THE_CORSICAN:			if(CheckAttribute(rShip,"period5") && sti(rShip.period5) > rand(100)) continue; break;
		}*/
		// PB: Periods <--
		// new version of chance - old was if(CheckAttribute(rShip,"chance")) { if(frnd() > stf(rShip.chance)) { continue; } } // 04-09-10 will skip if chance not met
		// NK mod so we can disregard shiptype if we want to: 04-09-04
		// LDH --> new fix for missing sShipType 03Sep06
//		if(sShipType != "") { if (!sti(rShip.Type.(sShipType))) { continue; } }	// Original NK code
		if(sShipType != "")
		{
			if (CheckAttribute(rShip, "Type."+sShipType))
			{
				if (!sti(rShip.Type.(sShipType))) continue;
			}
			else
			{
				trace("Fantom_GetShipType(): Ship " + rShip.id + " has no shiptype");
				continue;
			}
		}
		// LDH <--
		// NK -->
		if(CheckAttribute(rShip,"Nation") && iNation != -1)
		{
			shipnation = sti(rShip.Nation);
			if(shipnation != iNation && frnd() > NatSkipChance) { continue; }
		}
		iClass = sti(rShip.chance); // New version of chance 05-05-11
		iShips[iShipsNum] = i;
//		iShipsNum += iClass;
		iShipsNum++;
	}
	if (iShipsNum==0)
	{
		Trace("Can't find ship type '" + sShipType + "' with ClassMin = " + iClassMin + " and ClassMax = " + iClassMax);
		return INVALID_SHIP_TYPE;
	}
	i = rand(iShipsNum-1);
	while(i > 0 && iShips[i] == INVALID_SHIP_TYPE) i--;
	return iShips[i];
}

// return new added fantom character
void Fantom_AddFantomCharacter(string sGroupName, int iShipType, string sFantomType, int iEncounterType, int iNation) // NK 04-09-05 add nation argument
{
	ref rFantom = GetFantomCharacter(iNumFantoms);
	rFantom.nation = iNation; // NK

	DeleteAttribute(rFantom, "relation");

	rFantom.SeaAI.Group.Name = sGroupName;
	rFantom.Ship.Type = GetShipID(iShipType); // PS
	//trace("added fantom " + rFantom.index + " with ship " + rFantom.ship.type);
	rFantom.Ship.idx = iShipType; // PS
	rFantom.Ship.Mode = sFantomType;
	rFantom.ship.cannons.Charge.Type = GOOD_BALLS;
//NK -->
	DeleteAttribute(rFantom,"ship.cannons.borts"); rFantom.ship.cannons.borts = ""; // NK 05-04-18 cannon qty
	// PRS3 -->
	aref arship; makearef(arship, rFantom.ship);
	DeleteAttribute(rFantom, "ship.stats");
//KB - Tuning ships - changed call to SetRandomStatsToShip
	SetRandomStatsToShip(sti(rFantom.index), iShipType, iNation);
//KB - orig   SetRandomStatsToShip(arship, iShipType, iNation);
//KB
// PRS3 <--
	if(sti(rFantom.nation) == PIRATE) { sFantomType = "pirate"; }
	else { if(sFantomType == "pirate") { sFantomType = "war"; } }
	rFantom.shiptype = GetShipID(iShipType); // PS
	rFantom.FantomType = sFantomType;
	float mult = 1.0;
	switch(sFantomType)
	{
		case "trade":
			mult *= 1.0;
			rFantom.quest.officertype = OFFIC_TYPE_CAPMERCHANT;
			break;
			
		case "war":
			mult *= 1.25;
			rFantom.quest.officertype = OFFIC_TYPE_CAPNAVY;
			break;
			
		case "pirate":
			mult *= 1.25;
			rFantom.quest.officertype = OFFIC_TYPE_CAPPIRATE;
			break;

		case "error":
			mult *= 1.0;
			rFantom.quest.officertype = OFFIC_TYPE_CAPPIRATE;
			break;
	}
	ref Shiptype = GetShipByType(iShipType);
	int iMCShipClass = makeint(GetCharacterShipClass(GetMainCharacter()));
	if(makeint(Shiptype.Class) < iMCShipClass) mult *= 1.15;
	else { if(makeint(Shiptype.Class) > iMCShipClass) { mult *= 0.85; } }
	rFantom.Points = mult * stf(GetLocalShipAttrib(&arship,&Shiptype,"Weight")) / 5000; // PRS3
	//Log_SetStringToLog("Type: " + rFantom.FantomType + "; Mult: " + rFantom.Points);
// NK <--
	iNumFantoms++;
}

void Fantom_SetRandomMoney(ref rFantom, string sFantomType)
{
//NK, based on Stone-D -->
	// clear money from character
	rFantom.ShipMoney = 0;

	// ship class
	ref rShip = GetShipByType(GetCharacterShipType(rFantom));
	aref arship; makearef(arship, rFantom.ship); // PRS3 on down
	float cap = stf(GetLocalShipAttrib(arship,rShip,"Capacity")); //get ship's capacity.
	float weight = makefloat(sti(GetLocalShipAttrib(arship,rShip,"Weight"))) * 10000 / 508; //get ship's weight. Changed 04-09-19 to be more accurate, was simply *19.7
	int rank = sti(rFantom.rank);
	//make rankscalar
	float ranksc = makefloat(rank);
	if(ranksc<=5.0) ranksc = ranksc/5.0
	else ranksc = sqrt(ranksc) - 1.236;
	ranksc = ranksc*10;
	int rscale = makeint(ranksc);
	// add money
	// 04-09-22 add SHIPMONEY_MULT
	switch (rFantom.FantomType)
	{
		case "trade":
			rFantom.ShipMoney = makeint(SHIPMONEY_MULT * (cap * makefloat(30 + rand(20) + rand(20)) * (rscale/2.0 + rand(rscale))/40.0 + (rand(10)+5.0)/30.0));
			return;
		break;
		case "war":
			rFantom.ShipMoney = makeint(SHIPMONEY_MULT * (weight * makefloat(40 + rand(10) + rand(10)) * (rscale/2.0 + rand(rscale))/20.0 + (rand(10)+5.0)/30.0));
			return;
		break;
		case "pirate":
			rFantom.ShipMoney = makeint(SHIPMONEY_MULT * (weight * (5.0 + (rand(5)+1.0) * (rand(5)+1.0)) * (rscale/2.0 + rand(rscale))/20.0 + (rand(10)+5.0)/15.0));
			return;
		break;
	}
	//Trace("Fantom index = " + rFantom.index + ", group id = " + rFantom.SeaAI.Group.Name + ", have invalid encounter type = " + sFantomType);
// NK <--
}

// START MOD Code by Stone-D : 01/08/2003
// No longer relevant as this function is never used due to SD_GenSkills(). Kept for reference.
//int Fantom_CalcSkill(ref rMainCharacter, string sSkill, int iShipClass, int iSkillMin, int iSkillMax, int iSClass1, int iSClass2, int iSClass3, int iSClass4, int iSClass5, int iSClass6, int iSClass7)
int Fantom_CalcSkill(ref rMainCharacter, string sSkill, int iShipClass, int iSkillMin, int iSkillMax, int iSClass7, int iSClass6, int iSClass5, int iSClass4, int iSClass3, int iSClass2, int iSClass1)
// Stone-D : It was all backwards!
{
	int iSkill = GetSummonSkillFromName(rMainCharacter, sSkill);
	//Trace("iSkill = " + iSkill + ", sSkill = " + sSkill);
//	iSkill = iSkill + iSkillMin + rand(iSkillMax - iSkillMin);
	iSkill = iSkill + iSkillMin + rand(iSkillMax - iSkillMin) + rand(4); // Stone-D : Should up the ante a bit.
	switch (iShipClass)
	{
		case 1: iSkill = iSkill + iSClass1; break;
		case 2: iSkill = iSkill + iSClass2; break;
		case 3: iSkill = iSkill + iSClass3; break;
		case 4: iSkill = iSkill + iSClass4; break;
		case 5: iSkill = iSkill + iSClass5; break;
		case 6: iSkill = iSkill + iSClass6; break;
		case 7: iSkill = iSkill + iSClass7; break;
	}

	if (iSkill < 1)			iSkill = 1;
//	if (iSkill > SKILL_MAX) iSkill = SKILL_MAX; // Stone-D : This was totally unfair and made the game too easy. Fuckin XBOX.  :(
	if (iSkill > 10) iSkill = 10;
	return iSkill;
}
// END MOD Code by Stone-D : 01/08/2003

void Fantom_SetRandomSkills(ref rFantom, string sFantomType)
{
// START MOD Code by Stone-D : 01/08/2003
	SD_GenSkills(rFantom); // Stone-D : Totally replaces this function.
	return; // Stone-D : Remove this line or comment it if you want 'type' to affect skills. Less fair.
// END MOD Code by Stone-D : 01/08/2003
//	ref rCharacter = GetMainCharacter();
	ref rCharacter = rFantom;

	aref aFSkills; makearef(aFSkills, rFantom.Skill);

	CalculateAppropriateSkills(rFantom);

	int iSClass = GetCharacterShipClass(rFantom);

	switch (sFantomType)
	{
		case "trade":
			aFSkills.Leadership = Fantom_CalcSkill(rCharacter, SKILL_LEADERSHIP,iSClass, -3, 0, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Accuracy	= Fantom_CalcSkill(rCharacter, SKILL_ACCURACY,	iSClass, -3, 1, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Commerce	= Fantom_CalcSkill(rCharacter, SKILL_COMMERCE,	iSClass, -1, 3, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Cannons	= Fantom_CalcSkill(rCharacter, SKILL_CANNONS,	iSClass, -3, 1, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Grappling	= Fantom_CalcSkill(rCharacter, SKILL_GRAPPLING, iSClass, -3, 0, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Fencing	= Fantom_CalcSkill(rCharacter, SKILL_FENCING,	iSClass, -3, 1, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Repair		= Fantom_CalcSkill(rCharacter, SKILL_REPAIR,	iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Sailing	= Fantom_CalcSkill(rCharacter, SKILL_SAILING,	iSClass, -2, 2, 3, 2, 1, 0, 0, 0, 0);
			aFSkills.Sneak		= Fantom_CalcSkill(rCharacter, SKILL_SNEAK,		iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Defence	= Fantom_CalcSkill(rCharacter, SKILL_DEFENCE,	iSClass, -2, 2, 3, 2, 1, 0, 0, 0, 0);
			return;
		break;
		case "war":
			aFSkills.Leadership = Fantom_CalcSkill(rCharacter, SKILL_LEADERSHIP,iSClass, -1, 3, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Accuracy	= Fantom_CalcSkill(rCharacter, SKILL_ACCURACY,	iSClass, -3, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Commerce	= Fantom_CalcSkill(rCharacter, SKILL_COMMERCE,	iSClass, -3, 1, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Cannons	= Fantom_CalcSkill(rCharacter, SKILL_CANNONS,	iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Grappling	= Fantom_CalcSkill(rCharacter, SKILL_GRAPPLING, iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Fencing	= Fantom_CalcSkill(rCharacter, SKILL_FENCING,	iSClass, -2, 2, 3, 2, 1, 0, 0, 0, 0);
			aFSkills.Repair		= Fantom_CalcSkill(rCharacter, SKILL_REPAIR,	iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Sailing	= Fantom_CalcSkill(rCharacter, SKILL_SAILING,	iSClass, -2, 2, 3, 2, 1, 0, 0, 0, 0);
			aFSkills.Sneak		= Fantom_CalcSkill(rCharacter, SKILL_SNEAK,		iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Defence	= Fantom_CalcSkill(rCharacter, SKILL_DEFENCE,	iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			return;
		break;
		case "pirate":
			aFSkills.Leadership = Fantom_CalcSkill(rCharacter, SKILL_LEADERSHIP,iSClass, -2, 2, 3, 2, 1, 0, 0, 0, 0);
			aFSkills.Accuracy	= Fantom_CalcSkill(rCharacter, SKILL_ACCURACY,	iSClass, -2, 2, 3, 2, 1, 0, 0, 0, 0);
			aFSkills.Commerce	= Fantom_CalcSkill(rCharacter, SKILL_COMMERCE,	iSClass, -3, 1, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Cannons	= Fantom_CalcSkill(rCharacter, SKILL_CANNONS,	iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Grappling	= Fantom_CalcSkill(rCharacter, SKILL_GRAPPLING, iSClass, -1, 3, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Fencing	= Fantom_CalcSkill(rCharacter, SKILL_FENCING,	iSClass, -1, 3, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Repair		= Fantom_CalcSkill(rCharacter, SKILL_REPAIR,	iSClass, -3, 1, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Sailing	= Fantom_CalcSkill(rCharacter, SKILL_SAILING,	iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Sneak		= Fantom_CalcSkill(rCharacter, SKILL_SNEAK,		iSClass, -2, 2, 0, 0, 0, 0, 0, 0, 0);
			aFSkills.Defence	= Fantom_CalcSkill(rCharacter, SKILL_DEFENCE,	iSClass, -1, 3, 0, 0, 0, 0, 0, 0, 0);
			return;
		break;
	}
	Trace("Fantom index = " + rFantom.index + ", group id = " + rFantom.SeaAI.Group.Name + ", have invalid encounter type = " + sFantomType);
}

void Fantom_SetCannons(ref rFantom, string sFantomType)
{
	int iSClass = GetCharacterShipClass(rFantom);
	ref rShip = GetShipByType(GetCharacterShipType(rFantom));

	/*int iCannonsType = sti(rShip.Cannon);
	string sCannonType = "cannon";
	int iCaliber = sti(rShip.MaxCaliber);

	switch(rand(3))
	{
		case 0:
			iCaliber = 12;
		break;
		case 1:
			iCaliber = 16;
		break;
		case 2:
			iCaliber = 24;
		break;
		case 3:
			iCaliber = 32;
		break;
	}

	if(iCaliber>sti(rShip.MaxCaliber)) { iCaliber=sti(rShip.MaxCaliber); }

	switch (sFantomType)
	{
		case "trade":
			sCannonType = "culverine";
		break;
		case "war":
			if (rand(1) == 1) { sCannonType = "culverine"; }
		break;
		case "pirate":
			if (iSClass == 6) { sCannonType = "culverine"; }
		break;
	}

	if (sti(rShip.Cannon) == CANNON_TYPE_NONECANNON)
	{
		rFantom.Ship.Cannons.Type = CANNON_TYPE_NONECANNON;
		return;
	}

	if(iCaliber>24 && sCannonType == "culverine" ) { iCaliber=24; }
*/
	//Trace("sCannonType = " + sCannonType);
//NK -->
	aref arship; makearef(arship, rFantom.ship); // PRS3
	int iCaliber = sti(GetLocalShipAttrib(arship, rShip,"MaxCaliber")); // PRS3
	string sCannonType;
	ResetCannons(&rFantom); // whoops, need this!
	if(USE_REAL_CANNONS)
	{
		//KNB -->
		sCannonType = "long gun";
		if(rFantom.FantomType == "trade")
		{
			switch(rand(3))
			{
				case 0:
					iCaliber = 4;
				break;
				case 1:
					iCaliber = 6;
				break;
				case 2:
					iCaliber = 9;
				break;
				case 3:
					iCaliber = 12;
				break;
			}
			// NK start gun qty code 05-04-18 -->
			if(sti(rShip.Cannons.Borts.cannonl.qty) > 1) // if broadsides have >1 guns each
			{
				int newbsqty = 1+rand(sti(rShip.Cannons.Borts.cannonl.qty)-1); // new bs qty is random between 1 and normal
				arship.Cannons.Borts.cannonl.qty = newbsqty;
				arship.Cannons.Borts.cannonr.qty = newbsqty;
			}
			if(sti(rShip.Cannons.Borts.cannonb.qty) > 1) { arship.Cannons.Borts.cannonb.qty = 1+rand(sti(rShip.Cannons.Borts.cannonb.qty)-1); }
			// NK <--
		}
		else
		{
			if(rand(1) && iCaliber >= 6 && iCaliber <= 12) { sCannonType = "carronade"; }
		}
		if(iCaliber>sti(rShip.MaxCaliber)) { iCaliber=sti(rShip.MaxCaliber); }
		//KNB <--
	}
	else
	{
		sCannonType = "cannon";
		if(rFantom.FantomType == "trade") iCaliber = 12;
		else { if(rand(1) && iCaliber < 32) { sCannonType = "culverine"; } }
	}
	rFantom.Ship.Cannons.Type = GetCannonByTypeAndCaliber(sCannonType, iCaliber);
// NK <--
}

void Fantom_SetSails(ref rFantom, string sFantomType)
{
	rFantom.Ship.Sails.Gerald = false;
	if (sFantomType == "war") rFantom.Ship.Sails.Gerald = true;
}

// TIH --> used to reset the goods so they do not carry over from prior fantom slot thus causing overloaded ships
void Fantom_ClearCargo(ref rFantom)
{
	//Trace("CARGO: Fantom_ClearCargo prior char cargo load: " + GetCargoLoad(rFantom) + ", max: " + GetCargoMaxSpace(rFantom) );
	for (int i=0; i<GOODS_QUANTITY; i++)
	{
		string goodsName = Goods[i].Name;
		rFantom.Ship.Cargo.Goods.(goodsName) = 0;
	}
	RecalculateCargoLoad(&rFantom);
}
// TIH <--

void Fantom_SetBalls(ref rFantom, string sFantomType)
{
	//Trace("CARGO: Fantom_SetBalls cargo load prior: " + GetCargoLoad(rFantom) + ", max: " + GetCargoMaxSpace(rFantom) );

	float fKBalls;   int crewQ = GetCrewQuantity(rFantom);

	if (CANNONPOWDER_MOD) {// TIH --> mod toggle 7-7-06
		// added by MAXIMUS [gunpowder mod] -->
		float fKGunpowder = 0;
		ref rCannon; makeref(rCannon,Cannon[GetCaracterShipCannonsType(rFantom)]);
		if(CheckAttribute(rCannon,"gunpowder")) fKGunpowder = sti(rCannon.gunpowder)*sti(GetCannonCurQuantity(rFantom));
		// added by MAXIMUS [gunpowder mod] <--
	}// TIH <-- mod toggle

	if(USE_REAL_CANNONS)
	{
		  // KNB-->
		fKBalls = GetCannonQuantity(rFantom)/10;
		float fKGrape = fKBalls; //GetCannonQuantity(rFantom)/10;
		float fKChain = fKBalls; //GetCannonQuantity(rFantom)/10;

		switch (sFantomType)
		{
			case "war":
				if (CANNONPOWDER_MOD) fKGunpowder *= 0.45; //15-25 rpg // added by MAXIMUS [gunpowder mod]  // TIH mod toggle 7-7-06
				fKBalls *= 1.5; //15-25 rpg
				fKGrape *= 0.75; //8-13 rpg
				fKChain *= 0.45; //5-8 rpg
				Fantom_SetCharacterGoods(rFantom, GOOD_WHEAT, MakeInt(crewQ*FOOD_PER_CREW*30 + Rand(makeint(crewQ*FOOD_PER_CREW*30)) + Rand(makeint(crewQ*FOOD_PER_CREW*30))));
				Fantom_SetCharacterGoods(rFantom, GOOD_RUM, MakeInt(crewQ*FOOD_PER_CREW*5 + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(makeint(crewQ*FOOD_PER_CREW*10))));
			break;
			case "trade":
				if (CANNONPOWDER_MOD) fKGunpowder *= 0.4; //8-13 rpg // added by MAXIMUS [gunpowder mod]  // TIH mod toggle 7-7-06
				fKBalls *= 0.5; //8-13 rpg
				fKGrape *= 0;
				fKChain *= 0.4; //6-10 rpg
				Fantom_SetCharacterGoods(rFantom, GOOD_WHEAT, MakeInt(crewQ*FOOD_PER_CREW*20 + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(2) * Rand(makeint(crewQ*FOOD_PER_CREW*60))));
				Fantom_SetCharacterGoods(rFantom, GOOD_RUM, MakeInt(Rand(2)*Rand(makeint(crewQ*FOOD_PER_CREW*5))));
			break;
			case "pirate":
				if (CANNONPOWDER_MOD) fKGunpowder *= 0.45; //12-20 rpg // added by MAXIMUS [gunpowder mod]  // TIH mod toggle 7-7-06
				fKBalls *= 1.2; //12-20 rpg
				fKGrape *= 0.9; //9-15 rpg
				fKChain *= 0.45; //5-8 rpg
				Fantom_SetCharacterGoods(rFantom, GOOD_WHEAT, MakeInt(crewQ*FOOD_PER_CREW*10 + Rand(makeint(crewQ*FOOD_PER_CREW*20)) + Rand(makeint(crewQ*FOOD_PER_CREW*10))));
				Fantom_SetCharacterGoods(rFantom, GOOD_RUM, MakeInt(crewQ*FOOD_PER_CREW*15 + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(makeint(crewQ*FOOD_PER_CREW*10))));
			break;
		}

		// 15-25 rounds/gun baseline for all ammo types
		if (CANNONPOWDER_MOD) Fantom_SetCharacterGoods(rFantom, GOOD_GUNPOWDER, MakeInt(50 * fKGunpowder + rand(100 * fKGunpowder) + crewQ*3)); // added by MAXIMUS [gunpowder mod] // TIH mod toggle 7-7-06
		Fantom_SetCharacterGoods(rFantom, GOOD_BALLS, MakeInt(150 * fKBalls + rand(100 * fKBalls)));
		Fantom_SetCharacterGoods(rFantom, GOOD_GRAPES, MakeInt(150 * fKGrape + rand(100 * fKGrape)));
		Fantom_SetCharacterGoods(rFantom, GOOD_KNIPPELS, MakeInt(150 * fKChain + rand(100 * fKChain)));

		// KNB <--
	}
	else
		{
		// NK -->
		fKBalls = GetCannonQuantity(rFantom)/6; // 1.5 * (7 - GetCharacterShipClass(rFantom));

		switch (sFantomType)
		{
			case "war":
				if (CANNONPOWDER_MOD) fKGunpowder *= 0.75; // added by MAXIMUS // TIH mod toggle 7-7-06
				fKBalls = fKBalls * 1.5;
				Fantom_SetCharacterGoods(rFantom, GOOD_WHEAT, MakeInt(crewQ*FOOD_PER_CREW*30 + Rand(makeint(crewQ*FOOD_PER_CREW*30)) + Rand(makeint(crewQ*FOOD_PER_CREW*30))));
				Fantom_SetCharacterGoods(rFantom, GOOD_RUM, MakeInt(crewQ*FOOD_PER_CREW*5 + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(makeint(crewQ*FOOD_PER_CREW*10))));
			break;
			case "trade":
				if (CANNONPOWDER_MOD) fKGunpowder *= 0.75; // added by MAXIMUS // TIH mod toggle 7-7-06
				fKBalls = fKBalls * 0.7;
				Fantom_SetCharacterGoods(rFantom, GOOD_WHEAT, MakeInt(crewQ*FOOD_PER_CREW*20 + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(2) * Rand(makeint(crewQ*FOOD_PER_CREW*60))));
				Fantom_SetCharacterGoods(rFantom, GOOD_RUM, MakeInt(Rand(2)*Rand(makeint(crewQ*FOOD_PER_CREW*5))));
			break;
			case "pirate":
				if (CANNONPOWDER_MOD) fKGunpowder *= 0.8; // added by MAXIMUS // TIH mod toggle 7-7-06
				fKBalls = fKBalls * 1.25;
				Fantom_SetCharacterGoods(rFantom, GOOD_WHEAT, MakeInt(crewQ*FOOD_PER_CREW*10 + Rand(makeint(crewQ*FOOD_PER_CREW*20)) + Rand(makeint(crewQ*FOOD_PER_CREW*10))));
				Fantom_SetCharacterGoods(rFantom, GOOD_RUM, MakeInt(crewQ*FOOD_PER_CREW*15 + Rand(makeint(crewQ*FOOD_PER_CREW*10)) + Rand(makeint(crewQ*FOOD_PER_CREW*10))));
			break;
		}

		if (CANNONPOWDER_MOD) Fantom_SetCharacterGoods(rFantom, GOOD_GUNPOWDER, MakeInt(80 * fKGunpowder + rand(25 * fKGunpowder) + GetCrewQuantity(rFantom))); // added by MAXIMUS // TIH mod toggle 7-7-06
		Fantom_SetCharacterGoods(rFantom, GOOD_BALLS, MakeInt(200 * fKBalls + rand(50 * fKBalls))); // was 150,250
		Fantom_SetCharacterGoods(rFantom, GOOD_GRAPES, MakeInt(80 * fKBalls + rand(120 * fKBalls))); // was 130,140
		Fantom_SetCharacterGoods(rFantom, GOOD_KNIPPELS, MakeInt(50 * fKBalls + rand(150 * fKBalls))); // was 100,50
		Fantom_SetCharacterGoods(rFantom, GOOD_BOMBS, MakeInt(50 * fKBalls + rand(200 * fKBalls))); // was 100,200
		// NK <--
	}
/* this was done poorly, commented out and added to goods section
// START MOD Code by Stone-D : 01/08/2003
	// Stone-D : Let's let the encounter AI repair themselves, shall we?
	Fantom_SetCharacterGoods(rFantom, GOOD_SAILCLOTH, MakeInt(10 * fKBalls + rand(50 * fKBalls)));
	Fantom_SetCharacterGoods(rFantom, GOOD_PLANKS, MakeInt(20 * fKBalls + rand(100 * fKBalls)));
// END MOD Code by Stone-D : 01/08/2003
*/
	RecalculateCargoLoad(&rFantom);
	//Trace("CARGO: Fantom_SetBalls cargo load result: " + GetCargoLoad(rFantom));
}

void Fantom_SetGoods(ref rFantom, string sFantomType)
{
	RecalculateCargoLoad(&rFantom);
	//Trace("CARGO: Fantom_SetGoods cargo load prior: " + GetCargoLoad(rFantom) + ", max: " + GetCargoMaxSpace(rFantom) );

	int iMultiply = 10;
	int iRandMultiply = 1;

	int iShipClass = 7 - GetCharacterShipClass(rFantom);

	// START MOD Code by Stone-D : 01/08/2003
	switch (rFantom.FantomType) // NK
	{
		case "war":
		break;
		case "trade":
			iMultiply = (rand(10)+10) * (rand(iShipClass) + 2); // Stone-D : They ARE traders after all!
			iRandMultiply = 2 + rand(iShipClass);
		break;
		case "pirate":
			iMultiply = (rand(5)+5) * (rand(iShipClass) + 1); // Stone-D : They may have just come from a successful pillage
			iRandMultiply = 1 + rand(iShipClass / 2);
		break;
	}
	// END MOD Code by Stone-D : 01/08/2003

	// TIH --> rare gold & silver shipments mod Sep3'06
	if ( rFantom.FantomType == "trade" && rand(100) < 5 ) // 5% chance of finding one of these
	{
		switch(rand(2)) // one in three chance it will be gold! all gold!
		{
			case 0:
				Fantom_SetCharacterGoods(rFantom, GOOD_GOLD, GetCharacterFreeSpace(rFantom,GOOD_GOLD));
				Trace("CARGO: Fantom_SetGoods rare chance gold shipment!");
				break;
			//default:
				Fantom_SetCharacterGoods(rFantom, GOOD_SILVER, GetCharacterFreeSpace(rFantom,GOOD_SILVER));
				Trace("CARGO: Fantom_SetGoods rare chance silver shipment!");
		}
		return;// no point in continuing with this function now, the hold is full!
	}
	// TIH <--

	Fantom_SetCharacterGoods(rFantom, GOOD_SAILCLOTH, makeint(iShipClass + rand(iRandMultiply * 5))); // give ships a little bit of repair goods
	Fantom_SetCharacterGoods(rFantom, GOOD_PLANKS, makeint(iShipClass + rand(iRandMultiply * 5))); // give ships a little bit of repair goods

	//int iStart = GOOD_BOMBS + 1;
	int iStart = GOOD_PLANKS + 1;// TIH we start after repair goods now for random cargo

	// TIH --> we generate random different types now, instead of always 7 different types
	int randGoods = 1 + rand(6);
	for (int r=0;r<randGoods;r++)
	{
		Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), makeint(iMultiply * rand(iRandMultiply * 3)) );
	}
	/* prior method
	Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3));
	Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3));
	Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3));
	Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3));
	Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3));
	Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3));
	Fantom_SetCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3));
	*/
	// TIH <--

	// TIH --> better method, prevents overloaded ships due to innept mathmatics Sep3'06
	if(rFantom.FantomType == "trade")
	{
		int fillCargo = iStart + rand(GOODS_QUANTITY - iStart - 1);// random pick a good to be maxed
		int fillQuantity = GetCargoGoods(rFantom,fillCargo) + GetCharacterFreeSpace(rFantom,fillCargo);// fill up the hold
		Fantom_SetCharacterGoods(rFantom, fillCargo, fillQuantity);
	}
	/* causes overloaded ships
	//NK -->
	//Fill ship up to >= 90% full.
	float rndscl = 0.3 * frnd();
	if(rFantom.FantomType == "trade") {
		while(GetCargoFreeSpace(rFantom) > GetCargoMaxSpace(rFantom) * rndscl && GetCargoFreeSpace(rFantom) > 4) {
			AddCharacterGoods(rFantom, iStart + rand(GOODS_QUANTITY - iStart - 1), iMultiply * rand(iRandMultiply * 3)); } }
	// NK <--
	*/
	// TIH <--

	RecalculateCargoLoad(&rFantom);// moved down here after final additions are done (not really needed, but just in case)
	//Trace("CARGO: Fantom_SetGoods cargo load result: " + GetCargoLoad(rFantom));
}

// changed 05-05-02 by NK to set, not add, goods.
void Fantom_SetCharacterGoods(ref rFantom, int iGoods, int iQuantity)
{
	int traceprior = GetCargoLoad(rFantom);

	if (iQuantity == 0) { return; }
	string sGood = Goods[iGoods].name;
	
	int iFreeQuantity = GetCargoGoods(rFantom,iGoods) + GetCharacterFreeSpace(rFantom,iGoods);// TIH use proper functions
	if (iFreeQuantity < 0) { iFreeQuantity = 0; }
	if (iQuantity <= iFreeQuantity) { rFantom.Ship.Cargo.Goods.(sGood) = iQuantity; }
	else	{ rFantom.Ship.Cargo.Goods.(sGood) = iFreeQuantity;	}
// NK <-- 

	RecalculateCargoLoad(&rFantom);
	//Trace("CARGO: Fantom_SetCharacterGoods cargo load: " + traceprior + ", adding: " + sGood + " " + iQuantity + "qty" + ", set to: " + rFantom.Ship.Cargo.Goods.(sGood) + "qty");
}


// START MOD Code by Stone-D : 01/08/2003
// Sorry, no notes yet.

int skillbase = 1;

void SD_GenSkills(ref NPchar) // This function is not yet 'set in stone', ongoing testing.
{
	aref NPSkill;
	ref Pchar = GetMainCharacter();

//	NPchar.name = NPchar.name + " SD"; // Holdover from earlier attempt so I could ID who was affected by this function.

	int level, health, skillz, pointz, NPClass;

	NPClass = GetCharacterShipClass(NPchar);
	level = makeint((sti(Pchar.Rank)/2) + rand(sti(Pchar.Rank)+NPClass) + Rand(10)); // Nasty.
	skillz = (level*2)+NPClass; // Yes, I'm cheating. So sue me.
	pointz = level+NPClass; // Ditto.

	SDLog_AIFantom("Skill Gen: L=" + level + ", S=" + skillz + ", P=" + pointz + ", Class=" + NPClass);

	makearef(NPSkill, NPchar.skill);

		NPSkill.Leadership = SD_CalcSkills(skillz, 9); // Countdown the number of remaining skills
			skillz = skillz - sti(NPSkill.Leadership);
		NPSkill.Defence = SD_CalcSkills(skillz, 8);
			skillz = skillz - sti(NPSkill.Defence);
		NPSkill.Fencing = SD_CalcSkills(skillz, 7);
			skillz = skillz - sti(NPSkill.Fencing);
		NPSkill.Accuracy = SD_CalcSkills(skillz, 6);
			skillz = skillz - sti(NPSkill.Accuracy);
		NPSkill.Cannons = SD_CalcSkills(skillz, 5);
			skillz = skillz - sti(NPSkill.Cannons);
		NPSkill.Sneak = SD_CalcSkills(skillz, 4);
			skillz = skillz - sti(NPSkill.Sneak);
		NPSkill.Sailing = SD_CalcSkills(skillz, 3);
			skillz = skillz - sti(NPSkill.Sailing);
		NPSkill.Repair = SD_CalcSkills(skillz, 2);
			skillz = skillz - sti(NPSkill.Repair);
		NPSkill.Grappling = SD_CalcSkills(skillz, 1);
			skillz = skillz - sti(NPSkill.Grappling);
		NPSkill.Commerce = SD_CalcSkills(skillz, 0);
			skillz = skillz - sti(NPSkill.Commerce);

		NPSkill.Leadership = sti(NPSkill.Leadership) + skillbase;
		NPSkill.Sneak = sti(NPSkill.Sneak) + skillbase;
		NPSkill.Fencing = sti(NPSkill.Fencing) + skillbase;
		NPSkill.Sailing = sti(NPSkill.Sailing) + skillbase;
		NPSkill.Accuracy = sti(NPSkill.Accuracy) + skillbase;
		NPSkill.Cannons = sti(NPSkill.Cannons) + skillbase;
		NPSkill.Defence = sti(NPSkill.Defence) + skillbase;
		NPSkill.Repair = sti(NPSkill.Repair) + skillbase;
		NPSkill.Grappling = sti(NPSkill.Grappling) + skillbase;
		NPSkill.Commerce = sti(NPSkill.Commerce) + skillbase;

//		SDLog_AIFantom("Skill Gen: LD=" + sti(NPSkill.Leadership) + ", LK=" + sti(NPSkill.Sneak) + ", FE=" + sti(NPSkill.Leadership) + ", SA=" + sti(NPSkill.Sailing) + ", AC=" + sti(NPSkill.Accuracy) + ", CN=" + sti(NPSkill.Cannons) + ", DF=" + sti(NPSkill.Defence) + ", RP=" + sti(NPSkill.Repair) + ", GR=" + sti(NPSkill.Grappling) + ", CM=" + sti(NPSkill.Commerce));

		if (skillz<1) skillz = 0;
		NPchar.skill.freeskill = skillz;
		NPchar.perks.freepoints = pointz; // Dealt with but having issues so not released.
		NPchar.rank = level;
		NPchar.experience = CalculateExperienceFromRank(level) + rand(1000); // Hey, he might level during a fight.  :)
		health = makeint(40 + (level*5) + rand(40));
		LAi_SetHP(NPchar, makeint(rand(health)), health);
		SDLog_AIFantom("Skill Gen: XP=" + sti(NPchar.experience));
}

int SD_CalcSkills(int sp, int r) // This should generate characters with 10 across the board at high levels.
{
	int sm = SKILL_MAX-skillbase;
	r++;
	sp = makeint(sp/(10-r)); // Leadership gets top priority. Change, if you wish, to something like Accuracy for a laugh.
	sp = makeint((sp-2) + rand(r+1));
	if(sp<1) sp = 0;
	if(sp>sm) sp = sm;
	return sp;
}

void SDLog_AIFantom(string logtext)
{
// Ultra basic debugger. Uncomment this line if you want some feedback.
	if(DEBUGINFO) Log_SetStringToLog(logtext);
	return;
}

// PB -->
void Fantom_SetRandomModel(ref rFantom, string sFantomType)
{
	string sModel;
	switch (sFantomType)
	{
		case "war":
			switch(rand(1))
			{
				case 0: sModel = GetRandomModelForTypeExSubCheck(true, "Land_Officers", "man", rFantom.nation); break;
				case 1: sModel = GetRandomModelForTypeExSubCheck(true, "Captains", "man", rFantom.nation); break;
			}
			SetModel(&rFantom, sModel, "man", "man", 1.8, true);
		break;
		case "trade":
			switch(rand(3))
			{
				case 0: sModel = GetRandomModelForTypeExSubCheck(true, "Mates", "man", rFantom.nation); break;
				case 1: sModel = GetRandomModelForTypeExSubCheck(true, OFFIC_TYPE_FIRSTMATE, "man", rFantom.nation); break;
				case 2: sModel = GetRandomModelForTypeExSubCheck(true, OFFIC_TYPE_NAVIGATOR, "man", rFantom.nation); break;
				case 3: sModel = GetRandomModelForTypeExSubCheck(true, OFFIC_TYPE_QMASTER, "man", rFantom.nation); break;
			}
			SetModel(&rFantom, sModel, "man", "man", 1.8, true);
		break;
		case "pirate":
			if(rand(10)==0)
			{
				sModel = GetRandomModelForTypeExSubCheck(true, "Captains", "woman", rFantom.nation);
				SetModel(&rFantom, sModel, "woman", "woman", 1.75, true);
			}else{
				switch(rand(3))
				{
					case 0: sModel = GetRandomModelForTypeExSubCheck(true, "Captains", "man", rFantom.nation); break;
					case 1: sModel = GetRandomModelForTypeExSubCheck(true, "Mates", "man", rFantom.nation); break;
					case 2: sModel = GetRandomModelForTypeExSubCheck(true, OFFIC_TYPE_FIRSTMATE, "man", rFantom.nation); break;
					case 3: sModel = GetRandomModelForTypeExSubCheck(true, OFFIC_TYPE_NAVIGATOR, "man", rFantom.nation); break;
				}
				SetModel(&rFantom, sModel, "man", "man", 1.8, true);
			}
		break;
	}
}
// <-- PB
