/******************************************************************************* * * 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 } }