scraps

Abandon all hope, ye who enter here.
git clone https://git.neptards.moe/neptards/scraps.git
Log | Files | Refs | Submodules | README | LICENSE

if_object.cpp (14308B)


      1 #include "scraps/game/action_eval/if.hpp" // IWYU pragma: associated
      2 
      3 #include "scraps/algorithm.hpp"
      4 #include "scraps/game/action_eval/action_helper.hpp"
      5 #include "scraps/game/action_eval/test_helper.hpp"
      6 #include "scraps/game/character_state.hpp"
      7 #include "scraps/game/room_state.hpp"
      8 #include "scraps/uuid.hpp"
      9 
     10 #include <libshit/nonowning_string.hpp>
     11 
     12 #include <functional>
     13 #include <iterator>
     14 #include <variant>
     15 
     16 // IWYU pragma: no_include <type_traits>
     17 // IWYU pragma: no_forward_declare Scraps::Game::IdKey
     18 // IWYU pragma: no_forward_declare Scraps::Game::NameKey
     19 // IWYU pragma: no_forward_declare Scraps::Game::UuidKey
     20 
     21 namespace Scraps::Game::ActionEvalPrivate
     22 {
     23   TEST_SUITE_BEGIN("Scraps::Game::ActionEval");
     24 
     25   std::optional<bool> IfObjectCustomProperty(IfParam p)
     26   {
     27     RAGS_IF_CUSTOM_PROPERTY_GET_PARTS;
     28     auto o = GetObjectSelfOrName(*p.gc, parts[0], p.oa.object);
     29     if (!o) return {};
     30     return IfCustomPropertyCommon(p, o->GetProperties(), parts[1]);
     31   }
     32 
     33   TEST_CASE_FIXTURE(Fixture, "IfObjectCustomProperty")
     34   {
     35     SetCk("object_0:key_0", "Equals", "Value 0");
     36     CHECK(IfObjectCustomProperty(p) == true);
     37 
     38     SetCk("<Self>:key_0", "Equals", "Value 0");
     39     CHECK(IfObjectCustomProperty(p) == std::nullopt);
     40     p.oa.object = st.GetObjectColl().StateAt(0).id;
     41     CHECK(IfObjectCustomProperty(p) == true);
     42 
     43     SetCk("<self>:key_0", "Equals", "Value 0");
     44     CHECK(IfObjectCustomProperty(p) == std::nullopt); // case sensitive
     45   }
     46 
     47   // ---------------------------------------------------------------------------
     48 
     49   static std::optional<ObjectProxy> GetObject(
     50     IfParam p, Libshit::StringView name)
     51   {
     52     name = p.Replace(p.eval.tmp_str0, name);
     53     return GetObjectUuidOrName(*p.gc, name);
     54   }
     55 
     56   std::optional<bool> IfObjectInCharacter(IfParam p)
     57   {
     58     auto o = GetObject(p, p.check.GetParam1()); if (!o) return false;
     59     auto loc = o->GetLocation();
     60     auto cid = std::get_if<CharacterId>(&loc); if (!cid) return false;
     61 
     62     auto name = p.Replace(p.eval.tmp_str0, p.check.GetParam0());
     63     auto c = p.gc->GetRawCharacterColl().StateGet<NameKey>(name);
     64     if (!c || name != c->name) return false; // case sensitive name check
     65 
     66     return *cid == c->id;
     67   }
     68 
     69   TEST_CASE_FIXTURE(Fixture, "IfObjectInCharacter")
     70   {
     71     SetCk("nosuch", "nosuch", "");
     72     CHECK(IfObjectInCharacter(p) == false);
     73 
     74     SetCk("nosuch", "object_0", "");
     75     CHECK(IfObjectInCharacter(p) == false);
     76     SetCk("chara_0", "object_0", "");
     77     CHECK(IfObjectInCharacter(p) == false);
     78     st.GetObjectColl().At(0).SetLocation(st.GetCharacterColl().At(0).GetId());
     79     CHECK(IfObjectInCharacter(p) == true);
     80 
     81     st.GetObjectColl().At(1).SetLocation(st.GetObjectColl().At(0).GetId());
     82     SetCk("chara_0", "object_1", "");
     83     CHECK(IfObjectInCharacter(p) == false); // not recursive
     84 
     85     SetCk("chara_0", "Object_0", "");
     86     CHECK(IfObjectInCharacter(p) == true);
     87     SetCk("chara_0", "00000000-000b-1ec1-0000-000000000000", "");
     88     CHECK(IfObjectInCharacter(p) == true);
     89     SetCk("Chara_0", "00000000-000b-1ec1-0000-000000000000", "");
     90     CHECK(IfObjectInCharacter(p) == false); // not case sensitive
     91   }
     92 
     93   // ---------------------------------------------------------------------------
     94 
     95   std::optional<bool> IfObjectInGroup(IfParam p)
     96   {
     97     auto name = p.Replace(p.eval.tmp_str0, p.check.GetParam0());
     98     auto o = p.gc->GetObjectColl().Get<NameKey>(name);
     99 
    100     return IfInGroupCommon(
    101       p, p.gc->GetObjectGroupColl(), o ? o->GetGroupId() : GroupId{0},
    102       p.check.GetParam1(), "");
    103   }
    104 
    105   TEST_CASE_FIXTURE(Fixture, "IfObjectInGroup")
    106   {
    107     SetCk("nosuch", "", "");
    108     CHECK(IfObjectInGroup(p) == true);
    109     SetCk("nosuch", "object_group_0", "");
    110     CHECK(IfObjectInGroup(p) == false);
    111 
    112     SetCk("object_0", "object_group_0", "");
    113     CHECK(IfObjectInGroup(p) == true); // direct
    114     SetCk("Object_0", "object_group_0", "");
    115     CHECK(IfObjectInGroup(p) == true); // direct, case insensitive
    116     SetCk("object_2", "object_group_0", "");
    117     CHECK(IfObjectInGroup(p) == true); // in-direct
    118     SetCk("object_2", "object_group_2", "");
    119     CHECK(IfObjectInGroup(p) == true); // direct
    120     SetCk("object_2", "Object_group_2", "");
    121     CHECK(IfObjectInGroup(p) == false); // case sensitive
    122   }
    123 
    124   // ---------------------------------------------------------------------------
    125 
    126   // why is "not" a fucking keyword in c++
    127   static bool IfObjectInObjectCommon(IfParam p, bool not_)
    128   {
    129     auto o = GetObject(p, p.check.GetParam0()); if (!o) return false;
    130     auto loc = o->GetLocation();
    131     auto oid = std::get_if<ObjectId>(&loc); if (!oid) return not_;
    132 
    133     // TODO: this should be a case sensitive match
    134     auto oo = StateGetObjectUuid(
    135       *p.gc, p.Replace(p.eval.tmp_str0, p.check.GetParam1()));
    136     if (!oo) return not_;
    137 
    138     return (*oid == oo->id) ^ not_;
    139   }
    140 
    141   std::optional<bool> IfObjectInObject(IfParam p)
    142   { return IfObjectInObjectCommon(p, false); }
    143 
    144   TEST_CASE_FIXTURE(Fixture, "IfObjectInObject")
    145   {
    146     SetCk("nosuch", "nosuch", "");
    147     CHECK(IfObjectInObject(p) == false);
    148 
    149     SetCk("object_0", "nosuch", "");
    150     CHECK(IfObjectInObject(p) == false);
    151     SetCk("object_0", "00000000-000b-1ec1-0000-000000000001", "");
    152     CHECK(IfObjectInObject(p) == false);
    153     st.GetObjectColl().At(0).SetLocation(st.GetObjectColl().At(1).GetId());
    154     CHECK(IfObjectInObject(p) == true);
    155     // TODO case sensitive
    156     // Set("object_0", "00000000-000b-1EC1-0000-000000000001", "");
    157     // CHECK(IfObjectInObject(p) == false);
    158 
    159     st.GetObjectColl().At(1).SetLocation(st.GetObjectColl().At(2).GetId());
    160     SetCk("object_0", "00000000-000b-1ec1-0000-000000000002", "");
    161     CHECK(IfObjectInObject(p) == false); // not recursive
    162   }
    163 
    164   // ---------------------------------------------------------------------------
    165 
    166   std::optional<bool> IfObjectInPlayer(IfParam p)
    167   {
    168     auto o = GetObject(p, p.check.GetParam0()); if (!o) return false;
    169     auto loc = o->GetLocation();
    170 
    171     while (auto oid = std::get_if<ObjectId>(&loc))
    172     {
    173       o = p.gc->GetObjectColl().Get<IdKey>(*oid); if (!o) return false;
    174       loc = o->GetLocation();
    175     }
    176 
    177     auto cid = std::get_if<CharacterId>(&loc); if (!cid) return false;
    178     return *cid == p.gc->GetPlayerId();
    179   }
    180 
    181   TEST_CASE_FIXTURE(Fixture, "IfObjectInPlayer")
    182   {
    183     SetCk("nosuch", "", "");
    184     CHECK(IfObjectInPlayer(p) == false);
    185     SetCk("Object_0", "", "");
    186     CHECK(IfObjectInPlayer(p) == false);
    187     st.GetObjectColl().At(0).SetLocation(st.GetPlayerId());
    188     CHECK(IfObjectInPlayer(p) == true);
    189 
    190     st.GetObjectColl().At(1).SetLocation(st.GetObjectColl().At(0).GetId());
    191     SetCk("object_1", "", "");
    192     CHECK(IfObjectInPlayer(p) == true); // recursive...
    193   }
    194 
    195   // ---------------------------------------------------------------------------
    196 
    197   std::optional<bool> IfObjectInRoom(IfParam p)
    198   {
    199     auto o = GetObject(p, p.check.GetParam0()); if (!o) return false;
    200     auto loc = o->GetLocation();
    201     auto rid = std::get_if<RoomId>(&loc); if (!rid) return false;
    202 
    203     auto room = p.Replace(p.eval.tmp_str0, p.check.GetParam1());
    204     if (room == Uuid::PLAYER_ROOM_STR)
    205       return *rid == p.gc->GetPlayer().GetRoomId();
    206 
    207     auto uuid = Uuid::TryParse(room);
    208     if (!uuid) return false;
    209     auto oo = p.gc->GetRawRoomColl().StateGet<UuidKey>(*uuid);
    210     // TODO: this should be a case sensitive match
    211     if (!oo) return false;
    212     return *rid == oo->id;
    213   }
    214 
    215   TEST_CASE_FIXTURE(Fixture, "IfObjectInRoom")
    216   {
    217     SetCk("nosuch", "nosuch", "");
    218     CHECK(IfObjectInRoom(p) == false);
    219 
    220     SetCk("object_0", "nosuch", "");
    221     CHECK(IfObjectInRoom(p) == false);
    222     SetCk("object_0", "00000000-0000-4004-0000-000000000000", "");
    223     CHECK(IfObjectInRoom(p) == false);
    224     st.GetObjectColl().At(0).SetLocation(st.GetRoomColl().At(0).GetId());
    225     CHECK(IfObjectInRoom(p) == true);
    226 
    227     SetCk("object_0", Uuid::PLAYER_ROOM_STR, "");
    228     CHECK(IfObjectInRoom(p) == true);
    229     st.GetPlayer().SetRoomId(st.GetRoomColl().At(1).GetId());
    230     CHECK(IfObjectInRoom(p) == false);
    231 
    232     // void room - will always be false
    233     SetCk("object_0", Uuid::PLAYER_ROOM_STR, "");
    234     CHECK(IfObjectInRoom(p) == false);
    235     st.GetObjectColl().At(0).SetLocation(LocationNone{});
    236     CHECK(IfObjectInRoom(p) == false);
    237   }
    238 
    239   // ---------------------------------------------------------------------------
    240 
    241   std::optional<bool> IfObjectInRoomGroup(IfParam p)
    242   {
    243     // name not allowed, only uuid so can't use GetObject
    244     auto o = GetObjectUuid(
    245       *p.gc, p.Replace(p.eval.tmp_str0, p.check.GetParam0()));
    246     if (!o) return false;
    247 
    248     auto loc = o->GetLocation();
    249     auto rid = std::get_if<RoomId>(&loc); if (!rid) return false;
    250 
    251     auto r = p.gc->GetRoomColl().Get<IdKey>(*rid); if (!r) return false;
    252 
    253     return IfInGroupCommon(p, p.gc->GetRoomGroupColl(), r->GetGroupId(),
    254                            p.check.GetParam1(), "None");
    255   }
    256 
    257   TEST_CASE_FIXTURE(Fixture, "IfObjectInRoomGroup")
    258   {
    259     dummy.game.GetRooms()[1].SetGroupId(0);
    260 
    261     SetCk("nosuch", "None", "");
    262     CHECK(IfObjectInRoomGroup(p) == false);
    263     SetCk("00000000-000b-1ec1-0000-ffffffffffff", "None", "");
    264     CHECK(IfObjectInRoomGroup(p) == false);
    265     SetCk("00000000-000b-1ec1-0000-000000000000", "None", "");
    266     CHECK(IfObjectInRoomGroup(p) == false);
    267     st.GetObjectColl().At(0).SetLocation(st.GetRoomColl().At(1).GetId());
    268     CHECK(IfObjectInRoomGroup(p) == true); // room 1 has no group
    269     SetCk("00000000-000b-1ec1-0000-000000000000", "room_group_0", "");
    270     CHECK(IfObjectInRoomGroup(p) == false);
    271 
    272     st.GetObjectColl().At(0).SetLocation(st.GetRoomColl().At(0).GetId());
    273     SetCk("00000000-000b-1ec1-0000-000000000000", "None", "");
    274     CHECK(IfObjectInRoomGroup(p) == false); // room 0 is in group 0
    275     SetCk("00000000-000b-1ec1-0000-000000000000", "room_group_0", "");
    276     CHECK(IfObjectInRoomGroup(p) == true);
    277 
    278     st.GetObjectColl().At(0).SetLocation(st.GetRoomColl().At(2).GetId());
    279     SetCk("00000000-000b-1ec1-0000-000000000000", "None", "");
    280     CHECK(IfObjectInRoomGroup(p) == false); // room 2 is in group 2 in group 0
    281     SetCk("00000000-000b-1ec1-0000-000000000000", "room_group_0", "");
    282     CHECK(IfObjectInRoomGroup(p) == true);
    283   }
    284 
    285   // ---------------------------------------------------------------------------
    286 
    287   std::optional<bool> IfObjectNotInObject(IfParam p)
    288   { return IfObjectInObjectCommon(p, true); }
    289 
    290   TEST_CASE_FIXTURE(Fixture, "IfObjectNotInObject")
    291   {
    292     SetCk("nosuch", "nosuch", "");
    293     CHECK(IfObjectNotInObject(p) == false);
    294 
    295     SetCk("object_0", "nosuch", "");
    296     CHECK(IfObjectNotInObject(p) == true);
    297     SetCk("object_0", "00000000-000b-1ec1-0000-ffffffffffff", "");
    298     CHECK(IfObjectNotInObject(p) == true);
    299     SetCk("object_0", "00000000-000b-1ec1-0000-000000000001", "");
    300     CHECK(IfObjectNotInObject(p) == true);
    301     st.GetObjectColl().At(0).SetLocation(st.GetObjectColl().At(1).GetId());
    302     CHECK(IfObjectNotInObject(p) == false);
    303     // TODO case sensitive
    304     // Set("object_0", "00000000-000b-1EC1-0000-000000000001", "");
    305     // CHECK(IfObjectNotInObject(p) == true);
    306 
    307     st.GetObjectColl().At(1).SetLocation(st.GetObjectColl().At(2).GetId());
    308     SetCk("object_0", "00000000-000b-1ec1-0000-000000000002", "");
    309     CHECK(IfObjectNotInObject(p) == true); // not recursive
    310   }
    311 
    312   // ---------------------------------------------------------------------------
    313 
    314   std::optional<bool> IfObjectNotInPlayer(IfParam p)
    315   {
    316     auto o = GetObject(p, p.check.GetParam0()); if (!o) return false;
    317     auto loc = o->GetLocation();
    318     auto cid = std::get_if<CharacterId>(&loc); if (!cid) return true;
    319     return *cid != p.gc->GetPlayerId();
    320   }
    321 
    322   TEST_CASE_FIXTURE(Fixture, "IfObjectNotInPlayer")
    323   {
    324     SetCk("nosuch", "", "");
    325     CHECK(IfObjectNotInPlayer(p) == false);
    326     SetCk("Object_0", "", "");
    327     CHECK(IfObjectNotInPlayer(p) == true);
    328     st.GetObjectColl().At(0).SetLocation(st.GetPlayerId());
    329     CHECK(IfObjectNotInPlayer(p) == false);
    330 
    331     st.GetObjectColl().At(1).SetLocation(st.GetObjectColl().At(0).GetId());
    332     SetCk("object_1", "", "");
    333     CHECK(IfObjectNotInPlayer(p) == true); // not recursive...
    334   }
    335 
    336   // ---------------------------------------------------------------------------
    337 
    338   namespace
    339   {
    340     struct State
    341     {
    342       Libshit::NonowningString key;
    343       bool neg;
    344       bool (ConstObjectProxy::*fun)() const;
    345       constexpr operator Libshit::NonowningString() const noexcept { return key; }
    346     };
    347   }
    348 
    349   static constexpr const State STATES[] = {
    350     { "Closed",    true,  &ConstObjectProxy::GetOpen },
    351     { "Invisible", true,  &ConstObjectProxy::GetVisible },
    352     { "Locked",    false, &ConstObjectProxy::GetLocked },
    353     { "Open",      false, &ConstObjectProxy::GetOpen },
    354     { "Read",      false, &ConstObjectProxy::GetRead },
    355     { "Removed",   true,  &ConstObjectProxy::GetWorn },
    356     { "Unlocked",  true,  &ConstObjectProxy::GetLocked },
    357     { "Unread",    true,  &ConstObjectProxy::GetRead },
    358     { "Visible",   false, &ConstObjectProxy::GetVisible },
    359     { "Worn",      false, &ConstObjectProxy::GetWorn },
    360   };
    361   static_assert(IsSortedAry(STATES, std::less<Libshit::NonowningString>{}));
    362 
    363   std::optional<bool> IfObjectState(IfParam p)
    364   {
    365     auto o = GetObject(p, p.check.GetParam0()); if (!o) return false;
    366     auto key = p.Replace(p.eval.tmp_str0, p.check.GetParam1());
    367 
    368     auto it = BinarySearch(std::begin(STATES), std::end(STATES), key,
    369                            std::less<Libshit::NonowningString>{});
    370     if (it == std::end(STATES)) return {};
    371 
    372     return ((*o).*(it->fun))() ^ it->neg;
    373   }
    374 
    375   TEST_CASE_FIXTURE(Fixture, "IfObjectState")
    376   {
    377     SetCk("nosuch", "nosuch", "");
    378     CHECK(IfObjectState(p) == false);
    379 
    380     SetCk("00000000-000b-1ec1-0000-000000000000", "nosuch", "");
    381     CHECK(IfObjectState(p) == std::nullopt);
    382 
    383     SetCk("object_0", "nosuch", "");
    384     CHECK(IfObjectState(p) == std::nullopt);
    385 
    386     auto check = [&](const char* str, const char* str_neg, bool res)
    387     {
    388       CAPTURE(str); CAPTURE(str_neg);
    389       SetCk("object_0", str, "");
    390       CHECK(IfObjectState(p) == res);
    391       SetCk("object_0", str_neg, "");
    392       CHECK(IfObjectState(p) == !res);
    393     };
    394     check("Open",    "Closed",    true);
    395     check("Locked",  "Unlocked",  false);
    396     check("Worn",    "Removed",   true);
    397     check("Read",    "Unread",    false);
    398     check("Visible", "Invisible", false);
    399   }
    400 
    401   TEST_SUITE_END();
    402 }