Code Search for Developers
 
 
  

gamestate.cpp from FreePop at Krugle


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

FreePop

FreePop is a multi-platform tile-based game based on the great old game Populous 2 by Bullfrog Productions Ltd., but much improved.

Project homepage: http://sourceforge.net/projects/freepop
Programming language(s): C++
License: other

  Makefile.am
  client.cpp
  client.h
  clientmisc.cpp
  clientmisc.h
  clientstate.cpp
  clientstate.h
  connectstate.cpp
  connectstate.h
  cropsclient.cpp
  cropsclient.h
  entityclient.cpp
  entityclient.h
  entityclientfactory.cpp
  entityclientfactory.h
  firecolumnclient.cpp
  firecolumnclient.h
  gamestate.cpp
  gamestate.h
  loadstate.cpp
  loadstate.h
  mapclient.cpp
  mapclient.h
  maptileclient.cpp
  maptileclient.h
  messagebox.cpp
  messagebox.h
  oversprite.cpp
  oversprite.h
  paintable.cpp
  paintable.h
  pausefader.cpp
  pausefader.h
  peepclient.cpp
  peepclient.h
  peepmagnetclient.cpp
  peepmagnetclient.h
  playerclient.cpp
  playerclient.h
  playeroptionsdialog.cpp
  playeroptionsdialog.h
  rockclient.cpp
  rockclient.h
  swampclient.cpp
  swampclient.h
  townclient.cpp
  townclient.h
  treeclient.cpp
  treeclient.h
  worldclient.cpp
  worldclient.h