Show gamestate.cpp syntax highlighted
/***************************************************************************
gamestate.cpp
-------------------
begin : Fri Feb 4 2005
copyright : (C) 2005 by Brendon Lloyd Higgins
email : bh_doc@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include <client.h>
#include <clientmisc.h>
#include <common.h>
#include <corner.h>
#include <entityclientfactory.h>
#include <gamestate.h>
#include <maptileclient.h>
#include <messagebox.h>
#include <playerclient.h>
#include <rules.h>
#include <worldpos.h>
#include <worldclient.h>
#include <ClanLib/core.h>
GameState::GameState(CL_NetSession* ns, const CL_NetComputer& s,
PlayerList* p, PlayerClient* m, Rules* r, WorldClient* w,
bool sp):
client(0),
netsession(ns),
server(s),
players(p),
me(m),
rules(r),
world(w),
logicState(sp ? PAUSE : PLAY),
uiState(NOTHING),
dragging(false),
displayOffset(0, 0),
zoom(1.0),
zoomLevel(0),
cornerPointerDraw(-1),
messages(0),
pod(0),
componentManager(0) {
}
GameState::~GameState() {
}
ClientState* GameState::go(Client* c) {
client = c;
int screenWidth = CL_Display::get_width();
int screenHeight = CL_Display::get_height();
onNothingState();
CL_Slot slotCloseWindow = CL_Display::sig_window_close().connect(this,
&GameState::onCloseWindow);
CL_Slot slotInputUp = CL_Display::get_current_window()->get_ic()
->get_keyboard().sig_key_up().connect(this, &GameState::onInputUp);
CL_Slot fpsLogger = client->getTempo().getFramesSignal().connect(this,
&GameState::onFrames);
worldComp = new CL_Component(CL_Rect(0, 0, screenWidth,
screenHeight), client->getGuiManager());
// TODO Why the fuck doesn't this work?
CL_Slot slotTileMoved = world->getMap()->sigTileMoved().connect(
this, &GameState::onTileMoved);
CL_Slot slotMUp = worldComp->sig_mouse_up().connect(this,
&GameState::onMouseUp);
CL_Slot slotMDown = worldComp->sig_mouse_down().connect(this,
&GameState::onMouseDown);
cornerPointer = new CL_Sprite("gui/main/corner_pointer",
client->getResources());
subCornerPointer = new CL_Sprite("gui/main/corner_pointer_small",
client->getResources());
componentManager = new CL_ComponentManager(
"gui/main", client->getResources(), client->getGuiManager());
messages = new MessageBox(
CL_Rect(0, 0, screenWidth, 100), worldComp,
CL_Font("Button/font", client->getResources()));
messages->addLine("Howdy howdy!");
CL_Slot slotSay = netsession->sig_netpacket_receive(
Network::Channel::SAY).connect(this, &GameState::onSay);
CL_Slot slotAdmin = netsession->sig_netpacket_receive(
Network::Channel::ADMIN).connect(this, &GameState::onAdmin);
pod = new PlayerOptionsDialog(CL_Point(310, 10), worldComp, me);
CL_Slot slotPlayerOptionsDialogApply = pod->sigApply()
.connect(this, &GameState::onPlayerOptionsDialogApply);
CL_Slot slotPlayerColourChange = PlayerClient::sigColourChange().connect(
this, &GameState::onPlayerColourChange);
CL_Slot slotPlayerNameChange = PlayerClient::sigNameChange().connect(
this, &GameState::onPlayerNameChange);
CL_Button* button;
componentManager->get_component("close", &button);
button->set_position(screenWidth - 32, screenHeight - 32);
CL_Slot slotCloseButton = button->sig_clicked()
.connect(this, &GameState::onCloseWindow);
componentManager->get_component("pause", &button);
button->set_position(screenWidth - 32, screenHeight - 64);
CL_Slot slotPauseButton = button->sig_clicked()
.connect(this, &GameState::onPauseButton);
componentManager->get_component("zoom_out", &button);
button->set_position(screenWidth - 64, screenHeight - 32);
CL_Slot slotZoomOutButton = button->sig_clicked()
.connect(this, &GameState::onZoomOutButton);
componentManager->get_component("zoom_in", &button);
button->set_position(screenWidth - 64, screenHeight - 64);
CL_Slot slotZoomInButton = button->sig_clicked()
.connect(this, &GameState::onZoomInButton);
componentManager->get_component("rotate_anti", &button);
button->set_position(screenWidth - 96, screenHeight - 32);
CL_Slot slotRotateAntiButton = button->sig_clicked()
.connect(this, &GameState::onRotateAntiButton);
componentManager->get_component("rotate_clock", &button);
button->set_position(screenWidth - 96, screenHeight - 64);
CL_Slot slotRotateClockButton = button->sig_clicked()
.connect(this, &GameState::onRotateClockButton);
componentManager->get_component("config", &button);
button->set_position(screenWidth - 128, screenHeight - 32);
CL_Slot slotConfigButton = button->sig_clicked()
.connect(this, &GameState::onConfigButton);
componentManager->get_component("movemagnet", &button);
button->set_position(screenWidth - 128, screenHeight - 64);
CL_Slot slotMoveMagnetButton = button->sig_clicked()
.connect(this, &GameState::onMoveMagnetButton);
componentManager->get_component("land_updown", &button);
button->set_position(screenWidth - 160, screenHeight - 32);
CL_Slot slotLandManip = button->sig_clicked()
.connect(this, &GameState::onMovingLandButton);
componentManager->get_component("forest", &button);
button->set_position(screenWidth - 160, screenHeight - 64);
CL_Slot slotForestButton = button->sig_clicked()
.connect(this, &GameState::onForestButton);
componentManager->get_component("firecolumn", &button);
button->set_position(screenWidth - 192, screenHeight - 32);
CL_Slot slotFireColumnButton = button->sig_clicked()
.connect(this, &GameState::onFireColumnButton);
componentManager->get_component("swamp", &button);
button->set_position(screenWidth - 192, screenHeight - 64);
CL_Slot slotSwampButton = button->sig_clicked()
.connect(this, &GameState::onSwampButton);
while (logicState == PLAY || logicState == PAUSE) {
if (logicState == PLAY) {
world->predict(client->getTempo().getDelay());
world->drawUpdate(client->getTempo().getDelay());
}
CL_Display::clear(CL_Color(0, 0, 127));
CL_Display::push_modelview();
CL_Display::set_translate(-displayOffset.x, -displayOffset.y);
CL_Display::add_scale(zoom, zoom);
world->draw();
if (cornerPointerDraw != -1) {
for (int i = 0; i < 4; ++i) {
if (i == cornerPointerDraw) {
cornerPointer->draw(cornerPointerLoc[i].x,
cornerPointerLoc[i].y);
} else {
subCornerPointer->draw(cornerPointerLoc[i].x,
cornerPointerLoc[i].y);
}
}
}
CL_Display::pop_modelview();
client->getGuiManager()->show();
CL_Display::flip();
CL_System::keep_alive();
}
delete componentManager;
delete cornerPointer;
delete subCornerPointer;
delete pod;
delete messages;
delete worldComp;
if (logicState == END) {
// Go to the score screen, or something.
return 0;
} else if (logicState == DISCONNECT) {
// Kill some stuff, go to main menu.
return 0;
} else {
// logicState == QUIT
delete world;
EntityClientFactory::freeSprites();
MapTileClient::freeSprites();
delete rules;
for (PlayerList::iterator i = players->begin(); i != players->end();
++i) {
delete *i;
}
delete players;
server.disconnect("Client quitting.");
delete netsession;
return 0;
}
}
CL_Point GameState::screenToWorld(const CL_Point& p) const {
return CL_Point(int((p.x + displayOffset.x) / zoom),
int((p.y + displayOffset.y) / zoom));
}
CL_Point GameState::worldToScreen(const CL_Point& p) const {
return CL_Point(int(p.x * zoom) - displayOffset.x,
int(p.y * zoom) - displayOffset.y);
}
CL_Point GameState::getScreenCenterOffset() const {
return CL_Point(CL_Display::get_width() / 2, CL_Display::get_height() / 2);
}
WorldPos GameState::getScreenCenterPosLocal(bool* onWorld) const {
CL_Point p = screenToWorld(getScreenCenterOffset());
boost::optional<WorldPos> op = world->getMap()->findPosLocal(p);
if (op) {
if (onWorld) *onWorld = true;
return *op;
}
if (onWorld) *onWorld = false;
return world->getMap()->findPosFlatLocal(p);
}
void GameState::centerScreenLocal(const WorldPos& p, bool onWorld) {
MapClient* m = world->getMap();
CL_Point gp;
if (onWorld) {
gp = m->findPosLocal(m->clipLocal(p));
} else {
gp = m->findPosFlatLocal(m->clipLocal(p));
}
displayOffset += worldToScreen(gp) - getScreenCenterOffset();
}
bool GameState::limitDisplayOffset() const {
MapClient* m = world->getMap();
return m->isValidLocal(m->findPosFlatLocal(screenToWorld(
getScreenCenterOffset())));
}
void GameState::onInputUp(const CL_InputEvent& key) {
// TODO More hotkeys!
if (key.id == CL_KEY_ESCAPE) {
logicState = QUIT;
}
}
void GameState::onFrames(int fps) {
std::cout << "FPS: " << fps << std::endl;
}
void GameState::onCloseWindow() {
logicState = QUIT;
}
void GameState::turnUIStateOff() {
if (uiState == LAND_MANIP) movingLandOff();
}
void GameState::dragViewOn() {
CL_DisplayWindow* w = CL_Display::get_current_window();
CL_InputDevice& m = w->get_ic()->get_mouse();
// I shouldn't need this shit, but sig_ball_move doesn't seem to work.
lastMouse = CL_Point(m.get_x(), m.get_y());
// TODO: Doesn't fucking work with sprite cursor. ClabLib bug.
// TODO: Then make a different cursor?
// w->hide_cursor();
mouseViewDrag = m.sig_pointer_move().connect(this,
&GameState::onMouseDragView);
dragging = true;
}
void GameState::dragViewOff() {
CL_DisplayWindow* w = CL_Display::get_current_window();
CL_InputDevice& m = w->get_ic()->get_mouse();
m.sig_pointer_move().disconnect(mouseViewDrag);
m.set_position(lastMouse.x, lastMouse.y);
// w->show_cursor();
dragging = false;
}
void GameState::movingLandOn() {
mouseMove = CL_Display::get_current_window()->get_ic()
->get_mouse().sig_pointer_move().connect(this,
&GameState::onMouseMoveCornerPointer);
CL_Display::get_current_window()->set_cursor(
CL_Sprite("gui/main/mice/landmanip", client->getResources()));
}
void GameState::movingLandOff() {
CL_Display::get_current_window()->get_ic()
->get_mouse().sig_pointer_move().disconnect(mouseMove);
cornerPointerDraw = -1;
CL_Display::get_current_window()->set_cursor(
CL_Sprite("gui/main/mice/default", client->getResources()));
}
void GameState::onMouseDragView(const CL_InputEvent& e) {
CL_Point diff = lastMouse;
diff -= e.mouse_pos;
CL_Point old = displayOffset;
displayOffset += diff;
if (!limitDisplayOffset()) {
displayOffset = old;
}
// Make it so the mouse pointer stays put
CL_Display::get_current_window()->get_ic()->get_mouse()
.set_position(lastMouse.x, lastMouse.y);
}
void GameState::onMouseMoveCornerPointer(const CL_InputEvent& e) {
onMouseMoveCornerPointer(e.mouse_pos.x, e.mouse_pos.y);
}
void GameState::onMouseMoveCornerPointer(int x, int y) {
if (uiState == LAND_MANIP && !dragging) {
// Recalc cornerPointerLoc
CL_Point gp = screenToWorld(CL_Point(x, y));
boost::optional<WorldPos> op = world->getMap()->findPos(gp);
if (op) {
cornerPointerPos = op->getMap();
// Get the screen positions of all four corners, then find the
// nearest one by pixels.
MapTileClient* mtc = world->getMap()->getTile(cornerPointerPos);
CL_Point off = mtc->getOffset();
cornerPointerLoc[0] = mtc->findPosSlope(Corner::NORTH) + off;
cornerPointerLoc[1] = mtc->findPosSlope(Corner::EAST) + off;
cornerPointerLoc[2] = mtc->findPosSlope(Corner::SOUTH) + off;
cornerPointerLoc[3] = mtc->findPosSlope(Corner::WEST) + off;
cornerPointerDraw = findNearestOfFour(gp, cornerPointerLoc);
return;
}
}
cornerPointerDraw = -1;
}
void GameState::onMouseUp(const CL_InputEvent& e) {
if (e.id == CL_MOUSE_MIDDLE && dragging) {
dragViewOff();
}
}
void GameState::onMouseDown(const CL_InputEvent& e) {
if (e.id == CL_MOUSE_MIDDLE && !dragging) {
dragViewOn();
}
if (uiState == LAND_MANIP
&& (e.id == CL_MOUSE_LEFT || e.id == CL_MOUSE_RIGHT)
&& cornerPointerDraw != -1) {
CL_NetPacket packet;
cornerPointerPos.inject(packet.output);
MapClient* mc = world->getMap();
mc->serverOrient(Corner(cornerPointerDraw)).inject(packet.output);
if (e.id == CL_MOUSE_LEFT) {
server.send(Map::NET_RAISE, packet);
} else {
server.send(Map::NET_LOWER, packet);
}
}
if (uiState == MOVING_MAGNET && e.id == CL_MOUSE_LEFT) {
CL_Point gp = screenToWorld(CL_Point(e.mouse_pos.x, e.mouse_pos.y));
boost::optional<WorldPos> op = world->getMap()->findPos(gp);
if (op) {
sendMoveMagnet(*op);
}
onMoveMagnetButton();
}
if (uiState == PLACING_FIRECOLUMN && e.id == CL_MOUSE_LEFT) {
CL_Point gp = screenToWorld(CL_Point(e.mouse_pos.x, e.mouse_pos.y));
boost::optional<WorldPos> op = world->getMap()->findPos(gp);
if (op) {
sendCreateFireColumn(*op);
}
}
if (uiState == PLACING_SWAMP && e.id == CL_MOUSE_LEFT) {
CL_Point gp = screenToWorld(CL_Point(e.mouse_pos.x, e.mouse_pos.y));
boost::optional<WorldPos> op = world->getMap()->findPos(gp);
if (op) {
sendCreateSwamp(op->getMap());
}
}
}
void GameState::onSay(CL_NetPacket& packet, CL_NetComputer &computer) {
int s = packet.input.read_int32();
messages->addLine((s == -1 ? "Server console" : world->findPlayer(s)->getName())
+ ": " + packet.input.read_string());
}
void GameState::onAdmin(CL_NetPacket& packet, CL_NetComputer &computer) {
// TODO Make sure it's actually from the server.
int type = packet.input.read_int32();
if (type == Network::Admin::PAUSE_DEMAND) {
if (logicState == PLAY) {
std::cout << "Pausing on server demand." << std::endl;
logicState = PAUSE;
}
} else if (type == Network::Admin::UNPAUSE_DEMAND) {
if (logicState == PAUSE) {
std::cout << "Unpausing on server demand." << std::endl;
logicState = PLAY;
}
} else if (type == Network::Admin::PLAYER_CREATE) {
onPlayerCreate(packet.input);
} else if (type == Network::Admin::PLAYER_MESSAGE) {
onPlayerMessage(packet);
} else if (type == Network::Admin::PLAYER_REMOVE) {
onPlayerRemove(packet);
} else if (type == Network::Admin::STOP_DEMAND) {
logicState = END;
// EntityClientFactory::freeSprites();
// MapTileClient::freeSprites();
}
}
void GameState::onPlayerCreate(CL_InputSource& is) {
PlayerClient* pl = new PlayerClient(is);
players->push_back(pl);
if (pl->isLocal()) {
me = pl;
std::cout << "You (" << pl->getName() << " # " << pl->getSlot()
<< ") connected." << std::endl;
} else {
std::cout << "Player " << pl->getSlot() << " (" << pl->getName()
<< ") connected." << std::endl;
}
}
void GameState::onPlayerMessage(CL_NetPacket& p) {
int s = p.input.read_int32();
PlayerList::iterator i;
for (i = players->begin(); i != players->end() && (*i)->getSlot() != s;
++i) {
// NO-OP.
}
if (i == players->end()) {
return;
}
(*i)->onMessage(p);
}
void GameState::onPlayerRemove(CL_NetPacket& p) {
int s = p.input.read_int32();
int r = p.input.read_int32();
PlayerList::iterator i;
for (i = players->begin(); i != players->end() && (*i)->getSlot() != s;
++i) {
// NO-OP.
}
if (i == players->end()) {
return;
}
std::cout << "Player " << s << " (" << (*i)->getName()
<< ") has gone. " << Player::Remove::STRINGS[r] << std::endl;
players->erase(i);
}
void GameState::onNothingState() {
turnUIStateOff();
uiState = NOTHING;
CL_Display::get_current_window()->set_cursor(
CL_Sprite("gui/main/mice/default", client->getResources()));
}
void GameState::onPauseButton() {
CL_NetPacket packet;
if (logicState == PAUSE) {
packet.output.write_uint32(Network::Admin::UNPAUSE_DEMAND);
} else if (logicState == PLAY) {
packet.output.write_uint32(Network::Admin::PAUSE_DEMAND);
}
server.send(Network::Channel::ADMIN, packet);
}
void GameState::onZoomInButton() {
if (zoomLevel < 2) {
bool onWorld;
WorldPos p = getScreenCenterPosLocal(&onWorld);
++zoomLevel;
zoom = std::pow(2.0, zoomLevel);
centerScreenLocal(p, onWorld);
}
}
void GameState::onZoomOutButton() {
if (zoomLevel > -5) {
bool onWorld;
WorldPos p = getScreenCenterPosLocal(&onWorld);
--zoomLevel;
zoom = std::pow(2.0, zoomLevel);
centerScreenLocal(p, onWorld);
}
}
void GameState::onRotateClockButton() {
bool onWorld;
WorldPos p = getScreenCenterPosLocal(&onWorld);
p.rotate(Rotation::CLOCKWISE, world->getMap()->getWidth(),
world->getMap()->getHeight());
world->displayRotateClock();
centerScreenLocal(p, onWorld);
}
void GameState::onRotateAntiButton() {
bool onWorld;
WorldPos p = getScreenCenterPosLocal(&onWorld);
p.rotate(Rotation::ANTICLOCKWISE, world->getMap()->getWidth(),
world->getMap()->getHeight());
world->displayRotateAnti();
centerScreenLocal(p, onWorld);
}
void GameState::onConfigButton() {
if (pod->is_visible()) {
pod->show(false);
// TODO reset pod fields.
} else {
pod->show();
}
}
void GameState::onMoveMagnetButton() {
if (uiState == MOVING_MAGNET) {
onNothingState();
return;
}
turnUIStateOff();
uiState = MOVING_MAGNET;
CL_Display::get_current_window()->set_cursor(
CL_Sprite("gui/main/mice/movemagnet", client->getResources()));
}
void GameState::onForestButton() {
CL_NetPacket packet;
packet.output.write_uint32(Network::Effect::FOREST);
server.send(Network::Channel::EFFECT, packet);
}
void GameState::onMovingLandButton() {
if (uiState == LAND_MANIP) {
onNothingState();
return;
}
turnUIStateOff();
uiState = LAND_MANIP;
movingLandOn();
}
void GameState::onSwampButton() {
if (uiState == PLACING_SWAMP) {
onNothingState();
return;
}
turnUIStateOff();
uiState = PLACING_SWAMP;
CL_Display::get_current_window()->set_cursor(
CL_Sprite("gui/main/mice/swamp", client->getResources()));
}
void GameState::onFireColumnButton() {
if (uiState == PLACING_FIRECOLUMN) {
onNothingState();
return;
}
turnUIStateOff();
uiState = PLACING_FIRECOLUMN;
CL_Display::get_current_window()->set_cursor(
CL_Sprite("gui/main/mice/firecolumn", client->getResources()));
}
void GameState::onPlayerOptionsDialogApply() {
if (pod->getName() != me->getName()) {
me->setName(server, pod->getName());
}
if (pod->getColour() != me->getColour()) {
me->setColour(server, pod->getColour());
}
}
void GameState::onPlayerColourChange(unsigned int old, PlayerClient* p) {
messages->addLine(p->getName() + " changed his colour.");
world->playerColourChange();
}
void GameState::onPlayerNameChange(const std::string& old, PlayerClient* p) {
messages->addLine(old + " is now known as " + p->getName());
}
void GameState::onTileMoved(const MapPos& pos) {
if (uiState == LAND_MANIP
&& cornerPointerDraw != -1
&& cornerPointerPos == pos) {
CL_InputDevice& m = CL_Display::get_current_window()->get_ic()
->get_mouse();
onMouseMoveCornerPointer(m.get_x(), m.get_y());
}
}
void GameState::sendMoveMagnet(const WorldPos& p) {
CL_NetPacket packet;
packet.output.write_uint32(Network::Effect::MOVEMAGNET);
p.inject(packet.output);
server.send(Network::Channel::EFFECT, packet);
}
void GameState::sendCreateFireColumn(const WorldPos& p) {
CL_NetPacket packet;
packet.output.write_uint32(Network::Effect::FIRECOLUMN);
p.inject(packet.output);
server.send(Network::Channel::EFFECT, packet);
}
void GameState::sendCreateSwamp(const MapPos& p) {
CL_NetPacket packet;
packet.output.write_uint32(Network::Effect::SWAMP);
p.inject(packet.output);
server.send(Network::Channel::EFFECT, packet);
}
See more files for this project here