diff --git a/monthorders.cpp b/monthorders.cpp index bae41496..6dd16081 100644 --- a/monthorders.cpp +++ b/monthorders.cpp @@ -291,47 +291,12 @@ Location *Game::Do1SailOrder(ARegion *reg, Object *fleet, Unit *cap) (TerrainDefs[newreg->type].similar_type != R_OCEAN)) { cap->Error("SAIL: Can't sail inland."); stop = 1; - } else if (Globals->PREVENT_SAIL_THROUGH && - (TerrainDefs[reg->type].similar_type != R_OCEAN) && - (fleet->flying < 1) && - (fleet->prevdir != -1) && - (fleet->prevdir != x->dir)) { - // Check to see if sailing THROUGH land! - // always allow retracing steps - int blocked1 = 0; - int blocked2 = 0; - int d1 = fleet->prevdir; - int d2 = x->dir; - if (d1 > d2) { - int tmp = d1; - d1 = d2; - d2 = tmp; - } - for (int k = d1+1; k < d2; k++) { - ARegion *land1 = reg->neighbors[k]; - if ((!land1) || - (TerrainDefs[land1->type].similar_type != - R_OCEAN)) - blocked1 = 1; - } - int sides = NDIRS - 2 - (d2 - d1 - 1); - for (int l = d2+1; l <= d2 + sides; l++) { - int dl = l; - if (dl >= NDIRS) dl -= NDIRS; - ARegion *land2 = reg->neighbors[dl]; - if ((!land2) || - (TerrainDefs[land2->type].similar_type != - R_OCEAN)) - blocked2 = 1; - } - if ((blocked1) && (blocked2)) - { - cap->Error(AString("SAIL: Could not sail ") + - DirectionStrs[x->dir] + AString(" from ") + - reg->ShortPrint(®ions) + - ". Cannot sail through land."); - stop = 1; - } + } else if (fleet->SailThroughCheck(x->dir) < 1) { + cap->Error(AString("SAIL: Could not sail ") + + DirectionStrs[x->dir] + AString(" from ") + + reg->ShortPrint(®ions) + + ". Cannot sail through land."); + stop = 1; } if (!stop) { diff --git a/object.cpp b/object.cpp index eee59cb4..eae3c6ec 100644 --- a/object.cpp +++ b/object.cpp @@ -326,6 +326,23 @@ void Object::Report(Areport *f, Faction *fac, int obs, int truesight, temp += AString(" Sailors: ") + FleetSailingSkill(1) + "/" + GetFleetSize() + ";"; temp += AString(" MaxSpeed: ") + GetFleetSpeed(1); } + if ((Globals->PREVENT_SAIL_THROUGH) && + (!Globals->ALLOW_TRIVIAL_PORTAGE)) { + if ((flying < 1) && + (TerrainDefs[region->type].similar_type != R_OCEAN)) { + int dir = 0; + int first = 1; + temp += AString("; Sail directions: "); + for (dir = 0; dir < NDIRS; dir++) { + if (SailThroughCheck(dir) == 1) { + if (first == 1) first = 0; + else temp += AString(", "); + + temp += DirectionAbrs[dir]; + } + } + } + } if (describe) { temp += AString("; ") + *describe; } @@ -586,6 +603,77 @@ int Object::FleetLoad() return load; } +/* Return 1 if fleet can sail to a direction without sailing through land, or + * 0 if it cannot + */ +int Object::SailThroughCheck(int dir) +{ + if (IsFleet()) { + // flying fleets always can sail through + if (flying == 1) return 1; + + // from ocean sailing is always possible + if (TerrainDefs[region->type].similar_type == R_OCEAN) return 1; + + // fleet is not flying and it is in a land region. Check that it + // doesn's sail inland + if (TerrainDefs[region->neighbors[dir]->type].similar_type != R_OCEAN) { + // sailing inland + return 0; + } + + // sailing from land into ocean. If sail through is allowed, allow it + if (!Globals->PREVENT_SAIL_THROUGH) return 1; + + // if the fleet hadn't sailed before, it can go in any direction + if (prevdir == -1) return 1; + + // fleet can always sail backward + if (prevdir == dir) return 1; + + // Now we have to check that fleet is not sailing through land + { + // Fleet is on land, it is not flying and comes from another region + // so check that the fleet goes not through land + int blocked1 = 0; + int blocked2 = 0; + int d1 = prevdir; + int d2 = dir; + + if (d1 > d2) { + int tmp = d1; + d1 = d2; + d2 = tmp; + } + + for (int k = d1+1; k < d2; k++) { + ARegion *land1 = region->neighbors[k]; + if ((!land1) || + (TerrainDefs[land1->type].similar_type != + R_OCEAN)) + blocked1 = 1; + } + + int sides = NDIRS - 2 - (d2 - d1 - 1); + for (int l = d2+1; l <= d2 + sides; l++) { + int dl = l; + if (dl >= NDIRS) dl -= NDIRS; + ARegion *land2 = region->neighbors[dl]; + if ((!land2) || + (TerrainDefs[land2->type].similar_type != + R_OCEAN)) + blocked2 = 1; + } + + if ((blocked1) && (blocked2)) + return 0; + else + return 1; + } + } + return 0; +} + /* Returns the total skill level of all sailors. * If report is not 0, returns the total skill level of all * units regardless if they have sail orders (for report diff --git a/object.h b/object.h index 762de7a7..925d7d4f 100644 --- a/object.h +++ b/object.h @@ -121,6 +121,7 @@ class Object : public AListElem AString FleetDefinition(); int FleetCapacity(); int FleetLoad(); + int SailThroughCheck(int dir); int FleetSailingSkill(int); int GetFleetSize(); int GetFleetSpeed(int); diff --git a/runorders.cpp b/runorders.cpp index fba2c972..edd5d97b 100644 --- a/runorders.cpp +++ b/runorders.cpp @@ -2693,9 +2693,12 @@ int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) // give into existing fleet or form new fleet? newfleet = 0; + // target is not in fleet or not fleet owner if (!(t->object->IsFleet()) || (t->num != t->object->GetOwner()->num)) newfleet = 1; + + // Set fleet variable to target fleet if (newfleet == 1) { // create a new fleet fleet = new Object(r); @@ -2705,14 +2708,38 @@ int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) t->object->region->AddFleet(fleet); t->MoveUnit(fleet); } + else { + fleet = t->object; + } + if (ItemDefs[o->item].max_inventory) { cur = t->object->GetNumShips(o->item) + amt; if (cur > ItemDefs[o->item].max_inventory) { - u->Error(ord + ": Fleets cannot have more than "+ - ItemString(o->item, ItemDefs[o->item].max_inventory) +"."); + u->Error(ord + ": Fleets cannot have more than " + + ItemString(o->item, ItemDefs[o->item].max_inventory) + + "."); return 0; } } + + // Check if fleets are compatible + if ((Globals->PREVENT_SAIL_THROUGH) && + (!Globals->ALLOW_TRIVIAL_PORTAGE) && + // flying ships are always transferrable + (ItemDefs[o->item].fly == 0)) { + // if target fleet had not sailed, just copy shore from source + if (fleet->prevdir == -1) { + fleet->prevdir = s->object->prevdir; + } else { + // check that source ship is compatible with its new fleet + if (s->object->SailThroughCheck(fleet->prevdir) == 0) { + u->Error(ord + + ": Ships cannot be transferred through land."); + return 0; + } + } + } + s->Event(AString("Transfers ") + ItemString(o->item, amt) + " to " + *t->object->name + "."); if (s->faction != t->faction) {