using System.Drawing;
using Akwaier.Engine;
namespace Akwaier.Ui;
/// Een paneel dat zonder flikkeren tekent.
internal sealed class Tekenvlak : Panel
{
public Tekenvlak()
{
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint | ControlStyles.ResizeRedraw, true);
}
}
/// Het spelscherm: bord, gegevenspaneel, hand, knoppen en meldingen.
public sealed class SpelForm : Form
{
private const int TekenVak = 33; // vakgrootte bij 96 dpi
private const int TekenMarge = 22; // rand met de letters en cijfers
private const int InfoBreed = 372;
private Spel _spel;
private Thema _thema = Thema.Modern;
private float _s = 1f;
private int _vak, _marge;
private string _fase = "rust";
private int _gekozenPlaats = -1;
private Tekenvlak _bord, _info, _hand;
private FlowLayoutPanel _actie;
private Label _bericht, _beurtLabel;
private TextBox _log;
private Button _knopNieuw, _knopScores, _knopWeergave;
private CheckBox _knopSnel;
private readonly System.Windows.Forms.Timer _klok = new();
private Action _straks;
private Font _fGewoon, _fVet, _fKlein, _fVak, _fTitel;
public SpelForm()
{
Text = Taal.Titel;
FormBorderStyle = FormBorderStyle.FixedSingle;
MaximizeBox = false;
AutoScaleMode = AutoScaleMode.None;
StartPosition = FormStartPosition.CenterScreen;
// Het pictogram zit als Win32-hulpbron in de exe (ApplicationIcon).
try { Icon = Icon.ExtractAssociatedIcon(Environment.ProcessPath); }
catch (Exception) { /* zonder pictogram is ook prima */ }
_klok.Tick += (_, _) => { _klok.Stop(); var a = _straks; _straks = null; a?.Invoke(); };
BouwOp();
PasThemaToe();
Shown += (_, _) => NieuwSpel();
}
private int P(double v) => (int)Math.Round(v * _s);
private int Wacht(int gewoon) => _knopSnel.Checked ? Math.Max(15, gewoon / 8) : gewoon;
private void Straks(int ms, Action doen) { _straks = doen; _klok.Interval = Math.Max(1, ms); _klok.Start(); }
// --------------------------------------------------------------- opbouw
private void BouwOp()
{
_s = DeviceDpi / 96f;
_vak = P(TekenVak);
_marge = P(TekenMarge);
int zijde = 2 * _marge + 15 * _vak;
int rand = P(8);
int info = P(InfoBreed);
_knopNieuw = new Button { Text = Taal.NieuwSpel, AutoSize = true };
_knopNieuw.Click += (_, _) => NieuwSpel();
_knopScores = new Button { Text = Taal.Scorelijst, AutoSize = true };
_knopScores.Click += (_, _) => ToonScores();
_knopSnel = new CheckBox { Text = Taal.SnelSpelen, AutoSize = true };
_knopWeergave = new Button { Text = Taal.Weergave(Thema.Modern.Naam), AutoSize = true };
_knopWeergave.Click += (_, _) => WisselWeergave();
_beurtLabel = new Label { AutoSize = true, TextAlign = ContentAlignment.MiddleRight };
_bord = new Tekenvlak();
_bord.Paint += TekenBord;
_bord.MouseClick += BordAangeklikt;
_info = new Tekenvlak();
_info.Paint += TekenInfo;
_hand = new Tekenvlak();
_hand.Paint += TekenHand;
_hand.MouseClick += HandAangeklikt;
_actie = new FlowLayoutPanel { FlowDirection = FlowDirection.LeftToRight, WrapContents = false };
_bericht = new Label { AutoSize = false, TextAlign = ContentAlignment.MiddleLeft };
_log = new TextBox
{
Multiline = true, ReadOnly = true, ScrollBars = ScrollBars.Vertical,
BorderStyle = BorderStyle.None, TabStop = false,
};
int y = rand;
_knopNieuw.Location = new Point(rand, y);
Controls.Add(_knopNieuw);
_knopScores.Location = new Point(rand, y); // wordt hieronder verschoven
Controls.Add(_knopScores);
_knopSnel.Location = new Point(rand, y + P(4));
Controls.Add(_knopSnel);
Controls.Add(_knopWeergave);
Controls.Add(_beurtLabel);
int bordY = y + P(38);
_bord.SetBounds(rand, bordY, zijde, zijde);
_info.SetBounds(rand + zijde + rand, bordY, info, zijde);
Controls.Add(_bord);
Controls.Add(_info);
int handY = bordY + zijde + rand;
_hand.SetBounds(rand, handY, zijde, P(64));
Controls.Add(_hand);
int actieY = handY + P(72);
_actie.SetBounds(rand, actieY, zijde, P(34));
Controls.Add(_actie);
int berichtY = actieY + P(38);
_bericht.SetBounds(rand, berichtY, zijde, P(22));
Controls.Add(_bericht);
ClientSize = new Size(rand + zijde + rand + info + rand, berichtY + P(22) + rand);
_log.SetBounds(rand + zijde + rand, handY, info, ClientSize.Height - handY - rand);
Controls.Add(_log);
// de knoppen rechtsboven pas plaatsen nu de breedte bekend is
_knopNieuw.Location = new Point(rand, y);
_knopScores.Location = new Point(rand + _knopNieuw.Width + P(6), y);
_knopSnel.Location = new Point(_knopScores.Right + P(14), y + P(4));
_knopWeergave.Location = new Point(ClientSize.Width - rand - _knopWeergave.Width, y);
_beurtLabel.Location = new Point(_knopWeergave.Left - P(16) - _beurtLabel.Width, y + P(4));
}
///
/// Maakt de lettertypen van de gekozen weergave. De oude worden pas
/// weggegooid als geen enkel besturingselement ze meer gebruikt; anders
/// loopt de eerstvolgende tekenbeurt vast op een opgeruimd lettertype.
///
private Font[] MaakLettertypen()
{
var oud = new[] { _fGewoon, _fVet, _fKlein, _fVak, _fTitel };
string f = _thema.Lettertype;
_fGewoon = new Font(f, 9f);
_fVet = new Font(f, 9f, FontStyle.Bold);
_fKlein = new Font(f, 7.5f);
_fVak = new Font(f, 12f, FontStyle.Bold);
_fTitel = new Font(f, 11f, FontStyle.Bold);
return oud;
}
// ---------------------------------------------------------------- skins
private void WisselWeergave()
{
_thema = _thema == Thema.Modern ? Thema.Retro : Thema.Modern;
PasThemaToe();
}
private void PasThemaToe()
{
Font[] oudeLetters = MaakLettertypen();
var t = _thema;
BackColor = t.Achtergrond;
Font = _fGewoon;
foreach (var knop in new[] { _knopNieuw, _knopScores, _knopWeergave }) KnopKleur(knop);
_knopSnel.BackColor = t.Achtergrond;
_knopSnel.ForeColor = t.Voorgrond;
// Standard tekent een net vinkje en houdt zich wel aan ForeColor; bij
// System zet Windows de tekst in de systeemkleur en valt die weg op zwart.
_knopSnel.FlatStyle = FlatStyle.Standard;
_knopSnel.Font = _fGewoon;
_beurtLabel.BackColor = t.Achtergrond;
_beurtLabel.ForeColor = t.Voorgrond;
_beurtLabel.Font = _fTitel;
_bericht.BackColor = t.Achtergrond;
_bericht.ForeColor = t.Gedempt;
_bericht.Font = _fGewoon;
_actie.BackColor = t.Achtergrond;
_log.BackColor = t.LogAchter;
_log.ForeColor = t.LogVoor;
_log.Font = _fKlein;
_bord.BackColor = t.Achtergrond;
_info.BackColor = t.Achtergrond;
_hand.BackColor = t.Achtergrond;
_knopWeergave.Text = Taal.Weergave(t.Naam);
foreach (Control c in _actie.Controls)
{
switch (c)
{
case Button b when b.Tag is int keten: // knop met een ketenkleur
b.Font = _fVet;
b.BackColor = t.KetenAchter[keten];
b.ForeColor = t.KetenVoor[keten];
b.FlatAppearance.BorderColor = t.Raster;
b.FlatAppearance.MouseOverBackColor = t.KetenAchter[keten];
break;
case Button b:
KnopKleur(b);
break;
case Label l:
l.Font = _fGewoon;
l.BackColor = t.Achtergrond;
l.ForeColor = t.Voorgrond;
break;
}
}
HerplaatsKop();
Herteken();
foreach (var f in oudeLetters) f?.Dispose();
}
private void KnopKleur(Button b)
{
b.FlatStyle = FlatStyle.Flat;
b.FlatAppearance.BorderSize = 0;
b.FlatAppearance.MouseOverBackColor = _thema.KnopZweef;
b.BackColor = _thema.Knop;
b.ForeColor = _thema.KnopVoor;
b.Font = _fGewoon;
b.UseVisualStyleBackColor = false;
}
///
/// De vaste opschriften opnieuw zetten nadat er in het startvenster een
/// andere taal is gekozen. Het bord en het gegevenspaneel halen hun tekst
/// bij elke tekenbeurt op en hoeven hier niets te doen.
///
private void PasTaalToe()
{
Text = Taal.Titel;
_knopNieuw.Text = Taal.NieuwSpel;
_knopScores.Text = Taal.Scorelijst;
_knopSnel.Text = Taal.SnelSpelen;
_knopWeergave.Text = Taal.Weergave(_thema.Naam);
HerplaatsKop();
}
private void HerplaatsKop()
{
int rand = P(8), y = P(8);
_knopScores.Location = new Point(rand + _knopNieuw.Width + P(6), y);
_knopSnel.Location = new Point(_knopScores.Right + P(14), y + P(4));
_knopWeergave.Location = new Point(ClientSize.Width - rand - _knopWeergave.Width, y);
_beurtLabel.Location = new Point(_knopWeergave.Left - P(16) - _beurtLabel.Width, y + P(5));
}
private void Herteken()
{
_bord.Invalidate();
_info.Invalidate();
_hand.Invalidate();
if (_spel != null)
{
_beurtLabel.Text = _spel.Klaar
? Taal.SpelAfgelopen
: _spel.AanDeBeurt > 0
? Taal.BeurtVan(_spel.Beurt, Regels.MaxBeurten,
_spel.Spelers[_spel.AanDeBeurt].Naam)
: "";
HerplaatsKop();
}
}
// ----------------------------------------------------------- nieuw spel
private void NieuwSpel()
{
using var dlg = new NieuwSpelForm(_thema, _fGewoon, _fTitel, _fKlein);
if (dlg.ShowDialog(this) != DialogResult.OK) return;
PasTaalToe();
_spel = new Spel(dlg.Plaats, dlg.SpelerNaam);
_fase = "rust";
_gekozenPlaats = -1;
_log.Clear();
if (dlg.Plaats > 0)
{
Meld(Taal.JeSpeeltAls(dlg.Plaats, _spel.Spelers[dlg.Plaats].Naam));
Meld(Taal.KiesEenSteenKort);
}
else Meld(Taal.Kijkmodus);
Meld(new string('-', 44));
Herteken();
Straks(300, Stap);
}
// -------------------------------------------------------------- beurten
private void Stap()
{
if (_spel == null) return;
int p = _spel.VolgendeSpeler();
if (p == 0) { Afgelopen(); return; }
WisKnoppen();
Herteken();
if (_spel.Spelers[p].Mens) BeginMensBeurt();
else Straks(Wacht(320), () => ComputerZet(p));
}
private void ComputerZet(int p)
{
foreach (string r in _spel.ComputerBeurt(p)) Meld(r);
Herteken();
Straks(Wacht(300), Stap);
}
private void BeginMensBeurt()
{
_gekozenPlaats = -1;
_fase = "leggen";
var geldig = _spel.GeldigePlaatsen(_spel.AanDeBeurt);
Herteken();
WisKnoppen();
if (geldig.Count == 0)
{
_bericht.Text = Taal.GeenSteenKwijt;
_fase = "pas";
Knop(Taal.PasDezeBeurt, () =>
{
_spel.Past();
Meld(Taal.KanNiet(_spel.Spelers[_spel.AanDeBeurt].Naam));
WisKnoppen();
Stap();
});
return;
}
_bericht.Text = Taal.KiesEenSteen;
}
private void KiesPlaats(int plaats)
{
if (_fase != "leggen" || plaats < 0 || plaats >= Regels.HandGrootte) return;
int speler = _spel.AanDeBeurt;
int steen = _spel.Hand(speler, plaats);
if (steen == 0) { _bericht.Text = Taal.HandplaatsLeeg; return; }
_gekozenPlaats = plaats;
var (x, y) = Regels.TegelPositie(steen);
var kans = _spel.Bekijk(x, y);
WisKnoppen();
Tekstje(Taal.SteenIs(plaats + 1, Regels.Naam(x, y)));
if (kans.Mag)
{
string tekst = kans.Aanliggend.Count == 0
? Taal.LegLos(Regels.Naam(x, y))
: Taal.LegBij(Regels.Naam(x, y), Regels.KetenLetter(kans.Winnaar));
Knop(tekst, () => LegNeer(plaats, 0));
}
else Tekstje(Taal.MagHierNiet);
if (_spel.KanStichten(x, y) && _spel.TeStichten().Count > 0)
Knop(Taal.StichtOp(Regels.Naam(x, y)), () => VraagStichtKleur(plaats));
Knop(Taal.Annuleer, BeginMensBeurt);
Herteken();
}
private void VraagStichtKleur(int plaats)
{
_fase = "stichten";
WisKnoppen();
Tekstje(Taal.WelkeKetenStichten);
foreach (int c in _spel.TeStichten())
{
int keten = c;
KetenKnop(keten, "", () =>
{
var r = _spel.Sticht(_spel.AanDeBeurt, plaats, keten);
Meld(Taal.StichtKetenMetAandeel(_spel.Spelers[_spel.AanDeBeurt].Naam,
Regels.KetenLetter(keten),
Regels.Naam(r.X, r.Y)));
BeginKoopfase();
});
}
Knop(Taal.Annuleer, BeginMensBeurt);
}
private void LegNeer(int plaats, int gekozenWinnaar)
{
var (x, y) = Regels.TegelPositie(_spel.Hand(_spel.AanDeBeurt, plaats));
var kans = _spel.Bekijk(x, y);
if (kans.Gelijkspel && gekozenWinnaar == 0)
{
_fase = "gelijk";
WisKnoppen();
Tekstje(Taal.WelkeBlijft);
foreach (int c in kans.Gelijken)
{
int keten = c;
KetenKnop(keten, "", () => LegNeer(plaats, keten));
}
return;
}
var verslag = _spel.Leg(_spel.AanDeBeurt, plaats, gekozenWinnaar);
foreach (string r in _spel.Beschrijf(_spel.Spelers[_spel.AanDeBeurt].Naam, verslag)) Meld(r);
BeginKoopfase();
}
// ---------------------------------------------------------------- kopen
private void BeginKoopfase()
{
_gekozenPlaats = -1;
_fase = "kopen";
Herteken();
WisKnoppen();
int geld = _spel.Spelers[_spel.AanDeBeurt].Geld;
var ketens = _spel.BestaandeKetens().Where(c => _spel.Prijs(c) <= geld).ToList();
if (ketens.Count == 0)
{
_bericht.Text = Taal.NietsTeKopen;
Knop(Taal.Verder, RondBeurtAf);
return;
}
_bericht.Text = Taal.KoopHoogstensDrie;
Tekstje(Taal.KopenDubbelepunt);
foreach (int c in ketens)
{
int keten = c;
KetenKnop(keten, $" {_spel.Prijs(keten)}", () => VraagAantal(keten));
}
Knop(Taal.KoopNiets, RondBeurtAf);
}
private void VraagAantal(int keten)
{
int prijs = _spel.Prijs(keten);
int geld = _spel.Spelers[_spel.AanDeBeurt].Geld;
WisKnoppen();
Tekstje(Taal.HoeveelVan(Regels.KetenLetter(keten), prijs));
for (int n = 1; n <= 3; n++)
{
if (prijs * n > geld) continue;
int aantal = n;
Knop(aantal.ToString(), () =>
{
int gekocht = _spel.Koop(_spel.AanDeBeurt, keten, aantal);
if (gekocht > 0)
Meld(Taal.Koopt(_spel.Spelers[_spel.AanDeBeurt].Naam, gekocht,
Regels.KetenLetter(keten), prijs));
RondBeurtAf();
});
}
Knop(Taal.Terug, BeginKoopfase);
}
private void RondBeurtAf()
{
WisKnoppen();
_bericht.Text = "";
Herteken();
Straks(Wacht(200), Stap);
}
// ----------------------------------------------------------------- einde
private void Afgelopen()
{
_fase = "klaar";
WisKnoppen();
Herteken();
Meld(new string('=', 44));
Meld(Taal.Einde(_spel.Eindreden));
int plek = 1;
foreach (var (_, naam, vermogen) in _spel.Eindstand())
Meld($"{plek++}. {naam,-8} {vermogen}");
Scorelijst.Bijwerken(Enumerable.Range(1, Regels.AantalSpelers)
.Select(i => (_spel.Spelers[i].Naam, _spel.Vermogen(i))));
_bericht.Text = Taal.SpelAfgelopenMet(_spel.Eindreden);
Knop(Taal.Scorelijst, ToonScores);
Knop(Taal.NieuwSpel, NieuwSpel);
}
private void ToonScores()
{
using var dlg = new ScoreForm(_thema, _fGewoon, _fVet);
dlg.ShowDialog(this);
}
// --------------------------------------------------------- knoppenstrook
private void WisKnoppen()
{
foreach (Control c in _actie.Controls.Cast().ToList()) { _actie.Controls.Remove(c); c.Dispose(); }
}
private void Tekstje(string tekst)
{
var l = new Label
{
Text = tekst, AutoSize = true, ForeColor = _thema.Voorgrond,
BackColor = _thema.Achtergrond, Font = _fGewoon,
Margin = new Padding(0, P(6), P(8), 0),
};
_actie.Controls.Add(l);
}
private void Knop(string tekst, Action doen)
{
var b = new Button { Text = tekst, AutoSize = true, Margin = new Padding(P(3), P(2), P(3), 0) };
b.Click += (_, _) => doen();
KnopKleur(b);
_actie.Controls.Add(b);
}
private void KetenKnop(int keten, string extra, Action doen)
{
var b = new Button
{
Text = Regels.KetenLetter(keten) + extra,
AutoSize = true,
Margin = new Padding(P(2), P(2), P(2), 0),
FlatStyle = FlatStyle.Flat,
BackColor = _thema.KetenAchter[keten],
ForeColor = _thema.KetenVoor[keten],
Font = _fVet,
UseVisualStyleBackColor = false,
Tag = keten,
};
b.FlatAppearance.BorderSize = 1;
b.FlatAppearance.BorderColor = _thema.Raster;
b.FlatAppearance.MouseOverBackColor = _thema.KetenAchter[keten];
b.Click += (_, _) => doen();
_actie.Controls.Add(b);
}
private void Meld(string tekst)
{
_log.AppendText(tekst + Environment.NewLine);
_log.SelectionStart = _log.TextLength;
_log.ScrollToCaret();
}
// --------------------------------------------------------------- tekenen
private const TextFormatFlags Midden =
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding;
private const TextFormatFlags Links =
TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding;
private const TextFormatFlags Rechts =
TextFormatFlags.Right | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding;
private void TekenBord(object zender, PaintEventArgs e)
{
var g = e.Graphics;
var t = _thema;
g.Clear(t.Achtergrond);
if (_spel == null) return;
int mens = _spel.MensPlaats;
var eigen = new Dictionary<(int, int), int>();
if (mens > 0 && _spel.AanDeBeurt == mens && !_spel.Klaar)
for (int s = 0; s < Regels.HandGrootte; s++)
{
int steen = _spel.Hand(mens, s);
if (steen != 0) eigen[Regels.TegelPositie(steen)] = s;
}
// randlabels: kolommen boven en onder, rijletters links en rechts
for (int i = 1; i <= Regels.Grootte; i++)
{
string kop = t.BbcKolomkop ? (i % 10).ToString() : i.ToString();
int px = _marge + (i - 1) * _vak;
TekstIn(g, kop, _fKlein, new Rectangle(px, 0, _vak, _marge), t.Gedempt, Midden);
TekstIn(g, kop, _fKlein, new Rectangle(px, _marge + 15 * _vak, _vak, _marge), t.Gedempt, Midden);
string rij = ((char)('A' + i - 1)).ToString();
int py = _marge + (i - 1) * _vak;
TekstIn(g, rij, _fKlein, new Rectangle(0, py, _marge, _vak), t.Gedempt, Midden);
TekstIn(g, rij, _fKlein, new Rectangle(_marge + 15 * _vak, py, _marge, _vak), t.Gedempt, Midden);
}
using var raster = new Pen(t.Raster);
for (int x = 1; x <= Regels.Grootte; x++)
for (int y = 1; y <= Regels.Grootte; y++)
{
int x0 = _marge + (x - 1) * _vak, y0 = _marge + (y - 1) * _vak;
var vak = new Rectangle(x0 + 1, y0 + 1, _vak - 2, _vak - 2);
int v = _spel.Vak(x, y);
bool isEigen = eigen.TryGetValue((x, y), out int plaats);
bool mag = isEigen && _spel.Bekijk(x, y).Mag;
Color achter = v >= 1 && v <= 8 ? t.KetenAchter[v]
: v == Regels.Los ? t.Band
: mag ? t.Wenk : t.LeegVak;
using (var kwast = new SolidBrush(achter)) g.FillRectangle(kwast, vak);
g.DrawRectangle(raster, vak);
if (v >= 1 && v <= 8)
TekstIn(g, Regels.KetenLetter(v).ToString(), _fVak, vak, t.KetenVoor[v], Midden);
else if (v == Regels.Los)
{
int in8 = Math.Max(2, _vak / 4);
using var kwast = new SolidBrush(t.Los);
g.FillRectangle(kwast, x0 + in8, y0 + in8, _vak - 2 * in8, _vak - 2 * in8);
}
else if (!isEigen)
{
int r = Math.Max(1, _vak / 14);
using var kwast = new SolidBrush(t.Stip);
g.FillEllipse(kwast, x0 + _vak / 2 - r, y0 + _vak / 2 - r, 2 * r, 2 * r);
}
if (isEigen)
{
// net als regel 3571: de handnummers staan op het bord
TekstIn(g, (plaats + 1).ToString(), _fVet, vak, mag ? t.Voorgrond : t.Gedempt, Midden);
if (plaats == _gekozenPlaats)
{
using var dik = new Pen(t.Keuze, Math.Max(2, P(3)));
g.DrawRectangle(dik, x0 + 2, y0 + 2, _vak - 5, _vak - 5);
}
}
}
}
private void TekenHand(object zender, PaintEventArgs e)
{
var g = e.Graphics;
var t = _thema;
g.Clear(t.Achtergrond);
if (_spel == null) return;
int mens = _spel.MensPlaats;
if (mens == 0)
{
TekstIn(g, Taal.KijkmodusGeenStenen, _fGewoon,
new Rectangle(P(4), 0, P(400), _hand.Height), t.Gedempt, Links);
return;
}
TekstIn(g, Taal.StenenVan(_spel.Spelers[mens].Naam), _fKlein,
new Rectangle(P(4), 0, P(300), P(18)), t.Gedempt, Links);
var geldig = _spel.AanDeBeurt == mens
? new HashSet(_spel.GeldigePlaatsen(mens))
: new HashSet();
for (int s = 0; s < Regels.HandGrootte; s++)
{
int x0 = P(4) + s * P(66), y0 = P(20);
var vak = new Rectangle(x0, y0, P(60), P(38));
int steen = _spel.Hand(mens, s);
if (steen == 0)
{
using var stippel = new Pen(t.Raster) { DashStyle = System.Drawing.Drawing2D.DashStyle.Dot };
using var leeg = new SolidBrush(t.LeegVak);
g.FillRectangle(leeg, vak);
g.DrawRectangle(stippel, vak);
continue;
}
bool kan = geldig.Contains(s);
using (var kwast = new SolidBrush(kan ? t.Band : t.LeegVak)) g.FillRectangle(kwast, vak);
using (var pen = new Pen(s == _gekozenPlaats ? t.Keuze : t.Raster,
s == _gekozenPlaats ? Math.Max(2, P(3)) : 1))
g.DrawRectangle(pen, vak);
TekstIn(g, (s + 1).ToString(), _fKlein,
new Rectangle(x0 + P(6), y0 + P(2), P(16), P(14)), t.Gedempt, Links);
var (tx, ty) = Regels.TegelPositie(steen);
TekstIn(g, Regels.Naam(tx, ty), _fVet, vak, kan ? t.Voorgrond : t.Gedempt, Midden);
}
}
private void TekenInfo(object zender, PaintEventArgs e)
{
var g = e.Graphics;
var t = _thema;
g.Clear(t.Achtergrond);
if (_spel == null) return;
int w = _info.Width;
int Band(int y, params (double X, TextFormatFlags Vlag, string Tekst)[] kolommen)
{
using (var kwast = new SolidBrush(t.KopAchter)) g.FillRectangle(kwast, 0, y, w, P(20));
foreach (var (x, vlag, tekst) in kolommen)
TekstIn(g, tekst, _fVet, Vlak(x, y, vlag), t.KopVoor, vlag);
return y + P(22);
}
int ry = Band(0, (6, Links, Taal.KopKeten), (150, Rechts, Taal.KopPrijs),
(230, Rechts, Taal.KopTegels), (250, Links, Taal.KopStatus));
for (int c = 1; c <= Regels.AantalKetens; c++)
{
Vlagje(g, c, ry);
int n = _spel.KetenGrootte(c);
TekstIn(g, n > 0 ? _spel.Prijs(c).ToString() : "-", _fGewoon, Vlak(150, ry, Rechts), t.Voorgrond, Rechts);
TekstIn(g, n > 0 ? n.ToString() : "-", _fGewoon, Vlak(230, ry, Rechts), t.Voorgrond, Rechts);
if (n == 0) TekstIn(g, Taal.TeStichten, _fKlein, Vlak(250, ry, Links), t.Gedempt, Links);
ry += P(19);
}
ry = Band(ry + P(6), (6, Links, Taal.KopAandelen));
for (int i = 1; i <= Regels.AantalSpelers; i++)
TekstIn(g, i.ToString(), _fKlein,
new Rectangle(P(48 + i * 44), ry, P(24), P(16)), t.Gedempt, Midden);
ry += P(17);
for (int c = 1; c <= Regels.AantalKetens; c++)
{
Vlagje(g, c, ry);
int[] rang = _spel.Rangorde(c);
for (int i = 1; i <= Regels.AantalSpelers; i++)
{
int n = _spel.Spelers[i].Aandelen[c];
Color kleur = n == 0 ? t.Raster
: i == rang[0] ? t.Keuze
: i == rang[1] ? t.Gedempt : t.Voorgrond;
var vet = n > 0 && (i == rang[0] || i == rang[1]) ? _fVet : _fGewoon;
TekstIn(g, n > 0 ? n.ToString() : ".", vet,
new Rectangle(P(48 + i * 44), ry, P(24), P(18)), kleur, Midden);
}
ry += P(19);
}
ry = Band(ry + P(6), (8, Links, Taal.KopSpeler), (250, Rechts, Taal.KopGeld),
(360, Rechts, Taal.KopVermogen));
for (int i = 1; i <= Regels.AantalSpelers; i++)
{
var p = _spel.Spelers[i];
bool actief = i == _spel.AanDeBeurt && !_spel.Klaar;
if (actief)
using (var kwast = new SolidBrush(t.Band)) g.FillRectangle(kwast, 0, ry, w, P(18));
string naam = $"{p.Nummer} {p.Naam}" + (p.Mens ? Taal.Jij : "");
TekstIn(g, naam, actief ? _fVet : _fGewoon, Vlak(8, ry, Links), t.Voorgrond, Links);
TekstIn(g, p.Geld.ToString(), _fGewoon, Vlak(250, ry, Rechts), t.Voorgrond, Rechts);
TekstIn(g, _spel.Vermogen(i).ToString(), _fGewoon, Vlak(360, ry, Rechts), t.Voorgrond, Rechts);
ry += P(19);
}
TekstIn(g, Taal.StenenInDeZak(_spel.Zak.Count), _fKlein,
Vlak(8, ry + P(4), Links), t.Gedempt, Links);
}
/// Het gekleurde vierkantje met de ketenletter in het gegevenspaneel.
private void Vlagje(System.Drawing.Graphics g, int keten, int y)
{
var vak = new Rectangle(P(6), y, P(24), P(18));
using (var kwast = new SolidBrush(_thema.KetenAchter[keten])) g.FillRectangle(kwast, vak);
using (var pen = new Pen(_thema.Raster)) g.DrawRectangle(pen, vak);
TekstIn(g, Regels.KetenLetter(keten).ToString(), _fVet, vak, _thema.KetenVoor[keten], Midden);
}
/// Een tekstvak van 18 hoog dat links, rechts of midden uitlijnt op x.
private Rectangle Vlak(double x, int y, TextFormatFlags vlag)
{
int px = P(x), breed = P(150);
if (vlag == Rechts) return new Rectangle(px - breed, y, breed, P(18));
return new Rectangle(px, y, breed, P(18));
}
private static void TekstIn(System.Drawing.Graphics g, string s, Font f, Rectangle r,
Color kleur, TextFormatFlags vlag)
=> TextRenderer.DrawText(g, s, f, r, kleur, vlag);
// ----------------------------------------------------------------- muis
private void BordAangeklikt(object zender, MouseEventArgs e)
{
if (_spel == null || _fase != "leggen" || _spel.MensPlaats == 0) return;
int x = (e.X - _marge) / _vak + 1, y = (e.Y - _marge) / _vak + 1;
if (e.X < _marge || e.Y < _marge || x < 1 || x > Regels.Grootte || y < 1 || y > Regels.Grootte) return;
for (int s = 0; s < Regels.HandGrootte; s++)
{
int steen = _spel.Hand(_spel.AanDeBeurt, s);
if (steen != 0 && Regels.TegelPositie(steen) == (x, y)) { KiesPlaats(s); return; }
}
_bericht.Text = Taal.NietInJeHand(Regels.Naam(x, y));
}
private void HandAangeklikt(object zender, MouseEventArgs e)
{
if (_fase != "leggen") return;
int s = (e.X - P(4)) / P(66);
if (s >= 0 && s < Regels.HandGrootte) KiesPlaats(s);
}
protected override bool ProcessCmdKey(ref Message msg, Keys toets)
{
if (_fase == "leggen" && toets >= Keys.D1 && toets <= Keys.D8)
{
KiesPlaats(toets - Keys.D1);
return true;
}
return base.ProcessCmdKey(ref msg, toets);
}
}