2424using namespace std ::chrono_literals;
2525
2626BMRoom::BMRoom (Lobby& lobby, uint32_t id, const std::string& name, uint32_t attributes, Player *owner, asio::io_context& io_context)
27- : Room(lobby, id, name, attributes, owner, io_context), timer(io_context), gameTimer(io_context)
27+ : Room(lobby, id, name, attributes, owner, io_context), timer(io_context)
2828{
2929 // needed after the owner is added in the parent constructor
3030 updateSlots ();
@@ -353,10 +353,10 @@ void BMRoom::playerInGame(Player *player)
353353 int idx = getPlayerIndex (player);
354354 if (idx >= 0 )
355355 {
356- states[idx].status = State::MapInfoSent ;
356+ states[idx].status = State::InGame ;
357357 inGame = true ;
358358 for (unsigned i = 0 ; i < players.size (); i++)
359- inGame = inGame && (states[i].status == State::MapInfoSent );
359+ inGame = inGame && (states[i].status == State::InGame );
360360 if (inGame)
361361 {
362362 DEBUG_LOG (Game::Bomberman, " %s: all MapInfo sent. sending game time info" , player->getName ().c_str ());
@@ -372,7 +372,6 @@ void BMRoom::playerInGame(Player *player)
372372 packet.writeData (60u * 60u * (unsigned )getTimeLimit ().count ());
373373 packet.writeData (0u );
374374 Player::sendToAll (packet, players);
375- startGameTimer ();
376375 }
377376 }
378377}
@@ -429,6 +428,14 @@ void BMRoom::savePlayerCoords(Player *player, const uint8_t *data)
429428// cmd2
430429void BMRoom::savePowerUps (Player *player, const uint8_t *data)
431430{
431+ // States marked like (this) are set by the server
432+ // Appearing sequence:
433+ // hidden -> appearing -> visible
434+ // Successful pick up
435+ // claimed -> (granted) -> acquired
436+ // TODO: Denied pick up
437+ // Hyper bomber death sequence:
438+ // acquired -> released (with coords, unk1=1) -> (random) -> appearing -> visible
432439 for (unsigned i = 0 ; i < powerUps.size (); i++)
433440 {
434441 PowerUp pup (data + i * sizeof (pup));
@@ -442,13 +449,17 @@ void BMRoom::savePowerUps(Player *player, const uint8_t *data)
442449 if (pup.state == PowerUp::Visible) {
443450 powerUps[i] = pup;
444451 }
445- else if (pup.state == PowerUp::Claimed) {
452+ else if (pup.state == PowerUp::Claimed)
453+ {
454+ // TODO wait and arbitrate
446455 pup.state = PowerUp::Granted;
447456 powerUps[i] = pup;
448457 }
449458 break ;
450459 case PowerUp::Visible:
451- if (pup.state == PowerUp::Claimed) {
460+ if (pup.state == PowerUp::Claimed)
461+ {
462+ // TODO wait and arbitrate
452463 pup.state = PowerUp::Granted;
453464 powerUps[i] = pup;
454465 }
@@ -466,19 +477,24 @@ void BMRoom::savePowerUps(Player *player, const uint8_t *data)
466477 powerUps[i] = pup;
467478 }
468479 break ;
469- case PowerUp::Acquired:
480+ case PowerUp::Acquired: // Picked up by a player
470481 // Only transitions to 0 (or 4?) should be allowed? And only by the item owner
471482 if (pup.state == PowerUp::Gone && pup.slot == powerUps[i].slot )
472483 powerUps[i] = pup;
473- if (pup.state == PowerUp::Consumed && pup.slot == powerUps[i].slot )
474- // transition to consumed?
484+ if (pup.state == PowerUp::Released && pup.slot == powerUps[i].slot )
485+ {
486+ // item has been released to a random location. Make it visible
487+ pup.state = PowerUp::Random;
475488 powerUps[i] = pup;
476- else if (pup.state != PowerUp::Acquired && pup.slot == powerUps[i].slot )
489+ DEBUG_LOG (Game::Bomberman, " PowerUp Acquired -> Released (Random). Slot %d coords %d %d" , pup.slot , pup.pos .x , pup.pos .y );
490+ }
491+ else if (pup.state != PowerUp::Acquired && pup.slot == powerUps[i].slot ) {
477492 WARN_LOG (Game::Bomberman, " PowerUp transitioning from acquired to %x? by slot %d, owner %d" ,
478493 pup.state , pup.slot , powerUps[i].slot );
494+ }
479495 break ;
480496
481- case PowerUp::Granted:
497+ case PowerUp::Granted: // Granted to a player by the server
482498 if (pup.state == PowerUp::Acquired && pup.slot == powerUps[i].slot )
483499 powerUps[i] = pup;
484500 else if (pup.state != powerUps[i].state
@@ -488,15 +504,27 @@ void BMRoom::savePowerUps(Player *player, const uint8_t *data)
488504 WARN_LOG (Game::Bomberman, " PowerUp current state not handled: Granted -> %x" , pup.state );
489505 break ;
490506
491- case PowerUp::Consumed:
492- if (pup.state == PowerUp::Random && pup.slot == powerUps[i].slot ) {
493- // TODO choose random coords?
507+ case PowerUp::Released: // Released by a dead player in hyper bomber mode
508+ if (pup.state == PowerUp::Random && pup.slot == powerUps[i].slot )
509+ {
510+ // TODO Can this happen now? Can't find any occurrence
494511 powerUps[i] = pup;
495- DEBUG_LOG (Game::Bomberman, " PowerUp Consumed -> Random. coords %d %d" , pup.pos .x , pup.pos .y );
512+ DEBUG_LOG (Game::Bomberman, " PowerUp Released -> Random. coords %d %d" , pup.pos .x , pup.pos .y );
496513 }
514+ else if (pup.state == PowerUp::Acquired) {
515+ powerUps[i] = pup;
516+ DEBUG_LOG (Game::Bomberman, " PowerUp Released -> Acquired. Slot %d coords %d %d" , pup.slot , pup.pos .x , pup.pos .y );
517+ }
518+ else if (pup.state != powerUps[i].state && pup.slot == powerUps[i].slot )
519+ WARN_LOG (Game::Bomberman, " PowerUp current state not handled: Released -> %x" , pup.state );
520+ break ;
521+
522+ case PowerUp::Random:
523+ if ((pup.state == PowerUp::Appearing || pup.state == PowerUp::Visible)
524+ && pup.slot == powerUps[i].slot )
525+ powerUps[i] = pup;
497526 else if (pup.state != powerUps[i].state && pup.slot == powerUps[i].slot )
498- // TODO Consumed -> 5 after blowing self in hyp mode
499- WARN_LOG (Game::Bomberman, " PowerUp current state not handled: Consumed -> %x" , pup.state );
527+ WARN_LOG (Game::Bomberman, " PowerUp current state not handled: Random -> %x" , pup.state );
500528 break ;
501529
502530 default :
@@ -560,6 +588,7 @@ void BMRoom::writePlayersPos(Packet& packet)
560588 for (int i = pos + slots; i < 8 ; i++)
561589 memset (packet.advance (sizeof (CompactUser)), 0 , sizeof (CompactUser));
562590}
591+
563592void BMRoom::writeTimestamp (Packet& packet)
564593{
565594 uint32_t latest = 0 ;
@@ -573,7 +602,7 @@ void BMRoom::makeCmd1Packet(Player *player, Packet& packet)
573602 packet.init (Packet::REQ_CHAT );
574603 BMCmd cmd { BMCmd::BOMB_DATA , 0xC8 };
575604 packet.writeData (cmd.full );
576- packet.writeData ((uint16_t )0 ); // client id? mask?
605+ packet.writeData ((uint16_t )(inGame ? 0 : EOG_MARK ));
577606 writePlayersPos (packet);
578607 writeTimestamp (packet);
579608 for (const Bomb& bomb : bombs)
@@ -586,7 +615,7 @@ void BMRoom::makeCmd2Packet(Packet& packet)
586615 packet.init (Packet::REQ_CHAT );
587616 BMCmd cmd { BMCmd::MAP_DATA , 0xA4 };
588617 packet.writeData (cmd.full );
589- packet.writeData ((uint16_t )0 ); // client id? mask?
618+ packet.writeData ((uint16_t )(inGame ? 0 : EOG_MARK ));
590619 writePlayersPos (packet);
591620 for (const PowerUp& pup : powerUps)
592621 pup.writeTo (packet.advance (sizeof (PowerUp)));
@@ -598,34 +627,14 @@ void BMRoom::makeCmd3Packet(Packet& packet)
598627 packet.init (Packet::REQ_CHAT );
599628 BMCmd cmd { BMCmd::POS_DATA , 0x3C };
600629 packet.writeData (cmd.full );
601- packet.writeData ((uint16_t )0 ); // client id? mask?
630+ packet.writeData ((uint16_t )(inGame ? 0 : EOG_MARK ));
602631 writePlayersPos (packet);
603632}
604633
605634std::chrono::minutes BMRoom::getTimeLimit () const {
606635 return std::chrono::minutes (rules[3 ] + 1 );
607636}
608637
609- void BMRoom::startGameTimer ()
610- {
611- // Adding 2 sec to avoid ending the game before the game timer reaches 0
612- gameTimer.expires_after (getTimeLimit () + 2s);
613- gameTimer.async_wait ([this ](const std::error_code& ec) {
614- if (ec)
615- return ;
616- INFO_LOG (Game::Bomberman, " Game end: time limit" );
617- for (Player *player : players)
618- {
619- // force ending
620- states[getPlayerIndex (player)].endOfGameMask = 7 ;
621- Packet packet;
622- sendEndOfGame (player, packet);
623- if (!packet.empty ())
624- player->send (packet);
625- }
626- });
627- }
628-
629638void BMRoom::saveMapInfo (Player *player, const uint8_t *data, bool last)
630639{
631640 int idx = getPlayerIndex (player);
@@ -640,49 +649,16 @@ void BMRoom::saveMapInfo(Player *player, const uint8_t *data, bool last)
640649 DEBUG_LOG (Game::Bomberman, " %d bomb(s) per player" , bombsPerPlayer);
641650}
642651
643- bool BMRoom::checkEndOfGame (Player *player, uint8_t command)
652+ bool BMRoom::checkEndOfGame (Player *player, uint8_t command, uint8_t mark )
644653{
654+ if (mark != EOG_MARK )
655+ return false ;
645656 State& playerState = states[getPlayerIndex (player)];
646- if (playerState.status != State::MapInfoSent )
657+ if (playerState.status != State::InGame )
647658 return false ;
648- const int mask = 1 << (command - 1 );
649- if (rules[0 ] == 0 )
650- {
651- // Survival mode
652- // Check if more than 1 player is alive
653- int alivePlayers = 0 ;
654- for (unsigned pl = 0 ; pl < players.size () && alivePlayers <= 1 ; pl++)
655- {
656- const int slots = getSlotCount (players[pl]);
657- const State& state = states[pl];
658- for (int slot = 0 ; slot < slots && alivePlayers <= 1 ; slot++)
659- if (!state.dead [slot])
660- alivePlayers++;
661- }
662- if (alivePlayers <= 1 ) {
663- INFO_LOG (Game::Bomberman, " Game end: %d player remaining" , alivePlayers);
664- playerState.endOfGameMask |= mask;
665- return playerState.endOfGameMask == 7 ;
666- }
667- }
668- else
669- {
670- // Hyper-bomber mode
671- for (unsigned pl = 0 ; pl < players.size (); pl++)
672- {
673- const int slots = getSlotCount (players[pl]);
674- const State& state = states[pl];
675- for (int slot = 0 ; slot < slots; slot++)
676- // 80 appears briefly when a player respawns: ignore this case
677- if (state.positions [slot].unk == 0x80 && !state.dead [slot])
678- {
679- INFO_LOG (Game::Bomberman, " Game end: player %d won" , getPlayerPosition (players[pl]) + slot);
680- playerState.endOfGameMask |= mask;
681- return playerState.endOfGameMask == 7 ;
682- }
683- }
684- }
685- return false ;
659+ INFO_LOG (Game::Bomberman, " [%s] Game end" , player->getName ().c_str ());
660+ playerState.endOfGameMask |= 1 << (command - 1 );
661+ return playerState.endOfGameMask == 7 ;
686662}
687663
688664void BMRoom::sendEndOfGame (Player *player, Packet& packet)
@@ -765,7 +741,7 @@ bool BombermanServer::handlePacket(Player *player, const uint8_t *data, size_t l
765741 room->saveBombState (player, data + 0x38 );
766742 room->saveBrickMap (player, data + 0xC8 );
767743 room->makeCmd1Packet (player, replyPacket);
768- if (room->checkEndOfGame (player, BMCmd::BOMB_DATA ))
744+ if (room->checkEndOfGame (player, BMCmd::BOMB_DATA , data[ 0x13 ] ))
769745 {
770746 player->send (replyPacket);
771747 replyPacket.reset ();
@@ -795,7 +771,7 @@ bool BombermanServer::handlePacket(Player *player, const uint8_t *data, size_t l
795771 room->savePowerUps (player, data + 0x34 );
796772 room->saveBrickMap (player, data + 0xA4 );
797773 room->makeCmd2Packet (replyPacket);
798- if (room->checkEndOfGame (player, BMCmd::MAP_DATA ))
774+ if (room->checkEndOfGame (player, BMCmd::MAP_DATA , data[ 0x13 ] ))
799775 {
800776 player->send (replyPacket);
801777 replyPacket.reset ();
@@ -814,7 +790,7 @@ bool BombermanServer::handlePacket(Player *player, const uint8_t *data, size_t l
814790 }
815791 room->savePlayerCoords (player, data + 0x14 );
816792 room->makeCmd3Packet (replyPacket);
817- if (room->checkEndOfGame (player, BMCmd::POS_DATA ))
793+ if (room->checkEndOfGame (player, BMCmd::POS_DATA , data[ 0x13 ] ))
818794 {
819795 player->send (replyPacket);
820796 replyPacket.reset ();
@@ -1033,8 +1009,7 @@ bool BombermanServer::handlePacket(Player *player, const uint8_t *data, size_t l
10331009 replyPacket.init (Packet::REQ_CHAT );
10341010 replyPacket.writeData (cmd.full );
10351011 replyPacket.writeData ((uint16_t )data[0x12 ]); // Client ID
1036- replyPacket.writeData (0x10000000u ); // LE int. ping value? only lsbyte used. 1,4,10,80,c8 is red
1037- replyPacket.writeData (room->getSlotMask (player));
1012+ replyPacket.writeData (data + 0x14 , 5 );
10381013 break ;
10391014
10401015 default :
0 commit comments