• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

APN-Pucky / tyrant_optimize / 20667326985

02 Jan 2026 09:44PM UTC coverage: 70.383% (+0.06%) from 70.326%
20667326985

Pull #99

github

web-flow
Merge 9fd388750 into 72c6cbcb7
Pull Request #99: Fix/enhance hunt mark poison barrier

1 of 1 new or added line in 1 file covered. (100.0%)

10 existing lines in 1 file now uncovered.

4779 of 6790 relevant lines covered (70.38%)

8538106.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.15
/cards.cpp
1
#include "cards.h"
2

3
#include <boost/tokenizer.hpp>
4
#include <sstream>
5
#include <stdexcept>
6
#include <cstring>
7
#include <list>
8
#include <iostream>
9

10
#include "tyrant.h"
11
#include "card.h"
12

13
std::string simplify_name(const std::string& card_name)
7,769,451✔
14
{
15
    std::string simple_name;
7,769,451✔
16
    for(auto c : card_name)
123,625,201✔
17
    {
18
        if(!strchr(";:,\"'! ", c))
115,855,750✔
19
        {
20
            simple_name += ::tolower(c);
224,311,105✔
21
        }
22
    }
23
    return(simple_name);
7,769,451✔
24
}
×
25

26
std::list<std::string> get_abbreviations(const std::string& name)
×
27
{
28
    std::list<std::string> abbr_list;
×
29
    boost::tokenizer<boost::char_delimiters_separator<char>> word_token{name, boost::char_delimiters_separator<char>{false, " -", ""}};
×
30
    std::string initial;
×
31
    auto token_iter = word_token.begin();
×
32
    for(; token_iter != word_token.end(); ++token_iter)
×
33
    {
34
        abbr_list.push_back(simplify_name(std::string{token_iter->begin(), token_iter->end()}));
×
35
        initial += *token_iter->begin();
×
36
    }
37
    abbr_list.push_back(simplify_name(initial));
×
38
    return(abbr_list);
×
39
}
×
40

41
//------------------------------------------------------------------------------
42
Cards::~Cards()
82✔
43
{
44
    //for (Card* c: all_cards) { delete(c); }
45
    clear();
82✔
46
}
164✔
47

48
void Cards::clear()
245✔
49
{
50
    for (Card* c: all_cards) { delete(c); }
4,331,669✔
51
    all_cards.clear();
245✔
52
    cards_by_id.clear();
245✔
53
    player_cards.clear();
245✔
54
    cards_by_name.clear();
245✔
55
    player_commanders.clear();
245✔
56
    player_assaults.clear();
245✔
57
    player_structures.clear();
245✔
58
    visible_cardset.clear();
245✔
59
}
245✔
60

61
const Card* Cards::by_id(unsigned id) const
8,955,229✔
62
{
63
    const auto cardIter = cards_by_id.find(id);
8,955,229✔
64
    if (cardIter == cards_by_id.end())
8,955,229✔
65
    {
66
        throw std::runtime_error("No card with id " + tuo::to_string(id));
228✔
67
    }
68
    else
69
    {
70
        return(cardIter->second);
8,955,153✔
71
    }
72
}
73
//------------------------------------------------------------------------------
74
void Cards::organize()
81✔
75
{
76
    cards_by_id.clear();
81✔
77
    player_cards.clear();
81✔
78
    cards_by_name.clear();
81✔
79
    player_commanders.clear();
81✔
80
    player_assaults.clear();
81✔
81
    player_structures.clear();
81✔
82
    // Round 1: set cards_by_id
83
    for (Card* card: all_cards)
4,331,505✔
84
    {
85
        cards_by_id[card->m_id] = card;
4,331,424✔
86
    }
87

88
    // Round 2: depend on cards_by_id / by_id(); update m_name, [TU] m_top_level_card etc.; set cards_by_name; 
89
    for (Card* card: all_cards)
4,331,505✔
90
    {
91
        // Remove delimiters from card names
92
        size_t pos;
4,331,424✔
93
        while((pos = card->m_name.find_first_of(";:,")) != std::string::npos)
4,332,801✔
94
        {
95
            card->m_name.erase(pos, 1);
1,377✔
96
        }
97
        // set m_top_level_card for non base cards
98
        card->m_top_level_card = by_id(card->m_base_id)->m_top_level_card;
4,331,424✔
99
        // Cards available ("visible") to players have priority
100
        std::string base_name = card->m_name;
4,331,424✔
101
        if (card == card->m_top_level_card)
4,331,424✔
102
        {
103
            add_card(card, card->m_name + "-" + tuo::to_string(card->m_level));
1,433,188✔
104
        }
105
        else
106
        {
107
            card->m_name += "-" + tuo::to_string(card->m_level);
10,844,490✔
108
        }
109
        add_card(card, card->m_name);
4,331,424✔
110
    }
4,331,424✔
111

112
    // Round 3: depend on summon skill card_id check that card_id
113
    for (Card* card: all_cards)
4,331,505✔
114
    {
115
        unsigned summon_card_id(card->m_skill_value[Skill::summon]);
4,331,424✔
116
        if (!summon_card_id) { continue; }
4,331,424✔
117
        if (!cards_by_id[summon_card_id])
321,338✔
118
        {
119
            std::cerr << "WARNING: Card [" << card->m_id << "] (" << card->m_name
×
120
                << ") summons an unknown card [" << summon_card_id << "] (removing invalid skill Summon)" << std::endl;
×
121
            card->m_skills.erase(
×
122
                std::remove_if(card->m_skills.begin(), card->m_skills.end(), [](const SkillSpec& ss) {return ss.id == Skill::summon;}),
×
UNCOV
123
                card->m_skills.end()
×
124
            );
UNCOV
125
            card->m_skill_value[Skill::summon] = 0;
×
126
        }
127
    }
128
    //Test
129
    //Round 4: sort cards by id
130
    struct { bool operator()(Card* a, Card* b) const {return a->m_id < b->m_id;}} idsort;
89,081,841✔
131
    std::sort(all_cards.begin(),all_cards.end(),idsort);
81✔
132

133

134
}
81✔
135
//------------------------------------------------------------------------------
136
void Cards::fix_dominion_recipes()
81✔
137
{
138
    for (Card* card: all_cards)
4,331,505✔
139
    {
140
        if (card->m_category != CardCategory::dominion_alpha)
4,331,424✔
141
        { continue; }
4,302,426✔
142
        std::map<const Card*, unsigned> dom_cost = dominion_cost[card->m_fusion_level][card->m_level];
28,998✔
143
        for (auto recipe_it : dom_cost)
28,998✔
144
        {
145
            // except basic Alpha Dominion (id 50001 & 50002 for lvl 1 & 2 respectively)
UNCOV
146
            if ((card->m_id != 50001) && (card->m_id != 50002))
×
147
            {
UNCOV
148
                card->m_recipe_cards[recipe_it.first] += recipe_it.second;
×
149
            }
150
        }
151
        card->m_recipe_cost = 0; // no SP required
28,998✔
152
    }
28,998✔
153
}
81✔
154
//------------------------------------------------------------------------------
155
void Cards::add_card(Card * card, const std::string & name)
5,048,018✔
156
{
157
    std::string simple_name{simplify_name(name)};
5,048,018✔
158
    auto card_itr = cards_by_name.find(simple_name);
5,048,018✔
159
    signed old_visible = card_itr == cards_by_name.end() ? -1 : visible_cardset.count(card_itr->second->m_set);
5,121,291✔
160
    signed new_visible = visible_cardset.count(card->m_set);
5,048,018✔
161
    if (card_itr != cards_by_name.end())
5,048,018✔
162
    {
163
        if (old_visible == new_visible)
73,273✔
164
        {
165
            ambiguous_names.insert(simple_name);
44,023✔
166
        }
167
        _DEBUG_MSG(2, "Duplicated card name \"%s\" [%u] set=%u (visible=%u) : [%u] set=%u (visible=%u)\n", name.c_str(), card_itr->second->m_id, card_itr->second->m_set, old_visible, card->m_id, card->m_set, new_visible);
5,048,018✔
168
    }
169
    else if (old_visible < new_visible)
4,974,745✔
170
    {
171
        ambiguous_names.erase(simple_name);
4,974,745✔
172
        cards_by_name[simple_name] = card;
4,974,745✔
173
        if (new_visible && !player_cards.count(card))
5,586,500✔
174
        {
175
            player_cards.emplace(card);
3,621,877✔
176
            switch(card->m_type)
3,621,877✔
177
            {
178
                case CardType::commander: {
37,908✔
179
                    player_commanders.push_back(card);
37,908✔
180
                    break;
181
                }
182
                case CardType::assault: {
3,315,211✔
183
                    player_assaults.push_back(card);
3,315,211✔
184
                    break;
185
                }
186
                case CardType::structure: {
268,758✔
187
                    player_structures.push_back(card);
268,758✔
188
                    break;
189
                }
UNCOV
190
                case CardType::num_cardtypes: {
×
UNCOV
191
                    throw card->m_type;
×
192
                    break;
193
                }
194
            }
195
        }
196
    }
197
}
5,048,018✔
198

199
void Cards::erase_fusion_recipe(unsigned id)
×
200
{
UNCOV
201
    cards_by_id[by_id(id)->m_base_id]->m_recipe_cards.clear();
×
UNCOV
202
}
×
203

204
// class Card
205
void Card::add_skill(Skill::Trigger trigger, Skill::Skill id, unsigned x, Faction y, unsigned n, unsigned c, Skill::Skill s, Skill::Skill s2, bool all, unsigned card_id)
8,138,936✔
206
{
207
    std::vector<SkillSpec>* storage(nullptr);
8,138,936✔
208
    switch (trigger)
8,138,936✔
209
    {
210
    case Skill::Trigger::activate:
7,633,852✔
211
        storage = &m_skills;
7,633,852✔
212
        break;
7,633,852✔
213
    case Skill::Trigger::play:
208,843✔
214
        storage = &m_skills_on_play;
208,843✔
215
        break;
208,843✔
216
    //APN
217
    case Skill::Trigger::attacked:
188,515✔
218
        storage = &m_skills_on_attacked;
188,515✔
219
        break;
188,515✔
220
    case Skill::Trigger::death:
107,726✔
221
        storage = &m_skills_on_death;
107,726✔
222
        break;
107,726✔
UNCOV
223
    default:
×
UNCOV
224
        _DEBUG_ASSERT(false);
×
225
        __builtin_unreachable();
226
    }
227
    assert(storage);
8,138,936✔
228
    // remove previous copy of such skill.id
229
    {
8,138,936✔
230
        auto pred = [id](const SkillSpec& ss) { return ss.id == id; };
8,006,947✔
231
        m_skills.erase(std::remove_if(m_skills.begin(), m_skills.end(), pred), m_skills.end());
8,138,936✔
232
        m_skills_on_play.erase(std::remove_if(m_skills_on_play.begin(), m_skills_on_play.end(), pred), m_skills_on_play.end());
8,138,936✔
233
        m_skills_on_death.erase(std::remove_if(m_skills_on_death.begin(), m_skills_on_death.end(), pred), m_skills_on_death.end());
8,138,936✔
234
        //APN
235
        m_skills_on_attacked.erase(std::remove_if(m_skills_on_attacked.begin(), m_skills_on_attacked.end(), pred), m_skills_on_attacked.end());
8,138,936✔
236
    }
237
    // add a new one
238
    storage->push_back({id, x, y, n, c, s, s2, all, card_id});
8,138,936✔
239
    // setup value
240
    m_skill_value[id] = x ? x : n ? n : card_id ? card_id : 1;
8,138,936✔
241
    m_skill_trigger[id] = trigger;
8,138,936✔
242
}
8,138,936✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc