#include "TownFantoms\TownFantoms.c" // Town Fantoms
// RM -->
// all town defines in buildsettings.h

// NK 05-04-23 switch to towns[] 
#define MAX_TOWNS 65
object Towns[MAX_TOWNS];
int TOWNS_QUANTITY = 0;

// KK -->
#define TAX_NONE    0
#define TAX_LOW     1
#define TAX_NORMAL  2
#define TAX_HIGH    3
#define TAX_PLUNDER 4

extern void InitTowns(bool first);
// <-- KK

ref GetTownFromID(string sTownName)
{
	if(sTownName == "") return &NullCharacter; // just in case.
	else { if(sTownName == "Conceiçao") { sTownName = "Conceicao"; } }
	
	// NK 05-04-23 switch to towns[]
	int idx = GetTownIndex(sTownName);
	if(idx < 0 || idx >= TOWNS_QUANTITY) return &NullCharacter; // read only! But it's empty, so what. :)
	return &Towns[idx];
	/*ref ctown;
	string temp;
	if(sTownName == "Conceiçao") sTownName = "Conceicao";  // <-- fix by emrep for Trade Mission error
	for(int i = 0; i < TOWNS_QUANTITY; i++)
	{
		temp = "t" + i;
		makearef(ctown, objTownStateTable.towns.(temp));
		if(ctown.id == sTownName) break;
	}
	return ctown; // trying it out without the &*/
}
// WM -->
// 04-09-22
//get town of nation
string GetTownIDFromNation(int nat)
{
	string ptowns[100];
	int qty = 0;
	string temp;
	ref ctown;
	// NK 05-04-23 switch to towns[]
	for(int i = 0; i < TOWNS_QUANTITY; i++)
	{
		makeref(ctown, Towns[i]);
		if(sti(ctown.nation) == nat)
		{
			ptowns[qty] = ctown.id;
			qty++;
		}
	}
	if(qty == 0) return "";
	return ptowns[rand(qty-1)];
}
// WM <--

int GetTownIndex(string sTownName)
{
	if(sTownName == "Conceiçao") sTownName = "Conceicao";
	if (sTownName == "Antigua") sTownName = "St John's"; // KK
	// NK 05-04-23 switch to towns[]
	return NativeFindCharacter(&Towns, sTownName);
	/*ref ctown;
	string temp;
	if(sTownName == "Conceiçao") sTownName = "Conceicao";  // <-- fix by emrep for Trade Mission error
	for(int i = 0; i < TOWNS_QUANTITY; i++)
	{
		temp = "t" + i;
		makearef(ctown, objTownStateTable.towns.(temp));
		if(ctown.id == sTownName) return i;
	}
	return -1;*/
	
}

ref GetTownByIndex(int idx)
{
	// NK 05-04-23 switch to towns[]
	if(idx < 0 || idx >= TOWNS_QUANTITY) return &NullCharacter;
	return &Towns[idx];
	/*ref ctown;
	string temp = "t" + idx;
	if(CheckAttribute(objTownStateTable,"towns."+temp)) makearef(ctown, objTownStateTable.towns.(temp));
	return ctown;*/
}

// KK -->
string GetTownName(string townid)
{
	if (!TownExist(townid)) return "";
	ref rtown = GetTownFromID(townid);
	if (!CheckAttribute(rtown, "name")) {
		if (!CheckAttribute(rtown, "id")) return "";
		return rtown.id;
	}
	return rtown.name;
}

void SetTownName(string townid, string townname)
{
	if (!TownExist(townid)) return;
	ref rtown = GetTownFromID(townid);
	rtown.name = townname;
}

string FindTownName(string townid)
{
	string ret;
	if (REAL_CARIBBEAN == 1) {
		switch (townid) {
			case "Falaise de Fleur":
				ret = "St Pierre";
			break;
			case "Redmond":
				ret = "Port Royale";
			break;
			case "Isla Muelle":
				ret = "San Juan";
			break;
			case "Oxbay":
				ret = "Speightstown";
			break;
			case "Greenford":
				ret = "Bridgetown";
			break;
			case "Conceicao":
				ret = "Sao Jorge";
			break;
			case "Douwesen":
				ret = "Kralendijk";
			break;
			case "Quebradas Costillas":
				ret = "Pirate Settlement";
			break;
			case "Khael Roa":
				ret = "Cozumel";
			break;
			// default:
				ret = townid;
		}
	} else {
		ret = townid;
	}
	return ret;
}
// <-- KK

// 04-11-08 added this. Checks if town stownname exists.
bool TownExist(string sTownName)
{
	// NK 05-04-23 switch to towns[]
	int idx = GetTownIndex(sTownName);
	return idx >= 0 && idx < TOWNS_QUANTITY;
	/*ref ctown;
	string temp;
	if(sTownName == "Conceiçao") sTownName = "Conceicao";  // <-- fix by emrep for Trade Mission error
	for(int i = 0; i < TOWNS_QUANTITY; i++)
	{
		temp = "t" + i;
		makearef(ctown, objTownStateTable.towns.(temp));
		if(ctown.id == sTownName) return true;
	}
	return false;*/
}

//town-island interoperability
int GetIslandTownsQuantity(string islandid)
{
	if(islandid == "") return 0;
	ref island = GetIslandByID(islandid);
	if(CheckAttribute(island,"towns.quantity")) return sti(island.towns.quantity);
	return 0;
}

string GetTownIDFromIsland(string islandid, int townnum)
{
	string tn = townnum;
	if(islandid == "") return "";
	if(townnum == 0) return "";
	if(GetIslandTownsQuantity(islandid) < townnum) return "";
	ref island = GetIslandByID(islandid);
	return island.towns.(tn);
}


ref GetTownfromIsland(string islandid, int townnum)
{
	return GetTownFromID(GetTownIDFromIsland(islandid, townnum));
}

string GetIslandIDFromTown(string sTownName)
{
	if(sTownName == "") return "";
	ref ctown = GetTownFromID(sTownName);
	return ctown.island;
}

ref GetIslandFromTown(string sTownName)
{
	return GetIslandByID(GetIslandIDFromTown(sTownName));
}

//town-store interoperability
string GetTownIDFromGroup(string group)
{
	return group; // NK I have rewritten store group to just be town name. Yay, speed. 05-07-10
	// NK new 05-04-15 use lookup.
	// NK 05-04-23 because obj doesn't exist any more (switched to Towns[]) we use shiplookuptable.
	/*if(CheckAttribute(ShipLookupTable,"townlookup.names"))
	{
		if(CheckAttribute(ShipLookupTable,"townlookup.names."+group)) return ShipLookupTable.townlookup.names.(group);
		trace("town storegroup " + group + " not exist!");
	}
	return "";*/
	// <--
	/*ref ctown;
	string temp;
	string ret = "";
	if(!CheckAttribute(objTownStateTable,"towns.Quantity")) return ret;
	for(int i = 0; i < TOWNS_QUANTITY; i++)
	{
		temp = "t" + i;
		makearef(ctown, objTownStateTable.towns.(temp));
		if(ctown.id == group) {ret = ctown.id; break;}
		if(CheckAttribute(ctown, "storegroup"))
		{
			if(ctown.storegroup == group) {ret = ctown.id; break;}
		}
	}
	return ret;*/
}

ref GetTownFromGroup(string group)
{
	// NK 05-04-23 switch to towns[]
	return GetTownFromID(GetTownIDFromGroup(group));
	/*ref ctown;
	string temp;
	for(int i = 0; i < TOWNS_QUANTITY; i++)
	{
		temp = "t" + i;
		makearef(ctown, objTownStateTable.towns.(temp));
		if(ctown.id == group) break;
		if(CheckAttribute(ctown, "storegroup"))
		{
			if(ctown.storegroup == group) break;
		}
	}
	return &ctown;*/
}

string GetCurrentTownID() // added 04-09-08
{
	if(FindLoadedLocation() != -1)
	{
		if(CheckAttribute(Locations[FindLoadedLocation()],"townsack")) { return Locations[FindLoadedLocation()].townsack; }
		else { return ""; }
	}
	ref pchar = GetMainCharacter();
	if (!CheckAttribute(pchar, "location")) return ""; // KK
	int idx = FindLocation(pchar.location);
	if(idx != -1)
	{
		ref loc = &Locations[idx];
		if(CheckAttribute(loc,"townsack")) return loc.townsack;
	}
	return "";
}

string GetTownIDFromLocID(string id) // added 05-03-28
{
	if(id == "" || FindLocation(id)==-1) return "";
	if(CheckAttribute(Locations[FindLocation(id)],"townsack")) return Locations[FindLocation(id)].townsack;
	return "";
}


ref GetCurrentTown() // added 04-09-08
{
	return GetTownFromID(GetCurrentTownID());
}

int GetCurrentStore(string locID) // added by MAXIMUS 02.11.2007
{
	return GetTownStoreIndex(GetTownIDFromLocID(locID));
}

int GetTownStoreIndex(string sTownName)
{
	// NK 05-04-23 switch to towns[]
	if(!TownExist(sTownName)) return -1; // KK
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"store")) return sti(ctown.store);
	return -1;
}
ref GetTownStore(string sTownName)
{
// KK -->
	int store_idx = GetTownStoreIndex(sTownName);
	if (store_idx < 0 || store_idx > STORE_QUANTITY) return &NullCharacter;
	return &Stores[store_idx];
// <-- KK
}


//access town properties

//for CCC's Vice City
float GetTownMonsterProb(string sTownName)
{
	// NK 05-04-23 switch to towns[]
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"monsterprob")) return stf(ctown.monsterprob);
	return DEFAULT_TOWN_MONSTERPROB;
}

float SetTownMonsterProb(string sTownName, float bprob)
{
	// NK 05-04-23 switch to towns[]
	ref ctown = GetTownFromID(sTownName);
	float oldprob = -1;
	if(CheckAttribute(ctown,"monsterprob")) oldprob = stf(ctown.monsterprob);
	ctown.monsterprob = bprob;
	return oldprob;
}

//added 04-11-08
bool IsTownCaptured(string sTownName)
{
	int idx = GetTownIndex(sTownName);
	if(idx == -1) { trace("WARNING!!! Town name " + sTownName + " not found"); return false;}
	// NK 05-04-23 switch to towns[]
	ref ctown = GetTownByIndex(idx);
	if(checkAttribute(ctown,"captured")) return sti(ctown.captured);
	return false;
}

int GetTownSize(string sTownName)
{
	// NK 05-04-23 switch to towns[]
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"size")) return sti(ctown.size);
	return DEFAULT_TOWN_POP;
}

void SetTownSize(string sTownName, int size)
{
	if(sTownName == "") return;
	ref ctown = GetTownFromID(sTownName);
	if(size < 0) size = DEFAULT_TOWN_POP;
	ctown.size = size;
}

int GetTownGold(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"gold")) return sti(ctown.gold);
	return DEFAULT_TOWN_POP * TOWN_GOLD_SCALAR;
}

void SetTownGold(string sTownName, int tgold)
{
	if(sTownName == "") return;
	ref ctown = GetTownFromID(sTownName);
	ctown.gold = tgold;
}
// distance handling 05-05-12
float GetTownDistance2DbyID(string Town1, string Town2)
{
	ref t1 = GetTownFromID(Town1);
	ref t2 = GetTownFromID(Town2);
	return GetTownDistance2D(&t1, &t2);
}

float GetTownDistance2D(ref tn1, ref tn2)
{
	float x1, x2, z1, z2;
	x1 = stf(tn1.position.x);
	z1 = stf(tn1.position.z);
	x2 = stf(tn2.position.x);
	z2 = stf(tn2.position.z);
	return GetDistance2D(x1, z1, x2, z2);
}

// 05-05-12
void GetTownPosition(ref tn, ref x, ref z)
{
	x = stf(tn.position.x);
	z = stf(tn.position.z);
}

void GetTownPositionByID(string town, ref x, ref z)
{
	float x1, z1;
	GetTownPosition(GetTownFromID(town), &x1, &z1);
	x = x1; z = z1;
}

int GetTownNation(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"nation")) return sti(ctown.nation);
	return PIRATE;
}

void SetTownNation(string sTownName, int iNation)
{
	ref ctown = GetTownFromID(sTownName);
	ctown.nation = iNation;
}

// KK -->
int GetTownHomeland(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown, "homeland")) return sti(ctown.homeland);
	return GetTownNation(sTownName);
}
// <-- KK

int GetTownGovernorIndex(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	int gov = -1;
	if(CheckAttribute(ctown,"gov")) gov = GetCharacterIndex(ctown.gov); // KK
	return gov;
}

string GetTownGovernorID(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	string gov = "";
	if(CheckAttribute(ctown,"gov")) gov = ctown.gov;
	return gov;
}


ref GetTownGovernor(string sTownName)
{
	/*ref ctown = GetTownFromID(sTownName);
	ref gov;
	if(CheckAttribute(ctown,"gov")) gov = CharacterFromID(ctown.gov);
	return &gov;*/
	return GetCharacter(GetTownGovernorIndex(sTownName));
}

int GetTownNumForts(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"forts.Quantity")) return sti(ctown.forts.Quantity);
	return 0;
}

ref GetTownFortCommander(string sTownName, int fcom)
{
	ref ctown = GetTownFromID(sTownName);
	ref fcmdr;
	int fortsq = GetTownNumForts(sTownName);
	string curfort = fcom;
	if(fortsq)
	{
		if(CheckAttribute(ctown,"forts."+curfort+".fortchar")) fcmdr = CharacterFromID(ctown.forts.(curfort).fortchar);
	}
	return &fcmdr;
}

int GetTownNumTroops(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"troops")) return sti(ctown.troops);
	return makeint(makefloat(DEFAULT_TOWN_POP) * TOWN_TROOPS_SCALAR);
}

void TownDistributeTroops(string sTownName)
{
	if(sTownName == "") return;
	int troops = GetTownNumTroops(sTownName);
	int curtroops = troops;
	int numforts = GetTownNumForts(sTownName);
	int tmp = 0;
	if(numforts)
	{
		int i;
		ref fchar;
		for(i = 0; i < numforts; i++)
		{
			fchar = GetTownFortCommander(sTownName, i);
			fchar.town = sTownName;
			if(sti(fchar.nation) != GetTownNation(sTownName)) SetTownNation(sTownName,sti(fchar.nation)); // fix for Oxbay
			fchar.nation = GetTownNation(sTownName);
			LAi_SetImmortal(fchar, false); //fix for invulnerable forts
			if(i == numforts-1)
			{
				fchar.ship.crew.quantity = curtroops;
			}
			else
			{
				tmp = makeint(makefloat(troops)/makefloat(numforts));
				curtroops -= tmp;
				fchar.ship.crew.quantity = tmp;
			}
		}
	}
}

void SetTownNumTroops(string sTownName, int ntroops)
{
	if(sTownName == "") return;
	ref ctown = GetTownFromID(sTownName);
	ctown.troops = ntroops;
	TownDistributeTroops(sTownName);
}

int GetTownCrewQuantity(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"crew.quantity")) return sti(ctown.crew.quantity);
	return 0;
}

void SetTownCrewQuantity(string sTownName, int qty) // add 04-09-08
{
	ref ctown = GetTownFromID(sTownName);
	ctown.crew.quantity = qty;
}


int GetTownCrewMorale(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	if(CheckAttribute(ctown,"crew.morale")) return sti(ctown.crew.morale);
	return MORALE_NORMAL;
}

void SetTownCrewMorale(string sTownName, int morale) // add 04-09-08
{
	ref ctown = GetTownFromID(sTownName);
	ctown.crew.morale = morale;
}

// LocAI group functions - 05-07-06
// soldiers
string GetTownSoldierGroup(string sTownName)
{
	return GetTownSoldierGroup_R(GetTownFromID(sTownName));
}

string GetTownSoldierGroup_R(ref ctown)
{
	if(!CheckAttribute(ctown, "laigroup")) return LAI_GROUP_GUARDS;
	//if (ctown.laigroup == LAI_GROUP_PLAYER) return LAI_GROUP_PLAYER; // KK
	return ctown.laigroup + "SOLDIERS";	// ccc Nov05, was "_SOLDIERS" which returned e.g. "ENGLAND__SOLDIERS"; 
}

string GetCurrentSoldierGroup()
{
	return GetTownSoldierGroup_R(GetCurrentTown());
}

// citizens
string GetTownCitizenGroup(string sTownName)
{
	return GetTownCitizenGroup_R(GetTownFromID(sTownName));
}

string GetTownCitizenGroup_R(ref ctown)
{
	if(!CheckAttribute(ctown, "laigroup")) return LAI_GROUP_DEFAULT; // i.e. vagabonds
	//if (ctown.laigroup == LAI_GROUP_PLAYER) return LAI_GROUP_PLAYER; // KK
	return ctown.laigroup + "CITIZENS";	// ccc Nov05, was "_CITIZENS" which returned e.g. "ENGLAND__CITIZENS"; 
}

string GetCurrentCitizenGroup()
{
	return GetTownCitizenGroup_R(GetCurrentTown());
}



// NK WM/itemtrade 05-04-02 add ship in port check, right now just pchar
bool IsFleetInTown(string townn, string fleetid)
{
	if(townn == "") return false;
	ref ctown = GetTownFromID(townn);
	return CheckAttribute(ctown,"fleetsinport."+fleetid);
}

// sets fleet to this town. Give townname of "" to clear from all towns. Returns true if fleet found in a town, false if found in no towns.
bool SetFleetInTown(string sTownName, string fleetid)
{
	if(!TOWNS_QUANTITY) return false; //if(!CheckAttribute(objTownStateTable,"towns.Quantity")) return false; // for when this is called during loading of game.
	bool washere = false;
	ref ctown;
	//string temp;
	if(sTownName == "Conceiçao") sTownName = "Conceicao";  // <-- fix by emrep for Trade Mission error
	for(int i = 0; i < TOWNS_QUANTITY; i++)
	{
		//temp = "t" + i;
		//makearef(ctown, objTownStateTable.towns.(temp));
		makeref(ctown, Towns[i]);
		washere = washere || CheckAttribute(ctown,"fleetsinport."+fleetid);
		if(ctown.id == sTownName)
		{
			//washere = CheckAttribute(ctown,"fleetsinport."+fleetid);
			/*if(here && !washere)*/ ctown.fleetsinport.(fleetid) = true;
			//if(!here && washere) DeleteAttribute(ctown,"fleetsinport."+fleetid);
		}
		else DeleteAttribute(ctown,"fleetsinport."+fleetid);
	}
	return washere;
}
// NK WM/IT <--

// NK 05-04-15 cleaned this and TownUpdate to not reget the ref every time.
//town update functions
void TownRecalc(ref ctown, bool instant)
{
	/*if(sTownName == "") return;
	ref ctown = GetTownFromID(sTownName);
	bool pirtown = GetTownNation(sTownName) == PIRATE;
	int size = GetTownSize(sTownName);
	int ogold = GetTownGold(sTownName);
	int otroops = GetTownNumTroops(sTownName);	
	int ocrewQ = GetTownCrewQuantity(sTownName);
	int ocrewM = GetTownCrewMorale(sTownName);*/
	bool pirtown = sti(ctown.nation) == PIRATE;
	int size = sti(ctown.size);
	int ogold = sti(ctown.gold);
	int otroops = sti(ctown.troops);
	int ocrewQ = sti(ctown.crew.quantity);
	int ocrewM = sti(ctown.crew.morale);

	int gold = makeint(makefloat(size) * makefloat(TOWN_GOLD_SCALAR) * (0.8 + frand(0.4)));
	int troops = makeint(stf(ctown.size) * TOWN_TROOPS_SCALAR * (0.8 + frand(0.4))) * (0.5 + makefloat(GetDifficulty())/4.0) * (1 + pirtown); // NK 04-08-29 pirate towns get x2 troops

	int crewQ = makeint(stf(ctown.size)*TOWN_CREW_SCALAR * GetFame(GetMainCharacter(), -1) * (0.75 + frand(0.5))) * (1 + pirtown);
	if(crewQ < 5) crewQ = 5;
	if(DEBUGINFO) Log_SetStringToLog("Desired Crew Qty: " + crewQ);
	crewQ = makeint(makefloat(crewQ) * (2.5 - (makefloat(GetDifficulty()) / 2.0)));
	if(DEBUGINFO) Log_SetStringToLog("New Crew Qty: " + crewQ);
	int crewM = ((5-GetDifficulty()) * 10 + rand(20)) * (1 + pirtown);
	if(crewQ > size) crewQ = size;
	if(crewM > MORALE_MAX) crewM = MORALE_MAX;
	if(crewM < MORALE_MIN) crewM = MORALE_MIN;

	ctown.gold = ogold + makeint(makefloat(gold - ogold) * GOLD_CHANGE_RATIO);
	if(instant) ctown.gold = gold;
	gold = sti(ctown.gold);
	ctown.troops = otroops + makeint(makefloat(troops - otroops) * TROOPS_CHANGE_RATIO);
	if(instant) ctown.troops = troops;
	troops = sti(ctown.troops);
	TownDistributeTroops(ctown.id); // was sTownName
	ctown.crew.quantity = ocrewQ + makeint(makefloat(crewQ - ocrewQ) * CREW_CHANGE_RATIO);
	if(instant) ctown.crew.quantity = crewQ
	crewQ = sti(ctown.crew.quantity);
	ctown.crew.morale = crewM;
}

void TownUpdate(ref ctown, bool instant)
{
	if(!CheckAttribute(ctown, "name")) return; // NK change this so we pass the town as ref, not just its name
	//ref ctown = GetTownFromID(sTownName);
	// fill town lookup table.
	string tmpstr = ctown.id;
	/* Disable this, using IDs as groups now. 05-07-10.
	ShipLookupTable.townlookup.names.(tmpstr) = ctown.id;
	if(CheckAttribute(ctown, "storegroup"))
	{
		tmpstr = ctown.storegroup;
		ShipLookupTable.townlookup.names.(tmpstr) = ctown.id;
	}*/
	// KK ctown.name = ctown.id; // just in case. 05-04-23 on switch to towns[]
	bool captured = false;
	if(CheckAttribute(ctown,"captured")) { captured = sti(ctown.captured); }
	int size = sti(ctown.size);
	// 04-09-21 we do this already in fortcapture.c - if(captured) size = makeint(makefloat(size) * SACK_TOWN_DECREASE);
	int sidx = -1; if(CheckAttribute(ctown,"store")) sidx = sti(ctown.store);
	bool bstore = sidx != -1; //for towns with no store
	if(bstore) ref store = &Stores[sidx];
	int wheatQ = size;
	if(bstore)  wheatQ = GetStoreGoodsQuantity(store, GOOD_WHEAT);
	float starve = 0.0;
	if(CheckAttribute(ctown,"starve")) starve = stf(ctown.starve);
	if(DEBUGINFO) Log_SetStringToLog("Updating " + ctown.id + "." + stringRet(captured," Town is sacked.","") + " Size " + size + ", wheat " + wheatQ);
	if(bstore)
	{
		wheatQ -= (size * FOOD_PER_CREW /2); //eat food
		if (wheatQ < 0) wheatQ = 0;
		if(wheatQ * GROW_FOOD_SCALAR >= size)
		{
			starve = 0;
			size += POP_CH; //increase
			if(wheatQ * GROW_FOOD_SCALAR >= size*2) size += POP_CH; //big increase
		}
		else
		{
			//increment starving
			if(wheatQ < size * MIN_FOOD_SCALAR) starve += (1.0 - (makefloat(wheatQ)/makefloat(size))) * STARVE_SCALAR;
		}
		size -= makeint(starve)*POP_CH; //decrement based on starving
		//if(rounddown(starve)) Log_SetStringToLog("Starvation! " + (sti(ctown.size) - size) + " people die.");
		ctown.starve = starve;
		if(size > MAX_POP) size = MAX_POP;
		ctown.size = size;
		if(DEBUGINFO) Log_SetStringToLog("New size: " + size);
		SetStoreGoods(store, GOOD_WHEAT, wheatQ);
		if(size >= STORE_MINSIZE) { store.StoreSize = "large"; }
		else { store.StoreSize = "small"; }
	}
	TownRecalc(&ctown, instant);
// KK -->
	if(captured) {
		ctown.captured = false;
		LiberateTown(ctown.id);
	}
// <-- KK
	// Town size decrease moved to fortcapture.c
	// NK WM/itemtrade 05-04-02 add ship in port check, right now just pchar
	bool flt = false;
	if(CheckAttribute(GetMainCharacter(),"location.from_sea"))
	{
		if(GetTownIDFromLocID(Characters[GetMainCharacterIndex()].location.from_sea) == ctown.id) // was sTownName
		{
			flt = true;
			ctown.fleetsinport.pchar = true;
		}
	}
	if(!flt) { DeleteAttribute(ctown,"fleetsinport.pchar"); }
	// itemtrade 05-04-05
	// move quality before fleetsize, and fix the non-stick error, 05-04-15
	int quality = 0; if(CheckAttribute(ctown,"itemtrade.basequality")) quality = sti(ctown.itemtrade.basequality);
	if(size > STORE_MINSIZE) { quality++; }
	else { if(size < STORE_MINSIZE / 2) { quality --; } }
	int oq = 0; if(CheckAttribute(ctown,"itemtrade.quality")) oq = sti(ctown.itemtrade.quality);
	// add section to handle changing quality
	bool tupdate = CheckAttribute(ShipLookupTable,"itemtraders") && sti(ShipLookupTable.itemtraders);
	if(oq != quality) // if quality doesn't match previous
	{
		if(!tupdate)
		{
			ctown.itemtrade.quality = quality;
			DeleteAttribute(ctown,"newqualdays"); 
		}
		else
		{
			//trace("qual mismatch town " + ctown.id + ", size " + size + "; old qual " + oq + ", new " +quality);
			if(!CheckAttribute(ctown, "newqualdays")) { ctown.newqualdays = 1; } // on first day, add attribute
			else
			{
				int qdays = sti(ctown.newqualdays);
				//trace("qdays = " + qdays);
				if(qdays < IT_UPD_TOWNQUAL_DAYS) // wait IT_UPD_TOWNQUAL_DAYS days.
				{
					qdays++; ctown.newqualdays = qdays;
				}
				else
				{
					//trace("setting new quality to " + quality + ", oq was " + oq);
					
					ctown.itemtrade.quality = quality;
					aref ittable; makearef(ittable, ShipLookupTable.itemtraders);
					ref ch;
					string id;
					for(int i = 0; i < GetAttributesNum(ittable); i++)
					{
						id = GetAttributeName(GetAttributeN(ittable, i));
						ch = CharacterFromID(id);
						if(GetTownIDFromLocID(ch.location) == ctown.id) SetTraderItemStats(&ch, IT_RECALC_QL_TN);
					}
				}
			}
		}
	}
	else
	{
		DeleteAttribute(ctown, "newqualdays"); //otherwise start again.
	}
	if(tupdate)
	{
		if(flt) size += GetSquadronCrewQuantity(GetMainCharacter()) * IT_UPD_TS_FLEET_MULT;
		float chmag = 1.0; if(CheckAttribute(ctown,"itemtrade.qty.chmag")) chmag = stf(ctown.itemtrade.qty.chmag);
		float base = 1.0 * (1.0 + (flt * ( IT_UPD_INPORTPC_MULT-1.0))); if(CheckAttribute(ctown,"itemtrade.baseqty")) base *= stf(ctown.itemtrade.baseqty);
		ctown.itemtrade.qty = base * pow2(Bring2RangeNoCheck(IT_TSIZE_MIN, IT_TSIZE_MAX, IT_TSIZE_MIN * IT_TSIZE_NORMAL, IT_TSIZE_MAX * IT_TSIZE_NORMAL, size), chmag);
		chmag = 1.0; if(CheckAttribute(ctown,"itemtrade.price.chmag")) chmag = stf(ctown.itemtrade.price.chmag);
		base = 1.0 * (1.0 + (flt * ( IT_UPD_INPORTPC_MULT-1.0))); if(CheckAttribute(ctown,"itemtrade.baseprice")) base *= stf(ctown.itemtrade.baseprice);
		ctown.itemtrade.price = base* pow2(Bring2RangeNoCheck(IT_TSIZE_MIN, IT_TSIZE_MAX, IT_TSIZE_MIN * IT_TSIZE_NORMAL, IT_TSIZE_MAX * IT_TSIZE_NORMAL, size), chmag);
	}
	// itemtrade<--
	// NK <--
}

void UpdateAllTowns(bool instant)
{
	//trace("Gauging: NEXTDAY_towns start");
	//string tn;
	int q;
	ref curtn;
	for(q = 0; q < TOWNS_QUANTITY; q++)
	{
		//tn = "t" + q;
		//makearef(curtn, objTownStateTable.towns.(tn)); // now pass town as aref NK 05-04-15
		makeref(curtn, Towns[q]);
		TownUpdate(&curtn, instant);
	}
	//trace("Gauging: NEXTDAY_Towns end");
}

// added 05-04-17
void UpdateAllStores(bool instant)
{
	int s;
	if(instant) { for(s = 0; s < STORE_QUANTITY; s++) { FillStoreGoods2(&Stores[s]); } }
	else { for(s = 0; s < STORE_QUANTITY; s++) { UpdateStore(&Stores[s]); } }

	// hardcode, no loop. No real speed advantage with this, so we can safely loop.
	/*s = 0;
	UpdateStore(&Stores[s]); s++;
	UpdateStore(&Stores[0]);
	UpdateStore(&Stores[1]);
	UpdateStore(&Stores[2]);
	UpdateStore(&Stores[3]);
	UpdateStore(&Stores[4]);
	UpdateStore(&Stores[5]);
	UpdateStore(&Stores[6]);
	UpdateStore(&Stores[7]);
	UpdateStore(&Stores[8]);*/
}

// KK -->
void InitTownTable(bool first)
{
	string initfile = "Towns\InitTowns.c";
	if (LoadSegment(initfile)) {
		InitTowns(first);
		UnloadSegment(initfile);
	}
	string slpath = GetStorylineDir(FindCurrentStoryline());
	if (FindFile("PROGRAM\\" + slpath + "Towns", "*.c", "InitTowns.c") != "") {
		initfile = slpath + "Towns\InitTowns.c";
		if (LoadSegment(initfile)) {
			InitTowns(first);
			UnloadSegment(initfile);
		}
	}
}

void ModifyTown(ref refTown)
{
	if (!CheckAttribute(refTown, "id")) return;
	int tidx = GetTownIndex(refTown.id);
	if (tidx < 0) return;
	int iNation = -1;
	ref town; makeref(town, Towns[tidx]);
	if (CheckAttribute(refTown, "name"))
		town.name = refTown.name;
	else
		refTown.name = town.name;
	if (CheckAttribute(refTown, "monsterprob")) town.monsterprob = refTown.monsterprob;
	if (CheckAttribute(refTown, "size")) town.size = refTown.size;
	if (CheckAttribute(refTown, "gold")) town.gold = refTown.gold;
	if (CheckAttribute(refTown, "nation")) {
		iNation = sti(refTown.nation);
		town.homeland = iNation;
	}
	if (CheckAttribute(refTown, "gov")) town.gov = refTown.gov;
	if (CheckAttribute(refTown, "officiant")) town.officiant = refTown.officiant;
	if (CheckAttribute(refTown, "troops")) town.troops = refTown.troops;
	if (CheckAttribute(refTown, "crew.quantity")) town.crew.quantity = refTown.crew.quantity;
	if (CheckAttribute(refTown, "crew.morale")) town.crew.morale = refTown.crew.morale;
	CaptureTownForNation(town.id, iNation);
	SetTownName(town.id, refTown.name);
	Preprocessor_Delete(town.id);
	Preprocessor_Save(town.id, refTown.name));
	DeleteAttribute(refTown, "");
}
// <-- KK

// ****************** STORES SECTION *********************
void FillStoreGoods2(ref pRef)
{
	int i,j,nq,n,tt;
	string goodName;
	int goodBasePrice;

	int islandIdx = FindIsland(pRef.Island);
	aref arTypes,arCurGoods,arCurType;
	if(islandIdx!=-1)
	{
		ref rIsland = GetIslandByIndex(islandIdx);
		makearef(arTypes,rIsland.Trade);
		nq = GetAttributesNum(arTypes);
		for(i=0;i<nq;i++)
		{
			arCurType = GetAttributeN(arTypes,i);
			tt=TRADE_TYPE_NORMAL;
			switch(GetAttributeName(arCurType))
			{
			case "Export":		tt=TRADE_TYPE_EXPORT;		break;
			case "Import":		tt=TRADE_TYPE_IMPORT;		break;
			case "Contraband":	tt=TRADE_TYPE_CONTRABAND;	break;
			}
			n = GetAttributesNum(arCurType);
			for(j=0;j<n;j++)
			{
				goodName = Goods[sti(GetAttributeValue(GetAttributeN(arCurType,j)))].name;
				pRef.Goods.(goodName).TradeType = tt;
			}
		}
	}
	else
	{
		trace("Mistake island id into store:  id="+pRef.Island);
	}
	// NK -->
	int tsize = DEFAULT_TOWN_POP;
	bool pirtown = false;
	if(GetTownIDFromGroup(pRef.group) != "")
	{
		tsize = GetTownSize(GetTownIDFromGroup(pRef.group));
		if(tsize > STORE_MINSIZE) {pRef.StoreSize = "large";}
		else {pRef.StoreSize = "small";}
		pirtown = GetTownNation(GetTownIDFromGroup(pRef.group)) == PIRATE;
	}
	for(i=0; i<GOODS_QUANTITY; i++)
	{
		goodName = Goods[i].Name;
		if( i==GOOD_BALLS || i==GOOD_GRAPES || i==GOOD_KNIPPELS || i==GOOD_BOMBS )
		{
			pRef.Goods.(goodName).Quantity = makeint(TT_AMMO_SCALE * makefloat(1+pirtown) * makefloat(tsize)*(1.0 - GQTY_VARIANCE + frand(GQTY_VARIANCE*2.0)))*sti(goods[i].Units);
			pRef.Goods.(goodName).RndPriceModify = 1.0;
			pRef.Goods.(goodName).TradeType = TRADE_TYPE_AMMUNITION;
			continue;
		}
		/*if( i==GOOD_PLANKS || i==GOOD_SAILCLOTH )
		{
			pRef.Goods.(goodName).Quantity = 500+Rand(50)*sti(goods[i].Units);
			pRef.Goods.(goodName).RndPriceModify = 1.0;
			//pRef.Goods.(goodName).TradeType = TRADE_TYPE_AMMUNITION;
			continue;
		}*/
		goodBasePrice = MakeInt(goods[i].Cost);
		switch(sti(pRef.Goods.(goodName).TradeType))
		{
		case TRADE_TYPE_NORMAL:
			pRef.Goods.(goodName).Quantity = makeint(TT_NORMAL_SCALE * makefloat(tsize)*(1.0 - GQTY_VARIANCE + frand(GQTY_VARIANCE*2.0)))*sti(goods[i].Units);
			pRef.Goods.(goodName).RndPriceModify = frnd() * 0.4;
			break;

		case TRADE_TYPE_EXPORT:
			pRef.Goods.(goodName).Quantity = makeint(TT_EXPORT_SCALE * makefloat(tsize)*(1.0 - GQTY_VARIANCE + frand(GQTY_VARIANCE*2.0)))*sti(goods[i].Units);
			pRef.Goods.(goodName).RndPriceModify = frnd() * 0.4;
			break;

		case TRADE_TYPE_IMPORT:
			pRef.Goods.(goodName).Quantity = makeint(TT_IMPORT_SCALE * makefloat(tsize)*(1.0 - GQTY_VARIANCE + frand(GQTY_VARIANCE*2.0)))*sti(goods[i].Units);
			pRef.Goods.(goodName).RndPriceModify = frnd() * 0.4;
			break;

		case TRADE_TYPE_CONTRABAND:
			pRef.Goods.(goodName).Quantity = makeint(TT_CONTRABAND_SCALE * makefloat(tsize)*(1.0 - GQTY_VARIANCE + frand(GQTY_VARIANCE*2.0)))*sti(goods[i].Units);
			pRef.Goods.(goodName).RndPriceModify = frnd();
			break;
		}
		if(i == GOOD_WHEAT)
		{
			pRef.Goods.(goodName).Quantity = makeint(TT_NORMAL_SCALE * makefloat(tsize)*(1.0 - GQTY_VARIANCE/4.0 + frand(GQTY_VARIANCE*2.0/2.0)))*sti(goods[i].Units);
			//Log_SetStringToLog("Store " + pRef.group + " of town " +  GetTownIDFromGroup(pRef.group) + " (pop " + tsize + ") has " + pRef.Goods.(goodName).Quantity + " wheat.");
		}
	}
}
// RM <--

// KK -->
string GetBestTown(string id)
{
	string IslandName = "";
	float rel1;
	float rel;
	int n = 0;
	int sel = 1;
	if (CheckAttribute(Locations[FindLocation(id)], "townsack")) return Locations[FindLocation(id)].townsack; 
	if (CheckAttribute(Locations[FindLocation(id)], "island")) IslandName = Locations[FindLocation(id)].island;

	n = GetIslandTownsQuantity(IslandName);
	if (n < 1) return "";

	rel = GetActualNationRelation2MainCharacter(GetTownNation(GetTownIDFromIsland(IslandName, 1))));
	rel1 = rel;
	for (int i = 2; i <= n; i++) {
		rel1 = GetActualNationRelation2MainCharacter(GetTownNation(GetTownIDFromIsland(IslandName, i))));
		if (rel < rel1) {
			rel = rel1;
			sel = i;
		}
	}
	return GetTownIDFromIsland(IslandName, sel);
}

bool PlaceFleetNearShore(string id)
{
	ref mc = GetMainCharacter();
	if (FindLocation(id) == -1 || GetCharacterShipType(mc) == SHIP_NOTUSED) return false;
	SetCharacterShipLocation(mc, id);
	switch (id) {
		case "Antigua_port":
			worldMap.playerShipX = -635.48;
			worldMap.playerShipZ = 779.78;
		break;
		case "Antigua_shore":
			worldMap.playerShipX = -763.80;
			worldMap.playerShipZ = 743.93;
		break;
		case "Cayman_port":
			worldMap.playerShipX = 414.58;
			worldMap.playerShipZ = -410.89;
		break;
		case "Cayman_shore_01":
			worldMap.playerShipX = 370.36;
			worldMap.playerShipZ = -397.34;
		break;
		case "Cayman_shore_02":
			worldMap.playerShipX = 427.70;
			worldMap.playerShipZ = -433.27;
		break;
		case "Cayman_shore_03":
			worldMap.playerShipX = 465.58;
			worldMap.playerShipZ = -483.07;
		break;
		case "Conceicao_port":
			worldMap.playerShipX = 762.38;
			worldMap.playerShipZ = 622.52;
		break;
		case "Conceicao_shore_01":
			worldMap.playerShipX = 806.58;
			worldMap.playerShipZ = 580.07;
		break;
		case "Conceicao_shore_02":
			worldMap.playerShipX = 832.40;
			worldMap.playerShipZ = 664.72;
		break;
		case "Cuba_port":
			worldMap.playerShipX = 155.35;
			worldMap.playerShipZ = -893.23;
		break;
		case "Santiago_port":
			worldMap.playerShipX = -182.97;
			worldMap.playerShipZ = -536.68;
		break;
		case "Cuba_shore_01":
			worldMap.playerShipX = -84.39;
			worldMap.playerShipZ = -718.44;
		break;
		case "Cuba_shore_02":
			worldMap.playerShipX = 83.89;
			worldMap.playerShipZ = -794.65;
		break;
		case "Cuba_shore_03":
			worldMap.playerShipX = -30.95;
			worldMap.playerShipZ = -739.73;
		break;
		case "Cuba_shore_04":
			worldMap.playerShipX = -227.77;
			worldMap.playerShipZ = -692.75;
		break;
		case "Cuba_shore_05":
			worldMap.playerShipX = -135.25;
			worldMap.playerShipZ = -535.08;
		break;
		case "Cuba_shore_06":
			worldMap.playerShipX = 87.99;
			worldMap.playerShipZ = -931.16;
		break;
		case "Douwesen_port":
			worldMap.playerShipX = 795.56;
			worldMap.playerShipZ = 143.54;
		break;
		case "Douwesen_shore_01":
			worldMap.playerShipX = 744.87;
			worldMap.playerShipZ = 185.66;
		break;
		case "Douwesen_shore_02":
			worldMap.playerShipX = 830.07;
			worldMap.playerShipZ = 193.75;
		break;
		case "Douwesen_shore_ship":
			worldMap.playerShipX = 826.30;
			worldMap.playerShipZ = 167.30;
		break;
		case "Falaise_de_Fleur_port_01":
			worldMap.playerShipX = -107.67;
			worldMap.playerShipZ = 773.20;
		break;
		case "Falaise_de_Fleur_shore":
			worldMap.playerShipX = -160.15;
			worldMap.playerShipZ = 806.13;
		break;
		case "Guadeloupe_port":
			worldMap.playerShipX = -446.72;
			worldMap.playerShipZ = 628.86;
		break;
		case "Guadeloupe_shore_01":
			worldMap.playerShipX = -422.81;
			worldMap.playerShipZ = 695.83;
		break;
		case "Hispaniola_port":
			worldMap.playerShipX = -514.68;
			worldMap.playerShipZ = -341.95;
		break;
		case "Santo_Domingo_port":
			worldMap.playerShipX = -648.12;
			worldMap.playerShipZ = -183.32;
		break;
		case "Tortuga_port":
			worldMap.playerShipX = -515.69;
			worldMap.playerShipZ = -571.78;
		break;
		case "Hispaniola_shore_01":
			worldMap.playerShipX = -714.77;
			worldMap.playerShipZ = -140.58;
		break;
		case "Hispaniola_shore_02":
			worldMap.playerShipX = -659.29;
			worldMap.playerShipZ = -394.12;
		break;
		case "Hispaniola_shore_03":
			worldMap.playerShipX = -768.88;
			worldMap.playerShipZ = -354.27;
		break;
		case "Hispaniola_shore_04":
			worldMap.playerShipX = -546.89;
			worldMap.playerShipZ = 235.30;
		break;
		case "Muelle_port":
			worldMap.playerShipX = -707.28;
			worldMap.playerShipZ = 88.64;
		break;
		case "Muelle_shore":
			worldMap.playerShipX = -828.76;
			worldMap.playerShipZ = 162.73;
		break;
		case "Muelle_shore_02":
			worldMap.playerShipX = -704.76;
			worldMap.playerShipZ = 217.63;
		break;
		case "KhaelRoa_port":
			worldMap.playerShipX = 892.71;
			worldMap.playerShipZ = -531.59;
		break;
		case "Oxbay_port":
			worldMap.playerShipX = 255.21;
			worldMap.playerShipZ = 782.84;
		break;
		case "Greenford_port":
			worldMap.playerShipX = 350.66;
			worldMap.playerShipZ = 730.12;
		break;
		case "Oxbay_shore_01":
			worldMap.playerShipX = 283.65;
			worldMap.playerShipZ = 701.07;
		break;
		case "Oxbay_shore_02":
			worldMap.playerShipX = 332.48;
			worldMap.playerShipZ = 803.83;
		break;
		case "Oxbay_lighthouse":
			worldMap.playerShipX = 292.63;
			worldMap.playerShipZ = 697.66;
		break;
		case "QC_port":
			worldMap.playerShipX = -655.45;
			worldMap.playerShipZ = 548.53;
		break;
		case "Charlestown_Port":
			worldMap.playerShipX = -595.06;
			worldMap.playerShipZ = 491.34;
		break;
		case "QC_Shore1":
			worldMap.playerShipX = -710.99;
			worldMap.playerShipZ = 547.75;
		break;
		case "Redmond_port":
			worldMap.playerShipX = -47.82;
			worldMap.playerShipZ = -226.44;
		break;
		case "Redmond_shore_01":
			worldMap.playerShipX = 1.69;
			worldMap.playerShipZ = -229.16;
		break;
		case "Redmond_shore_02":
			worldMap.playerShipX = -41.09;
			worldMap.playerShipZ = -280.05;
		break;
		case "Marigot_port":
			worldMap.playerShipX = -945.50;
			worldMap.playerShipZ = 503.75;
		break;
		case "Philipsburg_port":
			worldMap.playerShipX = -912.25;
			worldMap.playerShipZ = 465.70;
		break;
		case "SaintMartin_shore_01":
			worldMap.playerShipX = -962.69;
			worldMap.playerShipZ = 449.80;
		break;
		case "SaintMartin_shore_02":
			worldMap.playerShipX = -889.46;
			worldMap.playerShipZ = 518.94;
		break;
		case "Turks_port":
			worldMap.playerShipX = -575.43;
			worldMap.playerShipZ = -793.75;
		break;
		case "Turks_shore_01":
			worldMap.playerShipX = -590.37;
			worldMap.playerShipZ = -742.53;
		break;
		case "Turks_shore_04":
			worldMap.playerShipX = -600.08;
			worldMap.playerShipZ = -817.63;
		break;
		case "Turks_shore_05":
			worldMap.playerShipX = -532.62;
			worldMap.playerShipZ = -777.90;
		break;
		case "Turks_lighthouse":
			worldMap.playerShipX = -555.48;
			worldMap.playerShipZ = -795.06;
		break;
		// default:
			return false;
	}
	worldMap.playerShipAY = 3.0;
	return true;
}

void SetTownGarrisonForNation(string town, int iNation)
{
	if (!TownExist(town)) return;
	bool chknation = iNation >= 0 && iNation < MAX_NATIONS;
	chknation = chknation || iNation == PERSONAL_NATION;
	if (!chknation) return;
	ref mchr = GetMainCharacter();

	for (int n = 0; n < CHARACTERS_QUANTITY; n++) {
		if (!CheckAttribute(characters[n], "location")) continue;
		if (FindLocation(characters[n].location) == -1) continue;
		if (GetTownIDFromLocID(characters[n].location) == town) {
			ref character = CharacterFromID(characters[n].id);
			if (isSoldier(character) != -1) {
				if (CheckAttribute(character, "old.location")) {
					character.location = character.old.location;
					DeleteAttribute(character, "old.location");
				}
				character.Dialog.Filename = GetSoldiersDialog(iNation, town);
				character.greeting = GetSoldiersGreeting(iNation, town);
				if (iNation != PERSONAL_NATION)
					LAi_group_MoveCharacter(character, GetSoldiersName(iNation) + "_SOLDIERS");
				else
					LAi_group_MoveCharacter(character, LAI_GROUP_PLAYER);
			} else {
				if (iNation != PERSONAL_NATION)
					LAi_group_MoveCharacter(character, GetCitizensName(iNation) + "_CITIZENS");
				else
					LAi_group_MoveCharacter(character, LAI_GROUP_PLAYER);
			}
			character.old.chr_ai.group = character.chr_ai.group;
			character.nation = iNation;
		}
	}
}

void OccupyTown(string town)
{
	if (!TownExist(town)) return;
	ref mchr = GetMainCharacter();

	for (int n = 0; n < CHARACTERS_QUANTITY; n++) {
		if (!CheckAttribute(characters[n], "location")) continue;
		if (FindLocation(characters[n].location) == -1) continue;
		if (GetTownIDFromLocID(characters[n].location) == town && isSoldier(characters[n]) != -1) {
			characters[n].old.location = characters[n].location;
			characters[n].location = "none";
		}
	}
	int nforts = GetTownNumForts(town);
	for (n = 0; n < nforts; n++) {
		ref fortchar = GetTownFortCommander(town, n);
		fortchar.nation = NEUTRAL_NATION;
	}
}

void LiberateTown(string town)
{
	if (!TownExist(town)) return;
	ref mchr = GetMainCharacter();

	for (int n = 0; n < CHARACTERS_QUANTITY; n++) {
		if (!CheckAttribute(characters[n], "old.location")) continue;
		if (FindLocation(characters[n].old.location) == -1) continue;
		if (GetTownIDFromLocID(characters[n].old.location) == town && isSoldier(characters[n]) != -1) {
			characters[n].location = characters[n].old.location;
			DeleteAttribute(&characters[n], "old.location");
		}
	}
}

void CaptureTownForNation(string town, int iNation)
{
	if (!TownExist(town)) return;
	bool chknation = iNation >= 0 && iNation < MAX_NATIONS;
	chknation = chknation || iNation == PERSONAL_NATION;
	if (!chknation) return;
	string sNation = "n" + iNation;
	int orgNation = GetTownNation(town);
	ref island = GetIslandFromTown(town);

	if (CheckAttribute(island, "smuggling_nation") == true && sti(island.smuggling_nation) == orgNation && iNation != PERSONAL_NATION) island.smuggling_nation = iNation;

	SetTownNation(town, iNation);
	SetWorldMapIcon(town, "", iNation);
	SetTownGarrisonForNation(town, iNation);

	if (iNation != PERSONAL_NATION)
		Towns[GetTownIndex(town)].laigroup = GetSoldiersName(iNation) + "_";
	else
		Towns[GetTownIndex(town)].laigroup = LAI_GROUP_PLAYER;

	if (IsEntity(GetMainCharacter())) {
		if (iNation == PERSONAL_NATION) {
			Log_SetStringToLog(TranslateString("", "Colony of") + " " + GetTownName(town) + " " + TranslateString("", "captured by") + " " + GetMyFullName(GetMainCharacter()) + ".");
		} else {
			Log_SetStringToLog(TranslateString("", "Colony of") + " " + GetTownName(town) + " " + TranslateString("", "captured by") + " " + TranslateString("", GetNationNameByType(iNation)) + ".");
		}
	}

	if (iNation != PERSONAL_NATION) {
		if (GetTownName(town) != FindTownName(town)) {
			SetTownName(town, FindTownName(town));
			Preprocessor_Delete(town);
			Preprocessor_Save(town, FindTownName(town));
		}

		int govidx = GetTownGovernorIndex(town);
		if (govidx >= 0) {
			ref gov = &characters[govidx];
			gov.nation = iNation;
			if (CheckAttribute(characters[govidx], "nation." + sNation)) {
				gov.name = TranslateString("", gov.nation.(sNation).name);
				gov.old.name = gov.name;
				if (CheckAttribute(gov, "nation." + sNation + ".middlename")) {
					gov.middlename = TranslateString("", gov.nation.(sNation).middlename);
					gov.old.middlename = gov.middlename;
				} else {
					DeleteAttribute(gov, "middlename");
				}
				gov.lastname = TranslateString("", gov.nation.(sNation).lastname);
				gov.old.lastname = gov.lastname;
				gov.sex = gov.nation.(sNation).sex;
				if (CheckAttribute(gov, "old.location")) {
					gov.location = gov.old.location;
					DeleteAttribute(gov, "old.location");
				}
				gov.greeting = gov.nation.(sNation).greeting;
				SetModelFromID(gov, gov.nation.(sNation).model);
			} else {
				if (iNation == PIRATE) {
					gov.old.location = gov.location;
					gov.location = "none";
				}
			}
		}
		int nforts = GetTownNumForts(town);
		for (int i = 0; i < nforts; i++) {
			ref fortchar = GetTownFortCommander(town, i);
			fortchar.nation = iNation;
			SetModelFromID(fortchar, SelectSoldierModelByNation(iNation, "officer"));
		}
	}
}

bool DisableTownCapture(string town, bool disable)
{
	if (!TownExist(town)) return true;
	ref rtown = GetTownFromID(town);
	rtown.disable_capture = disable;
	if (!disable && CheckAttribute(rtown, "disable_capture")) DeleteAttribute(rtown, "disable_capture");
	return disable;
}

bool isEnabledTownCapture(string town)
{
	if (!TownExist(town)) return false;
	ref rtown = GetTownFromID(town);
	if (CheckAttribute(rtown, "disable_capture")) {
		if (sti(rtown.disable_capture) == true) {
			return false;
		} else {
			DeleteAttribute(rtown, "disable_capture");
			return true;
		}
	}
	return true;
}

string FindTownTavern(string location)
{
	int idx = FindLocation(location);
	if (idx == -1) return "";
	string town = GetTownIDFromLocID(location);
	if (!TownExist(town)) return "";
	/*string island = GetIslandIDFromTown(town);
	if (island == "") return "";
	int nbegin = sti(Locations[0].IslandsList.(island).begin);
	int nend = sti(Locations[0].IslandsList.(island).end);
	for (int n = nbegin; n < nend; n++) {
		if (!CheckAttribute(Locations[n], "type") || !CheckAttribute(Locations[n], "townsack")) continue;
		if (Locations[n].type == "tavern" && Locations[n].townsack == Locations[idx].townsack) return Locations[n].id;
	}*/
	ref officiant = GetTownOfficiant(town);
	if (CheckAttribute(officiant, "tavern.location")) return officiant.tavern.location;
	return "";
}

int GetTownOfficiantIndex(string sTownName)
{
	ref ctown = GetTownFromID(sTownName);
	int officiant = -1;
	if(CheckAttribute(ctown, "officiant")) officiant = GetCharacterIndex(ctown.officiant);
	return officiant;
}

ref GetTownOfficiant(string sTownName)
{
	return GetCharacter(GetTownOfficiantIndex(sTownName));
}

ref GetTownStoreOwner(string sTownName)
{
	ref refStore = GetTownStore(sTownName);
	if (!CheckAttribute(refStore, "owner")) return &NullCharacter;
	return CharacterFromID(refStore.owner);
}
// <-- KK

//MAXIMUS -->
string FindTownStore(string townID)//townID = GetTownIDFromLocID(PChar.location)
{
	if(!TownExist(townID)) return "";
	string island = GetIslandIDFromTown(townID);
	if (island == "") return "";
	int nbegin = sti(Locations[0].IslandsList.(island).begin);
	int nend = sti(Locations[0].IslandsList.(island).end);
	for(int n = nbegin; n < nend; n++)
	{
		if(!CheckAttribute(Locations[n], "type") || !CheckAttribute(Locations[n], "townsack")) continue;
		if(HasSubStr(Locations[n].id,"store") && !HasSubStr(Locations[n].id,"tailor") && Locations[n].type == "shop" && Locations[n].townsack == townID) return Locations[n].id;
	}
	return "";
}
//MAXIMUS <--
