1105 lines
32 KiB
Plaintext
1105 lines
32 KiB
Plaintext
note
|
|
description: "[
|
|
Root class for all the game pieces in VITP.
|
|
]"
|
|
author: "Jimmy J. Johnson"
|
|
|
|
deferred class
|
|
ATTACK_UNIT
|
|
|
|
inherit
|
|
|
|
VITP_ITEM
|
|
redefine
|
|
make
|
|
end
|
|
|
|
COMPARABLE
|
|
undefine
|
|
copy,
|
|
is_equal
|
|
end
|
|
|
|
feature -- Initialization
|
|
|
|
make (a_game: like game)
|
|
-- Initialize with the values; these are initial values and cannot be changed
|
|
-- `a_name' = name of the ship or unit
|
|
-- `a_nationality' = country to which it belongs
|
|
-- `a_arrival_turn' = turn 1 to 9 in which the unit enters the game
|
|
-- `a_airstrike' = the unit's "airstrike factor"
|
|
-- `a_guns' = the unit's "gunnery factor"
|
|
-- `a_armor' = the unit's "armor factor"
|
|
-- `a_speed' = the unit's "speed factor"
|
|
-- `a_bonus' = true if the unit has an initial attack bonus
|
|
local
|
|
lin: LINEAR [PORT]
|
|
do
|
|
Precursor {VITP_ITEM} (a_game)
|
|
create task_force.make (a_game)
|
|
task_force.set_ordered
|
|
-- arrival_location := game.still_in_box
|
|
position := [0, 0]
|
|
-- Initialize to never return (changed for air and amphibious units)
|
|
returning_turn := 0
|
|
task_force.extend (Current)
|
|
end
|
|
|
|
feature -- Access
|
|
|
|
arrival_turn: INTEGER
|
|
-- Turn on which this unit enters the game.
|
|
deferred
|
|
end
|
|
|
|
airstrike_factor: INTEGER
|
|
-- The initial number of dice the unit rolls when attacking
|
|
-- during a "day action".
|
|
deferred
|
|
end
|
|
|
|
gunnery_factor: INTEGER
|
|
-- The initial value for the number of dice the unit rolls
|
|
-- when attacking during a "night action".
|
|
deferred
|
|
end
|
|
|
|
defense_factor: INTEGER
|
|
-- The number of damage points a unit can have without sinking.
|
|
-- (This is doubled when the unit is in port.)
|
|
deferred
|
|
end
|
|
|
|
speed_factor: INTEGER
|
|
-- The initial "speed" of the unit.
|
|
deferred
|
|
end
|
|
|
|
attack_bonus: BOOLEAN
|
|
-- The initial setting saying if a unit can add one to each die roll.
|
|
-- If the unit is a carrier this applies only to the airstrike factor.
|
|
deferred
|
|
end
|
|
|
|
returning_turn: INTEGER
|
|
-- The turn on which this unit can reenter the game.
|
|
|
|
home_port: PORT
|
|
-- The {PORT} from which Current is basing this turn.
|
|
attribute
|
|
Result := game.default_port
|
|
end
|
|
|
|
location: LOCATION
|
|
-- The sea, base, or port at which Current is located.
|
|
attribute
|
|
-- Result := game.still_in_box
|
|
if Current.is_japanese then
|
|
Result := game.japanese_oa_chart
|
|
else
|
|
if Current.arrival_turn = 1 then
|
|
Result := game.allied_starting_forces_chart
|
|
else
|
|
Result := game.allied_oa_chart
|
|
end
|
|
end
|
|
end
|
|
|
|
damage: INTEGER
|
|
-- The amount of total damage Current has taken
|
|
|
|
gunnery_count: INTEGER
|
|
-- Number of dice the unit rolls when attacking during a "night action".
|
|
-- It is the `Gunnery_factor' reduced by the amount of `damage'.
|
|
do
|
|
Result := (gunnery_factor - damage).max (1)
|
|
end
|
|
|
|
defense_count: INTEGER
|
|
-- The amount of armor remaining, used to determine if a unit is "sunk".
|
|
do
|
|
Result := defense_factor - damage
|
|
end
|
|
|
|
speed_count: INTEGER
|
|
-- The actual speed of Current calculated from other factors
|
|
do
|
|
Result := (speed_factor - damage).max (1)
|
|
end
|
|
|
|
airstrike_count: INTEGER
|
|
-- Number of dice the unit rolls when attacking during a "day actions".
|
|
do
|
|
Result := airstrike_factor
|
|
end
|
|
|
|
task_force: TASK_FORCE
|
|
-- The whole force including Current if others
|
|
|
|
target: ATTACK_UNIT
|
|
-- The target (if `is_targetting')
|
|
do
|
|
check attached target_imp as t then
|
|
Result := t
|
|
end
|
|
end
|
|
|
|
relative_value: INTEGER
|
|
-- Relative value of current to other units, calculated from the
|
|
-- current values of the gunnery, defense, and speed counts.
|
|
local
|
|
b_fac: INTEGER
|
|
do
|
|
if attack_bonus then
|
|
if airstrike_factor > 0 then
|
|
-- Apply bonus to airstrike only
|
|
b_fac := Bonus_weight * airstrike_weight
|
|
-- Result := (airstrike_count + Bonus_weight) * Airstrike_weight
|
|
-- Result := Result + gunnery_count * Gunnery_weight
|
|
else
|
|
-- apply bonus to guns unless too much damage
|
|
if defense_count > 0 then
|
|
b_fac := Bonus_weight * Gunnery_weight
|
|
-- Result := (gunnery_count + Bonus_weight) * Gunnery_weight
|
|
-- Result := Result + airstrike_count * Airstrike_weight
|
|
end
|
|
end
|
|
end
|
|
Result := b_fac + airstrike_count + gunnery_count
|
|
Result := Result + defense_count * Defense_weight + speed_factor * Speed_weight
|
|
-- if Current = Tone then
|
|
-- do_nothing
|
|
-- end
|
|
-- if Current = Mutsu then
|
|
-- do_nothing
|
|
-- end
|
|
end
|
|
|
|
patrol_distance: INTEGER
|
|
-- How may sea areas can Current move through as patroller?
|
|
-- Determined by the unit type and nationality
|
|
do
|
|
Result := 2
|
|
end
|
|
|
|
raid_distance: INTEGER
|
|
-- How many sea areas can Current move through as raider?
|
|
-- Determined by the unit type and nationality
|
|
local
|
|
has_non_major: BOOLEAN
|
|
do
|
|
if is_task_force then
|
|
from task_force.start
|
|
until task_force.exhausted or has_non_major
|
|
loop
|
|
if not task_force.item.is_major_power then
|
|
has_non_major := true
|
|
end
|
|
task_force.forth
|
|
end
|
|
end
|
|
if not has_non_major then
|
|
Result := patrol_distance + 1
|
|
end
|
|
end
|
|
|
|
feature -- Access
|
|
|
|
sailing_distance: INTEGER
|
|
-- The distance Current can patrol or raid (depending on `is_raiding').
|
|
-- This is the minimum of all contained units.
|
|
local
|
|
f: INTEGER
|
|
u: ATTACK_UNIT
|
|
do
|
|
Result := {INTEGER}.Max_value
|
|
from task_force.start
|
|
until task_force.is_after
|
|
loop
|
|
u := task_force.item
|
|
if u.sailing_distance < Result then
|
|
Result := f
|
|
end
|
|
task_force.forth
|
|
end
|
|
end
|
|
|
|
reinforceable_ports: LINKED_SET [PORT]
|
|
-- A list containing each {PORT} to which Current
|
|
-- can be moved during the reinforcement step.
|
|
require
|
|
is_reinforcing: game.sequence_of_play.is_reinforcement_step
|
|
deferred
|
|
end
|
|
|
|
patrolable_sea_areas: LINKED_SET [SEA_AREA]
|
|
-- A list containing each {SEA_AREA} to which Current
|
|
-- can be moved during the moving patrollers step.
|
|
local
|
|
sop: VITP_SEQUENCE_OF_PLAY
|
|
sd: INTEGER
|
|
s: SEA_AREA
|
|
dist: INTEGER
|
|
do
|
|
-- io.put_string ("ATTCK_UNIT.patrolable_sea_areas: fix using GRAPH_ITERATOR.shortest_paths %N")
|
|
create Result.make
|
|
sop := game.sequence_of_play
|
|
if sop.is_patrolling_step and
|
|
((not game.is_allied_nationality (nationality) and then sop.is_japanese_player) or else
|
|
(game.is_allied_nationality (nationality) and then sop.is_allied_player)) then
|
|
if home_port = game.yokosuka_navy_yard or home_port = game.okinawa then
|
|
Result.extend (game.japanese_islands)
|
|
if not is_opposed (game.japanese_islands) then
|
|
Result.extend (game.indonesia)
|
|
Result.extend (game.marianas_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
Result.extend (game.aleutian_islands)
|
|
end
|
|
elseif home_port = game.saigon or home_port = game.singapore then
|
|
Result.extend (game.indonesia)
|
|
if not is_opposed (game.indonesia) then
|
|
Result.extend (game.bay_of_bengal)
|
|
Result.extend (game.indian_ocean)
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.marianas_islands)
|
|
Result.extend (game.japanese_islands)
|
|
end
|
|
elseif home_port = game.ceylon or home_port = game.andaman_islands then
|
|
Result.extend (game.bay_of_Bengal)
|
|
if not is_opposed (game.bay_of_bengal) then
|
|
Result.extend (game.indonesia)
|
|
Result.extend (game.indian_ocean)
|
|
end
|
|
elseif home_port = game.philippines then
|
|
Result.extend (game.indonesia)
|
|
Result.extend (game.marianas_Islands)
|
|
if not is_opposed (game.indonesia) then
|
|
Result.extend (game.bay_of_bengal)
|
|
Result.extend (game.indian_ocean)
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.marianas_islands)
|
|
Result.extend (game.japanese_islands)
|
|
end
|
|
if not is_opposed (game.marianas_islands) then
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
Result.extend (game.japanese_islands)
|
|
end
|
|
elseif home_port = game.lae then
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.indonesia)
|
|
if not is_opposed (game.indonesia) then
|
|
Result.extend (game.japanese_islands)
|
|
Result.extend (game.marianas_islands)
|
|
end
|
|
if not is_opposed (game.south_pacific_ocean) then
|
|
Result.extend (game.marianas_islands)
|
|
Result.extend (game.coral_sea)
|
|
Result.extend (game.us_mandate)
|
|
Result.extend (game.marshall_islands)
|
|
end
|
|
elseif home_port = game.australia or home_port = game.port_moresby then
|
|
Result.extend (game.indian_ocean)
|
|
Result.extend (game.coral_sea)
|
|
if not is_opposed (game.indian_ocean) then
|
|
Result.extend (game.bay_of_bengal)
|
|
Result.extend (game.indonesia)
|
|
end
|
|
if not is_opposed (game.coral_sea) then
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.us_mandate)
|
|
end
|
|
elseif home_port = game.guadalcanal then
|
|
Result.extend (game.coral_sea)
|
|
Result.extend (game.south_pacific_ocean)
|
|
if not is_opposed (game.coral_sea) then
|
|
Result.extend (game.indian_ocean)
|
|
Result.extend (game.us_mandate)
|
|
end
|
|
if not is_opposed (game.south_pacific_ocean) then
|
|
Result.extend (game.indonesia)
|
|
Result.extend (game.marianas_islands)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.us_mandate)
|
|
end
|
|
elseif home_port = game.new_hebrides then
|
|
Result.extend (game.coral_sea)
|
|
Result.extend (game.us_mandate)
|
|
if not is_opposed (game.coral_sea) then
|
|
Result.extend (game.indian_ocean)
|
|
Result.extend (game.south_pacific_ocean)
|
|
end
|
|
if not is_opposed (game.us_mandate) then
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.hawaiian_islands)
|
|
end
|
|
elseif home_port = game.samoa then
|
|
Result.extend (game.us_mandate)
|
|
if not is_opposed (game.us_mandate) then
|
|
Result.extend (game.coral_sea)
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.hawaiian_islands)
|
|
end
|
|
elseif home_port = game.johnston_island or home_port = game.pearl_harbor then
|
|
Result.extend (game.hawaiian_islands)
|
|
if not not is_opposed (game.hawaiian_Islands) then
|
|
Result.extend (game.us_mandate)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
Result.extend (game.north_pacific_ocean)
|
|
end
|
|
elseif home_port = game.kwajalein or home_port = game.maloelap then
|
|
Result.extend (game.marshall_islands)
|
|
if not is_opposed (game.marshall_islands) then
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.us_mandate)
|
|
Result.extend (game.hawaiian_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
Result.extend (game.marianas_islands)
|
|
end
|
|
elseif home_port = game.truk then
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.marianas_islands)
|
|
if not is_opposed (game.south_pacific_ocean) then
|
|
Result.extend (game.indonesia)
|
|
Result.extend (game.coral_sea)
|
|
Result.extend (game.us_mandate)
|
|
end
|
|
if not is_opposed (game.marshall_islands) then
|
|
Result.extend (game.us_mandate)
|
|
Result.extend (game.hawaiian_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
end
|
|
if not is_opposed (game.marianas_islands) then
|
|
Result.extend (game.indonesia)
|
|
Result.extend (game.japanese_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
end
|
|
elseif home_port = game.saipan then
|
|
Result.extend (game.marianas_islands)
|
|
if not is_opposed (game.marianas_islands) then
|
|
Result.extend (game.japanese_Islands)
|
|
Result.extend (game.indonesia)
|
|
Result.extend (game.south_pacific_ocean)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
end
|
|
elseif home_port = game.midway then
|
|
Result.extend (game.central_pacific_ocean)
|
|
if not is_opposed (game.central_pacific_ocean) then
|
|
Result.extend (game.japanese_islands)
|
|
Result.extend (game.marianas_islands)
|
|
Result.extend (game.marshall_islands)
|
|
Result.extend (game.hawaiian_islands)
|
|
Result.extend (game.north_pacific_ocean)
|
|
Result.extend (game.aleutian_islands)
|
|
end
|
|
elseif home_port = game.dutch_harbor then
|
|
Result.extend (game.north_pacific_ocean)
|
|
Result.extend (game.aleutian_islands)
|
|
if not is_opposed (game.north_pacific_ocean) then
|
|
Result.extend (game.central_pacific_ocean)
|
|
Result.extend (game.hawaiian_islands)
|
|
end
|
|
if not is_opposed (game.aleutian_islands) then
|
|
Result.extend (game.japanese_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
end
|
|
elseif home_port = game.attu then
|
|
Result.extend (game.aleutian_islands)
|
|
if not is_opposed (game.aleutian_islands) then
|
|
Result.extend (game.japanese_islands)
|
|
Result.extend (game.central_pacific_ocean)
|
|
Result.extend (game.north_pacific_ocean)
|
|
end
|
|
else
|
|
end
|
|
end
|
|
end
|
|
|
|
landable_ports: LINKED_SET [PORT]
|
|
-- A list containing each {PORT} at which Current can make
|
|
-- a landing if at the appropriate point in the game
|
|
local
|
|
lin: LINEAR [PORT]
|
|
do
|
|
create Result.make
|
|
if attached {SEA_AREA} location as s then
|
|
lin := s.adjoining_ports
|
|
from lin.start
|
|
until lin.exhausted
|
|
loop
|
|
if not lin.item.is_enemy_controlled (nationality) then
|
|
Result.extend (lin.item)
|
|
end
|
|
lin.forth
|
|
end
|
|
end
|
|
-- Add all major ports to the set
|
|
from game.major_ports.start
|
|
until game.major_ports.after
|
|
loop
|
|
if not game.major_ports.item_for_iteration.is_enemy_controlled (nationality) then
|
|
Result.extend (game.major_ports.item_for_iteration)
|
|
end
|
|
game.major_ports.forth
|
|
end
|
|
end
|
|
|
|
arrivable_locations: LINKED_LIST [LOCATION]
|
|
-- The possible locations to which Current can move when
|
|
-- coming into [or back into] the game
|
|
local
|
|
sop: VITP_SEQUENCE_OF_PLAY
|
|
do
|
|
create Result.make
|
|
sop := game.sequence_of_play
|
|
if arrival_turn = sop.turn or returning_turn = sop.turn then
|
|
if nationality = sop.nationality then
|
|
if nationality = game.japanese then
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
arrival_location: LOCATION
|
|
-- The port or sea area at which this unit may enter the game
|
|
do
|
|
if nationality = game.japanese and game.yokosuka_navy_yard.nationality = game.japanese then
|
|
Result := game.yokosuka_navy_yard
|
|
elseif nationality = game.us then
|
|
if game.pearl_harbor.nationality = game.us then
|
|
Result := game.pearl_harbor
|
|
elseif game.samoa.nationality = game.us then
|
|
Result := game.samoa
|
|
else
|
|
io.put_string ("ATTACK_UNIT.arrival_location -- put it on US_chart. %N")
|
|
Result := game.still_in_box
|
|
end
|
|
elseif nationality = game.british and game.ceylon.nationality = game.us then
|
|
Result := game.ceylon
|
|
elseif nationality = game.australian then
|
|
Result := game.australia
|
|
else
|
|
Result := game.still_in_box
|
|
check
|
|
should_not_happpen: False
|
|
-- because all nationalities have been checked
|
|
end
|
|
end
|
|
end
|
|
|
|
arrival_port: like home_port
|
|
-- The port to which Current is assigned when it comes into
|
|
-- the game during a reinforcement action.
|
|
do
|
|
Result := game.default_port
|
|
if nationality = game.japanese and game.yokosuka_navy_yard.nationality = game.japanese then
|
|
Result := game.yokosuka_navy_yard
|
|
elseif nationality = game.us then
|
|
if game.pearl_harbor.nationality = game.us then
|
|
Result := game.pearl_harbor
|
|
else
|
|
Result := game.samoa
|
|
end
|
|
elseif nationality = game.british then
|
|
if Current = game.victorious and game.pearl_harbor.nationality = game.us then
|
|
Result := game.pearl_harbor
|
|
elseif game.ceylon.nationality = game.us then
|
|
Result := game.ceylon
|
|
end
|
|
elseif nationality = game.australian then
|
|
Result := game.australia
|
|
else
|
|
check
|
|
should_not_happpen: False
|
|
-- because all nationalities have been checked
|
|
end
|
|
end
|
|
end
|
|
|
|
arrival_position: like position
|
|
-- The location (latitude/longitude-like coordinates) where Current will enter the game
|
|
do
|
|
-- The following measurements in millimeters were taken from the game board
|
|
if arrival_location = game.Yokosuka_navy_yard then
|
|
Result := [300, 140]
|
|
elseif arrival_location = game.Pearl_Harbor then
|
|
Result := [700, 330]
|
|
elseif arrival_location = game.Samoa then
|
|
Result := [570, 480]
|
|
elseif arrival_location = game.Ceylon then
|
|
Result := [185, 15]
|
|
elseif arrival_location = game.Bay_of_Bengal then
|
|
Result := [10, 370]
|
|
elseif arrival_location = game.Indonesia then
|
|
Result := [130, 350]
|
|
elseif arrival_location = game.Philippines then
|
|
Result := [210, 270]
|
|
elseif arrival_location = game.Australia then
|
|
Result := [240, 470]
|
|
elseif arrival_location = game.Singapore then
|
|
Result := [90, 280]
|
|
elseif arrival_location = game.Coral_sea then
|
|
Result := [370, 520]
|
|
elseif arrival_location = game.US_mandate then
|
|
Result := [500, 500]
|
|
elseif arrival_location = game.Hawaiian_islands then
|
|
Result := [570, 380]
|
|
else
|
|
-- Return its Current position
|
|
Result := [position.longitude, position.latitude]
|
|
end
|
|
end
|
|
|
|
feature -- Element change
|
|
|
|
set_location (a_location: LOCATION)
|
|
-- Move all ships in `task_force' to `a_location'
|
|
require
|
|
is_valid_move: is_valid_move (a_location)
|
|
local
|
|
u: ATTACK_UNIT
|
|
do
|
|
io.put_string ("ATTACK_UNIT.set_location: " + name.out + " to " + a_location.name + "%N")
|
|
from task_force.start
|
|
until task_force.is_after
|
|
loop
|
|
u := task_force.item
|
|
u.set_location_internal (a_location)
|
|
task_force.forth
|
|
end
|
|
ensure
|
|
location_set: location = a_location
|
|
location_set_for_all:
|
|
end
|
|
|
|
set_home_port (a_port: PORT)
|
|
-- Change the unit's `home_port'
|
|
require
|
|
is_valid_base: is_valid_unit_move (a_port)
|
|
do
|
|
home_port := a_port
|
|
end
|
|
|
|
set_returning_turn (a_turn: INTEGER)
|
|
-- Set the turn on which Current can reenter the game
|
|
require
|
|
valid_turn: a_turn >= 3 and a_turn <= 9
|
|
do
|
|
returning_turn := a_turn
|
|
end
|
|
|
|
set_location_internal (a_location: LOCATION)
|
|
-- Used internally to bypass referential invariant checking
|
|
do
|
|
if location /= a_location then
|
|
is_stable := False
|
|
location.prune (Current)
|
|
location := a_location
|
|
if not a_location.has (Current) then
|
|
a_location.put (Current)
|
|
end
|
|
is_stable := True
|
|
end
|
|
end
|
|
|
|
set_target (a_target: ATTACK_UNIT)
|
|
-- Get ready to attack `a_target'
|
|
require
|
|
same_locations: location = a_target.location
|
|
do
|
|
target_imp := a_target
|
|
end
|
|
|
|
remove_target
|
|
-- Remove any target from Current sights
|
|
do
|
|
target_imp := Void
|
|
end
|
|
|
|
feature -- Query
|
|
|
|
is_valid_move (a_location: LOCATION): BOOLEAN
|
|
-- Can this {TASK_FORCE} (all units) move to `a_location'?
|
|
do
|
|
Result := True
|
|
from task_force.start
|
|
until task_force.is_after or not Result
|
|
loop
|
|
Result := task_force.item.is_valid_unit_move (a_location)
|
|
task_force.forth
|
|
end
|
|
end
|
|
|
|
is_valid_unit_move (a_location: LOCATION): BOOLEAN
|
|
-- Can Current (regardless of any other units that
|
|
-- may be in the `task_force') move to `a_location'?
|
|
do
|
|
io.put_string ("{ATTACK_UNIT}.is_valid_unit_move: fix to for restricted port %N")
|
|
Result := True
|
|
end
|
|
|
|
feature -- Access
|
|
|
|
position: VITP_POSITION
|
|
-- The position in millimeters (east/west and up/down) from the
|
|
-- top-left of the [logical] VITP world. That is, the position
|
|
-- of an attack unit is relative to the top-left corner of the
|
|
-- game board which is at point (0, 0).
|
|
|
|
unit_size: INTEGER
|
|
-- The size of Current (square).
|
|
-- Assume it is `Ship_size' and redefine for {AIR_UNIT} and
|
|
-- for {AMPHIBIOUS_UNIT}.
|
|
once
|
|
Result := game.initial_ship_size
|
|
end
|
|
|
|
corners: ARRAY [VITP_POSITION]
|
|
-- The four corner points of Current (square ships) calculated
|
|
-- from Current's location and `unit_size', starting at the top/
|
|
-- left and going clockwise.
|
|
local
|
|
p: VITP_POSITION
|
|
h: INTEGER
|
|
do
|
|
h := unit_size // 2
|
|
create Result.make_filled (create {VITP_POSITION}, 1, 4)
|
|
create p.set_xy (position.longitude - h, position.latitude - h)
|
|
Result.put (p, 1)
|
|
create p.set_xy (position.longitude + h, position.latitude - h)
|
|
Result.put (p, 2)
|
|
create p.set_xy (position.longitude + unit_size, position.latitude + h)
|
|
Result.put (p, 3)
|
|
create p.set_xy (position.longitude - unit_size, position.latitude + unit_size)
|
|
Result.put (p, 4)
|
|
end
|
|
|
|
feature -- Element change
|
|
|
|
set_position (a_position: like position)
|
|
-- Change the `position' of Current [and all units in `task_force']
|
|
require
|
|
position_exists: a_position /= Void
|
|
is_valid_position: not is_incompatible_position (a_position)
|
|
local
|
|
u: ATTACK_UNIT
|
|
do
|
|
from task_force.start
|
|
until task_force.is_after
|
|
loop
|
|
u := task_force.item
|
|
u.internal_set_position (a_position)
|
|
task_force.forth
|
|
end
|
|
ensure
|
|
position_set: position ~ a_position
|
|
end
|
|
|
|
feature -- Query
|
|
|
|
-- is_valid_position (a_position: VITP_POSITION): BOOLEAN
|
|
-- -- Is `a_position' valid? Yes if the position is on the board/table,
|
|
-- -- (garanteed by invariant of {VITP_POSITION}), not on an enemy unit,
|
|
-- -- and not on a unit of the wrong type (i.e. a submarine cannot join
|
|
-- -- a task force.)
|
|
-- do
|
|
-- Result := not is_on_incompatible_unit (a_position)
|
|
-- end
|
|
|
|
is_incompatible_position (a_position: VITP_POSITION): BOOLEAN
|
|
-- Yes if repositioning Current to `a_position' would cause Current
|
|
-- to overlap a unit that is incompatible for a `join_force' (e.g.
|
|
-- on a submarine or on an enemy)?
|
|
deferred
|
|
end
|
|
|
|
contains_position (a_position: VITP_POSITION): BOOLEAN
|
|
-- Is `a_position' on or in Current?
|
|
-- This feature uses a ray-casting algorithm which determines if the
|
|
-- number of edge crossings made by a ray to the right is odd (inside)
|
|
-- or even (outside).
|
|
local
|
|
pts: like corners
|
|
i, j: INTEGER
|
|
do
|
|
pts := corners
|
|
from
|
|
i := 1
|
|
j := 4
|
|
until i > 4
|
|
loop
|
|
-- Get integer values so algorithm can work.
|
|
-- if ( ((pts[i] >= a_position) /= (pts[j] >= a_position)) and
|
|
-- (a_position <= (pts[j] - pts[i]) *
|
|
-- (a_position - pts[i]) //
|
|
-- (pts[j] - pts[i]) + pts[i]) ) then
|
|
-- -- Invert Result every time an edge is crossed.
|
|
-- Result := not Result
|
|
-- end
|
|
j := i
|
|
i := i + 1
|
|
end
|
|
end
|
|
|
|
overlaps (a_other: ATTACK_UNIT): BOOLEAN
|
|
-- Does Current occupy any space occupied by a_other
|
|
local
|
|
pts: like corners
|
|
i: INTEGER
|
|
do
|
|
if Current /= a_other then
|
|
pts := corners
|
|
from i := 1
|
|
until i > pts.count or Result
|
|
loop
|
|
Result := a_other.contains_position (pts[i])
|
|
i := i + 1
|
|
end
|
|
-- Check the other way around
|
|
if not Result then
|
|
pts := a_other.corners
|
|
from i := 1
|
|
until i > pts.count or Result
|
|
loop
|
|
Result := contains_position (pts[i])
|
|
i := i + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- is_same_power (a_nationality: NATIONALITY): BOOLEAN
|
|
-- -- Is Current the same power (Axis or Allied) as `a_natinality'?
|
|
-- do
|
|
-- Result := (nationality.is_allied and a_nationality.is_allied) or else
|
|
-- (not nationality.is_allied and not a_nationality.is_allied)
|
|
-- end
|
|
|
|
feature -- Basic operations
|
|
|
|
join_force (a_other: ATTACK_UNIT)
|
|
-- Join forces with `a_other' as a single `task_force'
|
|
require
|
|
not_submarine: not attached {SUBMARINE} a_other and not attached {SUBMARINE} Current
|
|
lba_implication: attached {AIR_UNIT} task_force.first implies attached {AIR_UNIT} a_other
|
|
other_lba_implication: attached {AIR_UNIT} a_other implies attached {AIR_UNIT} task_force.first
|
|
not_lba_implication: not attached {AIR_UNIT} task_force.first implies not attached {AIR_UNIT} a_other
|
|
not_other_lba_implication: not attached {AIR_UNIT} a_other implies not attached {AIR_UNIT} task_force.first
|
|
not_same_units: not (a_other = Current)
|
|
not_same_task_forces: (is_task_force and a_other.is_task_force) implies
|
|
not (task_force = a_other.task_force)
|
|
not_opposing_sides: not is_opposed (a_other)
|
|
same_location: location = a_other.location
|
|
local
|
|
u: ATTACK_UNIT
|
|
pos: VITP_POSITION
|
|
do
|
|
is_stable := False
|
|
-- Put all units into `a_other's `task_force'
|
|
pos := a_other.position
|
|
from task_force.start
|
|
until task_force.is_after
|
|
loop
|
|
u := task_force.item
|
|
-- u.position.set_xy (pos.longitude, pos.latitude)
|
|
a_other.task_force.extend (u)
|
|
task_force.forth
|
|
end
|
|
-- Remove all the units from Current's `task_force'
|
|
task_force.wipe_out
|
|
-- Make to two tasks forces the same one
|
|
set_task_force (a_other.task_force)
|
|
is_stable := True
|
|
ensure
|
|
same_task_forces: task_force = a_other.task_force
|
|
has_multiple_units: task_force.count >= 2
|
|
end
|
|
|
|
leave_force
|
|
-- Remove Current from the `task_force' to which it belongs, but only
|
|
-- if there are other ships in the force, and put it in its own.
|
|
require
|
|
is_in_task_force: is_task_force
|
|
local
|
|
u: ATTACK_UNIT
|
|
do
|
|
task_force.prune (Current)
|
|
create task_force.make (game)
|
|
task_force.extend (Current)
|
|
ensure
|
|
not_in_force: not is_task_force
|
|
end
|
|
|
|
feature -- Status report
|
|
|
|
is_task_force: BOOLEAN
|
|
-- Is this unit part of a task force?
|
|
do
|
|
Result := task_force.count > 1
|
|
ensure
|
|
result_implies_in_force: task_force.has (Current)
|
|
result_implies_others: Result implies task_force.count >= 2
|
|
end
|
|
|
|
is_in_game: BOOLEAN
|
|
-- Is this unit in the game? (I.e. not sunk, not still to enter)
|
|
do
|
|
Result := is_at_sea or is_in_port or
|
|
location = game.uncommitted_japanese_location or
|
|
location = game.uncommitted_allied_location
|
|
end
|
|
|
|
is_at_sea: BOOLEAN
|
|
-- Is this unit at sea?
|
|
do
|
|
Result := attached {SEA_AREA} location
|
|
end
|
|
|
|
is_in_port: BOOLEAN
|
|
-- Is this unit in port?
|
|
do
|
|
Result := attached {PORT} location
|
|
end
|
|
|
|
is_movable: BOOLEAN
|
|
-- Can Current move (to sea or back to port) at
|
|
-- this time in the game?
|
|
local
|
|
u: ATTACK_UNIT
|
|
do
|
|
Result := true
|
|
from task_force.start
|
|
until task_force.is_after or not Result
|
|
loop
|
|
u := task_force.item
|
|
Result := u.internal_is_movable
|
|
task_force.forth
|
|
end
|
|
end
|
|
|
|
internal_is_movable: BOOLEAN
|
|
-- Can Current move (not the whole `task_force') move at this time?
|
|
local
|
|
sop: VITP_SEQUENCE_OF_PLAY
|
|
do
|
|
sop := game.sequence_of_play
|
|
print ("ATTACK_UNIT.internal_is_movable: %N")
|
|
print (" sop.is_allied_player = " + sop.is_allied_player.out + "%N")
|
|
print (" " + name + ".is_allied = " + is_allied.out + "%N")
|
|
print (" sop.is_japaneses_player = " + sop.is_japanese_player.out + "%N")
|
|
print (" " + name + ".is_japanese = " + is_japanese.out + "%N")
|
|
print (" sop.is_patrolling_step = " + sop.is_patrolling_step.out + "%N")
|
|
print (" " + name + ".is_patrolling = " + is_patrolling.out + "%N")
|
|
Result := ( (sop.is_allied_player and is_allied) or
|
|
(sop.is_japanese_player and is_japanese)) and then
|
|
( (sop.is_reinforcement_step and is_returning_unit) or
|
|
-- (sop.is_removing_sunk_units_phase and is_sunk) or
|
|
-- (sop.is_returning_disabled_units_stage and is_disabled) or
|
|
-- (sop.is_removing_sunk_units_phase and is_sunk) or
|
|
-- (sop.is_returning_to_port_stage and is_at_sea and not is_sunk) or
|
|
(sop.is_patrolling_step and is_patrolling) or
|
|
(sop.is_raiding_step and is_raiding))
|
|
print (" Result = " + Result.out + "%N")
|
|
end
|
|
|
|
is_stable: BOOLEAN
|
|
-- Set to false when pruning and adding for invariant checking
|
|
-- of referential integrity between units and locations
|
|
|
|
is_major_power: BOOLEAN
|
|
-- Is Current's `nationality' one of Japanese or US?
|
|
do
|
|
Result := nationality = game.japanese or nationality = game.us
|
|
end
|
|
|
|
is_sunk: BOOLEAN
|
|
-- Has this unit been sunk?
|
|
deferred
|
|
end
|
|
|
|
is_bottomed: BOOLEAN
|
|
-- Is unit in port with too much damage to sail?
|
|
-- Default is Fasle, so redefine for {SHIP}
|
|
do
|
|
Result := False
|
|
ensure
|
|
implication: Result implies is_in_port
|
|
end
|
|
|
|
is_disabled: BOOLEAN
|
|
-- Is the unit disabled?
|
|
|
|
is_returning_unit: BOOLEAN
|
|
-- Is the unit returning on this turn?
|
|
do
|
|
Result := returning_turn = game.sequence_of_play.turn
|
|
end
|
|
|
|
is_patrollable: BOOLEAN
|
|
-- Can this unit be a patroller for area control purposes?
|
|
deferred
|
|
end
|
|
|
|
is_raidable: BOOLEAN
|
|
-- Can this unit be a raider?
|
|
deferred
|
|
end
|
|
|
|
is_patrolling: BOOLEAN
|
|
-- Is this unit a patroller (as opposed to a raider)?
|
|
deferred
|
|
end
|
|
|
|
is_raiding: BOOLEAN
|
|
-- Is this unit a raider?
|
|
deferred
|
|
end
|
|
|
|
feature -- Status setting
|
|
|
|
|
|
set_disabled
|
|
-- Mark Current as `is_disabled'
|
|
do
|
|
is_disabled := True
|
|
end
|
|
|
|
set_not_disabled
|
|
-- Mark Current as not `is_disabled'
|
|
do
|
|
is_disabled := False
|
|
end
|
|
|
|
feature {ATTACK_UNIT} -- Implementation
|
|
|
|
internal_set_position (a_position: VITP_POSITION)
|
|
-- Change the `position' of [only] Current
|
|
require
|
|
position_exists: a_position /= Void
|
|
do
|
|
position.set_xy (a_position.longitude, a_position.latitude)
|
|
end
|
|
|
|
feature {ATTACK_UNIT} -- Implementation
|
|
|
|
feature -- Comparison
|
|
|
|
is_less alias "<" (other: like Current): BOOLEAN
|
|
-- Is current object less than `other'?
|
|
do
|
|
-- Weight the attack, defense, speed factors and compare result
|
|
Result := (relative_value > other.relative_value) or else
|
|
(relative_value = other.relative_value and then name < other.name)
|
|
-- Result := name < other.name
|
|
end
|
|
|
|
feature {NONE} -- Implementation (weighting factors for `relative_value')
|
|
|
|
gunnery_weight: INTEGER = 10
|
|
defense_weight: INTEGER = 1
|
|
speed_weight: INTEGER = 1
|
|
airstrike_weight: INTEGER = 10
|
|
bonus_weight: INTEGER = 2
|
|
|
|
feature {ATTACK_UNIT} -- Implementation
|
|
|
|
set_task_force (a_force: like task_force)
|
|
-- Set `task_force' to `a_force'
|
|
require
|
|
has_current: a_force.has (Current)
|
|
do
|
|
task_force.prune (Current)
|
|
task_force := a_force
|
|
ensure
|
|
task_force_assigned: task_force = a_force
|
|
in_task_force: task_force.has (Current)
|
|
end
|
|
|
|
remove_task_force
|
|
-- Remove Current from `task_force' and put it in its own `task_force'
|
|
do
|
|
task_force.prune (Current)
|
|
create task_force.make (game)
|
|
end
|
|
|
|
feature {NONE} -- Implementation (invariant routines)
|
|
|
|
same_location_for_all: BOOLEAN
|
|
-- Do all the unit have the same `location'?
|
|
local
|
|
c: CURSOR
|
|
do
|
|
c := task_force.cursor
|
|
Result := true
|
|
if is_task_force then
|
|
from task_force.start
|
|
until task_force.is_after
|
|
loop
|
|
Result := task_force.item.location = location
|
|
task_force.forth
|
|
end
|
|
end
|
|
task_force.go_to (c)
|
|
end
|
|
|
|
same_position_for_all: BOOLEAN
|
|
-- Do all the units have the same `location'?
|
|
local
|
|
c: CURSOR
|
|
do
|
|
c := task_force.cursor
|
|
Result := true
|
|
if is_task_force then
|
|
from task_force.start
|
|
until task_force.is_after
|
|
loop
|
|
Result := task_force.item.position ~ position
|
|
task_force.forth
|
|
end
|
|
end
|
|
task_force.go_to (c)
|
|
end
|
|
|
|
feature {NONE} -- Implementation
|
|
|
|
target_imp: detachable ATTACK_UNIT
|
|
-- The unit if any that Current is set to attack
|
|
|
|
|
|
|
|
invariant
|
|
|
|
location_exists: location /= Void
|
|
task_force_exists: task_force /= Void
|
|
|
|
-- longitude_big_enough: position.longitude >= {POSITION_CONSTANTS}.Minimum_longitude
|
|
-- longitude_small_enough: position.longitude <= {POSITION_CONSTANTS}.Maximum_longitude
|
|
-- latitude_big_enough: position.latitude >= {POSITION_CONSTANTS}.Minimum_latitude
|
|
-- latitude_small_enough: position.latitude <= {POSITION_CONSTANTS}.Maximum_latitude
|
|
|
|
contains_itself: task_force.has (Current)
|
|
valid_arrival_turn: arrival_turn >= 1 and arrival_turn <= 9
|
|
|
|
valid_gunnery_factor: gunnery_factor >= 0 and gunnery_factor <= 9
|
|
valid_defense_factor: defense_factor >= 0 and defense_factor <= 9
|
|
valid_speed_factor: speed_factor >= 3 and speed_factor <= 9
|
|
|
|
-- contains_current: task_force.first = Current
|
|
-- contains_only_current: task_force.count = 1
|
|
|
|
location_integrity: is_stable implies location.has (Current)
|
|
task_force_integrity: (is_stable and then is_task_force and then task_force.is_stable)
|
|
implies task_force.has (Current)
|
|
|
|
-- task_force_location_implication: is_stable implies (is_task_force implies same_location_for_all)
|
|
-- task_force_position_implication: is_stable implies (is_task_force implies same_position_for_all)
|
|
|
|
end
|