1354 lines
31 KiB
C#
1354 lines
31 KiB
C#
/*******************************************************************************
|
|
*
|
|
* Space Trader for Windows 2.00
|
|
*
|
|
* Copyright (C) 2005 Jay French, All Rights Reserved
|
|
*
|
|
* Additional coding by David Pierron
|
|
* Original coding by Pieter Spronck, Sam Anderson, Samuel Goldstein, Matt Lee
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option) any
|
|
* later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* If you'd like a copy of the GNU General Public License, go to
|
|
* http://www.gnu.org/copyleft/gpl.html.
|
|
*
|
|
* You can contact the author at spacetrader@frenchfryz.com
|
|
*
|
|
******************************************************************************/
|
|
using System;
|
|
using System.Collections;
|
|
|
|
namespace Fryz.Apps.SpaceTrader
|
|
{
|
|
public class Ship : ShipSpec
|
|
{
|
|
#region Member Declarations
|
|
|
|
private int _fuel;
|
|
private int _hull;
|
|
private int _tribbles = 0;
|
|
private int[] _cargo = new int[10];
|
|
private Weapon[] _weapons;
|
|
private Shield[] _shields;
|
|
private Gadget[] _gadgets;
|
|
private CrewMember[] _crew;
|
|
private bool _pod = false;
|
|
|
|
// The following does not need to be saved. It's more of a temp variable.
|
|
private bool[] _tradeableItems;
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
public Ship(ShipType type)
|
|
{
|
|
SetValues(type);
|
|
}
|
|
|
|
public Ship(OpponentType oppType)
|
|
{
|
|
if (oppType == OpponentType.FamousCaptain)
|
|
{
|
|
SetValues(Consts.ShipSpecs[Consts.MaxShip].Type);
|
|
|
|
for (int i = 0; i < Shields.Length; i++)
|
|
AddEquipment(Consts.Shields[(int)ShieldType.Reflective]);
|
|
|
|
for (int i = 0; i < Weapons.Length; i++)
|
|
AddEquipment(Consts.Weapons[(int)WeaponType.MilitaryLaser]);
|
|
|
|
AddEquipment(Consts.Gadgets[(int)GadgetType.NavigatingSystem]);
|
|
AddEquipment(Consts.Gadgets[(int)GadgetType.TargetingSystem]);
|
|
|
|
Crew[0] = Game.CurrentGame.Mercenaries[(int)CrewMemberId.FamousCaptain];
|
|
}
|
|
else if (oppType == OpponentType.Bottle)
|
|
{
|
|
SetValues(ShipType.Bottle);
|
|
}
|
|
else
|
|
{
|
|
int tries = oppType == OpponentType.Mantis ? (int)Game.CurrentGame.Difficulty + 1 :
|
|
Math.Max(1, Game.CurrentGame.Commander.Worth / 150000 + (int)Game.CurrentGame.Difficulty -
|
|
(int)Difficulty.Normal);
|
|
|
|
GenerateOpponentShip(oppType);
|
|
GenerateOpponentAddCrew();
|
|
GenerateOpponentAddGadgets(tries);
|
|
GenerateOpponentAddShields(tries);
|
|
GenerateOpponentAddWeapons(tries);
|
|
|
|
if (oppType != OpponentType.Mantis)
|
|
GenerateOpponentSetHullStrength();
|
|
|
|
if (oppType != OpponentType.Police)
|
|
GenerateOpponentAddCargo(oppType == OpponentType.Pirate);
|
|
}
|
|
}
|
|
|
|
public Ship(Hashtable hash): base(hash)
|
|
{
|
|
_fuel = (int)GetValueFromHash(hash, "_fuel");
|
|
_hull = (int)GetValueFromHash(hash, "_hull");
|
|
_tribbles = (int)GetValueFromHash(hash, "_tribbles", _tribbles);
|
|
_cargo = (int[])GetValueFromHash(hash, "_cargo", _cargo);
|
|
_weapons = (Weapon[])ArrayListToArray((ArrayList)GetValueFromHash(hash, "_weapons"), "Weapon");
|
|
_shields = (Shield[])ArrayListToArray((ArrayList)GetValueFromHash(hash, "_shields"), "Shield");
|
|
_gadgets = (Gadget[])ArrayListToArray((ArrayList)GetValueFromHash(hash, "_gadgets"), "Gadget");
|
|
_pod = (bool)GetValueFromHash(hash, "_pod", _pod);
|
|
|
|
int[] crewIds = (int[])GetValueFromHash(hash, "_crewIds");
|
|
_crew = new CrewMember[crewIds.Length];
|
|
for (int index = 0; index < _crew.Length; index++)
|
|
{
|
|
CrewMemberId id = (CrewMemberId)crewIds[index];
|
|
_crew[index] = (id == CrewMemberId.NA ? null : Game.CurrentGame.Mercenaries[(int)id]);
|
|
}
|
|
}
|
|
|
|
public void AddEquipment(Equipment item)
|
|
{
|
|
Equipment[] equip = EquipmentByType(item.EquipmentType);
|
|
|
|
int slot = -1;
|
|
for (int i = 0; i < equip.Length && slot == -1; i++)
|
|
if (equip[i] == null)
|
|
slot = i;
|
|
|
|
if (slot >= 0)
|
|
equip[slot] = item.Clone();
|
|
}
|
|
|
|
public int BaseWorth(bool forInsurance)
|
|
{
|
|
int i;
|
|
int price =
|
|
// Trade-in value is three-fourths the original price
|
|
Price * (Tribbles > 0 && !forInsurance ? 1 : 3) / 4
|
|
// subtract repair costs
|
|
- (HullStrength - Hull) * RepairCost
|
|
// subtract costs to fill tank with fuel
|
|
- (FuelTanks - Fuel) * FuelCost;
|
|
// Add 3/4 of the price of each item of equipment
|
|
for (i = 0; i < _weapons.Length; i++)
|
|
if (_weapons[i] != null)
|
|
price += _weapons[i].SellPrice;
|
|
for (i = 0; i < _shields.Length; i++)
|
|
if (_shields[i] != null)
|
|
price += _shields[i].SellPrice;
|
|
for (i = 0; i < _gadgets.Length; i++)
|
|
if (_gadgets[i] != null)
|
|
price += _gadgets[i].SellPrice;
|
|
|
|
return price;
|
|
}
|
|
|
|
public int Bounty()
|
|
{
|
|
int price = Price;
|
|
|
|
for (int i = 0; i < Weapons.Length; i++)
|
|
if (Weapons[i] != null)
|
|
price += Weapons[i].Price;
|
|
|
|
for (int i = 0; i < Shields.Length; i++)
|
|
if (Shields[i] != null)
|
|
price += Shields[i].Price;
|
|
|
|
// Gadgets aren't counted in the price, because they are already taken into account in
|
|
// the skill adjustment of the price.
|
|
|
|
price = price * (2 * Pilot + Engineer + 3 * Fighter) / 60;
|
|
|
|
// Divide by 200 to get the bounty, then round down to the nearest 25.
|
|
int bounty = price / 200 / 25 * 25;
|
|
|
|
return Math.Max(25, Math.Min(2500, bounty));
|
|
}
|
|
|
|
public Equipment[] EquipmentByType(EquipmentType type)
|
|
{
|
|
Equipment[] equip = null;
|
|
switch (type)
|
|
{
|
|
case EquipmentType.Weapon:
|
|
equip = Weapons;
|
|
break;
|
|
case EquipmentType.Shield:
|
|
equip = Shields;
|
|
break;
|
|
case EquipmentType.Gadget:
|
|
equip = Gadgets;
|
|
break;
|
|
}
|
|
return equip;
|
|
}
|
|
|
|
public void Fire(CrewMemberId crewId)
|
|
{
|
|
int skill = Trader;
|
|
bool found = false;
|
|
CrewMember merc = null;
|
|
for (int i = 0; i < Crew.Length; i++)
|
|
{
|
|
if (Crew[i] != null && Crew[i].Id == crewId)
|
|
{
|
|
found = true;
|
|
merc = Crew[i];
|
|
}
|
|
|
|
if (found)
|
|
Crew[i] = (i < Crew.Length - 1) ? Crew[i + 1] : null;
|
|
}
|
|
|
|
if (Trader != skill)
|
|
Game.CurrentGame.RecalculateBuyPrices(Game.CurrentGame.Commander.CurrentSystem);
|
|
|
|
if (merc != null && !Consts.SpecialCrewMemberIds.Contains(merc.Id))
|
|
{
|
|
StarSystem[] universe = Game.CurrentGame.Universe;
|
|
|
|
// The leaving Mercenary travels to a nearby random system.
|
|
merc.CurrentSystemId = StarSystemId.NA;
|
|
while (merc.CurrentSystemId == StarSystemId.NA)
|
|
{
|
|
StarSystem system = universe[Functions.GetRandom(universe.Length)];
|
|
if (Functions.Distance(system, Game.CurrentGame.Commander.CurrentSystem) < Consts.MaxRange)
|
|
merc.CurrentSystemId = system.Id;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateOpponentAddCargo(bool pirate)
|
|
{
|
|
if (CargoBays > 0)
|
|
{
|
|
Difficulty diff = Game.CurrentGame.Difficulty;
|
|
int baysToFill = CargoBays;
|
|
|
|
if (diff >= Difficulty.Normal)
|
|
baysToFill = Math.Min(15, 3 + Functions.GetRandom(baysToFill - 5));
|
|
|
|
if (pirate)
|
|
{
|
|
if (diff < Difficulty.Normal)
|
|
baysToFill = baysToFill * 4 / 5;
|
|
else
|
|
baysToFill = Math.Max(1, baysToFill / (int)diff);
|
|
}
|
|
|
|
for (int bays, i = 0; i < baysToFill; i += bays)
|
|
{
|
|
int item = Functions.GetRandom(Consts.TradeItems.Length);
|
|
bays = Math.Min(baysToFill - i, 1 + Functions.GetRandom(10 - item));
|
|
Cargo[item] += bays;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateOpponentAddCrew()
|
|
{
|
|
CrewMember[] mercs = Game.CurrentGame.Mercenaries;
|
|
Difficulty diff = Game.CurrentGame.Difficulty;
|
|
|
|
Crew[0] = mercs[(int)CrewMemberId.Opponent];
|
|
Crew[0].Pilot = 1 + Functions.GetRandom(Consts.MaxSkill);
|
|
Crew[0].Fighter = 1 + Functions.GetRandom(Consts.MaxSkill);
|
|
Crew[0].Trader = 1 + Functions.GetRandom(Consts.MaxSkill);
|
|
|
|
if (Game.CurrentGame.WarpSystem.Id == StarSystemId.Kravat && WildOnBoard && Functions.GetRandom(10) < (int)diff + 1)
|
|
Crew[0].Engineer = Consts.MaxSkill;
|
|
else
|
|
Crew[0].Engineer = 1 + Functions.GetRandom(Consts.MaxSkill);
|
|
|
|
int numCrew = 0;
|
|
if (diff == Difficulty.Impossible)
|
|
numCrew = CrewQuarters;
|
|
else
|
|
{
|
|
numCrew = 1 + Functions.GetRandom(CrewQuarters);
|
|
if (diff == Difficulty.Hard && numCrew < CrewQuarters)
|
|
numCrew++;
|
|
}
|
|
|
|
for (int i = 1; i < numCrew; i++)
|
|
{
|
|
// Keep getting a new random mercenary until we have a non-special one.
|
|
while (Crew[i] == null || Consts.SpecialCrewMemberIds.Contains(Crew[i].Id))
|
|
Crew[i] = mercs[Functions.GetRandom(mercs.Length)];
|
|
}
|
|
}
|
|
|
|
private void GenerateOpponentAddGadgets(int tries)
|
|
{
|
|
if (GadgetSlots > 0)
|
|
{
|
|
int numGadgets = 0;
|
|
|
|
if (Game.CurrentGame.Difficulty == Difficulty.Impossible)
|
|
numGadgets = GadgetSlots;
|
|
else
|
|
{
|
|
numGadgets = Functions.GetRandom(GadgetSlots + 1);
|
|
if (numGadgets < GadgetSlots && (tries > 4 || (tries > 2 && Functions.GetRandom(2) > 0)))
|
|
numGadgets++;
|
|
}
|
|
|
|
for (int i = 0; i < numGadgets; i++)
|
|
{
|
|
int bestGadgetType = 0;
|
|
for (int j = 0; j < tries; j++)
|
|
{
|
|
int x = Functions.GetRandom(100);
|
|
int sum = Consts.Gadgets[0].Chance;
|
|
int gadgetType = 0;
|
|
while (sum < x && gadgetType <= Consts.Gadgets.Length - 1)
|
|
{
|
|
gadgetType++;
|
|
sum += Consts.Gadgets[gadgetType].Chance;
|
|
}
|
|
if (!HasGadget(Consts.Gadgets[gadgetType].Type) && gadgetType > bestGadgetType)
|
|
bestGadgetType = gadgetType;
|
|
}
|
|
|
|
AddEquipment(Consts.Gadgets[bestGadgetType]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateOpponentAddShields(int tries)
|
|
{
|
|
if (ShieldSlots > 0)
|
|
{
|
|
int numShields = 0;
|
|
|
|
if (Game.CurrentGame.Difficulty == Difficulty.Impossible)
|
|
numShields = ShieldSlots;
|
|
else
|
|
{
|
|
numShields = Functions.GetRandom(ShieldSlots + 1);
|
|
if (numShields < ShieldSlots && (tries > 3 || (tries > 1 && Functions.GetRandom(2) > 0)))
|
|
numShields++;
|
|
}
|
|
|
|
for (int i = 0; i < numShields; i++)
|
|
{
|
|
int bestShieldType = 0;
|
|
for (int j = 0; j < tries; j++)
|
|
{
|
|
int x = Functions.GetRandom(100);
|
|
int sum = Consts.Shields[0].Chance;
|
|
int shieldType = 0;
|
|
while (sum < x && shieldType <= Consts.Shields.Length - 1)
|
|
{
|
|
shieldType++;
|
|
sum += Consts.Shields[shieldType].Chance;
|
|
}
|
|
if (!HasShield(Consts.Shields[shieldType].Type) && shieldType > bestShieldType)
|
|
bestShieldType = shieldType;
|
|
}
|
|
|
|
AddEquipment(Consts.Shields[bestShieldType]);
|
|
|
|
Shields[i].Charge = 0;
|
|
for (int j = 0; j < 5; j++)
|
|
{
|
|
int charge = 1 + Functions.GetRandom(Shields[i].Power);
|
|
if (charge > Shields[i].Charge)
|
|
Shields[i].Charge = charge;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateOpponentAddWeapons(int tries)
|
|
{
|
|
if (WeaponSlots > 0)
|
|
{
|
|
int numWeapons = 0;
|
|
|
|
if (Game.CurrentGame.Difficulty == Difficulty.Impossible)
|
|
numWeapons = WeaponSlots;
|
|
else if (WeaponSlots == 1)
|
|
numWeapons = 1;
|
|
else
|
|
{
|
|
numWeapons = 1 + Functions.GetRandom(WeaponSlots);
|
|
if (numWeapons < WeaponSlots && (tries > 4 || (tries > 3 && Functions.GetRandom(2) > 0)))
|
|
numWeapons++;
|
|
}
|
|
|
|
for (int i = 0; i < numWeapons; i++)
|
|
{
|
|
int bestWeaponType = 0;
|
|
for (int j = 0; j < tries; j++)
|
|
{
|
|
int x = Functions.GetRandom(100);
|
|
int sum = Consts.Weapons[0].Chance;
|
|
int weaponType = 0;
|
|
while (sum < x && weaponType <= Consts.Weapons.Length - 1)
|
|
{
|
|
weaponType++;
|
|
sum += Consts.Weapons[weaponType].Chance;
|
|
}
|
|
if (!HasWeapon((WeaponType)weaponType, true) && weaponType > bestWeaponType)
|
|
bestWeaponType = weaponType;
|
|
}
|
|
|
|
AddEquipment(Consts.Weapons[bestWeaponType]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateOpponentSetHullStrength()
|
|
{
|
|
// If there are shields, the hull will probably be stronger
|
|
if (ShieldStrength == 0 || Functions.GetRandom(5) == 0)
|
|
{
|
|
Hull = 0;
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
int hull = 1 + Functions.GetRandom(HullStrength);
|
|
if (hull > Hull)
|
|
Hull = hull;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateOpponentShip(OpponentType oppType)
|
|
{
|
|
Commander cmdr = Game.CurrentGame.Commander;
|
|
PoliticalSystem polSys = Game.CurrentGame.WarpSystem.PoliticalSystem;
|
|
|
|
if (oppType == OpponentType.Mantis)
|
|
SetValues(ShipType.Mantis);
|
|
else
|
|
{
|
|
ShipType oppShipType;
|
|
int tries = 1;
|
|
|
|
switch (oppType)
|
|
{
|
|
case OpponentType.Pirate:
|
|
// Pirates become better when you get richer
|
|
tries = 1 + cmdr.Worth / 100000;
|
|
tries = Math.Max(1, tries + (int)Game.CurrentGame.Difficulty - (int)Difficulty.Normal);
|
|
break;
|
|
case OpponentType.Police:
|
|
// The police will try to hunt you down with better ships if you are
|
|
// a villain, and they will try even harder when you are considered to
|
|
// be a psychopath (or are transporting Jonathan Wild)
|
|
if (cmdr.PoliceRecordScore < Consts.PoliceRecordScorePsychopath || cmdr.Ship.WildOnBoard)
|
|
tries = 5;
|
|
else if (cmdr.PoliceRecordScore < Consts.PoliceRecordScoreVillain)
|
|
tries = 3;
|
|
else
|
|
tries = 1;
|
|
tries = Math.Max(1, tries + (int)Game.CurrentGame.Difficulty - (int)Difficulty.Normal);
|
|
break;
|
|
}
|
|
|
|
if (oppType == OpponentType.Trader)
|
|
oppShipType = ShipType.Flea;
|
|
else
|
|
oppShipType = ShipType.Gnat;
|
|
|
|
int total = 0;
|
|
for (int i = 0; i < Consts.MaxShip; i++)
|
|
{
|
|
ShipSpec spec = Consts.ShipSpecs[i];
|
|
if (polSys.ShipTypeLikely(spec.Type, oppType))
|
|
total += spec.Occurrence;
|
|
}
|
|
|
|
for (int i = 0; i < tries; i++)
|
|
{
|
|
int x = Functions.GetRandom(total);
|
|
int sum = -1;
|
|
int j = -1;
|
|
|
|
do
|
|
{
|
|
j++;
|
|
if (polSys.ShipTypeLikely(Consts.ShipSpecs[j].Type, oppType))
|
|
{
|
|
if (sum > 0)
|
|
sum += Consts.ShipSpecs[j].Occurrence;
|
|
else
|
|
sum = Consts.ShipSpecs[j].Occurrence;
|
|
}
|
|
} while (sum < x && j < Consts.MaxShip);
|
|
|
|
if (j > (int)oppShipType)
|
|
oppShipType = Consts.ShipSpecs[j].Type;
|
|
}
|
|
|
|
SetValues(oppShipType);
|
|
}
|
|
}
|
|
|
|
// *************************************************************************
|
|
// Returns the index of a trade good that is on a given ship that can be
|
|
// bought/sold in the current system.
|
|
// JAF - Made this MUCH simpler by storing an array of booleans indicating
|
|
// the tradeable goods when HasTradeableItem is called.
|
|
// *************************************************************************
|
|
public int GetRandomTradeableItem()
|
|
{
|
|
int index = Functions.GetRandom(TradeableItems.Length);
|
|
|
|
while (!TradeableItems[index])
|
|
index = (index + 1) % TradeableItems.Length;
|
|
|
|
return index;
|
|
}
|
|
|
|
public bool HasCrew(CrewMemberId id)
|
|
{
|
|
bool found = false;
|
|
for (int i = 0; i < Crew.Length && !found; i++)
|
|
{
|
|
if (Crew[i] != null && Crew[i].Id == id)
|
|
found = true;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
public bool HasEquipment(Equipment item)
|
|
{
|
|
bool found = false;
|
|
switch (item.EquipmentType)
|
|
{
|
|
case EquipmentType.Weapon:
|
|
found = HasWeapon(((Weapon)item).Type, true);
|
|
break;
|
|
case EquipmentType.Shield:
|
|
found = HasShield(((Shield)item).Type);
|
|
break;
|
|
case EquipmentType.Gadget:
|
|
found = HasGadget(((Gadget)item).Type);
|
|
break;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
public bool HasGadget(GadgetType gadgetType)
|
|
{
|
|
bool found = false;
|
|
for (int i = 0; i < Gadgets.Length && !found; i++)
|
|
{
|
|
if (Gadgets[i] != null && Gadgets[i].Type == gadgetType)
|
|
found = true;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
public bool HasShield(ShieldType shieldType)
|
|
{
|
|
bool found = false;
|
|
for (int i = 0; i < Shields.Length && !found; i++)
|
|
{
|
|
if (Shields[i] != null && Shields[i].Type == shieldType)
|
|
found = true;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
// *************************************************************************
|
|
// Determines if a given ship is carrying items that can be bought or sold
|
|
// in the current system.
|
|
// *************************************************************************
|
|
public bool HasTradeableItems()
|
|
{
|
|
bool found = false;
|
|
bool criminal = Game.CurrentGame.Commander.PoliceRecordScore <
|
|
Consts.PoliceRecordScoreDubious;
|
|
_tradeableItems = new bool[10];
|
|
|
|
for (int i = 0; i < Cargo.Length; i++)
|
|
{
|
|
// Trade only if trader is selling and the item has a buy price on the
|
|
// local system, or trader is buying, and there is a sell price on the
|
|
// local system.
|
|
// Criminals can only buy or sell illegal goods, Noncriminals cannot buy
|
|
// or sell such items.
|
|
// Simplified this - JAF
|
|
if (Cargo[i] > 0 && !(criminal ^ Consts.TradeItems[i].Illegal) && (
|
|
(!CommandersShip && Game.CurrentGame.PriceCargoBuy[i] > 0) ||
|
|
(CommandersShip && Game.CurrentGame.PriceCargoSell[i] > 0)))
|
|
{
|
|
found = true;
|
|
TradeableItems[i] = true;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
public bool HasWeapon(WeaponType weaponType, bool exactCompare)
|
|
{
|
|
bool found = false;
|
|
for (int i = 0; i < Weapons.Length && !found; i++)
|
|
{
|
|
if (Weapons[i] != null && (Weapons[i].Type == weaponType || !exactCompare && Weapons[i].Type > weaponType))
|
|
found = true;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
public void Hire(CrewMember merc)
|
|
{
|
|
int skill = Trader;
|
|
|
|
int slot = -1;
|
|
for (int i = 0; i < Crew.Length && slot == -1; i++)
|
|
if (Crew[i] == null)
|
|
slot = i;
|
|
|
|
if (slot >= 0)
|
|
Crew[slot] = merc;
|
|
|
|
if (Trader != skill)
|
|
Game.CurrentGame.RecalculateBuyPrices(Game.CurrentGame.Commander.CurrentSystem);
|
|
}
|
|
|
|
public string IllegalSpecialCargoActions()
|
|
{
|
|
ArrayList actions = new ArrayList();
|
|
|
|
if (ReactorOnBoard)
|
|
actions.Add(Strings.EncounterPoliceSurrenderReactor);
|
|
else if (WildOnBoard)
|
|
actions.Add(Strings.EncounterPoliceSurrenderWild);
|
|
|
|
if (SculptureOnBoard)
|
|
actions.Add(Strings.EncounterPoliceSurrenderSculpt);
|
|
|
|
return actions.Count == 0 ? "" : Functions.StringVars(Strings.EncounterPoliceSurrenderAction,
|
|
Functions.FormatList(Functions.ArrayListToStringArray(actions)));
|
|
}
|
|
|
|
public string IllegalSpecialCargoDescription(string wrapper, bool includePassengers, bool includeTradeItems)
|
|
{
|
|
ArrayList items = new ArrayList();
|
|
|
|
if (includePassengers && WildOnBoard)
|
|
items.Add(Strings.EncounterPoliceSubmitWild);
|
|
|
|
if (ReactorOnBoard)
|
|
items.Add(Strings.EncounterPoliceSubmitReactor);
|
|
|
|
if (SculptureOnBoard)
|
|
items.Add(Strings.EncounterPoliceSubmitSculpture);
|
|
|
|
if (includeTradeItems && DetectableIllegalCargo)
|
|
items.Add(Strings.EncounterPoliceSubmitGoods);
|
|
|
|
string allItems = Functions.FormatList(Functions.ArrayListToStringArray(items));
|
|
|
|
if (allItems.Length > 0 && wrapper.Length > 0)
|
|
allItems = Functions.StringVars(wrapper, allItems);
|
|
|
|
return allItems;
|
|
}
|
|
|
|
public void PerformRepairs()
|
|
{
|
|
// A disabled ship cannot be repaired.
|
|
if (CommandersShip || !Game.CurrentGame.OpponentDisabled)
|
|
{
|
|
// Engineer may do some repairs
|
|
int repairs = Functions.GetRandom(Engineer);
|
|
if (repairs > 0)
|
|
{
|
|
int used = Math.Min(repairs, HullStrength - Hull);
|
|
Hull += used;
|
|
repairs -= used;
|
|
}
|
|
|
|
// Shields are easier to repair
|
|
if (repairs > 0)
|
|
{
|
|
repairs *= 2;
|
|
|
|
for (int i = 0; i < Shields.Length && repairs > 0; i++)
|
|
{
|
|
if (Shields[i] != null)
|
|
{
|
|
int used = Math.Min(repairs, Shields[i].Power - Shields[i].Charge);
|
|
Shields[i].Charge += used;
|
|
repairs -= used;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RemoveEquipment(EquipmentType type, int slot)
|
|
{
|
|
Equipment[] equip = EquipmentByType(type);
|
|
|
|
int last = equip.Length - 1;
|
|
for (int i = slot; i < last; i++)
|
|
equip[i] = equip[i + 1];
|
|
equip[last] = null;
|
|
}
|
|
|
|
public void RemoveEquipment(EquipmentType type, object subType)
|
|
{
|
|
bool found = false;
|
|
Equipment[] equip = EquipmentByType(type);
|
|
|
|
for (int i = 0; i < equip.Length && !found; i++)
|
|
{
|
|
if (equip[i] != null && equip[i].TypeEquals(subType))
|
|
{
|
|
RemoveEquipment(type, i);
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RemoveIllegalGoods()
|
|
{
|
|
for (int i = 0; i < Consts.TradeItems.Length; i++)
|
|
{
|
|
if (Consts.TradeItems[i].Illegal)
|
|
{
|
|
Cargo[i] = 0;
|
|
Game.CurrentGame.Commander.PriceCargo[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override Hashtable Serialize()
|
|
{
|
|
Hashtable hash = base.Serialize();
|
|
|
|
// We don't want the actual CrewMember objects - we just want the ids.
|
|
int[] crewIds = new int[_crew.Length];
|
|
for (int i = 0; i < crewIds.Length; i++)
|
|
crewIds[i] = (int)(_crew[i] == null ? CrewMemberId.NA : _crew[i].Id);
|
|
|
|
hash.Add("_fuel", _fuel);
|
|
hash.Add("_hull", _hull);
|
|
hash.Add("_tribbles", _tribbles);
|
|
hash.Add("_cargo", _cargo);
|
|
hash.Add("_weapons", ArrayToArrayList(_weapons));
|
|
hash.Add("_shields", ArrayToArrayList(_shields));
|
|
hash.Add("_gadgets", ArrayToArrayList(_gadgets));
|
|
hash.Add("_crewIds", crewIds);
|
|
hash.Add("_pod", _pod);
|
|
|
|
return hash;
|
|
}
|
|
|
|
protected override void SetValues(ShipType type)
|
|
{
|
|
base.SetValues(type);
|
|
|
|
_weapons = new Weapon[WeaponSlots];
|
|
_shields = new Shield[ShieldSlots];
|
|
_gadgets = new Gadget[GadgetSlots];
|
|
_crew = new CrewMember[CrewQuarters];
|
|
_fuel = FuelTanks;
|
|
_hull = HullStrength;
|
|
}
|
|
|
|
public int WeaponStrength()
|
|
{
|
|
return WeaponStrength(WeaponType.PulseLaser, WeaponType.QuantumDistruptor);
|
|
}
|
|
|
|
public int WeaponStrength(WeaponType min, WeaponType max)
|
|
{
|
|
int total = 0;
|
|
|
|
for (int i = 0; i < Weapons.Length; i++)
|
|
if (Weapons[i] != null && Weapons[i].Type >= min && Weapons[i].Type <= max)
|
|
total += Weapons[i].Power;
|
|
|
|
return total;
|
|
}
|
|
|
|
public int Worth(bool forInsurance)
|
|
{
|
|
int price = BaseWorth(forInsurance);
|
|
for (int i = 0; i < _cargo.Length; i++)
|
|
price += Game.CurrentGame.Commander.PriceCargo[i];
|
|
|
|
return price;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public bool AnyIllegalCargo
|
|
{
|
|
get
|
|
{
|
|
int illegalCargo = 0;
|
|
for (int i = 0; i < Consts.TradeItems.Length; i++)
|
|
{
|
|
if (Consts.TradeItems[i].Illegal)
|
|
illegalCargo += Cargo[i];
|
|
}
|
|
|
|
return illegalCargo > 0;
|
|
}
|
|
}
|
|
|
|
public bool ArtifactOnBoard
|
|
{
|
|
get
|
|
{
|
|
return CommandersShip && Game.CurrentGame.QuestStatusArtifact == SpecialEvent.StatusArtifactOnBoard;
|
|
}
|
|
}
|
|
|
|
public int[] Cargo
|
|
{
|
|
get
|
|
{
|
|
return _cargo;
|
|
}
|
|
}
|
|
|
|
// Changed the semantics of Filled versus total Cargo Bays. Bays used for
|
|
// transporting special items are now included in the total bays and in the
|
|
// filled bays. JAF
|
|
public override int CargoBays
|
|
{
|
|
get
|
|
{
|
|
int bays = base.CargoBays;
|
|
|
|
for (int i = 0; i < Gadgets.Length; i++)
|
|
if (Gadgets[i] != null && (Gadgets[i].Type == GadgetType.ExtraCargoBays ||
|
|
Gadgets[i].Type == GadgetType.HiddenCargoBays))
|
|
bays += 5;
|
|
|
|
return base.CargoBays + ExtraCargoBays + HiddenCargoBays;
|
|
}
|
|
}
|
|
|
|
public bool Cloaked
|
|
{
|
|
get
|
|
{
|
|
int oppEng = CommandersShip ? Game.CurrentGame.Opponent.Engineer : Game.CurrentGame.Commander.Ship.Engineer;
|
|
return HasGadget(GadgetType.CloakingDevice) && Engineer > oppEng;
|
|
}
|
|
}
|
|
|
|
public bool CommandersShip
|
|
{
|
|
get
|
|
{
|
|
return this == Game.CurrentGame.Commander.Ship;
|
|
}
|
|
}
|
|
|
|
public CrewMember[] Crew
|
|
{
|
|
get
|
|
{
|
|
return _crew;
|
|
}
|
|
}
|
|
|
|
public int CrewCount
|
|
{
|
|
get
|
|
{
|
|
int total = 0;
|
|
for (int i = 0; i < Crew.Length; i++)
|
|
if (Crew[i] != null)
|
|
total++;
|
|
return total;
|
|
}
|
|
}
|
|
|
|
public bool DetectableIllegalCargo
|
|
{
|
|
get
|
|
{
|
|
int illegalCargo = 0;
|
|
for (int i = 0; i < Consts.TradeItems.Length; i++)
|
|
{
|
|
if (Consts.TradeItems[i].Illegal)
|
|
illegalCargo += Cargo[i];
|
|
}
|
|
|
|
return (illegalCargo - HiddenCargoBays) > 0;
|
|
}
|
|
}
|
|
|
|
public bool DetectableIllegalCargoOrPassengers
|
|
{
|
|
get
|
|
{
|
|
return DetectableIllegalCargo || IllegalSpecialCargo;
|
|
}
|
|
}
|
|
|
|
public bool Disableable
|
|
{
|
|
get
|
|
{
|
|
return !CommandersShip && Type != ShipType.Bottle && Type != ShipType.Mantis &&
|
|
Type != ShipType.SpaceMonster;
|
|
}
|
|
}
|
|
|
|
public int Engineer
|
|
{
|
|
get
|
|
{
|
|
return Skills[(int)SkillType.Engineer];
|
|
}
|
|
}
|
|
|
|
public bool EscapePod
|
|
{
|
|
get
|
|
{
|
|
return _pod;
|
|
}
|
|
set
|
|
{
|
|
_pod = value;
|
|
}
|
|
}
|
|
|
|
public int ExtraCargoBays
|
|
{
|
|
get
|
|
{
|
|
int bays = 0;
|
|
|
|
for (int i = 0; i < Gadgets.Length; i++)
|
|
if (Gadgets[i] != null && Gadgets[i].Type == GadgetType.ExtraCargoBays)
|
|
bays += 5;
|
|
|
|
return bays;
|
|
}
|
|
}
|
|
|
|
public int Fighter
|
|
{
|
|
get
|
|
{
|
|
return Skills[(int)SkillType.Fighter];
|
|
}
|
|
}
|
|
|
|
// Changed the semantics of Filled versus total Cargo Bays. Bays used for
|
|
// transporting special items are now included in the total bays and in the
|
|
// filled bays. JAF
|
|
public int FilledCargoBays
|
|
{
|
|
get
|
|
{
|
|
int filled = FilledNormalCargoBays;
|
|
|
|
if (CommandersShip && Game.CurrentGame.QuestStatusJapori == SpecialEvent.StatusJaporiInTransit)
|
|
filled += 10;
|
|
|
|
if (ReactorOnBoard)
|
|
filled += 5 + 10 - (Game.CurrentGame.QuestStatusReactor - 1) / 2;
|
|
|
|
return filled;
|
|
}
|
|
}
|
|
|
|
public int FilledNormalCargoBays
|
|
{
|
|
get
|
|
{
|
|
int filled = 0;
|
|
|
|
for (int i = 0; i < _cargo.Length; i++)
|
|
filled += _cargo[i];
|
|
|
|
return filled;
|
|
}
|
|
}
|
|
|
|
public int FreeCargoBays
|
|
{
|
|
get
|
|
{
|
|
return CargoBays - FilledCargoBays;
|
|
}
|
|
}
|
|
|
|
public int FreeCrewQuarters
|
|
{
|
|
get
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < Crew.Length; i++)
|
|
{
|
|
if (Crew[i] == null)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
public int FreeSlots
|
|
{
|
|
get
|
|
{
|
|
return FreeSlotsGadget + FreeSlotsShield + FreeSlotsWeapon;
|
|
}
|
|
}
|
|
|
|
public int FreeSlotsGadget
|
|
{
|
|
get
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < Gadgets.Length; i++)
|
|
{
|
|
if (Gadgets[i] == null)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
public int FreeSlotsShield
|
|
{
|
|
get
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < Shields.Length; i++)
|
|
{
|
|
if (Shields[i] == null)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
public int FreeSlotsWeapon
|
|
{
|
|
get
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < Weapons.Length; i++)
|
|
{
|
|
if (Weapons[i] == null)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
public int Fuel
|
|
{
|
|
get
|
|
{
|
|
return _fuel;
|
|
}
|
|
set
|
|
{
|
|
_fuel = value;
|
|
}
|
|
}
|
|
|
|
public override int FuelTanks
|
|
{
|
|
get
|
|
{
|
|
return base.FuelTanks + (HasGadget(GadgetType.FuelCompactor) ? Consts.FuelCompactorTanks : 0);
|
|
}
|
|
}
|
|
|
|
public Gadget[] Gadgets
|
|
{
|
|
get
|
|
{
|
|
return _gadgets;
|
|
}
|
|
}
|
|
|
|
public bool HagglingComputerOnBoard
|
|
{
|
|
get
|
|
{
|
|
return CommandersShip && Game.CurrentGame.QuestStatusJarek == SpecialEvent.StatusJarekDone;
|
|
}
|
|
}
|
|
|
|
public int HiddenCargoBays
|
|
{
|
|
get
|
|
{
|
|
int bays = 0;
|
|
|
|
for (int i = 0; i < Gadgets.Length; i++)
|
|
if (Gadgets[i] != null && Gadgets[i].Type == GadgetType.HiddenCargoBays)
|
|
bays += 5;
|
|
|
|
return bays;
|
|
}
|
|
}
|
|
|
|
public int Hull
|
|
{
|
|
get
|
|
{
|
|
return _hull;
|
|
}
|
|
set
|
|
{
|
|
_hull = value;
|
|
}
|
|
}
|
|
|
|
public string HullText
|
|
{
|
|
get
|
|
{
|
|
return Functions.StringVars(Strings.EncounterHullStrength,
|
|
Functions.FormatNumber((int)Math.Floor((double)100 * Hull / HullStrength)));
|
|
}
|
|
}
|
|
|
|
public bool IllegalSpecialCargo
|
|
{
|
|
get
|
|
{
|
|
return WildOnBoard || ReactorOnBoard || SculptureOnBoard;
|
|
}
|
|
}
|
|
|
|
public bool JarekOnBoard
|
|
{
|
|
get
|
|
{
|
|
return HasCrew(CrewMemberId.Jarek);
|
|
}
|
|
}
|
|
|
|
public int Pilot
|
|
{
|
|
get
|
|
{
|
|
return Skills[(int)SkillType.Pilot];
|
|
}
|
|
}
|
|
|
|
public bool PrincessOnBoard
|
|
{
|
|
get
|
|
{
|
|
return HasCrew(CrewMemberId.Princess);
|
|
}
|
|
}
|
|
|
|
public bool ReactorOnBoard
|
|
{
|
|
get
|
|
{
|
|
int status = Game.CurrentGame.QuestStatusReactor;
|
|
return CommandersShip && status > SpecialEvent.StatusReactorNotStarted &&
|
|
status < SpecialEvent.StatusReactorDelivered;
|
|
}
|
|
}
|
|
|
|
public bool SculptureOnBoard
|
|
{
|
|
get
|
|
{
|
|
return CommandersShip && Game.CurrentGame.QuestStatusSculpture == SpecialEvent.StatusSculptureInTransit;
|
|
}
|
|
}
|
|
|
|
public int ShieldCharge
|
|
{
|
|
get
|
|
{
|
|
int total = 0;
|
|
|
|
for (int i = 0; i < Shields.Length; i++)
|
|
if (Shields[i] != null)
|
|
total += Shields[i].Charge;
|
|
|
|
return total;
|
|
}
|
|
}
|
|
|
|
public Shield[] Shields
|
|
{
|
|
get
|
|
{
|
|
return _shields;
|
|
}
|
|
}
|
|
|
|
public int ShieldStrength
|
|
{
|
|
get
|
|
{
|
|
int total = 0;
|
|
|
|
for (int i = 0; i < Shields.Length; i++)
|
|
if (Shields[i] != null)
|
|
total += Shields[i].Power;
|
|
|
|
return total;
|
|
}
|
|
}
|
|
|
|
public string ShieldText
|
|
{
|
|
get
|
|
{
|
|
return (Shields.Length > 0 && Shields[0] != null) ?
|
|
Functions.StringVars(Strings.EncounterShieldStrength,
|
|
Functions.FormatNumber((int)Math.Floor((double)100 * ShieldCharge / ShieldStrength))) :
|
|
Strings.EncounterShieldNone;
|
|
}
|
|
}
|
|
|
|
public int[] Skills
|
|
{
|
|
get
|
|
{
|
|
int[] skills = new int[4];
|
|
|
|
// Get the best skill value among the crew for each skill.
|
|
for (int skill = 0; skill < skills.Length; skill++)
|
|
{
|
|
int max = 1;
|
|
|
|
for (int crew = 0; crew < Crew.Length; crew++)
|
|
{
|
|
if (Crew[crew] != null && Crew[crew].Skills[skill] > max)
|
|
max = Crew[crew].Skills[skill];
|
|
}
|
|
|
|
skills[skill] = Math.Max(1, Functions.AdjustSkillForDifficulty(max));
|
|
}
|
|
|
|
// Adjust skills based on any gadgets on board.
|
|
for (int i = 0; i < Gadgets.Length; i++)
|
|
{
|
|
if (Gadgets[i] != null && Gadgets[i].SkillBonus != SkillType.NA)
|
|
skills[(int)Gadgets[i].SkillBonus] += Consts.SkillBonus;
|
|
}
|
|
|
|
return skills;
|
|
}
|
|
}
|
|
|
|
// Crew members that are not hired/fired - Commander, Jarek, Princess, and Wild - JAF
|
|
public CrewMember[] SpecialCrew
|
|
{
|
|
get
|
|
{
|
|
ArrayList list = new ArrayList();
|
|
for (int i = 0; i < Crew.Length; i++)
|
|
{
|
|
if (Crew[i] != null && Consts.SpecialCrewMemberIds.Contains(Crew[i].Id))
|
|
list.Add(Crew[i]);
|
|
}
|
|
|
|
CrewMember[] crew = new CrewMember[list.Count];
|
|
for (int i = 0; i < crew.Length; i++)
|
|
crew[i] = (CrewMember)list[i];
|
|
|
|
return crew;
|
|
}
|
|
}
|
|
|
|
// Sort all cargo based on value and put some of it in hidden bays, if they are present.
|
|
public ArrayList StealableCargo
|
|
{
|
|
get
|
|
{
|
|
// Put all of the cargo items in a list and sort it. Reverse it so the most expensive items are first.
|
|
ArrayList tradeItems = new ArrayList();
|
|
for (int tradeItem = 0; tradeItem < Cargo.Length; tradeItem++)
|
|
{
|
|
for (int count = 0; count < Cargo[tradeItem]; count++)
|
|
tradeItems.Add((int)tradeItem);
|
|
}
|
|
tradeItems.Sort();
|
|
tradeItems.Reverse();
|
|
|
|
int hidden = HiddenCargoBays;
|
|
if (PrincessOnBoard)
|
|
hidden--;
|
|
if (SculptureOnBoard)
|
|
hidden--;
|
|
|
|
if (hidden > 0)
|
|
tradeItems.RemoveRange(0, hidden);
|
|
|
|
return tradeItems;
|
|
}
|
|
}
|
|
|
|
public bool[] TradeableItems
|
|
{
|
|
get
|
|
{
|
|
return _tradeableItems;
|
|
}
|
|
}
|
|
|
|
public int Trader
|
|
{
|
|
get
|
|
{
|
|
return Skills[(int)SkillType.Trader] + (HagglingComputerOnBoard ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
public int Tribbles
|
|
{
|
|
get
|
|
{
|
|
return _tribbles;
|
|
}
|
|
set
|
|
{
|
|
_tribbles = value;
|
|
}
|
|
}
|
|
|
|
public Weapon[] Weapons
|
|
{
|
|
get
|
|
{
|
|
return _weapons;
|
|
}
|
|
}
|
|
|
|
public bool WildOnBoard
|
|
{
|
|
get
|
|
{
|
|
return HasCrew(CrewMemberId.Wild);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|