import dfl.all;
import util;
import game;
import driver;
class GUI(Solver) : Form, GameObserver
{
this(in Game g)
{
this.solver = new Solver(g);
setup_size(g.map.W, g.map.H);
setup_resources(g);
draw(g);
}
void run(void delegate(char c) command, bool automate = true)
{
if(automate) {
Timer t = new Timer;
t.interval = 50;
t.tick ~= (Timer s, EventArgs e){command(solver.single_step());};
t.start();
this.closing ~= (Form f,CancelEventArgs c){t.stop();};
} else {
setup_keyhandling(command);
}
Application.run(this);
}
override void on_game_changed(char c, in Game g, bool finished)
{
draw(g);
}
private:
void setup_size(int W, int H)
{
this.formBorderStyle = FormBorderStyle.FIXED_DIALOG;
this.maximizeBox = false;
this.minimizeBox = false;
this.cell = min(1024/W, 640/H);
this.clientSize = Size(W*cell, H*cell);
}
int cell;
Font font;
Color[char] colors;
string[char] render;
Graphics graphicContext;
void setup_resources(in Game g)
{
this.graphicContext = new MemoryGraphics(this.clientSize.width, this.clientSize.height);
this.setStyle(ControlStyles.OPAQUE, true);
this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL);
this.backColor = Color(255,255,255);
this.colors['#'] =
this.colors['.'] = Color(255,191,127);
this.colors['*'] =
this.colors['@'] = Color(255,127,127);
this.colors['R'] = Color(128,128,0);
this.colors['r'] = Color(100,128,255);
this.colors['d'] = Color(255,0,0);
this.colors['\\'] =
this.colors['L'] =
this.colors['O'] = Color(127,255,127);
this.colors['w'] = Color(204,229,255);
this.colors['W'] =
this.colors['!'] = Color(159,159,159);
foreach(char c; 'A'..'J') this.colors[c] = Color(142,142,255);
foreach(char c; '1'..':') this.colors[c] = Color(255,142,255);
this.render['#'] = "■";
this.render['*'] = "✹";
this.render['@'] = "❁";
this.render['.'] = "♒";
this.render['\\'] = "λ";
this.render['R'] = "☃";
this.render['r'] = "☃";
this.render['d'] = "☠";
this.render['L'] = "☒";
this.render['O'] = "☐";
this.render['W'] = "ꔣ";
this.render['!'] = "✄";
foreach(c,tp; g.map.tr_target) this.render[c] = [cast(dchar)('☢'+g.map[tp]-'1')].to!string();
foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1')].to!string();
this.paint ~= (Control c, PaintEventArgs ev) {
graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientSize.width,this.clientSize.height));
};
}
void draw(in Game g)
{
int scrW = this.clientSize.width;
int scrH = this.clientSize.height;
// Fill bg.
graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH));
// Fill water.
int w = g.water_level();
graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell*w-1, scrW, cell*w+1));
// Paint map.
for(int y=1; y<=g.map.H; ++y)
for(int x=1; x<=g.map.W; ++x) {
Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell);
char c = g.map[y,x];
if( c != ' ' ) {
if( c == 'R' )
c = (g.dead ? 'd' : g.cleared ? 'r' : 'R');
graphicContext.drawText(this.render[c], font, this.colors[c], r);
}
}
// Update textual info.
this.text = .text(
"Score: ", g.score,
" Air: ", g.hp,
" Tide: ", g.water_until_rise,
" Wadler: ", g.hige_until_rise,
" Razor: ", g.map.razor);
invalidate();
}
private:
void setup_keyhandling(void delegate(char c) command)
{
noMessageFilter();
this.keyDown ~= (Control c, KeyEventArgs ev) {
void do_manual_command(char c)
{
solver.force(c);
command(c);
}
switch(ev.keyCode)
{
case Keys.DOWN: do_manual_command('D'); break;
case Keys.UP: do_manual_command('U'); break;
case Keys.LEFT: do_manual_command('L'); break;
case Keys.RIGHT: do_manual_command('R'); break;
case Keys.W: do_manual_command('W'); break;
case Keys.S: do_manual_command('S'); break;
case Keys.A: do_manual_command('A'); break;
case Keys.G: command(solver.single_step()); break;
default: break;
}
};
}
Solver solver;
}