LCOV - code coverage report
Current view: top level - src - mobsystem.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 34 142 23.9 %
Date: 2020-10-15 20:26:03 Functions: 5 8 62.5 %

          Line data    Source code
       1             : #include "mobsystem.h"
       2             : 
       3             : #include "game.h"
       4             : #include "rendersystem.h"
       5             : 
       6             : #include <string>
       7             : using namespace std::string_literals;
       8             : 
       9           3 : MobInfo MI(MobCategory category, std::string name, int32_t health, int32_t speed) {
      10           3 :     MobInfo mi;
      11           3 :     mi.category = category;
      12           3 :     mi.name = name;
      13           3 :     mi.health = health;
      14           3 :     mi.speed = speed;
      15           3 :     return mi;
      16             : }
      17             : 
      18           4 : MobInfo MI(MobCategory category, std::string name, int32_t health, int32_t speed,
      19             :            int32_t strength) {
      20           4 :     MobInfo mi;
      21           4 :     mi.category = category;
      22           4 :     mi.name = name;
      23           4 :     mi.health = health;
      24           4 :     mi.speed = speed;
      25           4 :     mi.attacks = true;
      26           4 :     mi.strength = strength;
      27           4 :     return mi;
      28             : }
      29             : 
      30           1 : const std::unordered_map<MobType, MobInfo> MobDatabase{
      31           2 :     {MobType::Unknown, MI(MobCategory::Unknown, "Unknown"s, 0, 1)},
      32           2 :     {MobType::Rabbit, MI(MobCategory::Rabbit, "Rabbit"s, 1, 7)},
      33           2 :     {MobType::RabbitWere, MI(MobCategory::Rabbit, "Were-Rabbit"s, 1, 6, 1)},
      34           2 :     {MobType::Snake, MI(MobCategory::Snake, "Snake"s, 1, 5)},
      35           2 :     {MobType::OrcWeak, MI(MobCategory::Orc, "Little Orc"s, 5, 3, 3)},
      36           2 :     {MobType::OrcStrong, MI(MobCategory::Orc, "Big Orc"s, 6, 2, 5)},
      37           2 :     {MobType::Player, MI(MobCategory::Player, "Player"s, 5, 6, 3)},
      38          15 : };
      39             : 
      40           5 : void MobSystem::update() {
      41         205 :     for (auto& mob : game_.mobs.values()) {
      42         200 :         if (mob.info->category == MobCategory::Player)
      43           5 :             continue;
      44             : 
      45         195 :         mob.tick += mob.info->speed;
      46         195 :         mob.tick = std::min(mob.tick, 2 * Mob::TicksPerAction - 1);
      47         195 :         if (mob.tick >= Mob::TicksPerAction) {
      48           0 :             auto& e = game_.entities[mob.entity];
      49           0 :             updateMob(e, mob);
      50           0 :             mob.tick -= Mob::TicksPerAction;
      51             :         }
      52             :     }
      53           5 : }
      54             : 
      55           0 : void MobSystem::handleEvent(const EvAny& any) {
      56           0 :     if (any.is<EvTryWalk>()) {
      57           0 :         const auto& ev = any.get<EvTryWalk>();
      58           0 :         auto& mob = game_.mobs[ev.mob];
      59           0 :         auto& info = *mob.info;
      60             : 
      61             :         // check position is clear
      62           0 :         bool blocked = false;
      63           0 :         for (auto& other : game_.mobs.values()) {
      64           0 :             if (other.id != mob.id && other.position == ev.to) {
      65           0 :                 blocked = true;
      66           0 :                 break;
      67             :             }
      68             :         }
      69             : 
      70           0 :         if (!game_.worldBounds.contains(ev.to)) {
      71           0 :             blocked = true;
      72             :         }
      73             : 
      74           0 :         if (!blocked) {
      75           0 :             mob.position = ev.to;
      76             : 
      77             :             // Mob overrides sprite position
      78           0 :             auto& sprite = game_.sprites[game_.entities[mob.entity].sprite];
      79           0 :             sprite.position = mob.position;
      80             : 
      81             :             // Additional pieces
      82           0 :             switch (info.category) {
      83           0 :             default:
      84           0 :                 break;
      85           0 :             case MobCategory::Snake: {
      86           0 :                 if (randInt(0, 3) < 3) {
      87           0 :                     game_.groundTile(mob.position) = '_';
      88             :                 }
      89             : 
      90           0 :                 game_.sprites[mob.extraSprite].position = mob.position + mob.dir;
      91           0 :                 break;
      92             :             }
      93           0 :             case MobCategory::Orc: {
      94           0 :                 if (randInt(0, 1) == 0) {
      95             :                     // smash ground
      96           0 :                     game_.groundTile(mob.position) = '_';
      97             :                 }
      98           0 :                 game_.sprites[mob.extraSprite].position = mob.position + vec2i{-1, 1};
      99           0 :                 game_.sprites[mob.extraSprite2].position = mob.position + vec2i{1, 1};
     100           0 :                 break;
     101             :             }
     102             :             }
     103             : 
     104           0 :             game_.queueEvent(EvWalked{mob.id, ev.from, mob.position});
     105             :         }
     106           0 :     } else if (any.is<EvWalked>()) {
     107             :         // ...
     108           0 :     } else if (any.is<EvAttack>()) {
     109           0 :         const auto& ev = any.get<EvAttack>();
     110           0 :         auto& mob = game_.mobs[ev.mob];
     111           0 :         auto& mobInfo = *mob.info;
     112           0 :         auto& targetMob = game_.mobs[ev.target];
     113             :         // auto& targetMobInfo = *targetMob.info;
     114             : 
     115           0 :         if (mob && targetMob) {
     116           0 :             targetMob.health -= mobInfo.strength;
     117           0 :             if (targetMob.health <= 0) {
     118           0 :                 game_.queueEvent(EvKillMob{targetMob.id});
     119             :             } else {
     120             :                 // Flash-hit
     121           0 :                 const int flashDuration = 2;
     122           0 :                 auto& e = game_.entities[targetMob.entity];
     123           0 :                 game_.sprites[e.sprite].flashTimer = flashDuration;
     124           0 :                 if (targetMob.extraSprite)
     125           0 :                     game_.sprites[targetMob.extraSprite].flashTimer = flashDuration;
     126           0 :                 if (targetMob.extraSprite2)
     127           0 :                     game_.sprites[targetMob.extraSprite2].flashTimer = flashDuration;
     128             :             }
     129             :         }
     130             :     }
     131           0 : }
     132             : 
     133           0 : void MobSystem::updateMob(Entity& e, Mob& mob) {
     134           0 :     auto& info = *mob.info;
     135           0 :     auto& sprite = game_.sprites[e.sprite];
     136           0 :     vec2i pos = mob.position;
     137             : 
     138           0 :     const int margin = 6; // min distance from edge mobs prefer to be
     139           0 :     auto dirToNearestEdge = [&](vec2i pos) -> vec2i {
     140           0 :         const auto& b = game_.worldBounds;
     141             : 
     142           0 :         if (pos.y > b.top - margin)
     143           0 :             return {0, -1};
     144           0 :         else if (pos.y < b.top - b.height + margin)
     145           0 :             return {0, 1};
     146           0 :         else if (pos.x < b.left + margin)
     147           0 :             return {1, 0};
     148           0 :         else if (pos.x > b.left + b.width - margin)
     149           0 :             return {-1, 0};
     150           0 :         return {0, 0};
     151           0 :     };
     152             : 
     153           0 :     switch (info.category) {
     154           0 :     case MobCategory::Rabbit: {
     155           0 :         if (randInt(0, 500) == 0) {
     156             :             // Too many rabbits!
     157             :             // game_.queueEvent(EvSpawnMob { MobType::Rabbit, pos });
     158             :         } else {
     159             :             // Move randomly
     160           0 :             vec2i dir = dirToNearestEdge(pos);
     161           0 :             if (dir == vec2i{0, 0}) {
     162           0 :                 dir = vec2i{randInt(-1, 1), randInt(-1, 1)};
     163             :             }
     164           0 :             game_.queueEvent(EvTryWalk{mob.id, pos, pos + dir});
     165             :         }
     166           0 :         break;
     167             :     }
     168           0 :     case MobCategory::Snake: {
     169           0 :         if (randInt(0, 6) == 0) {
     170           0 :             if (mob.dir.x != 0) {
     171           0 :                 mob.dir = choose<vec2i>({{0, 1}, {0, -1}});
     172             :             } else {
     173           0 :                 mob.dir = choose<vec2i>({{1, 0}, {-1, 0}});
     174             :             }
     175             : 
     176           0 :             vec2i dir = dirToNearestEdge(pos);
     177           0 :             if (dir != vec2i{0, 0})
     178           0 :                 mob.dir = dir;
     179             :         } else {
     180           0 :             if (mob.dir.y == 1)
     181           0 :                 sprite.frame = 0;
     182           0 :             else if (mob.dir.y == -1)
     183           0 :                 sprite.frame = 1;
     184           0 :             else if (mob.dir.x == 1)
     185           0 :                 sprite.frame = 2;
     186           0 :             else if (mob.dir.x == -1)
     187           0 :                 sprite.frame = 3;
     188             : 
     189           0 :             game_.queueEvent(EvTryWalk{mob.id, pos, pos + mob.dir});
     190             :         }
     191           0 :         break;
     192             :     }
     193           0 :     case MobCategory::Orc: {
     194           0 :         if (randInt(0, 2) == 0) {
     195           0 :             game_.groundTile(pos) = choose({'_', '_'});
     196             :         }
     197             : 
     198           0 :         vec2i dir = dirToNearestEdge(pos);
     199           0 :         if (dir == vec2i{0, 0}) {
     200           0 :             if (randInt(0, 3) == 0) {
     201             :                 // stay here
     202             :             } else {
     203             :                 // move randomly
     204           0 :                 int32_t move = choose({-1, 1});
     205           0 :                 dir = choose({vec2i{move, 0}, vec2i{0, move}});
     206             :             }
     207             :         }
     208             : 
     209           0 :         if (dir != vec2i{0, 0}) {
     210           0 :             game_.queueEvent(EvTryWalk{mob.id, pos, pos + dir});
     211             :         }
     212           0 :         break;
     213             :     }
     214           0 :     default:
     215           0 :         break;
     216             :     }
     217           3 : }

Generated by: LCOV version 1.13