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

Direct Sail feature...(island to island)

mhhh...damn windoof...tried again...now it should work, sorry :modding

http://www.file-upload.net/download-2326898/Directsail_COAS.zip.html
 
Have you looked at this which allows you to encounter fleets in direct sailing mod?

This is from POTC
Code:
// ccc Nov 06 directsailing without worldmap

// ----------------------- Tweaks and settings --------------------------------------
#define DIRECTENCOUNTERCHANCE 50   // chance in percent that an encounter fleet appears every hour
#define DIRECTENCOUNTERDISTANCE 1000 // distance from player at which random ships appear 

#define ACCURATE_NAVIGATION 1 // Jan07: Screwface found a method to determine the worldmapcoords of a ship sailing in 3D seaview.
// That makes accurate navigation possible. However, due to the confined worldmap voyages are rather short, and sometimes you appear BEHIND a coast.
// To try this set this to 1, with 0 you'll use the old "islandcell" islandhopping navigation

#define ISLANDSWITCHDISTANCE 5000.0 // for islandcell mode only: distance from island at which transfer to neighbour island starts
// distance set for testing, should be at least 10000 for playing !!!

#define ENCOUNTERBREAK 1.0 // LDH - Changed to float, number is hours per encounter, directsail is called every 5 minutes occasionally
// so you can let the clock run faster (by increasing #define TIMESCALAR_SEA in internalSettings.h ), meaning longer voyagetimes, without getting too many encounters.

#define MINES 1	// set to 0 to disable enconters with random mines

#define DS_DEBUGINFO 0	// Set this to 1 to get on-screen debug information, 0 to get just normal information - 12Jan09
//int DS_DEBUGINFO = 0;	// Set this to 1 to get on-screen debug information, 0 to get just normal information - 01Feb09

int DirectsailCheckFrequency = 15;		// check for new island every this many minutes - 07Jan09, also used for abort distances 12Jan09

//------------------------ Initial checks and trigger -----------------------------

bool DirectsailCheck()  // called hourly by Whr_UpdateWeather - now also called by procUpdateTime()
// ever growing list of conditions when Directsail shall NOT run
{
ref pchar = GetMainCharacter();

if( CheckAttribute(pchar,"nodirectsail") ){Traceandlog("Directsail toggled, press 0 to enable"); return false;} // ccc Jan07, Directsail can be toggled
/* PB: Why do I keep getting the French invasion movie all the time???
//MAXIMUS -[reload to the WorldMap not needed anymore]->
if(!CheckQuestAttribute("StartAdventure", "begin"))
{
if(!CheckAttribute(pchar,"quest.StartAdventure.counter")) pchar.quest.StartAdventure.counter = 1;
else pchar.quest.StartAdventure.counter = sti(pchar.quest.StartAdventure.counter)+1;
if(sti(pchar.quest.StartAdventure.counter)==2)
{
pchar.quest.StartAdventure.win_condition.l1 = "Timer";
pchar.quest.StartAdventure.win_condition.l1.date.min = GetMinute()+Rand(sti(50-GetMinute())+10);
pchar.quest.StartAdventure.win_condition.l1.date.hour = GetHour();
pchar.quest.StartAdventure.win_condition.l1.date.day = GetDataDay();
pchar.quest.StartAdventure.win_condition.l1.date.month = GetDataMonth();
pchar.quest.StartAdventure.win_condition.l1.date.year = GetDataYear();
pchar.quest.StartAdventure.win_condition = "StartAdventure";
}
}

if(CheckAttribute(pchar,"quest.Story_OxbayCaptured"))
{
aref cQuest = GetQuestData("Story_OxbayCaptured");
if(!CheckQuestRecord(cQuest, "2"))
{
if(!CheckAttribute(pchar,"quest.Story_InvasionVideoAfterLeaveOxbay.counter")) pchar.quest.Story_InvasionVideoAfterLeaveOxbay.counter = 1;
else pchar.quest.Story_InvasionVideoAfterLeaveOxbay.counter = sti(pchar.quest.Story_InvasionVideoAfterLeaveOxbay.counter)+1;
if(sti(pchar.quest.Story_InvasionVideoAfterLeaveOxbay.counter)==2)
{
pchar.quest.Story_InvasionVideoAfterLeaveOxbay.win_condition.l1 = "Timer";
pchar.quest.Story_InvasionVideoAfterLeaveOxbay.win_condition.l1.date.min = GetMinute()+Rand(sti(50-GetMinute())+10);
pchar.quest.Story_InvasionVideoAfterLeaveOxbay.win_condition.l1.date.hour = GetHour();
pchar.quest.Story_InvasionVideoAfterLeaveOxbay.win_condition.l1.date.day = GetDataDay();
pchar.quest.Story_InvasionVideoAfterLeaveOxbay.win_condition.l1.date.month = GetDataMonth();
pchar.quest.Story_InvasionVideoAfterLeaveOxbay.win_condition.l1.date.year = GetDataYear();
pchar.quest.Story_InvasionVideoAfterLeaveOxbay.win_condition = "Story_InvasionVideoAfterLeaveOxbay";
}
}
}
//MAXIMUS <-[reload to the WorldMap not needed anymore]-
*/
// Navigation point "Battle Rocks" is added to worldmap if not yet done
if(!CheckAttribute(worldMap,"islands.Battle_Rocks.name") ) DirectsailAddBattle_Rocks();

if(pchar.location=="") // Jan07 open sea without island
{
Logit("No island within reach");  // Jan07, hint added
Logit("Enter the map to sail to some island");
return false;	// aborts function if location is open sea without island
}

/*------ moved to DirectSailRun() so we can get map updates near coast - 29Dec08
// Jan07, aborts if you are too close to the coast 
float coastzone = GetIslandSize(pchar.location)+1000;
if( abs(stf(pchar.Ship.Pos.x))<coastzone && abs(stf(pchar.Ship.Pos.z))<coastzone )
{
Trace("Directsail aborted, too close to coast");
Logit("Directsail aborted, too close to coast");	// LDH added for test 29Dec08
return false;
}
---------*/

// aborts function if enemyships near, so that you aren't teleported out of an engagement
int enemydist = 0;
int nextenemy = 0;
int enemyDistLimit;
int neutralDistLimit;
if (DirectsailCheckFrequency < 15 && CheckAttribute(worldmap, "islands."+pchar.location))
{
// note: by the time DirectsailCheckFrequency is set to other than default 15, pchar.directsail1 attributes will exist
if (pchar.directsail1.closestisland != pchar.location && stf(pchar.directsail1.closestdist) < 2000.0/WDM_MAP_TO_SEA_SCALE)
{
// LDH 29Jan09
// if we're very close to an island we're not logged in to,
// we need stricter limits on how close another ship has to be to prevent island change
enemyDistLimit   = 500; 
neutralDistLimit = 400;
}
else
{
// if we're near the border between two islands but not particularly close a different island, need less strict limits
enemyDistLimit   = 800; 
neutralDistLimit = 500;
}
/*
if (CheckAttribute(pchar, "directsail1.approaching") && pchar.directsail1.approaching != "*")
{
//			logit("Captain, we are approaching " + pchar.directsail1.approaching + ".");	// LDH 04Apr09
TraceAndLog("Captain, we are approaching " + pchar.directsail1.approaching + ".");	// LDH 04Apr09
pchar.directsail1.approaching = "*";
}
*/
}
else 
{
enemyDistLimit   = 1000;
neutralDistLimit = 1000;
//		DeleteAttribute(pchar, "directsail1.approaching");
}

nextenemy = FindClosestShipofRel(GetMainCharacterIndex(), &enemydist, RELATION_ENEMY);
DSTrace("DirectsailCheck; next enemy: "+nextenemy + " dist: "+enemydist);		// LDH changed to DSTrace 08Apr09
if(nextenemy!= -1 && enemydist<enemyDistLimit ) 
{
DSTrace("Directsail aborted due to hostile ship, dist = " + enemydist);	// LDH - 07Jan09
if(ACCURATE_NAVIGATION) GetMapIslandZone(pchar.location); // DirectIslandCoordCheck();		// update the map
return false;
}

// Jan 07, same for neutral ships
nextenemy = FindClosestShipofRel(GetMainCharacterIndex(), &enemydist, RELATION_NEUTRAL);
DSTrace("DirectsailCheck; next neutral ship: "+nextenemy + " dist: "+enemydist);		// LDH changed to DSTrace 08Apr09
if(nextenemy!= -1 && enemydist<neutralDistLimit && Characters[nextenemy].ship.type != SHIP_FORT_NAME ) // LDH added fort check 08Jan09
{
DSTrace("Directsail aborted due to neutral ship, dist = " + enemydist);	// LDH added logit to trace - 07Jan09
if(ACCURATE_NAVIGATION) GetMapIslandZone(pchar.location); // DirectIslandCoordCheck();		// update the map
return false;
}

// looks like this doesn't always work, so I added another check for being in battle
if(!bMapEnter) {DSTrace("Directsail aborted in battle"); return false;}		// LDH added logit to trace 07Jan09

if(CheckAttribute(pchar, "sailtostring") ){Trace("Directsail aborted during sail to"); return false;}
// ccc Dec17, aborts Directsail if you use the "sail to" interfaceoption

if(CheckAttribute(pchar,"IsOnDeck") && pchar.IsOnDeck==true) {Trace("Directsail aborted below decks"); return false;}
// Maximus Jan07; aborts Directsail if you are below decks 

// once all those conditions are checked we trigger an event that runs DS some seconds later
SetEventHandler("DirectsailRun", "DirectsailRun", 0);  // Jan 07,		// LDH changed last parameter from 1 to zero - 24Mar09
//	int delay = 5000 + rand(60000);  // Jan 07, random delaytime in millisec
int delay = 12000;	// LDH always one game minute delay in sea time -30Dec08
if(CheckAttribute(GetMainCharacter(),"mapEnter")) { delay = 500; }//MAXIMUS: check added into BattleInterface for islands search after enable MapEnter
PostEvent("DirectsailRun", delay);  // Jan 07, calls DirectsailRun() after delay to create break
return true;
}



void DirectsailRun()  // Jan 07, taken out of DirectsailCheck() to create break
{
DelEventHandler("DirectsailRun", "DirectsailRun");

//	if (!bSeaActive) return;	// LDH so we don't try running after mooring - 05Jan09

ref pchar = GetMainCharacter();

// check if islandchange takes place
bool islandswitch;
if(ACCURATE_NAVIGATION){islandswitch = DirectIslandCoordCheck();} // use Screwface's mapcoord method
else {islandswitch = DirectIslandCellCheck();} // use islandcell method

if(islandswitch)
{
// islandchange
// some eyecandy
CreateEntity(&SeaFader, "fader");
SendMessage(&SeaFader, "ls", FADER_PICTURE0, FindReloadPicture("LandHo.tga")); // KK
SendMessage(&SeaFader, "lfl", FADER_IN, 0.5, true);
PlaySound("land_ho");
// LDH Only set the encounter flag if we're due for an encounter - 11Feb09
if(stf(pchar.directsail.count) >= ENCOUNTERBREAK) 
pchar.directsail.encounter = 1; // for new ships at new island
// LDH 21Feb09 - Set MapEnter condition for quests, removed when MapEnter condition is checked in ProcessCondition()
pchar.directsail1.QuestCheckMapEnter = true;

Sea_ReloadStartDirect();	// reloads Sea with new island at horizon
}
else
{
if(CheckAttribute(GetMainCharacter(),"mapEnter")) { DeleteAttribute(GetMainCharacter(),"mapEnter"); return; }//MAXIMUS: prevents from uninterrupted encounters (check added into BattleInterface for islands search after enable MapEnter)
// no islandchange, instead random check if an shipencounter or flotsam shall appear

// Jan07 counter that allows us to set encounterfrequency independent of clockspeed/hourly weatherchange
if(!CheckAttribute(pchar,"directsail.count")) pchar.directsail.count = 0.0;
//		pchar.directsail.count = sti(pchar.directsail.count) + 1;	// done in LogInterface clock code now 07Jan09
if(stf(pchar.directsail.count) < ENCOUNTERBREAK) 
{ 
DSTrace("Directsail encounter aborted, encounterbreak "+stf(pchar.directsail.count));
return; 
}

// LDH abort here if too close to coast, only for encounters - 29Dec08 - added abort for too close to island transition 09Apr09
if (ACCURATE_NAVIGATION && CheckAttribute(pchar, "directsail1.closestdist"))
{
// LDH added 09Apr09
if (CheckAttribute(pchar, "directsail1.approaching"))
{
DSTrace("Directsail encounter aborted, too close to island transition");	// change to DSTrace after testing
return;
}

float islandDistLimit;
if (DirectsailCheckFrequency < 15) islandDistLimit = 1500.0; else islandDistLimit = 2000.0;
if (stf(pchar.directsail1.closestdist) < islandDistLimit/WDM_MAP_TO_SEA_SCALE)
{
DSTrace("Directsail encounter aborted, too close to coast of " + FindIslandName(pchar.directsail1.closestisland) + ", " + makeint(sti(pchar.directsail1.closestdist)*WDM_MAP_TO_SEA_SCALE) + " of " + makeint(islandDistLimit) + " yards");
return;
}
}
else
{
float coastzone = GetIslandSize(pchar.location)+1000;
//			if ( abs(stf(pchar.Ship.Pos.x)) < coastzone && abs(stf(pchar.Ship.Pos.z)) < coastzone )			// orig code
float coastdistance = GetDistance2D(0.0, 0.0, stf(pchar.Ship.Pos.x), stf(pchar.Ship.Pos.z));	// LDH 06Jan09
if (coastdistance < coastzone)		// LDH 06Jan09
{	
DSTrace("Directsail encounter aborted, too close to coast of " + FindIslandName(pchar.location) + ", " + makeint(coastdistance) + " of " + makeint(coastzone));
return;
}
}

if (DIRECTENCOUNTERCHANCE > rand(100)) // chance check for shipencounter
{
// encounter markerattribute is attached to player
pchar.directsail.encounter = 1;

CreateEntity(&SeaFader, "fader");
SendMessage(&SeaFader, "ls", FADER_PICTURE0, FindReloadPicture("SailHo.tga")); // KK
SendMessage(&SeaFader, "lfl", FADER_IN, 0.5, true);
PlaySound("sail_ho");
Sea_ReloadStartDirect();	// reloads Sea with new ships at horizon
}
}
else	// LDH - this appears to be an error, but executes properly after the preceeding else code if original condition is false
{ 
Randomshipevent(); 	// random shiplife events
//TraceAndLog("DS: Randomshipevent() ran and encounter count was set to zero");	// LDH 12Feb09
pchar.directsail.count = 0.0;		// LDH - 08Jan09
}
if(CheckAttribute(GetMainCharacter(),"mapEnter")) { DeleteAttribute(GetMainCharacter(),"mapEnter"); }//MAXIMUS: check added into BattleInterface for islands search after enable MapEnter
}

// ----------------------------- Island check using worldmap coords --------------------

bool DirectIslandCoordCheck()  // called by DirectsailCheck()
//  Jan07 , uses Screwface's new worldmap coord check
{
ref pchar = GetMainCharacter();

DSTrace("directsail runs at " +  FindIslandName(pchar.location));	// LDH translate name 02Jan09

string toislandname = GetMapIslandzone(pchar.location); // the islandzone you may have sailed into

if(toislandname != "")
{
pchar.directsail.toisland = toislandname; // neighbour island stored as playerattribute for Sea_ReloadDirect function
// Sea_ReloadDirect & SeaLoginDirect will later recognize from that player attribute that you left OldIsland
// and delete the current island from the sea environment. The neighbour island is added in the correct location.

// LDH add bearing and direction to new island 04Mar09
float x = stf(worldMap.playerShipX)-stf(worldMap.islands.(toislandname).position.x);
float z = stf(worldMap.playerShipZ)-stf(worldMap.islands.(toislandname).position.z);
if (z == 0.0) z = 0.00001;	// prevent division by zero
float dir = atan(x/z);
if (z > 0.0) dir += PI;
Traceandlog("Captain, " + FindIslandName(toislandname) + " in sight "		// LDH translate name 02Jan09
+ GetBearingFromShip16(dir-stf(pchar.ship.ang.y))						// LDH add bearing 04Mar09
//			+ " " + GetCompassDirFromHeading16(dir)									// LDH add direction 04Mar09
);
/* keep for testing for now
dir = Radian2Degree(dir) + 180.0;
while (dir < 0.0) dir += 360.0;
while (dir > 360.0) dir -= 360.0;
if (dir > 180.0) dir -= 360.0;
TraceAndLog("Bearing to island = " + dir);
*/
return true;	// returns that islandchange has taken place
}
else
{
DSTrace("DirectIslandCoordCheck false ");	
pchar.directsail.toisland = pchar.location;		// LDH used in ship encounters, should be island we're logged into - 08Jan09
return false;	// returns that NO islandchange has taken place
}
}

string GetMapIslandzone(string Island)
// Screwface Jan07, converts your Seaview coords to mapcoords and checks if you are near some island
// Only called if ACCURATE_NAVIGATION is true
// LDH optimizations - 13Mar09
{
ref Pchar = GetMaincharacter();

DSTrace("== Directsail checked island zone at " + GetStringTime(stf(Pchar.CurrentTime)));

if (!CheckAttribute(worldmap, "islands."+Island))	// LDH so we don't try getting island after mooring - 05Jan09
{
DSTrace("** GetMapIslandzone tried to process " + Island);
return "";
}

float psX = MakeFloat(pchar.Ship.Pos.x);
float psZ = MakeFloat(pchar.Ship.Pos.z);
float ix = MakeFloat(worldMap.islands.(Island).position.rx);
float iz = MakeFloat(worldMap.islands.(Island).position.rz);

//REAL CONVERTION OF YOUR SEAVIEW COORDS IN WORLD MAP COORDS
worldMap.playerShipX = (psX/WDM_MAP_TO_SEA_SCALE) + ix;
worldMap.playerShipZ = (psZ/WDM_MAP_TO_SEA_SCALE) + iz;

float pmX = MakeFloat(worldMap.playerShipX);
float pmZ = MakeFloat(worldMap.playerShipZ);

// LDH 29Dec08
float ClosestDist1 = 99999.0;	// arbitrary high value
string ClosestIsland1 = "";
string ClosestDir1 = "";
float ClosestDist2 = 99999.0;
string ClosestIsland2 = "";
string ClosestDir2 = "";
float ClosestDist3 = 99999.0;
string ClosestIsland3 = "";
string ClosestDir3 = "";
float tempDist = 99999.0;
//	string tempDir = "";	// optimization
string isName;

// AFTER THAT YOU CHECK IF YOU ARE IN THE RANGE OF ANOTHER ISLAND ON THE WORLDMAP
for(int i=0; i<ISLANDS_QUANTITY; i++)
{
isName = Islands[i].id;
if(!CheckAttribute(worldMap,"islands."+isName)) continue;
float isX = stf(worldMap.islands.(isName).position.x);
float isZ = stf(worldMap.islands.(isName).position.z);

// LDH - we need to find the closest island that's not the island we're already at - 29Dec08
tempDist = GetDistance2D(pmX, pmZ, isX, isZ);
//		tempDir = GetCompassDirFromPoints16(pmX, pmZ, isX, isZ);	// optimization
if (tempDist < ClosestDist1)
{
ClosestDist3   = ClosestDist2;
ClosestIsland3 = ClosestIsland2;
ClosestDir3	   = ClosestDir2;
ClosestDist2   = ClosestDist1;
ClosestIsland2 = ClosestIsland1;
ClosestDir2	   = ClosestDir1;
ClosestDist1   = tempDist;
ClosestIsland1 = isName;
//			ClosestDir1    = tempDir;	// optimization
ClosestDir1    = GetCompassDirFromPoints16(pmX, pmZ, isX, isZ);
}
else 
{
if (tempDist < ClosestDist2)
{
ClosestDist3   = ClosestDist2;
ClosestIsland3 = ClosestIsland2;
ClosestDir3	   = ClosestDir2;
ClosestDist2   = tempDist;
ClosestIsland2 = isName;
//				ClosestDir2	   = tempDir;	// optimization
ClosestDir2	   = GetCompassDirFromPoints16(pmX, pmZ, isX, isZ);
}
else 
{
if (tempDist < ClosestDist3)
{
ClosestDist3   = tempDist;
ClosestIsland3 = isName;
//					ClosestDir3    = tempDir;	// optimization
ClosestDir3    = GetCompassDirFromPoints16(pmX, pmZ, isX, isZ);
}
}
}
}

/*
// LDH traces for testing closest island 30Dec08
DSTrace("=== DirectSail Closest1 " + StrLeft(FindIslandName(ClosestIsland1)+"        ",10) + " distance: " + makeint(ClosestDist1*WDM_MAP_TO_SEA_SCALE) + " yards");
DSTrace("=== DirectSail Closest2 " + StrLeft(FindIslandName(ClosestIsland2)+"        ",10) + " distance: " + makeint(ClosestDist2*WDM_MAP_TO_SEA_SCALE) + " yards");
DSTrace("=== DirectSail Closest3 " + StrLeft(FindIslandName(ClosestIsland3)+"        ",10) + " distance: " + makeint(ClosestDist3*WDM_MAP_TO_SEA_SCALE) + " yards");
DSTrace("=== DirectSail");
*/
// LDH 03Jan09
// Now find the closest landfall on these three islands

float ClosestLandfallDist1 = 99999.0;
string ClosestLandfallIsland1 = "";
string ClosestLandfallName1 = "";
string ClosestLandfallDir1 = "";
float ClosestLandfallDist2 = 99999.0;
string ClosestLandfallIsland2 = "";
string ClosestLandfallName2 = "";
string ClosestLandfallDir2 = "";
/* optimization
float ClosestLandfallDist3 = 99999.0;
string ClosestLandfallIsland3 = "";
string ClosestLandfallName3 = "";
string ClosestLandfallDir3 = "";
*/

string LandfallIsland;
float tempIslandDist;
string tempLandfall = "";
string tempLandfallDir = "";

aref arLandfalls; 
string sLandfallName;
int nLandfalls;
float LFx;
float LFz;
for ( int j=0 ; j<3 ; j++ )
{
switch(j)
{
case 0: LandfallIsland = ClosestIsland1; tempIslandDist = ClosestDist1; tempLandfallDir = ClosestDir1; break; // added dir 15Jan09
case 1: LandfallIsland = ClosestIsland2; tempIslandDist = ClosestDist2; tempLandfallDir = ClosestDir2; break;
case 2: LandfallIsland = ClosestIsland3; tempIslandDist = ClosestDist3; tempLandfallDir = ClosestDir3; break;
}
makearef(arLandfalls, worldMap.islands.(LandfallIsland).locations);

tempIslandDist = 99999.0;
tempLandfall = "";
nLandfalls = GetAttributesNum(arLandfalls);
for( i=0 ; i<nLandfalls ; i++)
{
sLandfallName = GetAttributeName(GetAttributeN(arLandfalls,i));
LFx = stf(arLandFalls.(sLandfallName).position.x);
LFz = stf(arLandFalls.(sLandfallName).position.z);
tempDist = GetDistance2D(pmX, pmZ, LFx, LFz);

if (tempDist < tempIslandDist)
{
tempIslandDist = tempDist;
if (worldMap.islands.(LandfallIsland).locations.(sLandfallName).label.text == "")
tempLandfall = worldMap.islands.(LandfallIsland).locations.(sLandfallName).label.old.text;
else
tempLandfall = worldMap.islands.(LandfallIsland).locations.(sLandfallName).label.text;
}
}

// LDH add additional location checks here - 07Jan09
for(i=0; i<ISLANDS_QUANTITY; i++)
{
if ( LandfallIsland == Islands[i].id) break;
}
makearef(arLandfalls, Islands[i].reload);
nLandfalls = GetAttributesNum(arLandfalls);
// for each reload, translate the location and get the name
for( i=0 ; i<nLandfalls ; i++)
{
string tempattrname = GetAttributeName(GetAttributeN(arLandfalls,i));
sLandfallName = arLandfalls.(tempattrname).label;
if (CheckAttribute(arLandfalls, tempattrname+".x"))
{
LFx = stf(arLandfalls.(tempattrname).x)/WDM_MAP_TO_SEA_SCALE + stf(worldMap.islands.(LandfallIsland).position.rx);
LFz = stf(arLandfalls.(tempattrname).z)/WDM_MAP_TO_SEA_SCALE + stf(worldMap.islands.(LandfallIsland).position.rz);
}
else
{
// this is mostly to handle battle_rocks, which doesn't have any landfalls
LFx = stf(worldMap.islands.(isName).position.x);
LFz = stf(worldMap.islands.(isName).position.z);
}

tempDist = GetDistance2D(pmX, pmZ, LFx, LFz);
//			tempDir = GetCompassDirFromPoints16(pmX, pmZ, LFx, LFz);	// optimization

if (tempDist < tempIslandDist)
{
tempIslandDist  = tempDist;
tempLandfall    = sLandfallName;
//				tempLandfallDir = tempDir;	// optimization
tempLandfallDir = GetCompassDirFromPoints16(pmX, pmZ, LFx, LFz);
}
}

if (tempIslandDist < ClosestLandfallDist1)
{
/* optimization
ClosestLandfallDist3 = ClosestLandfallDist2;
ClosestLandfallIsland3 = ClosestLandfallIsland2;
ClosestLandfallName3 = ClosestLandfallName2;
ClosestLandfallDir3  = ClosestLandfallDir2;
*/
ClosestLandfallDist2 = ClosestLandfallDist1;
ClosestLandfallIsland2 = ClosestLandfallIsland1;
ClosestLandfallName2 = ClosestLandfallName1;
ClosestLandfallDir2  = ClosestLandfallDir1;
ClosestLandfallDist1 = tempIslandDist;
ClosestLandfallIsland1 = LandfallIsland;
ClosestLandfallName1 = tempLandfall;
ClosestLandfallDir1  = tempLandfallDir;
}
else
{
if (tempIslandDist < ClosestLandfallDist2)
{
/* optimization
ClosestLandfallDist3 = ClosestLandfallDist2;
ClosestLandfallIsland3 = ClosestLandfallIsland2;
ClosestLandfallName3 = ClosestLandfallName2;
ClosestLandfallDir3  = ClosestLandfallDir2;
*/
ClosestLandfallDist2 = tempIslandDist;
ClosestLandfallIsland2 = LandfallIsland;
ClosestLandfallName2 = tempLandfall;
ClosestLandfallDir2  = tempLandfallDir;
}
/* optimization
else
{
if (tempIslandDist < ClosestLandfallDist3)
{
ClosestLandfallDist3 = tempIslandDist;
ClosestLandfallIsland3 = LandfallIsland;
ClosestLandfallName3 = tempLandfall;
ClosestLandfallDir3  = tempLandfallDir;
}
}
*/
}
}

string strLog;

strLog = "=== DirectSail Closest1 ";
strLog += StrLeft(FindIslandName(ClosestLandfallIsland1)+"        ",10) + " ";
if (ClosestLandfallName1 == "")
{
strLog += "                    ";
}
else
{
strLog += StrLeft(ClosestLandfallName1+"                    ",20);
}
strLog += " distance: " + makeint(ClosestLandfallDist1*WDM_MAP_TO_SEA_SCALE) + " yards";
strLog += " " + ClosestLandfallDir1;
DSTrace(strLog);

strLog = "=== DirectSail Closest2 ";
strLog += StrLeft(FindIslandName(ClosestLandfallIsland2)+"        ",10) + " ";
if (ClosestLandfallName2 == "")
{
strLog += "                    ";
}
else
{
strLog += StrLeft(ClosestLandfallName2+"                    ",20);
}
strLog += " distance: " + makeint(ClosestLandfallDist2*WDM_MAP_TO_SEA_SCALE) + " yards";
strLog += " " + ClosestLandfallDir2;
DSTrace(strLog);
/*
strLog = "=== DirectSail Closest3 ";
strLog += StrLeft(FindIslandName(ClosestLandfallIsland3)+"        ",10) + " ";
if (ClosestLandfallName3 == "")
{
strLog += "                    ";
}
else
{
strLog += StrLeft(ClosestLandfallName3+"                    ",20);
}
strLog += " distance: " + makeint(ClosestLandfallDist3*WDM_MAP_TO_SEA_SCALE) + " yards";
strLog += " " + ClosestLandfallDir3;
DSTrace(strLog);
*/
pchar.directsail1.closestdist = ClosestLandfallDist1;
pchar.directsail1.closestisland = ClosestLandfallIsland1;

// LDH 07Jan09
//	if ( ClosestlandfallDist1 + ClosestlandfallDist2 < 5000.0/WDM_MAP_TO_SEA_SCALE )		// under 5000 yards
// if we're likely to cross into another island zone in less than 15 minutes - 20Jan09
// Note: speed in knots times about 100 gives yards traveled in 15 game minutes, 180 sec real time
float transitionDistance = (ClosestlandfallDist2 - ClosestlandfallDist1)/2.0*WDM_MAP_TO_SEA_SCALE;
if ( stf(pchar.Ship.Speed.z) * 100.0 > transitionDistance || Island != ClosestLandfallIsland1 ) 
DirectsailCheckFrequency = 5;		// check every 5 minutes
else	
DirectsailCheckFrequency = 15;		// check every 15 minutes

strLog = "= Directsail speed = " + stf(pchar.Ship.Speed.z) +
", Diff in distances / 2 = " + ((ClosestlandfallDist2 - ClosestlandfallDist1)/2.0*WDM_MAP_TO_SEA_SCALE) +
", Check frequency = " + DirectsailCheckFrequency;
DSTrace(strLog);

// LDH 04Apr09
if (stf(pchar.Ship.Speed.z) * 50.0 > transitionDistance)	// if 7.5 minutes sailing can put us closer to another island
{
if (!CheckAttribute(pchar, "directsail1.approaching"))	// the first time this happens, tell the player
{
pchar.directsail1.approaching = FindIslandName(ClosestLandfallIsland2);
TraceAndLog("Captain, we are approaching " + pchar.directsail1.approaching + ".");
PlayStereoSound("notebook_note");
}
else
{
if (pchar.directsail1.approaching != FindIslandName(ClosestLandfallIsland2) &&
pchar.directsail1.approaching != FindIslandName(ClosestLandfallIsland1))
{
pchar.directsail1.approaching = FindIslandName(ClosestLandfallIsland2);		// if we approach a third island, tell the player
TraceAndLog("Captain, we are approaching " + pchar.directsail1.approaching + "!");
PlayStereoSound("notebook_note");
}
}
}
else
{
DeleteAttribute(pchar, "directsail1.approaching");
}

if (ClosestLandfallDist1 < 6000.0/WDM_MAP_TO_SEA_SCALE && Island != ClosestLandfallIsland1)
{
return ClosestLandfallIsland1;
}

DSTrace("At mapcoords x " + pmX + " z "+pmZ+" you are in no new islandzone");

return ""; // default
}



// ----------------------------- Island check using island cells --------------------

bool DirectIslandCellCheck()  // called by DirectsailCheck(), based on islandcells
// checks if we are so far from an island that location switches to the next island
// if yes playerattributes for new island and new coords are set
{
ref pchar = GetMainCharacter();
DSTrace("DirectIslandCellCheck runs at " +  pchar.location );

string dir = "";
string attr;

// info on the Build13 ship coordsystem: positive z coords mean South, -z North, +x is West, -x East
// the center of the coordsystem  (x=0, z=0) is also the center of the islandmodel
float psX = MakeFloat(pchar.ship.pos.x);
float psZ = MakeFloat(pchar.ship.pos.Z);

float swdist = ISLANDSWITCHDISTANCE + GetIslandSize(pchar.location) + GetIslandRemoteness(pchar.location);  // ccc Jan07
// GetIslandSize is the aprox size(coastradius) of the island
// GetIslandRemoteness increases that for remote islands so that sailing to them takes longer
// we add the distance after which we want to switch to the next island and get the swdist from islandmodelcenter (x=0, z=0)

// several checks if the player left the vicinity of the island, and in which direction
if(psX < -swdist) //east
{
dir="east";	// you leave the OLD island eastbound

if(psZ < -(swdist*3/5)) // AND north
{dir="northeast";}	// you are ALSO north, i.e. northeast

if(psZ > swdist*3/5) // AND south
{dir="southeast";}
}

if(psX > swdist) //west
{
dir="west";

if(psZ < -(swdist*3/5)) // AND north
{dir="northwest";}

if(psZ > swdist*3/5) // AND south
{dir="southwest";}
}

if(psZ < -swdist) //north
{
dir="north";

if(psX < -(swdist*3/5)) // AND east
{dir="northeast";}

if(psX > swdist*3/5) // AND west
{dir="northwest";}
}

if(psZ > swdist) //south
{
dir="south";

if(psX < -(swdist*3/5)) // AND east
{dir="southeast";}

if(psX > swdist*3/5) // AND west
{dir="southwest";}
}
DSTrace("DirectIslandCellCheck dir is " +  dir );

if(dir=="")return false;	// aborts if no leaving anywhere was detected

string toislandname = GetNeighbourIsland(pchar.location, dir); // neighbour island in DIRection

if(toislandname != "")
// if there is a neighbouring island in the leaving direction	
{
pchar.directsail.toisland = toislandname; // neighbour island stored as playerattribute for Sea_ReloadDirect function
int NewDist = ISLANDSWITCHDISTANCE + GetIslandSize(toislandname) - 1000.0;
// distance at which you appear from the CENTER of the neighbour island,
// minus 1000 so that you don't switch back right away

// with that we determine the coords at which you appear at the neighbour island
// (the opposite of the leaving dir: if you leave old island southbound you appear north of new island)
switch(dir)
{
case "North": pchar.directsail.tox= 0; pchar.directsail.toz= +NewDist; break;
case "Northeast": pchar.directsail.tox= +NewDist; pchar.directsail.toz= +NewDist; break;
case "Northwest": pchar.directsail.tox= -NewDist; pchar.directsail.toz= +NewDist; break;

case "South": pchar.directsail.tox= 0; pchar.directsail.toz= -NewDist; break;
case "Southeast": pchar.directsail.tox= +NewDist; pchar.directsail.toz= -NewDist; break;
case "Southwest": pchar.directsail.tox= -NewDist; pchar.directsail.toz= -NewDist; break;

case "East": pchar.directsail.tox= +NewDist; pchar.directsail.toz= 0; break;
case "West": pchar.directsail.tox= -NewDist; pchar.directsail.toz= 0; break;
}

DSTrace("pchar.directsail.tox " + pchar.directsail.tox + " pchar.directsail.toz " + pchar.directsail.toz );

// those data are now stored as playerattributes.
// Sea_ReloadDirect & SeaLoginDirect will recognize from those player attributes that you left OldIsland to the leavingdirection dir
// and delete the current island from the sea environment. The neighbour island is added
// and you will be placed so that it looks as if you had arrived from the OldIsland.

Traceandlog("Captain, " + toislandname + " to the " + dir );

// Change worldmap coordinates accordingly
// Some strange spelling in worldmap_init must be taken into account:

// this converts the seaview position into map coords (still inaccurate)
worldMap.playerShipX = stf(worldMap.islands.(toislandname).position.x)+(stf(pchar.directsail.tox)/60); //divisor needs adjusting for final version
worldMap.playerShipZ = stf(worldMap.islands.(toislandname).position.z)+(stf(pchar.directsail.toz)/60); // increase to get closer to the island
DSTrace("Player map coord set to x: " + worldMap.playerShipX + " , z : " + worldMap.playerShipZ );

return true;	// returns that islandchange has taken place
}
else
{
DSTrace("DirectIslandCellCheck false ");	
return false;	// returns that NO islandchange has taken place
}
}

string GetNeighbourIsland(string Island, string dir)
// returns which neighbour island lies in the DIRection you leave an Island
// could also be done in Islands_init.c, but this way I can leave that file undisturbed
{
//MAXIMUS: translation -->
//int tmpLangFileID = LanguageOpenFile("interface_strings.txt");
string cptHint = TranslateString("","Captain, a hint:")+" ";
string direcTo = TranslateString("",dir)+" ";
string drcFrom = TranslateString("","of"+"_island")+" ";
string direcIs = TranslateString("",Island)+" ";
string drcLies = TranslateString("","lies nothing but open sea!");
//LanguageCloseFile(tmpLangFileID);
//MAXIMUS: translation <--

switch(Island)
{

case "FalaiseDeFleur":
switch(dir)
{
case "North": return "Battle_Rocks"; break;
case "Northeast": return "Guadeloupe"; break;
case "Northwest": return "Battle_Rocks"; break;
case "East": return "Antigua"; break;
case "West": return "Oxbay"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Redmond":
switch(dir)
{
case "North": return "Cuba"; break;
case "Northeast": return "Hispaniola"; break;
case "Northwest": if (FindIsland("IslaDeMuerte") < 0) return "Eleuthera"; else return "IslaDeMuerte"; break; // KK

case "South": return "Battle_Rocks"; break;
case "Southeast": return "IslaMuelle"; break;
case "Southwest": return "Douwesen"; break;

case "East": return "Hispaniola"; break;
case "West": return "Cayman"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "IslaMuelle":
switch(dir)
{
case "North": return "Hispaniola"; break;
case "Northwest": return "Redmond"; break;

case "South": return "QuebradasCostillas"; break;
case "Southeast": return "SaintMartin"; break;
case "Southwest": return "Battle_Rocks"; break;

case "West": return "Battle_Rocks"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Oxbay":
switch(dir)
{
case "North": return "Curacao"; break; // KK
case "Northeast": return "Battle_Rocks"; break;
case "Northwest": return "Douwesen"; break; // KK
case "East": return "FalaiseDeFleur"; break;
case "West": return "Conceicao"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Conceicao":
switch(dir)
{
case "North": return "Douwesen"; break;
case "Northeast": return "Curacao"; break; // KK
case "Southeast": return "Oxbay"; break;
case "East": return "Oxbay"; break;
traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Douwesen":
switch(dir)
{
case "North": return "KhaelRoa"; break;
case "Northeast": return "Redmond"; break;
case "South": return "Conceicao"; break;
case "Southeast": return "Oxbay"; break;
case "East": return "Curacao"; break; // KK

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "QuebradasCostillas":
switch(dir)
{
case "North": return "IslaMuelle"; break;
case "Northeast": return "IslaMuelle"; break;
case "Northwest": return "Battle_Rocks"; break;

case "South": return "Antigua"; break;
case "Southwest": return "Guadeloupe"; break;

case "East": return "SaintMartin"; break;
case "West": return "Guadeloupe"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "KhaelRoa":
switch(dir)
{
case "South": return "Douwesen"; break;
case "Southeast": return "Battle_Rocks"; break;
case "East": return "Cayman"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Cayman":
switch(dir)
{
case "North": return "Eleuthera"; break; // KK
case "Northeast": if (FindIsland("IslaDeMuerte") < 0) return "Cuba"; else return "IslaDeMuerte"; break; // KK
case "South": return "Battle_Rocks"; break;
case "Southeast": return "Redmond"; break;
case "Southwest": return "Aruba"; break; // KK
case "East": return "Cuba"; break;
case "West": return "KhaelRoa"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Hispaniola":
switch(dir)
{
case "North": return "Turks"; break;
case "Northwest": return "Cuba"; break;
case "South": return "IslaMuelle"; break;
case "Southeast": return "IslaMuelle"; break;
case "Southwest": return "Battle_Rocks"; break;
case "West": return "Redmond"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Cuba":
switch(dir)
{
case "South": return "Redmond"; break;
case "Southeast": return "Hispaniola"; break;
case "Southwest": if (FindIsland("IslaDeMuerte") < 0) return "Cayman"; else return "IslaDeMuerte"; break; // KK

case "East": return "Turks"; break;
case "West": return "Eleuthera"; break; // KK

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Guadeloupe":
switch(dir)
{
case "North": return "Battle_Rocks"; break;
case "Northeast": return "QuebradasCostillas"; break;
case "Northwest": return "Battle_Rocks"; break;

case "Southeast": return "Antigua"; break;
case "Southwest": return "FalaiseDeFleur"; break;

case "East": return "QuebradasCostillas"; break;
case "West": return "FalaiseDeFleur"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "SaintMartin":
switch(dir)
{
case "North": return "IslaMuelle"; break;
case "Northwest": return "IslaMuelle"; break;
case "Southwest": return "Antigua"; break;
case "West": return "QuebradasCostillas"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Antigua":
switch(dir)
{
case "North": return "QuebradasCostillas"; break;
case "Northeast": return "SaintMartin"; break;
case "Northwest": return "Guadeloupe"; break;
case "West": return "FalaiseDeFleur"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Turks":
switch(dir)
{
case "South": return "Hispaniola"; break;
case "Southwest": return "Hispaniola"; break;
case "West": return "Cuba"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

// KK -->
case "Curacao":
switch(dir)
{
case "North": return "Redmond"; break;
case "Northeast": return "Battle_Rocks"; break;
case "Northwest": return "Aruba"; break;

case "South": return "Oxbay"; break;
case "Southeast": return "FalaiseDeFleur"; break;
case "Southwest": return "Conceicao"; break;

case "East": return "Battle_Rocks"; break;
case "West": return "Douwesen"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Eleuthera":
switch(dir)
{
case "North": return "Redmond"; break;
case "Northeast": return "Cuba"; break;
case "South": return "Cayman"; break;
case "Southeast": if (FindIsland("IslaDeMuerte") < 0) return "Redmond"; else return "IslaDeMuerte"; break;
case "East": return "Cuba"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "Aruba":
switch(dir)
{
case "North": return "KhaelRoa"; break;
case "Northeast": return "Cayman"; break;
case "South": return "Douwesen"; break;
case "Southeast": return "Douwesen"; break;
case "East": return "Redmond"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;

case "IslaDeMuerte":
switch(dir)
{
case "North": return "Eleuthera"; break;
case "Northeast": return "Cuba"; break;
case "Northwest": return "Eleuthera"; break;

case "South": return "Cayman"; break;
case "Southeast": return "Redmond"; break;
case "Southwest": return "Cayman"; break;

case "East": return "Redmond"; break;
case "West": return "Cayman"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;
// <-- KK

case "Battle_Rocks":
switch(dir)
{
case "North": return "Redmond"; break;
case "Northeast": return "Hispaniola"; break;
case "Northwest": return "Redmond"; break;

case "South": return "FalaiseDeFleur"; break;
case "Southeast": return "QuebradasCostillas"; break;
case "Southwest": return "Oxbay"; break;

case "East": return "IslaMuelle"; break;
case "West": return "Douwesen"; break;

traceandlog(cptHint + direcTo + drcFrom + direcIs + drcLies);//MAXIMUS: changed for translation
return "";  // default, no neighbour island in this dir
}
break;
trace("GetNeighbourIsland couldnt find " + Island)
return "";  // default
}

trace("GetNeighbourIsland for" + Island + " direction "+dir+" went wrong")
return "";  // default
}


// -------------------------------- Reloading of sea environment -----------------------------------------

void Sea_ReloadStartDirect()  // called by DirectsailCheck, structure like original Sea_ReloadStart
{
softWeatherReset = true;
if (!bSeaActive) { return; }
DeleteSeaEnvironment();

SetEventHandler("Sea_ReloadDirect", "Sea_ReloadDirect", 0);
PostEvent("Sea_ReloadDirect", 1.0);
}



void Sea_ReloadDirect() // Jan 07, new version by Screwface that works also with worldmapcoords
// called by Sea_ReloadStartDirect(), structure like original Sea_Reload
{
DelEventHandler("Sea_ReloadDirect", "Sea_ReloadDirect");

ReloadProgressStart(); // KK

ref rPlayer = GetMainCharacter();

object Login;
Login.PlayerGroup.ay = stf(rPlayer.Ship.Ang.y);
Login.PlayerGroup.x = MakeFloat(rPlayer.ship.pos.x); 
Login.PlayerGroup.y = 0.0;
Login.PlayerGroup.z = MakeFloat(rPlayer.ship.pos.z);
Login.Island = Characters[0].location;

if(CheckAttribute(rPlayer,"directsail.toisland"))
// if Directsail() calls islandchange island and playerposition are changed
{
Login.Island = rPlayer.directsail.toisland;
string toislandname = rPlayer.directsail.toisland;

if(ACCURATE_NAVIGATION)  // if worldmapcoords are to be used 
{
// SECTION TO APPEAR IN THE NEW REAL POSITION AT THE NEW ISLAND 
float psX = MakeFloat(worldMap.playerShipX);
float psZ = MakeFloat(worldMap.playerShipZ);

float ix = MakeFloat(worldMap.islands.(toislandname).position.rx);
float iz = MakeFloat(worldMap.islands.(toislandname).position.rz);
Login.playerGroup.x = (psX - ix)*WDM_MAP_TO_SEA_SCALE;
Login.playerGroup.z = (psZ - iz)*WDM_MAP_TO_SEA_SCALE;
}
else
{
// old islandcell method
Login.PlayerGroup.x = stf(rPlayer.directsail.tox);
Login.PlayerGroup.z = stf(rPlayer.directsail.toz);
}

Login.PlayerGroup.ay = stf(rPlayer.Ship.Ang.y); // your old heading
}
DSTrace("Sea_reloadDirect at "+ FindIslandName(Login.Island));	// LDH translate name 02Jan09

SeaLoginDirect(&Login);

ReloadProgressEnd(); // KK
}


void SeaLoginDirect(ref Login)  // called by Sea_ReloadDirect(), structure like original SeaLogin
// reloads Sea with new ships at horizon, and with new island if DirectIslandCheck() was true
{
int		i, j, iShipType;
float	x, y, z, ay;
ref		rCharacter, rGroup, rEncounter;
aref	rRawGroup;
aref	arQCGroups;
string	sGName;
int		iNumQCGroups;

int iRDTSC = RDTSC_B();

// clear load groups now object
DeleteAttribute(&LoginGroupsNow, "");

iStormLockSeconds = 0;
iNumFantoms = 0;
bSkipSeaLogin = false;
bSeaReloadStarted = false;
bSeaQuestGroupHere = false;
bIslandLoaded = false;

fSeaExp = 0.0;
fSeaExpTimer = 0.0;
// NK 04-09-21 timeupdate
if(TIMEUPDATE_BLOCK_LAND)
{
AddTimeToCurrent(0, (locTmpTime * TIMESCALAR_LAND)/60);
}
locTmpTime = 0.0;
// NK <--

Sea_FreeTaskList();
Encounter_DeleteDeadQuestMapEncounters();
// Island
int iIslandIndex = FindIsland(Login.Island);
//Trace("Island id = " + Login.Island + ", Island index = " + iIslandIndex);
string sIslandID = "";
if (iIslandIndex != -1) { sIslandID = Islands[iIslandIndex].id; }

// main character
ref rPlayer = GetMainCharacter();
rPlayer.Ship.Stopped = false;
DeleteAttribute(rPlayer,"LastSailState"); // NK 05-04-20 so it doesn't say it during loading
rPlayer.Ship.POS.Mode = SHIP_SAIL;
rPlayer.location = sIslandID;

// clear old fantom relations in our character
if (CheckAttribute(rPlayer, "Relation"))
{
aref	arRelations; makearef(arRelations, rPlayer.Relation);
int		iNumRelations = GetAttributesNum(arRelations);
for (i=0; i<iNumRelations; i++)
{
aref arRelation = GetAttributeN(arRelations, i);
string sRName = GetAttributeName(arRelation);
if (sti(sRName) >= FANTOM_CHARACTERS)
{
DeleteAttribute(arRelations, sRName);
iNumRelations--;
i--;
}
}
}
// Quest check
Event(EVENT_SEA_LOGIN, "");
if (bSkipSeaLogin) return;
// create all sea modules
CreateSeaEnvironment();
// delete our group
Group_DeleteGroup(PLAYER_GROUP);

// set commander to group
Group_SetGroupCommander(PLAYER_GROUP, Characters[GetMainCharacterIndex()].id);

// set our group position
Group_SetXZ_AY(PLAYER_GROUP, stf(Login.PlayerGroup.x), stf(Login.PlayerGroup.z), stf(Login.PlayerGroup.ay) );
Trace("Set group : " + PLAYER_GROUP + ", x = " + Login.PlayerGroup.x + ", z = " + Login.PlayerGroup.z + ", ay = " + Login.PlayerGroup.ay);
Sea.MaxSeaHeight = 50.0;

ReloadProgressUpdate();

float wdmBaseX, wdmBaseZ; // WM base coords for fleets 05-05-02

// login island if exist
if (sIslandID != "")
{
trace("SealoginDirect loading island " + FindIslandName(sIslandID));	// LDH translate name 02Jan09
CreateEntity(&Island, "Island");
Island.LightingPath = GetLightingPath();
SendMessage(&SeaLighter, "ss", "ModelsPath", Islands[iIslandIndex].filespath.models);
SendMessage(&SeaLighter, "ss", "LightPath", GetLightingPath());

SendMessage(&Island, "lsss", MSG_ISLAND_LOAD_GEO, "islands", Islands[iIslandIndex].filespath.models, Islands[iIslandIndex].model);
LayerAddObject(SEA_REALIZE, &Island, 65529);
LayerAddObject("mast_island_trace", &Island, 1);
LayerAddObject("sun_trace", &Island, 1);

CreateEntity(&IslandReflModel, "MODELR");
string sReflModel = Islands[iIslandIndex].filespath.models + "\\" + Islands[iIslandIndex].refl_model;
SendMessage(&IslandReflModel, "ls", MSG_MODEL_SET_LIGHT_PATH, GetLightingPath());
SendMessage(&IslandReflModel, "ls", MSG_MODEL_LOAD_GEO, sReflModel);
LayerAddObject("sea_reflection", &IslandReflModel, -1);
SendMessage(SeaLighter, "ssi", "AddModel", Islands[iIslandIndex].refl_model, &IslandReflModel);

bIslandLoaded = true;
SendMessage(&SeaLocatorShow, "a", &Islands[iIslandIndex]);
Fort_Login(iIslandIndex);
Sea.MaxSeaHeight = 3.0;
// WM base coords for fleets 05-05-02 -->
// 05-05-03 get correct wdm name for island.
string wdmisland = wdmGetIslandNameFromID(sIslandID);
if(wdmisland != "" && CheckAttribute(worldMap,".islands."+wdmisland))
{
wdmBaseX = MakeFloat(worldMap.islands.(wdmisland).position.rx);
wdmBaseZ = MakeFloat(worldMap.islands.(wdmisland).position.rz);
}
else { wdmBaseX = makefloat(worldMap.playerShipX); wdmBaseZ = makefloat(worldMap.playerShipZ); }
}
else { wdmBaseX = makefloat(worldMap.playerShipX); wdmBaseZ = makefloat(worldMap.playerShipZ); } // WM base coords for fleets 05-05-02 <--
AISea.Island = sIslandID;

// clear some of group attributes
for (i=0; i<MAX_SHIP_GROUPS; i++)
{
rGroup = Group_GetGroupByIndex(i);
if (CheckAttribute(rGroup, "AlreadyLoaded")) { DeleteAttribute(rGroup, "AlreadyLoaded"); }
}
ReloadProgressUpdate();

// from coast check (move / stop)
bFromCoast = false;
if (CheckAttribute(&Login, "FromCoast")) { bFromCoast = sti(Login.FromCoast); }

// login main player and his friends
int iMainCharacter,iCompanionIndex;
iMainCharacter = GetMainCharacterIndex();

rPlayer.SeaAI.Group.Name = PLAYER_GROUP;
rPlayer.Ship.Type = Characters[iMainCharacter].Ship.Type;
rPlayer.Ship.Stopped = false;
Ship_Add2Sea(iMainCharacter, bFromCoast, "");
trace("added pchar to sea");
Group_AddCharacter(PLAYER_GROUP, Characters[iMainCharacter].id);
for (i=1; i<COMPANION_MAX; i++)
{
iCompanionIndex = GetCompanionIndex(&Characters[iMainCharacter],i);
if (iCompanionIndex == -1) { continue; }
Characters[iCompanionIndex].SeaAI.Group.Name = PLAYER_GROUP;
Ship_Add2Sea(iCompanionIndex, bFromCoast, "");

// add companion to player group
Group_AddCharacter(PLAYER_GROUP, Characters[iCompanionIndex].id);
}
//trace("added comps to sea");

// set ship for sea camera
// CCC SeaCameras.Camera = "SeaDeckCamera"; // so that you look FORWARD, spyglass ready
SeaCameras_SetShipForSeaCamera(&rPlayer);

// login encounters
object oResult;
int iFantomIndex;

// login quest group if island exist 
ReloadProgressUpdate();
if(CheckAttribute(rPlayer,"directsail.toisland"))
// if DirectsailCheck() calls islandchange coastal ships are created
{
if (AUTOCREATE_CR == 1) { SetCoastTraffic(sIslandID); }
}

if (sIslandID != "")
{
for (i=0; i<MAX_SHIP_GROUPS; i++)
{
rGroup = Group_GetGroupByIndex(i);
if (!CheckAttribute(rGroup,"AlreadyLoaded")) { DeleteAttribute(rGroup,"AlreadyLoaded");	} // NK: HUH!?

if (!CheckAttribute(rGroup, "id")) { continue; }
if (!CheckAttribute(rGroup, "location")) { continue; }
if (rGroup.location != sIslandID) { continue; }

Sea_LoginGroup(rGroup.id);
}
}
// trace("Did any groups");

// login quest groups to sea
if (CheckAttribute(&Login, "QuestGroups"))
{
arQCGroups; makearef(arQCGroups, Login.QuestGroups);
iNumQCGroups = GetAttributesNum(arQCGroups);
for (i=0; i<iNumQCGroups; i++)
{
Sea_LoginGroup(GetAttributeValue(GetAttributeN(arQCGroups, i)));
}
}

ReloadProgressUpdate();

// login quest groups to sea from LoginGroupsNow object
if (CheckAttribute(&LoginGroupsNow, "QuestGroups"))
{
makearef(arQCGroups, LoginGroupsNow.QuestGroups);
iNumQCGroups = GetAttributesNum(arQCGroups);
for (i=0; i<iNumQCGroups; i++)
{
Sea_LoginGroup(GetAttributeValue(GetAttributeN(arQCGroups, i)));
}
}

ReloadProgressUpdate();

if(CheckAttribute(rPlayer,"directsail.encounter")) // if set so in DirectsailCheck() random encounter ships are created
{
rPlayer.ship.pos.x = stf(Login.PlayerGroup.x); // so that DirectEncounter doesn't use OLD coords
rPlayer.ship.pos.z = stf(Login.PlayerGroup.z);
DirectEncounter( stf(Login.PlayerGroup.ay) );
//TraceAndLog("DS: directsail attributes were cleared because encounter attribute existed");	// LDH 12Feb09
DeleteAttribute(rPlayer,"directsail");	// clears tags from player
}

// set tasks 2 all groups
int c; //NK bugfix 5-1
for (i=0; i<GetArraySize(&sTaskList)-2; i++)
{
string sGroupID = sTaskList[i];

rGroup = Group_GetGroupByID(sGroupID);

// set task
switch (sti(rGroup.Task))
{
case AITASK_RUNAWAY:
Group_SetTaskRunAway(sGroupID);
break;
case AITASK_ATTACK:
Group_SetTaskAttack(sGroupID, rGroup.Task.Target);
break;
case AITASK_MOVE:
if (CheckAttribute(rGroup, "Task.Target.Pos"))
{
Group_SetTaskMove(sGroupID, stf(rGroup.Task.Target.Pos.x), stf(rGroup.Task.Target.Pos.z));
}
else
{
x = 10000.0 * sin(stf(rGroup.Pos.ay));
z = 10000.0 * cos(stf(rGroup.Pos.ay));
Group_SetTaskMove(sGroupID, x, z);
}
break;
}

rCharacter = Group_GetGroupCommanderR(rGroup);
int iRelation = GetRelation(GetMainCharacterIndex(), sti(rCharacter.index));

// set relations to all characters in this group
c = 0;
while (true)
{
int iCharacterIndex = Group_GetCharacterIndexR(rGroup, c); c++;
if (iCharacterIndex < 0) { break; }
SetCharacterRelationBoth(iCharacterIndex, GetMainCharacterIndex(), iRelation);
}
}
trace("Set tasks");

// update AISea ----------------------------------
AISea.isDone = "";
InitBattleInterface();							ReloadProgressUpdate();
StartBattleInterface();							ReloadProgressUpdate();
RefreshBattleInterface();						ReloadProgressUpdate();

CreateEntity(&Seafoam,"Seafoam");				ReloadProgressUpdate();
LayerAddObject(SEA_EXECUTE, &Seafoam, -1);
LayerAddObject(SEA_REALIZE, &Seafoam, -1);
if (Whr_IsStorm()) { Seafoam.storm = "true"; }

SendMessage(&Telescope, "leee", MSG_TELESCOPE_INIT_ARRAYS, &Nations, &ShipsTypes, &Goods);

PostEvent(SHIP_CHECK_RELOAD_ENABLE, 100);

SetSchemeForSea();								ReloadProgressUpdate();

iRDTSC = RDTSC_E(iRDTSC);
//Trace("SeaLogin RDTSC = " + iRDTSC);
//Trace("iNumShips = " + iNumShips);

PostEvent("Sea_FirstInit", 100);
trace("Direct Sea_login done");
}




//-------------------------------- Encounters and events -----------------------------------

void DirectEncounter(float encay)  // called by SeaLoginDirect
// creates ships that appear in the direction encay (playerheading as currently called )
{
int i, j;
float x, z, ay;
ref rGroup;
ref rPlayer = GetMainCharacter();
string groupname = "Directenc"+rand(100);
int Encnation = rand(5); // RANDOM nation for encounterships
// int Encnation = FindEnemyNation2Character(GetMainCharacterIndex()); // another choice: Only ENEMY encounters

object oResult;
int iFantomIndex;



// ships shall appear ahead of player(aprox!), so we set coords according to player coords & heading
//	encay = encay - 1.5 + rand(3); // random deviation from playerheading, so that ships are not always dead ahead
float bearing = randnorm(60.0, 30.0);		   // LDH better random number for bearing - 10Jan09
if (bearing > 90.0) bearing = 180.0 - bearing;
if (rand(1)) bearing = -bearing;
if (bearing > 180.0) Bearing -= 360.0;
DSTrace("Encounter - bearing to ship " + makeint(bearing));

encay += Degree2Radian(bearing);
z = stf(rPlayer.Ship.Pos.z) + (cos(encay)*DIRECTENCOUNTERDISTANCE); // add Z component
x = stf(rPlayer.Ship.Pos.x) + (sin(encay)*DIRECTENCOUNTERDISTANCE); // add X component

//	Traceandlog("Strange sail to the " + GetCompassDirFromAY( encay )  );
Traceandlog("Strange sail " + GetBearingFromShip16(Degree2Radian(bearing)));	// LDH 26Feb09
//	ay = encay + 3.2; // heading to player
ay = randnorm(encay + 3.2, Degree2Radian(20.0));	// LDH random heading 29Jan09
ReloadProgressUpdate();

Sea_AddGroup2TaskList(groupname);

rGroup = Group_GetGroupByIndex(Group_CreateGroup(groupname));
Group_SetXZ_AY(groupname, x, z, ay);
Group_SetType(groupname, "war");
Group_DeleteAtEnd(groupname);

// encountertype ? Rand(6) for now
int enctype = makeint(rand(6) );
int iNumShips = Fantom_GenerateEncounter(groupname, &oResult, enctype, Encnation);

DSTrace("Directsail encounter type: " + enctype + ", at x = " + x + ", z = " + z);

// load ships to sea
if (iNumShips)
{
for (j=0; j<iNumShips; j++)
{
iFantomIndex = FANTOM_CHARACTERS + iNumFantoms - iNumShips + j;
ref rFantom = &Characters[iFantomIndex];

rFantom.id = "fenc_" + iFantomIndex;

// Screwface
if(Checkattribute(rFantom,"recognized"))
{
DeleteAttribute(rFantom,"recognized");
DeleteAttribute(rFantom,"EnemyShipName");
DeleteAttribute(rFantom,"EnemyShipType");
} // Screwface : end

// set commander to group
if (j==0) { Group_SetGroupCommander(groupname, Characters[iFantomIndex].id); }

// set random character and ship names, face id
rFantom.sex = "man";
rFantom.Nation = Encnation;  // change for battle enc ?

SetRandomNameToCharacter(rFantom);
SetRandomNameToShip(rFantom);
SetRandomFaceToCharacter(rFantom);
// KK -->
rFantom.location = "none";
rFantom.location.group = "";
rFantom.location.locator = "";
// <-- KK
//MAXIMUS Jan07-->
Fantom_SetRandomModel(rFantom, rFantom.fantomtype);
Facemaker(rFantom);
//MAXIMUS <--

LAi_Create_Officer(0, rFantom);
Fantom_SetRandomMoney(rFantom, rFantom.fantomtype);
Ship_SetFantomData(rFantom); // KK
Fantom_SetCannons(rFantom, rFantom.fantomtype);
Fantom_SetSails(rFantom, rFantom.fantomtype);

rFantom.SeaAI.Group.Name = groupname;

// KK -->
if (CheckAttribute(rFantom, "after_1st_sailto")) DeleteAttribute(rFantom, "after_1st_sailto");
RestoreCharacter(rFantom);
// <-- KK

// add fantom
Group_AddCharacter(groupname, rFantom.id);

// add to sea
Ship_Add2Sea(iFantomIndex, 0, rFantom.fantomtype);
Trace("Directencounter adds " + rFantom.id);
}
}

// task: ENEMY attacks you, others sail towards you
if (GetRMRelationType(GetRMRelation(GetMainCharacter(),Encnation)) != RELATION_ENEMY)
{
// LDH 29Jan09
x = x + 10000.0 * sin(ay);
z = z + 10000.0 * cos(ay);
Group_SetTaskMove(groupname, x, z);
//		Group_SetTaskMove(groupname, stf(rPlayer.ship.pos.x), stf(rPlayer.ship.pos.z));
Trace("Directsail encounter nation: " + Encnation + ", task move ");
}
else
{
Group_SetTaskAttack(groupname, PLAYER_GROUP);
Group_LockTask(groupname);
Trace("Directsail encounter nation: " + Encnation + ", task attack ");
UpdateRelations();
}

ReloadProgressUpdate();
Trace("Directencounter done ");
}



void Randomshipevent()
// jan 07 creates random shiplife events
// for the time being only flotsam
{
ref pchar = GetMainCharacter();
// float bearing = rand(3) - 1.5; // random deviation from playerheading, so that salvage is not always dead ahead
float bearing = randnorm(30.0, 30.0);		   // LDH better random number for bearing - 10Jan09
if (bearing > 90.0) bearing = 180.0 - bearing;
if (rand(1)) bearing = -bearing;
if (bearing > 180.0) bearing -= 360.0;
DSTrace("Encounter - bearing to flotsam " + makeint(bearing));
bearing = Degree2Radian(bearing);

int sp = 8 - stf(ShipsTypes[GetCharacterShipType(pchar)].Class); // factor that increases amount of goodies for bigger shipclasses

String sound = "objects\shipcharge\CannonReload-000.wav";
String message = "Captain, there is something drifting in the water";

switch(rand( 22 ) ) // 22 greater than number of cases to create blanks, increase for more
{

case 1:
Direct_AddGood(pchar, "Sailcloth", "roll_of_rolls", 400.0, (rand(20)+5)*sp, 200, bearing);
break;

case 2:
Direct_AddGood(pchar, "Planks", "roll_of_planks", 400.0, (rand(20)+5)*sp, 200, bearing);
break;

case 3:
Direct_AddGood(pchar, "Wheat", "sack", 400.0, (rand(10)+2)*sp, 200, bearing);
break;

case 4:
Direct_AddGood(pchar, "Rum", "barrel", 400.0, (rand(10)+2)*sp, 200, bearing);
break;

case 5:
Direct_AddGood(pchar, "Gunpowder", "barrel", 400.0, (rand(10)+2)*sp, 200, bearing);
break;

case 6:
Direct_AddGood(pchar, "Ebony", "roll_of_planks", 400.0, (rand(10)+2)*sp, 200, bearing);
break;

case 7:
Direct_AddGood(pchar, "Mahogany", "roll_of_planks", 400.0, (rand(20)+5)*sp, 200, bearing);
break;

case 8:
Direct_AddGood(pchar, "Silk", "roll_of_rolls", 400.0, (rand(20)+5)*sp, 200, bearing);
break;

case 9:
Direct_AddGood(pchar, "Sandal", "bale", 400.0, (rand(20)+5)*sp, 200, bearing);
break;

case 10:
Direct_AddGood(pchar, "Cinnamon", "bale", 400.0, (rand(20)+5)*sp, 200, bearing);
break;

case 11:
bearing = 0.0;	// LDH added 02Feb09
Direct_AddGood(pchar, "Oil", "log", 1000.0, 102, 100, bearing); // 102 trunk, dead ahead
sound = "objects\shipcharge\_Abandon3.wav";
message = "Something is drifting there, DEAD AHEAD";
bearing = -99.0;	// LDH keep directing from displaying - 04Mar09
break;

case 12:
bearing = 0.0;	// LDH added 02Feb09
Direct_AddGood(pchar, "Oil", "log", 1000.0, 102, 100, bearing); // 102 trunk, repeated to increase frequency
sound = "objects\shipcharge\_Abandon3.wav";
message = "Something is drifting there, DEAD AHEAD";
bearing = -99.0;	// LDH keep directing from displaying - 04Mar09
break;

case 13:
Direct_AddGood(pchar, "Oil", "boat", 3000.0, (rand(5)+2)*sp, 500, bearing); // lifeboat with survivors
message = "Captain, a boat";
break;

case 14:
Direct_AddGood(pchar, "Oil", "boat", 3000.0, (rand(5)+2)*sp, 500, bearing); // lifeboat with survivors
message = "Captain, a boat";
break;

case 15:
Direct_AddGood(pchar, "Oil", "indianraft", 3000.0, 103, 800, bearing); // 103 indian raft
message = "Captain, a native raft";
break;

case 16:
Direct_AddGood(pchar, "Oil", "hulk", 3000.0, 104, 800, bearing); // 104 abandoned hulk
message = "Captain, a dismasted vessel";
break;

case 17:
Direct_AddGood(pchar, "Oil", "hulk", 3000.0, 104, 800, bearing); // 104 abandoned hulk
message = "Captain, a dismasted vessel";
break;

case 18:
If (MINES) 
{
bearing = 0.0;	// LDH added 02Feb09
Direct_AddGood(pchar, "Oil", "mine", 1000.0, 101, 100, bearing); // 101 mine, dead ahead
sound = "objects\shipcharge\_Abandon3.wav";
message = "Something is drifting there, DEAD AHEAD";
bearing = -99.0;	// LDH keep directing from displaying - 04Mar09
}
else
{
message = "";
}
break;

message = ""; // blank, nothing happens
}

If(message!="")
{ 
//  Logit(message + " to the " + GetCompassDirFromAY( stf(pchar.Ship.Ang.y) + bearing ) );
Logit(message + " " + GetBearingFromShip16( bearing ) );		// LDH 26Feb09
PlayStereoSound(sound);
}

}

void Direct_AddGood(ref rCharacter, string sGood, string sModel, float fTime, int iQuantity, float dist, float bearing)
// ccc Jan 07, mostly like AISeaGoods_AddGood, but salvage is set at a certain dist from rCharacter
// bearing is the angle to the flotsam's position from the ship heading: 0= ahead, 1.6=right, 3.2=astern, 4.8=left 
{
if (!bSeaActive) return;

Trace("Add good direct : " + sGood + ", rCharacter.id = " + rCharacter.id + ", iQuantity = " + iQuantity);

// calculate position from ship according to dist and bearing
float ay = stf(rCharacter.Ship.Ang.y) + bearing; // get angle
float z = cos(ay)*dist; // add Z component
float x = sin(ay)*dist; // add X component

AISeaGoods.Good = sGood;
AISeaGoods.Pos.x = stf(rCharacter.Ship.Pos.x) + x;
AISeaGoods.Pos.z = stf(rCharacter.Ship.Pos.z) + z;

AISeaGoods.CharIndex = "9"; // must NOT be rCharacter.Index, cause AISeaGoods_ShipEatGood() returns false if salvage and salvager have the same index; assume that 9 is not used for any shipcaptain

AISeaGoods.Time = fTime;
AISeaGoods.Quantity = iQuantity;
AISeaGoods.Model = sModel;
AISeaGoods.Add = "";
}


void LaunchMine(ref rCharacter)
// ccc Jan 07, places mine "good" behind ship of rCharacter.
// a new check in AISeaGoods_ShipEatGood() explodes any ship that sails onto that mine
{
if (!bSeaActive) return;

if(GetCargoGoods(rCharacter, GOOD_GUNPOWDER)>300 ) // you need gunpowder for a mine
{
AddCharacterGoods(rCharacter, GOOD_GUNPOWDER, -300 );
float dist = 51.0-(stf(ShipsTypes[GetCharacterShipType(rCharacter)].Class)*4); // drop distance from shipcenter, depending on shipsize

// calculate dropping position astern of ship
float ay = stf(rCharacter.Ship.Ang.y) + 3.0; // get angle astern
float z = cos(ay)*dist + stf(rCharacter.Ship.Pos.z); // Z coord
float x = sin(ay)*dist + stf(rCharacter.Ship.Pos.x); // X coord

// place mine "good" behind ship
AISeaGoods.Good = "oil";
AISeaGoods.Pos.x = x;
AISeaGoods.Pos.z = z;

AISeaGoods.CharIndex = "9"; // must NOT be rCharacter.Index, cause AISeaGoods_ShipEatGood() returns false if salvage and salvager have the same index; assume that 9 is not used for any shipcaptain

AISeaGoods.Time = 5000;
AISeaGoods.Quantity = 101;
AISeaGoods.Model = "mine";
AISeaGoods.Add = "";

// launch effects
PlayStereoSound("objects\shipcharge\ball_splash1.wav");
Logit("Mine launched");
CreateParticleSystemX("ball_splash", x, 1.0, z, 0.0, 3.0, 0.0, 2);

}
else { Logit("You don't have enough gunpowder for a mine !"); }
}


void SwimGoodEvent(ref rCharacter, int iQuantity)
// ccc Jan 07, special events that happen if you sail over flotsam of a certain kind
// called by AISeaGoods_ShipEatGood() if you sail over "swim goods" of the oil type
{
//int tmpLangFileID = LanguageOpenFile("interface_strings.txt");//MAXIMUS: moved here
int n;
ref pchar = GetMainCharacter();
int sp = 8 - stf(ShipsTypes[GetCharacterShipType(pchar)].Class); // factor that increases amount of goodies for bigger shipclasses

switch(iQuantity) // Direct_AddGood calls with certain quantities of oil determine encountertype
// rest ensured, that is a safe method: the game will never ever create more that 100 "swim goods" of oil
{
case 101: // 101 mine
AddPartyExp(PChar, 1000*sp ); // reward to player for successful minelaying, or compensation for bad exp ;)
Log_SetStringToLog("A mine ! ");   //screenmessage
Ship_Detonate(rCharacter, true, true);
break;

case 102: // 102 floating trunk
Logit("Collision with a drifting trunk ! ");   //screenmessage
rCharacter.ship.hp = makeint(sti(rCharacter.ship.hp) * (70+ rand(20)) / 100 ); // ship hp reduced to 70 - 90%
PlaySound("objects\shipcharge\hit_torock.wav");
break;

case 103: // 103 indian raft
if(!sti(rCharacter.index) == GetMainCharacterIndex() ) break;  //runs only for the player
PlaySound("cargo_aboard");

switch(rand(4) )
{
case 1:
for(n=1; n<17; n++){TakenItems(rCharacter, "indian"+n, rand(1)*sp );}
Logit("You find some votive items on an Indian ceremonial raft");
break;

case 2:
for(n=1; n<5; n++){TakenItems(rCharacter, "potion"+n, rand(4)*sp );}
Logit("You find some burial objects on a witch doctor's funeral raft");
break;

case 3:
for(n=1; n<4; n++){TakenItems(rCharacter, "mineral"+n, rand(1)*sp );}
for(n=7; n<10; n++){TakenItems(rCharacter, "mineral"+n, rand(1)*sp );}
Logit("You find some burial objects on a voodoo priest's funeral raft");
break;

Logit("This Indian funeral raft has already been plundered..."); // default, bad luck event
}
break; // 103

case 104: // 104 abandoned hulk
if(!sti(rCharacter.index) == GetMainCharacterIndex() ) break;  //runs only for the player
PlaySound("cargo_aboard");

switch(rand(4) )
{
case 1:
for(n=1; n<17; n++){TakenItems(rCharacter, "jewelry"+n, rand(1)*sp );}
Logit("You find some jewels on an abandoned packet boat");
break;

case 2:
AddMoneyToCharacter(rCharacter, (rand(10000)+1000)*sp );
Logit("You find some money on an abandoned packet boat");
break;

case 3:
AddCharacterGoods(pchar, GOOD_BOMBS, rand(200)*sp );
AddCharacterGoods(pchar, GOOD_GUNPOWDER, rand(5000)*sp );
TakenItems(rCharacter, "pistolgrenade", rand(20)*sp );
Logit("You find some ordinance on an abandoned ammo tender");
break;

Logit("Someone has already emptied this abandoned hulk..."); // default, bad luck event
}
break; // 104

// more events will be added in the future

// Default: original rescue survivors code from AISeaGoods.c
if (sti(rCharacter.index) == GetMainCharacterIndex() )   //runs only for the player
{
AddCharacterCrew(rCharacter,iQuantity);   //adds crew
Log_SetStringToLog(iQuantity + " " + TranslateString("","survivors rescued"));   //screenmessage
PlaySound("objects\abordage\abordage_loosing.wav");   //soundeffect
ChangeCharacterReputation(rCharacter, 1);   //rescuer deserves praise :)
}
// ccc rescue survivors end

}
//LanguageCloseFile(tmpLangFileID);//MAXIMUS: moved here
}



// ------------------- Utilities ---------------------------------------------

float GetIslandSize(string island)   // ccc Jan07 returns the aprox radius of an islands coastline
{
switch(island)
{
case "Redmond": return 2000.0; break;
case "IslaMuelle": return 2000.0; break;
case "Oxbay": return 2000.0; break;
case "Conceicao": return 2000.0; break;
case "Hispaniola": return 7000.0; break;
case "Cuba": return 8000.0; break;
case "IslaDeMuerte": return 100.0; break; // KK

return 1000.0;  // default size for average island
}
}


float GetIslandRemoteness(string island)   // ccc Jan07 for remote islands so that direct sailing to them takes longer
{
switch(island)
{
case "Redmond": return 1000.0; break;
case "IslaMuelle": return 1000.0; break;
case "Oxbay": return 1000.0; break;
case "Conceicao": return 1000.0; break;
case "Douwesen": return 5000.0; break; // remote
case "KhaelRoa": return 5000.0; break; // remote
case "Cayman": return 3000.0; break; // remote
case "Battle_Rocks": return 5000.0; break; // long range navpoint
case "Aruba": return 5000.0; break; // KK
case "Curacao": return 5000.0; break; // KK
case "Eleuthera": return 5000.0; break; // KK
case "IslaDeMuerte": return 2500.0; break; // KK

return 0.0;  // default for average island
}
}




string GetCompassDirFromAY(float ay)
{
// Traceandlog("Compass Ay before " + ay );
while(ay < 0) {ay += 6.3;}
while(ay > 6.3) {ay -= 6.3;}
// Traceandlog("Ay corrected " + ay );

if(ay < 0.4) return "south";
if(ay < 1.2) return "southwest";
if(ay < 2.0) return "west";
if(ay < 2.8) return "northwest";
if(ay < 3.55) return "north";
if(ay < 4.35) return "northeast";
if(ay < 5.15) return "east";
if(ay < 5.9) return "southeast";
if(ay < 6.31) return "south";
return "somewhere"; // just in case :)
}




void DirectsailAddBattle_Rocks()
{
if(CheckAttribute(worldMap,"islands.Battle_Rocks.name") ) return;
//int tmpLangFileID = LanguageOpenFile("interface_strings.txt");//MAXIMUS

// Navigation point "Battle Rocks" is added to worldmap if not yet done
// could also be done in worldmap_init.c, but this way I can leave that file undisturbed
//Name
worldMap.islands.Battle_Rocks.name = "Battle_Rocks";
//Geometry parameters
worldMap.islands.Battle_Rocks.isVisibleName = 0;
worldMap.islands.Battle_Rocks.position.x = -100.0;
worldMap.islands.Battle_Rocks.position.y = 20.0;
worldMap.islands.Battle_Rocks.position.z = 200.0;
worldMap.islands.Battle_Rocks.position.rx = -70.0;
worldMap.islands.Battle_Rocks.position.rz = 230.0;
worldMap.islands.Battle_Rocks.radius = 10.0;
worldMap.islands.Battle_Rocks.kradius = 0.1;
//Island label
worldMap.islands.Battle_Rocks.label.text = TranslateString("","Battle Rocks (uncharted, deserted)");//MAXIMUS
worldMap.islands.Battle_Rocks.label.icon = PIRATE;
worldMap.islands.Battle_Rocks.label.visible = "true";


// Navigation point "Battle Rocks" is added to the Islands[n] array
// KK -->
// PLEASE, VERY PLEASE, don't make anything _HARDCODED_!!!
Islands[ISLANDS_QUANTITY].id = "Battle_Rocks";
Islands[ISLANDS_QUANTITY].model = "Terks";
Islands[ISLANDS_QUANTITY].filespath.models = "islands\Terks";
Islands[ISLANDS_QUANTITY].refl_model = "Terks_refl";
Islands[ISLANDS_QUANTITY].locators = "Terks_locators";
Islands[ISLANDS_QUANTITY].visible = false;
Islands[ISLANDS_QUANTITY].Enc_enable = false;
Islands[ISLANDS_QUANTITY].skipCR = true; // KK
Islands[ISLANDS_QUANTITY].smuggling_nation = PIRATE;
Islands[ISLANDS_QUANTITY].towns.quantity = 0;

Islands[ISLANDS_QUANTITY].reload.l2.label = "Devil Creek";
Islands[ISLANDS_QUANTITY].reload.l2.name = "reload_2";
Islands[ISLANDS_QUANTITY].reload.l2.go = "Devil_Creek";
Islands[ISLANDS_QUANTITY].reload.l2.emerge = "see";
Islands[ISLANDS_QUANTITY].reload.l2.radius = 200.0;
Islands[ISLANDS_QUANTITY].reload.l2.pic = 0;
Islands[ISLANDS_QUANTITY].reload.l2.tex = "t1";
/*Islands[ISLANDS_QUANTITY].reload.l2.ships.l0.x = -104.94;
Islands[ISLANDS_QUANTITY].reload.l2.ships.l0.z = 196.16;
Islands[ISLANDS_QUANTITY].reload.l2.ships.l0.ay = 0.0;*/
Islands[ISLANDS_QUANTITY].reload.l2.enable = false;

Islands[ISLANDS_QUANTITY].InterfaceTextures.t1 = "battle_interface\moor_5.tga";
Islands[ISLANDS_QUANTITY].InterfaceTextures.t1.h = 1;
Islands[ISLANDS_QUANTITY].InterfaceTextures.t1.v = 1;
ISLANDS_QUANTITY++;


// That should be all attributes that the game needs, cause KhaelRoa hasn't more either 
// But if you get any "missing attribute" reports in connection with islands add them here
// <-- KK

trace("Battle_Rocks added");
//LanguageCloseFile(tmpLangFileID);//MAXIMUS
}



void ProcessCCCkeys(string ControlName) // Jan07, called by Seadogs.c. Put the code here so that I don't have to mess with seadogs.c for every control change
{
if(bSeaActive && !bAbordageStarted) // checks if you are in sailing mode
{
switch(ControlName)
{
case "BI_ChargeKey9": //"Minedrop":
LaunchMine(GetMainCharacter());
break;

case "BI_ChargeKey0": //Toggle directsail
if(CheckAttribute(GetMainCharacter(),"nodirectsail"))
{
DeleteAttribute(GetMainCharacter(),"nodirectsail");
Logit("Directsail mod active");
}
else
{
characters[GetMainCharacterIndex()].nodirectsail = 1;
Logit("Directsail mod deactivated");
}
break;

case "BI_ChargeKey8": //"Seaview position":
DisplaySeaviewCoords();
break;
}
}
}


void DisplaySeaviewCoords()
{
if(bSeaActive && !bAbordageStarted)
{
string xtext, ztext;
int pX = MakeInt(characters[GetMainCharacterIndex()].ship.pos.x);
int pZ = MakeInt(characters[GetMainCharacterIndex()].ship.pos.Z);
if(pX<0){xtext = "(east)";}else{xtext = "(west)";}
if(pZ<0){ztext = "(north)";}else{ztext = "(south)";}
LogIt("Our position from "+characters[GetMainCharacterIndex()].location+": "+pZ+" "+ztext+", "+pX+" "+xtext);
}
}

void DSTrace(string logtext)
{
return;		// LDH 26Mar09
if (DS_DEBUGINFO)
{
LogIt(logtext);
}
Trace("DS: " + logtext);
return;
}

// LDH 14Jan09
string Directions[16] = {"N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW",};
string GetCompassDirFromHeading16(float ay)
{

float dir = Radian2Degree(ay) + 180.0;

while (dir < 0.0) dir += 360.0;
while (dir > 360) dir -= 360.0;

int index = makeint((dir / 22.5) + 0.5);
if (index >= 16) index = 0;

return Directions[index];
}

string GetCompassDirFromPoints16(float fromX, float fromZ, float toX, float toZ)
{
float angle;
if (toZ == fromZ) toZ += 0.0001;	// unlikely possibility of divide by zero
angle = atan((fromX-toX)/(fromZ-toZ));
if (toZ < fromZ) angle = angle - PI;

return GetCompassDirFromHeading16(angle);
}

string GetBearingFromShip16(float ay)
{
if (ay == -99.0) return "";		// LDH keep directing from displaying - 04Mar09

float dir = Radian2Degree(ay);

while (dir < 0.0) dir += 360.0;
while (dir > 360) dir -= 360.0;

int index = makeint((dir / 22.5) + 0.5);
if (index >= 16) index = 0;

switch (index)
{
case  0: return "ahead"; break;
case  1: return "fine on the starboard bow"; break;
case  2: return "on the starboard bow";	break;
case  3: return "broad on the starboard bow"; break;
case  4: return "on the starboard beam"; break;
case  5: return "broad on the starboard quarter"; break;
case  6: return "on the starboard quarter"; break;
case  7: return "fine on the starboard quarter"; break;
case  8: return "astern"; break;
case  9: return "fine on the port quarter"; break;
case 10: return "on the port quarter"; break;
case 11: return "broad on the port quarter"; break;
case 12: return "on the port beam"; break;
case 13: return "broad on the port bow"; break;
case 14: return "on the port bow"; break;
case 15: return "fine on the port bow"; break;
}
}
 
this seems to be a newer version of the CCCdirectsail.c, but there are a lot of errors(maybe mostly the same than in the other)...think because CoaS using some other scripting commands than PotC.
 
Copying and paste anything from PotC to CoAS is most likely to cause errors you need to change a fair bit of code for it to work
 
this seems to be a newer version of the CCCdirectsail.c, but there are a lot of errors(maybe mostly the same than in the other)...think because CoaS using some other scripting commands than PotC.

Yes you can't use the above code for COAS, i posted it so you could get an idea of how it works in POTC and then you might be able to figure out how to add it to COAS perhaps saving you day's of work. Of course its not going to be high flying since there will have been other files that would have to be edited too. At the moment i'm far to busy laying a new floor so i haven't had time to do anything since Saturday night. Good luck and hope you can figure it out soon. :onya
 
Build 14 Beta 1 contains some less game-specific DirectSail code.
But probably the easiest way to get it in CoAS is to recreate it in CoAS.
Just dropping the PotC code in will not work; many, many changes would probably be required.
But CCC managed to do it and he wasn't a programming wizard (though he DID do MANY very cool things!).
That means that there's a good chance it actually IS reasonable to try it.
 
At the moment we haven't tried to get direct sail into the game, our main aim was to get the reinit button into COAS, thanks to Ashley that has been achieved however its still has some way to go before its finished. Direct sail will be something i want to look into but i'm not sure if i can get it to work in COAS however i will have a damn good try. It will not be ready for CMV3, perhaps CMV4 we will see. :onya
 
Might I suggest that you wait on this, we can probably improve it greatly now that we have the source for the storm engine 2.8. I havnt looked at the source yet so Im unsure
 
No problem bud, we have alot of testing to be done for CMV3 anyway and i don't have all the data on direct sail. :onya
 
Just so everyone knows, there seems to be a problem with this thread. Whenever I try to view this thread in firefox it locks the browser up completely. Even in IE 8 it keeps halting, then starting again. Someone besides me needs to look this thread over and see if one of the posts is the culprit in the problems I am having.

Thank folks!

cap'n drow
 
Do you have a anti virus running that was updating at the time?

The page loads up fine for me, although it does become slugish when writing a message, i'm running IE8 and have not got any problems with any other topics, just this one when as i say replying to a message. :shrug
 
since one or two days I have the same problem with mozilla. I think it's a problem with mozilla or windows...maybe one of the latest updates made the problems.
if you wait a few time mozilla work on.
 
Yep mine was also very sluggish and took ages to load (IE8), I have put the CCC code from Lukes post in a spoiler and it seems to have had a good effect :onya
 
At the moment we haven't tried to get direct sail into the game, our main aim was to get the reinit button into COAS, thanks to Ashley that has been achieved however its still has some way to go before its finished. Direct sail will be something i want to look into but i'm not sure if i can get it to work in COAS however i will have a damn good try. It will not be ready for CMV3, perhaps CMV4 we will see. :onya


Sorry, if this migth occur as a stupid question, but what is this "reinit button" for?
 
To enable you to add some things into the game that normally require a new game without having to start a new game ;)
 
We haven't started work on dircet sail, it was something i was going to look into for COAS CM V4 but that will be put on hold till its sorted out in POTC.

The reinit button on the other hand has been added and works most of the init files, so we can add new ships, change ship value's, new cannons or edit the current ones, iteam's, goods and more without having to start a new game. The realistic spy glass has been added now aswell and both of these are thanks to Ashley. :will
 
All the new features like the reinit button, realistic spy glass are in CMV3 which will be released after we have finished testing and are happy its stable and all bugs have been fixed. I don't know about the other's who are testing but on my part i have only found bugs on the things i'm working on right now, which i hope to have fixed and released in CMV3 or a patch if we do one later on. :onya

Takeda-One whats your speciality in modding, because we could alway's do with someone to help fix the ships in COAS.
 
Back
Top