#include "handler.h" #include "level.h" #include "protocol.h" #include #include #include #include #include "config.h" #include "qcanvas.h" #include "ai_player.h" #include "item.h" #include "cell.h" #include "knet.h" #include "bomb.h" #include "exit.h" #include "blast.h" #include "rule.h" #include #include #include using namespace std; static Handler *o; template T at(std::list l, int position) { typename std::list::iterator it; for(it = l.begin(); it != l.end() && position; it++, position--); return (*it); } Handler::Handler() { level = NULL; o = this; m_state = state_launched; net = new KNet(); exit = NULL; rules = NULL; selected_map = NULL; selected_bots = 0; } Handler::~Handler() { if(exit) delete exit; if(level) delete level; delete net; } bool Handler::walkableTile(int x, int y) { list::iterator bit; list::iterator iit; bool valid = true; Item *item; if((x >= 0) && (y >= 0) && (x < level->width()) && (y < level->height())) { if((level->tile(x, y) == Level::wall) || (level->tile(x, y) == Level::invalid) || (level->tile(x, y) == Level::space)) return false; if((level->tile(x, y) == Level::itemBomb) || (level->tile(x, y) == Level::itemLive) || (level->tile(x, y) == Level::itemPower)) { for(iit = itemlist.begin(); iit != itemlist.end(); iit++) if(((*iit)->x() == x) && ((*iit)->y() == y)) if(!(*iit)->isActive()) return false; } if(exit) { if (exit->x() == x && exit->y() == y && !exit->isHighlighted()) return false; } if(level->tile(x, y) == Level::itemScree) { if((item = findItem(x, y)) != NULL) return false; } for(bit = bomblist.begin(); bit != bomblist.end(); bit++) { if(((*bit)->x() == x) && ((*bit)->y() == y)) return false; } } else { return false; } return valid; } Item *Handler::findItem(int x, int y) { list::iterator it; for(it = itemlist.begin(); it != itemlist.end(); it++) if(((*it)->x() == x) && ((*it)->y() == y)) return (*it); return NULL; } void Handler::checkItem(Player *p, bool isplayer) { Item *item; if((item = findItem(p->x(), p->y())) != NULL) { switch(item->type()) { case Level::itemBomb: p->numBombs(p->numBombs() + 1); *net << MNet::multicast; *net << Net::begin << opcode_action << action_item << p->id() << Level::itemBomb << 1 << Net::end << Net::flush; *net << MNet::peer; break; case Level::itemLive: p->numLives(p->numLives() + 1); *net << MNet::multicast; *net << Net::begin << opcode_action << action_item << p->id() << Level::itemLive << 1 << Net::end << Net::flush; *net << MNet::peer; break; case Level::itemPower: p->power(p->power() + 1); *net << MNet::multicast; *net << Net::begin << opcode_action << action_item << p->id() << Level::itemPower << 1 << Net::end << Net::flush; *net << MNet::peer; break; } itemlist.remove(item); level->setTile(p->x(), p->y(), Level::ground); freecelllist.push_back(new Cell(p->x(), p->y())); // iterate over all players *net << MNet::multicast; *net << Net::begin << opcode_action << action_removeitem << item->id() << Net::end << Net::flush; *net << MNet::peer; } if(isplayer) { if((exit) && (exit->isActive())) { if((p->x() == exit->x()) && (p->y() == exit->y())) { *net << MNet::multicast; *net << Net::begin << opcode_state << state_stop << Net::end << Net::flush; *net << MNet::peer; // FIXME - erm, what else to do here, if player has won? :) } } } } void Handler::moveMonsters() { list::iterator it; int direction; bool hasmoved; for(it = monsterlist.begin(); it != monsterlist.end(); it++) { AI_Player *monster = (*it); int x = monster->x(); int y = monster->y(); if(monster->counter() == 3) { if(rand() % 2 == 0) { switch(monster->direction()) { case AI_Player::Up: monster->direction(AI_Player::Down); break; case AI_Player::Down: monster->direction(AI_Player::Up); break; case AI_Player::Left: monster->direction(AI_Player::Right); break; case AI_Player::Right: monster->direction(AI_Player::Left); break; } } } if(monster->counter() == 4) { if(rand() % 2 == 0) { switch(monster->direction()) { case AI_Player::Up: monster->direction(AI_Player::Left); break; case AI_Player::Down: monster->direction(AI_Player::Right); break; case AI_Player::Left: monster->direction(AI_Player::Down); break; case AI_Player::Right: monster->direction(AI_Player::Up); break; } } monster->counter(0); } else { monster->counter(monster->counter() + 1); } hasmoved = false; if(monster->direction() == AI_Player::Up) { if(walkableTile(x + 1, y)) { monster->move(x + 1, y); monster->direction(AI_Player::Right); hasmoved = true; } else if(walkableTile(x, y - 1)) { monster->move(x, y - 1); monster->direction(AI_Player::Up); hasmoved = true; } else if(walkableTile(x - 1, y)) { monster->move(x - 1, y); monster->direction(AI_Player::Left); hasmoved = true; } else if(walkableTile(x, y + 1)) { monster->move(x, y + 1); monster->direction(AI_Player::Down); hasmoved = true; } } else if(monster->direction() == AI_Player::Down) { if(walkableTile(x - 1, y)) { monster->move(x - 1, y); monster->direction(AI_Player::Left); hasmoved = true; } else if(walkableTile(x, y + 1)) { monster->move(x, y + 1); monster->direction(AI_Player::Down); hasmoved = true; } else if(walkableTile(x + 1, y)) { monster->move(x + 1, y); monster->direction(AI_Player::Right); hasmoved = true; } else if(walkableTile(x, y - 1)) { monster->move(x, y - 1); monster->direction(AI_Player::Up); hasmoved = true; } } else if(monster->direction() == AI_Player::Left) { if(walkableTile(x, y - 1)) { monster->move(x, y - 1); monster->direction(AI_Player::Up); hasmoved = true; } else if(walkableTile(x - 1, y)) { monster->move(x - 1, y); monster->direction(AI_Player::Left); hasmoved = true; } else if(walkableTile(x, y + 1)) { monster->move(x, y + 1); monster->direction(AI_Player::Down); hasmoved = true; } else if(walkableTile(x + 1, y)) { monster->move(x + 1, y); monster->direction(AI_Player::Right); hasmoved = true; } } else if(monster->direction() == AI_Player::Right) { if(walkableTile(x, y + 1)) { monster->move(x, y + 1); monster->direction(AI_Player::Down); hasmoved = true; } else if(walkableTile(x + 1, y)) { monster->move(x + 1, y); monster->direction(AI_Player::Right); hasmoved = true; } else if(walkableTile(x, y - 1)) { monster->move(x, y - 1); monster->direction(AI_Player::Up); hasmoved = true; } else if(walkableTile(x - 1, y)) { monster->move(x - 1, y); monster->direction(AI_Player::Left); hasmoved = true; } } direction = monster->direction(); if(hasmoved) { /*if(direction == AI_Player::Up) direction = move_up; else if(direction == AI_Player::Down) direction = move_down; else if(direction == AI_Player::Left) direction = move_left; else if(direction == AI_Player::Right) direction = move_right;*/ *net << MNet::multicast; *net << Net::begin << opcode_move << /*FIXME*//*gen*/0 << move_monster << monster->id() << direction << Net::end << Net::flush; *net << MNet::peer; checkItem(monster, false); } } } bool Handler::placeBlast(int x, int y) { Blast *blast; if((level->tile(x, y) == Level::invalid) || (level->tile(x, y) == Level::wall)) return false; blast = new Blast(generator(), x, y, NULL); blastlist.push_back(blast); // iterate over all players *net << MNet::multicast; *net << Net::begin << opcode_action << action_newblast << blast->id() << x << y << Net::end << Net::flush; *net << MNet::peer; if(level->tile(x, y) > Level::space) return false; else return true; } void Handler::createMonster(int id, int x, int y) { AI_Player *monster = new AI_Player(id, x, y, NULL); monster->numLives(rules->monster_lives); monster->numBombs(rules->monster_bombs); monster->power(rules->monster_power); monsterlist.push_back(monster); //iterate over all players *net << MNet::multicast; *net << Net::begin << opcode_action << action_newmonster << monster->id() << x << y << Net::end << Net::flush; *net << MNet::peer; } void Handler::createMonster(int count) { for(int i = 0; i < count; i++) { int pos = rand () % freecelllist.size(); Cell *c = at(freecelllist, pos); createMonster(generator(), c->x(), c->y()); freecelllist.remove(c); } } void Handler::progress() { Item *item; list::iterator blit, xblit; list::iterator bit, xbit; list::iterator pit, xpit; list::iterator apit, xapit; list::iterator iit; // proceed blasts for(blit = blastlist.begin(); blit != blastlist.end(); blit++) { (*blit)->proceed(); // check for player, standing in a blast area for(pit = playerlist.begin(); pit != playerlist.end(); pit++) { if(((*pit)->x() == (*blit)->x()) && ((*pit)->y() == (*blit)->y()) && ((*blit)->step() == 1)) { cout << "death caused by blast" << endl; cout << "player: " << (*pit)->id() << " - " << (*pit)->x() << "/" << (*pit)->y() << endl; cout << "blast: " << (*blit)->x() << "/" << (*blit)->y() << endl; (*pit)->numLives((*pit)->numLives() - 1); cout << "lives left: " << (*pit)->numLives() << endl; *net << MNet::multicast; *net << Net::begin << opcode_action << action_item << (*pit)->id() << Level::itemLive << -1 << Net::end << Net::flush; *net << MNet::peer; } } for(apit = monsterlist.begin(); apit != monsterlist.end(); apit++) { if(((*apit)->x() == (*blit)->x()) && ((*apit)->y() == (*blit)->y()) && ((*blit)->step() == 1)) { cout << "monster death caused by blast" << endl; (*apit)->numLives((*apit)->numLives() - 1); *net << MNet::multicast; *net << Net::begin << opcode_action << action_item << (*apit)->id() << Level::itemLive << -1 << Net::end << Net::flush; *net << MNet::peer; } } // check for other bombs, lieing in a blast area for(bit = bomblist.begin(); bit != bomblist.end(); bit++) { if(((*bit)->x() == (*blit)->x()) && ((*bit)->y() == (*blit)->y())) (*bit)->setStep(0); } // when exit is hit, generate a new monster if(exit) { if((exit->x() == (*blit)->x()) && (exit->y() == (*blit)->y()) && ((*blit)->step() == 1)) { if (!exit->isActive()) { exit->activate(true); *net << MNet::multicast; *net << Net::begin << opcode_action << action_activateexit << Net::end << Net::flush; *net << MNet::peer; } if (!exit->isHighlighted()) createMonster(generator(), exit->x(), exit->y()); } } // check for other items, lieing in a blast area if((item = findItem((*blit)->x(), (*blit)->y())) != NULL) { if((*blit)->step() == 1) { if (!item->isActive()) { if(item->type() == Level::itemScree) { level->setTile(item->x(), item->y(), Level::ground); *net << MNet::multicast; *net << Net::begin << opcode_action << action_removeitem << item->id() << Net::end << Net::flush; *net << MNet::peer; itemlist.remove(item); } else { if(!item->isActive()) { item->activate(true); *net << MNet::multicast; *net << Net::begin << opcode_action << action_activateitem << item->id() << Net::end << Net::flush; *net << MNet::peer; } } } else { *net << MNet::multicast; *net << Net::begin << opcode_action << action_removeitem << item->id() << Net::end << Net::flush; *net << MNet::peer; itemlist.remove(item); } } } if((*blit)->finished()) { *net << MNet::multicast; *net << Net::begin << opcode_action << action_removeblast << (*blit)->id() << Net::end << Net::flush; *net << MNet::peer; xblit = blit--; blastlist.remove((*xblit)); } } // let bombs tick for(bit = bomblist.begin(); bit != bomblist.end(); bit++) { (*bit)->proceed(); if((*bit)->finished()) { (*bit)->player()->numBombs((*bit)->player()->numBombs() + 1); *net << MNet::multicast; *net << Net::begin << opcode_action << action_item << (*bit)->player()->id() << Level::itemBomb << 1 << Net::end << Net::flush; *net << MNet::peer; // create explosion bool left, right, top, bottom; placeBlast((*bit)->x(), (*bit)->y()); left = right = top = bottom = true; for(int i = 1; i < (*bit)->player()->power() + 1; i++) { if(right) right = placeBlast((*bit)->x() + i, (*bit)->y()); if(left) left = placeBlast((*bit)->x() - i, (*bit)->y()); if(top) top = placeBlast((*bit)->x(), (*bit)->y() + i); if(bottom) bottom = placeBlast((*bit)->x(), (*bit)->y() - i); } *net << MNet::multicast; *net << Net::begin << opcode_action << action_removebomb << (*bit)->id() << Net::end << Net::flush; *net << MNet::peer; xbit = bit--; bomblist.remove((*xbit)); } } // clashes between players and monsters for(pit = playerlist.begin(); pit != playerlist.end(); pit++) { for(apit = monsterlist.begin(); apit != monsterlist.end(); apit++) { if(((*apit)->x() == (*pit)->x()) && ((*apit)->y() == (*pit)->y())) { cout << "death caused by clash with monster " << (*apit)->id() << endl; (*pit)->numLives((*pit)->numLives() - 1); *net << MNet::multicast; *net << Net::begin << opcode_action << action_item << (*pit)->id() << Level::itemLive << -1 << Net::end << Net::flush; *net << MNet::peer; } } /* player died*/ if((*pit)->numLives() == 0) { cout << "remove fd " << (*pit)->fd() << " completely from mnet" << endl; *net << Net::channel << (*pit)->fd(); *net << Net::begin << opcode_state << state_stop << Net::end << Net::flush; *net << MNet::remove << (*pit)->fd(); // FIXME - erm, what else to do here? :) xpit = pit--; playerlist.remove((*xpit)); } } // check for monster deaths for(apit = monsterlist.begin(); apit != monsterlist.end(); apit++) { if((*apit)->numLives() == 0) { *net << MNet::multicast; *net << Net::begin << opcode_action << action_removemonster << (*apit)->id() << Net::end << Net::flush; *net << MNet::peer; xapit = apit--; monsterlist.remove((*xapit)); } } // no more monsters, level is finished if(monsterlist.size() == 0) { if(exit) { if(!exit->isHighlighted()) { exit->setHighlighted(true); *net << MNet::multicast; *net << Net::begin << opcode_action << action_highlightexit << Net::end << Net::flush; *net << MNet::peer; } } for(iit = itemlist.begin(); iit != itemlist.end(); iit++) { if((*iit)->type() >= Level::itemBomb) { if(!(*iit)->isHighlighted()) { (*iit)->setHighlighted(true); *net << MNet::multicast; *net << Net::begin << opcode_action << action_highlightitem << (*iit)->id() << Net::end << Net::flush; *net << MNet::peer; } } } } // proceed items for(iit = itemlist.begin(); iit != itemlist.end(); iit++) (*iit)->proceed(); } void Handler::checkStart(GGZdMod *mod) { // int fd; cout << "checkStart()" << endl; cout << "open seats: " << ggzdmod_count_seats(mod, GGZ_SEAT_OPEN) << endl; if(m_state != state_waiting) return; if(ggzdmod_count_seats(mod, GGZ_SEAT_OPEN) == 0) { // // setup broadcasting // for(int i = 0; i < ggzdmod_get_num_seats(mod); i++) // { // // inform of game start // fd = ggzdmod_get_seat(mod, i).fd; // if(fd < 0) continue; // *net << MNet::add << fd; // } // start broadcasting selected_players = ggzdmod_count_seats(mod, GGZ_SEAT_PLAYER); *net << MNet::multicast; *net << Net::begin << opcode_state << state_start << Net::end << Net::flush; // determine free cells for(int j = 0; j < level->height(); j++) for(int i = 0; i < level->height(); i++) if((level->tile(i, j) != Level::invalid) && (level->tile(i, j) != Level::wall) && (level->tile(i, j) != Level::space)) { Cell *c = new Cell(i, j); freecelllist.push_back(c); } // fill up one quarter of them with scree int size = (int)(freecelllist.size() * rules->scree_percentage / 100); for(int i = 0; i < size; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); level->setTile(c->x(), c->y(), Level::itemScree); Item *item = new Item(generator(), c->x(), c->y(), NULL, Level::itemScree); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << Level::itemScree << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); } *net << Net::flush; // randomly place 10 items if(!rules->custom()) { for(int i = 0; i < 10; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); int type = Level::itemScree; switch(rand() % 3) { case 0: type = Level::itemBomb; break; case 1: type = Level::itemPower; break; case 2: type = Level::itemLive; break; } level->setTile(c->x(), c->y(), type); Item *item = new Item(generator(), c->x(), c->y(), NULL, type); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << type << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); } // place a grail int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); Item *item = new Item(generator(), c->x(), c->y(), NULL, Level::itemGrail); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << Level::itemGrail << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); *net << Net::flush; } else { for(int i = 0; i < rules->bomb_number; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); Item *item = new Item(generator(), c->x(), c->y(), NULL, Level::itemBomb); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << Level::itemBomb << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); } for(int i = 0; i < rules->life_number; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); Item *item = new Item(generator(), c->x(), c->y(), NULL, Level::itemLive); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << Level::itemLive << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); } for(int i = 0; i < rules->power_number; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); Item *item = new Item(generator(), c->x(), c->y(), NULL, Level::itemPower); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << Level::itemPower << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); } for(int i = 0; i < rules->grail_number; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); Item *item = new Item(generator(), c->x(), c->y(), NULL, Level::itemGrail); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << Level::itemGrail << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); } for(int i = 0; i < rules->speed_number; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); Item *item = new Item(generator(), c->x(), c->y(), NULL, Level::itemSpeed); itemlist.push_back(item); *net << Net::begin << opcode_action << action_newitem << Level::itemSpeed << item->id() << c->x() << c->y() << Net::end; freecelllist.remove(c); } *net << Net::flush; } // create players // ggzdmod_get_num_seats(mod) with GGZ_SEAT_PLAYER should equal selected_players !!! for(int i = 0; i < ggzdmod_get_num_seats(mod); i++) { int fd = ggzdmod_get_seat(mod, i).fd; if(fd < 0) continue; int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); Player *p = new Player(generator(), c->x(), c->y(), NULL); p->numLives(rules->player_lives); p->numBombs(rules->player_bombs); p->power(rules->player_power); p->setFd(fd); playerlist.push_back(p); cout << "player " << i << " with fd " << fd << " placed on map" << endl; *net << Net::begin << opcode_action << action_newplayer << i << c->x() << c->y() << Net::end << Net::flush; freecelllist.remove(c); } // create monsters for(int i = 0; i < selected_bots; i++) { int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); createMonster(generator(), c->x(), c->y()); freecelllist.remove(c); } // create exit int pos = rand() % freecelllist.size(); Cell *c = at(freecelllist, pos); exit = new Exit(-1, c->x(), c->y(), NULL); *net << Net::begin << opcode_action << action_newexit << c->x() << c->y() << Net::end << Net::flush; freecelllist.remove(c); *net << MNet::peer; m_state = state_playing; } cout << "checkStart() done" << endl; } void Handler::dataEvent(GGZdMod *mod, int fd) { int opcode; int minor; char *map; int bots; int gen, direction; std::string file; bool success; Player *p; list::iterator pit; // Find player p = NULL; cout << "playerlist size is " << playerlist.size() << endl; for(pit = playerlist.begin(); pit != playerlist.end(); pit++) { cout << "check player fd " << (*pit)->fd() << endl; if((*pit)->fd() == fd) { p = (*pit); cout << "found player " << p << endl; break; } } //if(!p) //{ // std::cerr << "No player with fd " << fd << " known!" << std::endl; //} *net << Net::channel << fd; *net << Net::input; while(1) { // Network buffering *net << Net::channel << fd; //if(net->empty()) *net << Net::input; if(net->empty()) break; *net >> &opcode; cout << "opcode: " << opcode << endl; switch(opcode) { case opcode_move: // Read move from player cout << "move!" << endl; *net >> &gen >> &direction; cout << "generator: " << gen << endl; cout << "direction: " << direction << endl; // evaluate move if(m_state != state_playing) { cout << "Cheater! Not playing yet." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); return; } // sanity check if(!p) { cout << "Cheater! No player with fd " << fd << " found." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); return; } // check boundaries int x, y; x = p->x(); y = p->y(); if(direction == move_up) y--; else if(direction == move_down) y++; else if(direction == move_left) x--; else if(direction == move_right) x++; if(walkableTile(x, y)) { // execute move p->move(x, y); cout << "[current position] " << p->x() << "/" << p->y() << endl; // broadcast move *net << MNet::multicast; *net << Net::begin << opcode_move << gen << move_player << p->id() << direction << Net::end << Net::flush; *net << MNet::peer; // check for items checkItem(p, true); } break; case opcode_action: cout << "action!" << endl; // sanity check if(!p) { cout << "Cheater! No player assigned yet." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); return; } *net >> &minor; if(minor == action_newbomb) { // broadcast bomb creation Bomb *bomb = new Bomb(generator(), p->x(), p->y(), NULL, p); bomblist.push_back(bomb); *net << MNet::multicast; *net << MNet::begin << opcode_action << action_newbomb << p->id() << bomb->id() << p->x() << p->y() << Net::end << Net::flush; *net << MNet::peer; } break; case opcode_map: cout << "map!" << endl; *net >> &minor; switch(minor) { case map_selected: // read information about selected map *net >> &map >> &bots; cout << "selected map: " << map << endl; // check for validity if(m_state != state_map) { cout << "Cheater! No map selection allowed yet." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); return; } if(bots > ggzdmod_count_seats(mod, GGZ_SEAT_BOT)) { cout << "Cheater! Bots (" << bots << ") > ggzmod_count_seats(bots) (" << ggzdmod_count_seats(mod, GGZ_SEAT_BOT) << ")." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); return; } // try to load level = new Level(); file = DATADIR "/levels/"; file += map; file += ".txt"; success = level->loadLevel(file.c_str()); if(!success) { cout << "Cheater! Map (" << file.c_str() << ") doesn't exist." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); return; } // broadcast map choice *net << MNet::multicast; *net << Net::begin << opcode_map << map_selected << map << bots << Net::end << Net::flush; *net << MNet::peer; /*ggz_free(map);*/ selected_map = map; selected_bots = bots; // move to new state m_state = state_waiting; // are we there yet? if(rules) checkStart(mod); break; } break; case opcode_rules: cout << "rules!" << endl; if(!rules) { rules = new Rule(); *net >> &rules; // broacast rules *net << MNet::multicast; *net << opcode_rules; *net << rules; *net << MNet::peer; checkStart(mod); } else { cout << "Cheater! Already got rules." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); } break; default: // detect cheating clients cout << "Cheater! Unknown opcode." << endl; *net << Net::channel << fd << opcode_cheat; close(fd); break; } } } void Handler::leaveEvent(GGZdMod *mod, int fd) { *net << MNet::remove << fd; } void Handler::joinEvent(GGZdMod *mod, int fd) { // First player must select the map /*if(ggzdmod_count_seats(mod, GGZ_SEAT_PLAYER) == 1)*/ *net << MNet::add << fd; if(m_state == state_launched) { cout << "require map" << endl; m_state = state_map; *net << Net::channel << fd; *net << Net::begin << opcode_map << map_select << ggzdmod_count_seats(mod, GGZ_SEAT_BOT); *net << Net::end << Net::flush; } else if((m_state == state_waiting) || (m_state == state_playing)) { *net << Net::channel << fd; *net << Net::begin << opcode_map << map_selected << selected_map << selected_bots; *net << Net::end << Net::flush; // Are we ready yet? checkStart(mod); } } void Handler::event(GGZdMod *ggzdmod, GGZdModEvent event, const void *data) // static !!! pass object? { int player = -1; int spectator; int fd; GGZSeat *seat; cout << "================"<< endl; cout << "Got event: " << event << endl; fd = -1; if((event == GGZDMOD_EVENT_JOIN) || (event == GGZDMOD_EVENT_PLAYER_DATA)) { player = *(int*)data; fd = ggzdmod_get_seat(ggzdmod, player).fd; cout << "* Associated player: " << player << " (" << ggzdmod_get_seat(ggzdmod, player).name << ")" << endl; } if(event == GGZDMOD_EVENT_LEAVE) { seat = (GGZSeat*)data; player = seat->num; fd = seat->fd; cout << "* Associated player: " << player << " (" << seat->name << ")" << endl; } if((event == GGZDMOD_EVENT_SPECTATOR_JOIN) || (event == GGZDMOD_EVENT_SPECTATOR_LEAVE)) { spectator = *(int*)data; fd = ggzdmod_get_spectator(ggzdmod, spectator).fd; cout << "* Associated spectator: " << spectator << " (" << ggzdmod_get_spectator(ggzdmod, spectator).name << ")" << endl; } if((event == GGZDMOD_EVENT_JOIN) || (event == GGZDMOD_EVENT_SPECTATOR_JOIN)) { //fcntl(fd, F_SETFL, O_NONBLOCK); } switch(event) { case GGZDMOD_EVENT_STATE: cout << "* Type: state change" << endl; break; case GGZDMOD_EVENT_JOIN: cout << "* Type: join" << endl; o->joinEvent(ggzdmod, fd); break; case GGZDMOD_EVENT_LEAVE: // TODO: remove player from map, send updates to all remaining cout << "* Type: leave" << endl; o->leaveEvent(ggzdmod, fd); break; case GGZDMOD_EVENT_PLAYER_DATA: cout << "* Type: player data" << endl; o->dataEvent(ggzdmod, fd); break; case GGZDMOD_EVENT_SPECTATOR_JOIN: break; case GGZDMOD_EVENT_SPECTATOR_LEAVE: break; case GGZDMOD_EVENT_SEAT: case GGZDMOD_EVENT_LOG: case GGZDMOD_EVENT_SPECTATOR_DATA: #ifdef GGZDMOD_VERSION_MAJOR /* GGZ >= 0.0.7 */ case GGZDMOD_EVENT_SPECTATOR_SEAT: case GGZDMOD_EVENT_GAMEREPORT: case GGZDMOD_EVENT_REQ_BOT: case GGZDMOD_EVENT_REQ_BOOT: case GGZDMOD_EVENT_REQ_OPEN: case GGZDMOD_EVENT_REQ_NUM_SEATS: #if GGZDMOD_VERSION_MICRO >= 11 case GGZDMOD_EVENT_SAVEGAMEREPORT: #endif #endif case GGZDMOD_EVENT_ERROR: /* not supported */ break; } } void Handler::loop() { GGZdMod *ggzdmod; int ret; long diff; struct timeval oldtimer, timer, oldtimer2, timer2; cout << "(handler: loop)" << endl; ggzdmod = ggzdmod_new(GGZDMOD_GAME); ggzdmod_set_handler(ggzdmod, GGZDMOD_EVENT_STATE, &event); ggzdmod_set_handler(ggzdmod, GGZDMOD_EVENT_JOIN, &event); ggzdmod_set_handler(ggzdmod, GGZDMOD_EVENT_LEAVE, &event); ggzdmod_set_handler(ggzdmod, GGZDMOD_EVENT_PLAYER_DATA, &event); ggzdmod_set_handler(ggzdmod, GGZDMOD_EVENT_SPECTATOR_JOIN, &event); ggzdmod_set_handler(ggzdmod, GGZDMOD_EVENT_SPECTATOR_LEAVE, &event); ret = ggzdmod_connect(ggzdmod); if(ret != -1) { cout << "(handler: connected)" << endl; gettimeofday(&oldtimer, NULL); gettimeofday(&oldtimer2, NULL); #ifndef GGZDMOD_VERSION_MAJOR /* GGZ < 0.0.7 */ while(ggzdmod_get_state(ggzdmod) != GGZDMOD_STATE_DONE) { #endif //ret = ggzdmod_loop(ggzdmod); while((ret = ggzdmod_dispatch(ggzdmod)) != -1) { if(m_state == state_playing) { /* monster timer (500 msec) */ gettimeofday(&timer, NULL); diff = timer.tv_sec - oldtimer.tv_sec; diff = diff * 1000 * 1000 + (timer.tv_usec - oldtimer.tv_usec); if(diff > 500 * 1000) { oldtimer.tv_sec = timer.tv_sec; oldtimer.tv_usec = timer.tv_usec; //cout << "## timer (500)" << endl; moveMonsters(); } /* player timer (100 msec) */ timer2.tv_sec = timer.tv_sec; timer2.tv_usec = timer.tv_usec; diff = timer2.tv_sec - oldtimer2.tv_sec; diff = diff * 1000 * 1000 + (timer2.tv_usec - oldtimer2.tv_usec); if(diff > 100 * 1000) { oldtimer2.tv_sec = timer2.tv_sec; oldtimer2.tv_usec = timer2.tv_usec; //cout << "## timer (100)" << endl; progress(); } } } #ifndef GGZDMOD_VERSION_MAJOR /* GGZ < 0.0.7 */ } #endif cerr << "Warning: game will end in 10 seconds" << endl; sleep(10); cerr << "Warning: game ends now" << endl; ggzdmod_disconnect(ggzdmod); } else { cerr << "Error: Couldn't connect to ggzd." << endl; } ggzdmod_free(ggzdmod); } int Handler::generator() { static int gen = 0; return ++gen; }