You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
19 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Otter;
using _1869_Remake;
namespace _1869_Remake.Entities
{
public class Schiff : Entity
{
//Eventuell eine Auflistung machen von den Verschiedenen Schiffstypen hier und andere Entitäten davon objekte erstellen lassen
//Hinweis: Wenn waren eingeladert/ausgelagert werden, die NICHT verderblich sind kann gefahrlos immer nur ein Objekt dieser Ware in der Ladeliste stehen bleiben.
//Problematisch wird es bei Verderblichen Sachen -> Hier muss mit dem Verderblich kennzeichen der Ware gearbeitet werden damit bei Ankauf und Verkauf der Ware richtiges Handling stattfindet
//-> Bei einkauf: Immer neue Objekte erstellen und Einkaufspreis ist abhängig von Verderbtheitsgrad
//-> Bei Verkauf: Durchlauf der gesamten Ware und verkauf aller Exemplare dieser Ware; Verkaufspreis ist wie bei Einkaufspreis abhängig von Verderbtheitsgrad -> Alle Warenexemplare müssen mit ihrem jeweiligen Verderbtheitsmultiplikator verrechnet werden und als Angebotspreis angeboten werden.
//-> Preisberechnung sollte immer vom Hafen aus erfolgen um Kosten/Wert zentral berechnen zu lassen
//-> Schiffe sind wie eigene Filiale, die aber nicht Hafengebunden sind (und eventuell Kampfgefährt im Freibeuter modus)
#region Schiffsbasis Vars
// Name des Schiffs
public string NAME;
// Besitzer des Schiffs
public Spieler COMMANDEUR;
//Zustandseigenschaften des Schiffs
// SCHIFFSTYP beschreibt die Art von Schiff -> Es gibt unterkategorien jedoch wird der hier eingetragene Wert größtenteils generalisiert
public string SCHIFFSTYP;
// Mögliche Baumaterialien
// HOLZ
// EISEN
public string BAUMATERIAL;
//Anzahl Kabinen für Passagiere
public int KABINEN;
//Größe des Lagerraums(in Tonnen)
public int LADERAUM;
// Bauzeit -> Wird von Werftklasse benötigt für ermittlung der benötigten Bauzeit
public int LIEFERZEIT;
// Wird bei errichten des Schiffes gesetzt und be jedem Jahr hochgezählt -> Schiffe mit hohem alter haben höhere Wahrscheinlichkeit kaputt zu gehen
public int ALTER;
// Maximal Mögliche Geschwindigkeit (Ohne Abzüge durch äußere Einflüsse)
public int OPTIMALSPEED;
//Altags-Schiffszustände
public int ZUSTAND_GEFLUTET;
public int ZUSTAND_VERMUSCHELT;
public int ZUSTAND_TAKELAGE;
public string angedocktAnHafen;
public DateTime FERTIGSTELLUNGSDATUM;
public bool inBau = false;
public bool inBereitstellung = false;
public bool inReparatur = false;
#endregion
#region Geldspezifischen Vars
// Neuwert, den Werften für das Bauen des Schiffes oder für ein <1 Jahre altes Schiff verlangen werden
public int NEUWERT;
public int ANZAHLUNGSPREIS;
// Tatsächliche Preis der zuletzt für dieses Schiff bezahlt wurde
public int VERKAUFSWERT;
// Kasse des Schiffs -> Hiervon wird Sold der Crew und geschäfte mit Häfen über das Schiff verrechnet
public int SCHIFFSBUDGET;
// Laufende Kosten durch Crew -> wenn Schiffsbudget nicht groß genug ist für nächste Reise wird crew streiken (Außnahme erste Reise nach Rekrutierung der Crew)
public int BESATZUNGSKOSTEN;
public int RESTBETRAGKAUFPREIS;
public bool bezahlt = false;
#endregion
#region Ladungsspezifische Vars
// Liste der geladenen Waren
public List<Ware> LADUNG = new List<Ware>();
#endregion
#region Mannschafts Vars
// Indikator, ob eine Crew vorhanden ist
public bool MANNSCHAFT_VORHANDEN;
public bool MANNSCHAFT_UNTERWEGS;
// Indikator, wie erfahren Crew ist -> Erfahrene Crew erhält weniger Malus auf Reise und nutzt das Schiff nicht so stark ab
public int MANNSCHAFT_ERFAHRUNG;
// Indikator, wie ausgelaugt Crew ist -> Wenn Fittness zu niedrig für nächste Reise, wird Crew streiken (Außnahme erste Reise nach Rektrutierung der Crew))
public int MANNSCHAFT_VITALITÄT;
// Indikator für Befehlsgewalt des Captains -> Je nach Abstufung wird Schiff schneller befördert oder nicht (schneller = mehr VITALITÄTSVERLUST & mehr Abnutzung)
public string KAPITÄNSORDER;
// Maximale Besatzungsgröße
public int MANNSCHAFT_MAXGRÖßE;
#endregion
//Standardkonstruktor
public Schiff()
{
}
//ParameterKontruktor
public Schiff(string Name, string Typ, int Alter, Spieler Commandeur = null)
{
this.NAME = Name;
this.ALTER = Alter;
if(ALTER > 0)
{
//Wenn Alter gesetzt ist muss das theoretische Fertigstellungsdatum errechnet werden
FERTIGSTELLUNGSDATUM = Globals.AktuellesDatum-new TimeSpan(ALTER*365,0,0,0);
}
if (Commandeur != null)
this.COMMANDEUR = Commandeur;
this.SCHIFFSTYP = Typ;
setzeSchiffsTypParameter(SCHIFFSTYP);
Globals.registriereEntität(this);
}
//Kopierkonstruktor
public Schiff(Schiff KopierSchiff)
{
this.NAME = KopierSchiff.NAME;
this.ALTER = KopierSchiff.ALTER;
if(COMMANDEUR != null)
this.COMMANDEUR = KopierSchiff.COMMANDEUR;
this.angedocktAnHafen = KopierSchiff.angedocktAnHafen;
this.SCHIFFSTYP = KopierSchiff.SCHIFFSTYP;
this.setzeSchiffsTypParameter(SCHIFFSTYP);
this.bezahlt = KopierSchiff.bezahlt;
this.FERTIGSTELLUNGSDATUM = KopierSchiff.FERTIGSTELLUNGSDATUM;
this.inBau = KopierSchiff.inBau;
this.inReparatur = KopierSchiff.inReparatur;
this.ZUSTAND_GEFLUTET = KopierSchiff.ZUSTAND_GEFLUTET;
this.ZUSTAND_TAKELAGE = KopierSchiff.ZUSTAND_TAKELAGE;
this.ZUSTAND_VERMUSCHELT = KopierSchiff.ZUSTAND_VERMUSCHELT;
this.SCHIFFSBUDGET = KopierSchiff.SCHIFFSBUDGET;
this.LADUNG = KopierSchiff.LADUNG;
this.BESATZUNGSKOSTEN = KopierSchiff.BESATZUNGSKOSTEN;
this.MANNSCHAFT_ERFAHRUNG = KopierSchiff.MANNSCHAFT_ERFAHRUNG;
this.MANNSCHAFT_VITALITÄT = KopierSchiff.MANNSCHAFT_VITALITÄT;
this.MANNSCHAFT_VORHANDEN = KopierSchiff.MANNSCHAFT_VORHANDEN;
this.MANNSCHAFT_UNTERWEGS = KopierSchiff.MANNSCHAFT_UNTERWEGS;
this.KAPITÄNSORDER = KopierSchiff.KAPITÄNSORDER;
}
public override void Update()
{
base.Update();
}
//Verwaltungsmethoden für Budget
public void erhöhenBudget(int Einnahmen)
{
SCHIFFSBUDGET += Einnahmen;
}
public void vermindernBudget(int Ausgaben)
{
SCHIFFSBUDGET -= Ausgaben;
}
public void initiereBau(DateTime FertigstellungAm)
{
//Funktion wird bei Bau des Schiffs aufgerufen um alles für den Bau festzusetzen
bezahlt = false;
inBau = true;
FERTIGSTELLUNGSDATUM = FertigstellungAm;
RESTBETRAGKAUFPREIS = NEUWERT - ANZAHLUNGSPREIS;
}
public void initiereBereitstellung(DateTime BereitstellungAm)
{
bezahlt = false;
inBereitstellung = true;
FERTIGSTELLUNGSDATUM = BereitstellungAm;
}
public void initiiereFertigstellung()
{
bezahlt = true;
inBau = false;
inBereitstellung = false;
}
public string schiffAbbezahlen(int GeldBetrag)
{
//Funktion wird aufgerufen um restbetrag zu tilgen (Aufrufendes Programm muss vorab abfangen, ob zu zahlender Betrag <= RESTBETRAGDESKAUFPREISES ist)
RESTBETRAGKAUFPREIS -= GeldBetrag;
if(RESTBETRAGKAUFPREIS > 0)
{
//Teilbetrag wurde getilgt
return "ERFOLG";
}
else
{
if (RESTBETRAGKAUFPREIS == 0)
{
//Schiff ist abbezahlt und bei erreichen des Datums wird schiff auf Spieler geschrieben
bezahlt = true;
return "ERFOLG_BEZAHLT";
}
else
{
//Falls man versucht hat mehr als den Restbetrag zu bezahlen
RESTBETRAGKAUFPREIS += GeldBetrag;
return "FEHLER";
}
}
}
public void setzeSchiffsTypParameter(string Typ)
{
//Hier werden alle Parameter des Schiffs gemäß seines Typs gesetzt
switch (Typ)
{
case "SCHONER":
KABINEN = 0;
MANNSCHAFT_MAXGRÖßE = 12;
LADERAUM = 300;
LIEFERZEIT = 78;
BAUMATERIAL = "HOLZ";
NEUWERT = 400000;
ANZAHLUNGSPREIS = 100000;
break;
case "BARK":
KABINEN = 0;
MANNSCHAFT_MAXGRÖßE = 14;
LADERAUM = 450;
LIEFERZEIT = 88;
BAUMATERIAL = "HOLZ";
NEUWERT = 600000;
ANZAHLUNGSPREIS = 150000;
break;
case "HOLZDAMPFSCHIFF":
KABINEN = 0;
MANNSCHAFT_MAXGRÖßE = 12;
LADERAUM = 399;
LIEFERZEIT = 85;
BAUMATERIAL = "HOLZ";
NEUWERT = 800000;
ANZAHLUNGSPREIS = 200000;
break;
case "EISENDAMPFSCHIFF":
KABINEN = 30;
MANNSCHAFT_MAXGRÖßE = 19;
LADERAUM = 699;
LIEFERZEIT = 104;
BAUMATERIAL = "EISEN";
NEUWERT = 1400000;
ANZAHLUNGSPREIS = 350000;
break;
case "BRIGG":
KABINEN = 0;
MANNSCHAFT_MAXGRÖßE = 19;
LADERAUM = 600;
LIEFERZEIT = 97;
BAUMATERIAL = "EISEN";
NEUWERT = 800000;
ANZAHLUNGSPREIS = 200000;
break;
case "FREGATTE":
KABINEN = 40;
MANNSCHAFT_MAXGRÖßE = 25;
LADERAUM = 999;
LIEFERZEIT = 123;
BAUMATERIAL = "EISEN";
NEUWERT = 1600000;
ANZAHLUNGSPREIS = 400000;
break;
case "KLIPPER":
KABINEN = 45;
MANNSCHAFT_MAXGRÖßE = 27;
LADERAUM = 1197;
LIEFERZEIT = 135;
BAUMATERIAL = "HOLZ";
NEUWERT = 1900000;
ANZAHLUNGSPREIS = 475000;
break;
}
}
//Verwaltungsmethoden für Waren (Überladung, damit man die Verwaltung sowohl mit dem Namen der Ware als auch mit der Ware selbst erledigen kann... jedenfalls beim Auslagern)
public void einlagernLadung(Ware neueWare)
{
// Einlagerung von Waren benötigt immer die effektiv erzeugte Ware
Ware TempWare = new Ware(neueWare);
//Überprüfen, ob dies hinzuzufügende Ware verderblich ist
if (neueWare.istVerderblich())
{
// Wenn ja, regulär hinzubuchen (verderbliche Ware verfolgt angepasste Logik)
// To Do: Einlagerlogik für verderbliche Ware implementieren
}
else
{
// Wenn Nein neue Ware wird erstellt und der Ladung hinzugefügt oder bei existierender Ware hinzugebucht
bool wareHinzugebucht = false;
foreach (Ware item in LADUNG)
{
if (item.BEZEICHNUNG == neueWare.BEZEICHNUNG)
{
item.MENGE += neueWare.MENGE;
wareHinzugebucht = true;
break;
}
}
if (!wareHinzugebucht)
{
LADUNG.Add(TempWare);
}
}
}
public void löscheLadung(string Ladung, int Menge)
{
// gegebenenfalls feature im Remake: Löschen der Ladung hat zeitaufwand(Eventuelle Dauer = 1 Tag in dem eventuell ausgeraubt werden kann)
bool verderblich = false;
// Vorabcheck ob Ware existiert und ob diese verderblich ist
foreach (Ware item in LADUNG)
{
if (item.BEZEICHNUNG == Ladung)
{
verderblich = item.istVerderblich();
//Wenn Ware gefunden wurde müssen wir nicht mehr weiter durchsuchen
break;
}
}
if (verderblich)
{
// Sonderlogik bei verderblicher Ware
// To Do: Implementieren / durchdenken!!
}
else
{
foreach (Ware item in LADUNG)
{
if (item.BEZEICHNUNG == Ladung)
{
// Angefragte Menge Reduzieren
// Wenn nicht mehr genug ware vorhanden ist wird null ausgegeben
if (item.MENGE - Menge < 0)
{
// Wenn auszulagernder Menge unter 0 ist ist ein fehler Passiert ergo nichts tun!
}
else
{
item.MENGE -= Menge;
// Wenn wir mit der Auslagerung das Lager geleert haben wird es aus dem Bestand genommen
if (item.MENGE == 0)
LADUNG.Remove(item);
}
//Wenn Ware gefunden wurde müssen wir nicht mehr weiter durchsuchen
break;
}
}
}
}
private void sortiereVerderblichListe()
{
//Aufspalten in 2 Listen(Verderbliche/normale Waren) -> am Ende wieder zusammen setzen (normale Waren werden an verderblichen drangehängt [damit die zuerst gelesen werden]
List<Ware> TempListe = new List<Ware>();
List<Ware> VerderbListe = new List<Ware>();
foreach (Ware item in LADUNG)
{
if (item.istVerderblich())
{
if (VerderbListe.Count() == 0)
{
VerderbListe.Add(item);
}
else
{
//Wenn Liste nicht leer ist -> Vergleiche MHDs miteinander und vorne/hinten anstellen (immer nur check erstes und letztes element weil rest bereits sortiert wurde
// schnelle sortiercodes gugen (ToDo)
}
}
else
{
//Wenn Ware nicht verderblich -> keine besondere Sortierlogik
TempListe.Add(item);
}
}
}
public void fahreInHafenEin(string HafenName)
{
angedocktAnHafen = HafenName;
}
public void fahreAusHafenHeraus()
{
if (angedocktAnHafen != "")
angedocktAnHafen = "";
}
public int verkaufsWertBestimmen()
{//Funktion ist vorgesehen für interner Verkaufswert zu bestimmen
// Wird erst eingebaut wenn schiffszustand(Reperaturen) implementiert sind und
// die Berechnung des Verkaufswertes vom schiff übernommen wird statt vom aufrufer
//Berechnung: (Neuwert/(Alter+1))*(100-Zustand des Schiffs in %)
return 0;
}
public void besatzungBereitstellen()
{
MANNSCHAFT_UNTERWEGS = true;
}
public void besatzungEinstellen(string BesatzungsTyp)
{
int PreisProNase = 0;
//Setzen der spezifischen Eigenschaften
switch (BesatzungsTyp)
{
case "SPITZE":
MANNSCHAFT_ERFAHRUNG = 100;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[0];
break;
case "ERFAHREN":
MANNSCHAFT_ERFAHRUNG = 90;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[1];
break;
case "TÜCHTIG":
MANNSCHAFT_ERFAHRUNG = 80;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[2];
break;
case "ZUVERLÄSSIG":
MANNSCHAFT_ERFAHRUNG = 70;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[3];
break;
case "STANDARD":
MANNSCHAFT_ERFAHRUNG = 60;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[4];
break;
case "FÄHIG":
MANNSCHAFT_ERFAHRUNG = 50;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[5];
break;
case "BRAUCHBAR":
MANNSCHAFT_ERFAHRUNG = 40;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[6];
break;
case "BILLIG":
MANNSCHAFT_ERFAHRUNG = 30;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[7];
break;
case "GRÜNSCHNABEL":
MANNSCHAFT_ERFAHRUNG = 20;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[8];
break;
case "IDIOTEN":
MANNSCHAFT_ERFAHRUNG = 10;
PreisProNase = Globals.MannschaftskostenMin + Globals.ErfahrungsFaktor[9];
break;
}
//Setzen Mannschaftskosten
this.BESATZUNGSKOSTEN = PreisProNase * MANNSCHAFT_MAXGRÖßE;
//Setzen der allgemeinen Eigenschaften
MANNSCHAFT_VORHANDEN = true;
MANNSCHAFT_UNTERWEGS = false;
MANNSCHAFT_VITALITÄT = 100;
KAPITÄNSORDER = "MITTEL";
}
}
}