载入中...
搜索中...
未找到
Card.cpp
浏览该文件的文档.
1#include "card/Card.h"
3#include "card/CardControl.h"
4
5#include <cmath>
6
7#include "common/Json.h"
8#include "common/SubjectRef.h"
10#include "graphics/Graphics.h"
11
12#include <simplesquirrel/simplesquirrel.hpp>
13#include <squirrel.h>
14
15#include <algorithm>
16#include <cstdint>
17#include <utility>
18
19namespace eve::card {
20
22
23void CardPlaneMapper::setLogicalRect(float x, float y, float width, float height) {
24 logicalX_ = x;
25 logicalY_ = y;
26 logicalWidth_ = width;
27 logicalHeight_ = height;
28}
29
30void CardPlaneMapper::setPlane(float ox, float oy, float oz, float ux, float uy, float uz,
31 float vx, float vy, float vz) {
32 origin_ = glm::vec3(ox, oy, oz);
33 axisU_ = glm::vec3(ux, uy, uz);
34 axisV_ = glm::vec3(vx, vy, vz);
35}
36
37bool CardPlaneMapper::mapRay(float ox, float oy, float oz, float dx, float dy, float dz) {
38 const glm::vec3 normal = glm::cross(axisU_, axisV_);
39 const glm::vec3 direction(dx, dy, dz);
40 const float denominator = glm::dot(normal, direction);
41 if (std::abs(denominator) < 1e-6f) return false;
42 const float t = glm::dot(normal, origin_ - glm::vec3(ox, oy, oz)) / denominator;
43 if (t < 0.f) return false;
44 resultWorld_ = glm::vec3(ox, oy, oz) + direction * t;
45 const glm::vec3 relative = resultWorld_ - origin_;
46 const float uu = glm::dot(axisU_, axisU_);
47 const float uv = glm::dot(axisU_, axisV_);
48 const float vv = glm::dot(axisV_, axisV_);
49 const float determinant = uu * vv - uv * uv;
50 if (std::abs(determinant) < 1e-8f || logicalWidth_ == 0.f || logicalHeight_ == 0.f)
51 return false;
52 const float wu = glm::dot(relative, axisU_);
53 const float wv = glm::dot(relative, axisV_);
54 const float u = (wu * vv - wv * uv) / determinant;
55 const float v = (wv * uu - wu * uv) / determinant;
56 resultLogicalX_ = logicalX_ + u * logicalWidth_;
57 resultLogicalY_ = logicalY_ + v * logicalHeight_;
58 return true;
59}
60
61bool CardPlaneMapper::mapLayout(float x, float y) {
62 if (logicalWidth_ == 0.f || logicalHeight_ == 0.f) return false;
63 const float u = (x - logicalX_) / logicalWidth_;
64 const float v = (y - logicalY_) / logicalHeight_;
65 resultLogicalX_ = x;
66 resultLogicalY_ = y;
67 resultWorld_ = origin_ + axisU_ * u + axisV_ * v;
68 return true;
69}
70
71namespace {
72
74
75bool parseDefinition(Value o, std::unordered_map<std::string, CardDefinition> &defs) {
76 std::string id = o.getString("id");
77 if (id.empty()) return false;
79 def.id = id;
80 def.name = o.getString("name", id);
81 def.kind = o.getString("kind", "creature");
82 def.cost = o.getInt("cost");
83 def.attack = o.getInt("attack");
84 def.health = o.getInt("health");
85 def.tags = o.getStringArray("tags");
86 auto tint = o.getFloatArray("tint");
87 if (tint.size() >= 3) def.tint = glm::vec3(tint[0], tint[1], tint[2]);
88 defs[id] = def;
89 return true;
90}
91
92template <typename T>
93T *resolve(const ecs::EntityHandle &h) {
94 return static_cast<T *>(ecs::try_get(h));
95}
96
97bool ownsCard(const std::vector<ecs::EntityHandle> &handles, const CardData &card) {
98 const auto live = ecs::handle_of(const_cast<CardData *>(&card));
99 return std::any_of(handles.begin(), handles.end(), [&live](const auto &handle) {
100 return handle.table == live.table && handle.type == live.type && handle.id == live.id &&
101 handle.generation == live.generation;
102 });
103}
104
105void destroyHandles(std::vector<ecs::EntityHandle> &hs) {
106 for (auto &h : hs) {
107 if (ecs::Entity *e = ecs::try_get(h)) ecs::DestroyEntity(e);
108 }
109 hs.clear();
110}
111
112template <typename T>
113void registerCppEntityClassForScript(const ssq::Class &cls) {
114 eve::registerCppEntityView(cls, [](ssq::Array &out) {
115 HSQUIRRELVM vm = out.getHandle();
116 sq_pushobject(vm, out.getRaw());
117 ecs::Table *table = ecs::current();
118 if (table == nullptr) {
119 sq_pop(vm, 1);
120 return;
121 }
122 ecs::IComponentManager &cm = table->getOrCreateManager<T>();
123 auto *reg = cm.getOrCreateRegistryComponentBuffer<T>();
124 std::vector<ecs::IComponentBuffer *> stack;
125 stack.push_back(reg);
126 while (!stack.empty()) {
127 ecs::IComponentBuffer *buf = stack.back();
128 stack.pop_back();
129 auto *r = dynamic_cast<ecs::IRegistryComponentBuffer *>(buf);
130 if (r != nullptr) {
131 for (uint32_t i = 0; i < r->entity_count(); ++i) {
132 ecs::Entity *ent = r->entity_at(i);
133 if (ent != nullptr && ecs::is_entity_visible(ent)) {
134 ssq::detail::pushByPtr<T>(vm, static_cast<T *>(ent));
135 sq_arrayappend(vm, -2);
136 }
137 }
138 }
139 if (buf->children != nullptr) stack.push_back(buf->children);
140 if (buf->next != nullptr) stack.push_back(buf->next);
141 }
142 sq_pop(vm, 1);
143 });
144}
145
146} // namespace
147
148Card::Card() = default;
149
150Card::Card(Card &&) noexcept = default;
151Card &Card::operator=(Card &&) noexcept = default;
152
154 clearGameplayControls();
155 destroyHandles(hands_);
156 destroyHandles(decks_);
157 destroyHandles(zones_);
158 destroyHandles(cards_);
159 activeDeck_ = nullptr;
160 activeConfig_ = nullptr;
161}
162
163eve::Result<void> Card::publishGameplay(const std::string &instanceId, const std::string &ownerId, Hand *hand,
165 if (instanceId.empty() || ownerId.empty() || hand == nullptr)
168 "publishGameplay needs an instance id, an owner id and a hand", "instanceId"));
169 const auto instance = eve::PersistentId::parse(instanceId);
170 const auto owner = eve::PersistentId::parse(ownerId);
171 if (!instance.has_value() || !owner.has_value())
174 "instance and owner ids must be canonical persistent ids", "instanceId"));
175 if (!gameplay_) gameplay_ = std::make_unique<CardControl>(*this);
176 return gameplay_->publish(eve::SubjectRef::fromPersistentId(*instance), eve::SubjectRef::fromPersistentId(*owner),
177 *hand, account);
178}
179
180eve::Result<void> Card::unpublishGameplay(const std::string &instanceId) {
181 if (!gameplay_)
183 eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "no card instance is published", "instanceId"));
184 const auto instance = eve::PersistentId::parse(instanceId);
185 if (!instance.has_value())
187 eve::DiagnosticCode::InvalidArgument, "the instance id must be a canonical persistent id", "instanceId"));
188 return gameplay_->unpublish(eve::SubjectRef::fromPersistentId(*instance));
189}
190
192 if (gameplay_) gameplay_->clear();
193}
194
195int Card::gameplayControlCount() const { return gameplay_ ? gameplay_->count() : 0; }
196
197std::vector<std::string> Card::gameplayInstances() const {
198 std::vector<std::string> result;
199 if (!gameplay_) return result;
200 for (const auto &instance : gameplay_->instances()) result.push_back(instance.format());
201 return result;
202}
203
204// ---------------------------------------------------------------------------
205// 卡牌类型定义
206// ---------------------------------------------------------------------------
207
208int Card::registerCardsFromJson(const std::string &json) {
210 if (!doc.valid()) return 0;
211 const Value root = doc.root();
212 int n = 0;
213 if (root.isArray()) {
214 for (size_t i = 0; i < root.size(); ++i)
215 if (parseDefinition(root.at(i), defs_)) ++n;
216 } else if (root.isObject()) {
217 if (parseDefinition(root, defs_)) ++n;
218 }
219 if (n > 0) definitionViewDirty_ = true;
220 return n;
221}
222
224 defs_.clear();
225 definitionView_.clear();
226 definitionViewDirty_ = false;
227}
228
229int Card::getCardDefinitionCount() { return static_cast<int>(defs_.size()); }
230
231std::string Card::getCardDefinitionId(int index) const {
232 if (definitionViewDirty_) {
233 definitionView_.clear();
234 definitionView_.reserve(defs_.size());
235 for (const auto &[id, definition] : defs_) definitionView_.push_back(id);
236 std::sort(definitionView_.begin(), definitionView_.end());
237 definitionViewDirty_ = false;
238 }
239 return index >= 0 && index < static_cast<int>(definitionView_.size())
240 ? definitionView_[static_cast<size_t>(index)]
241 : std::string{};
242}
243
244bool Card::hasCardDefinition(const std::string &id) { return defs_.count(id) != 0; }
245
246bool Card::setCardDefinition(const std::string &id, const std::string &name, const std::string &kind,
247 int cost, int attack, int health, float tintR, float tintG, float tintB) {
248 if (id.empty() || cost < 0 || attack < 0 || health < 0) return false;
249 CardDefinition definition;
250 definition.id = id;
251 definition.name = name.empty() ? id : name;
252 definition.kind = kind.empty() ? "creature" : kind;
253 definition.cost = cost;
254 definition.attack = attack;
255 definition.health = health;
256 definition.tint = glm::vec3(std::clamp(tintR, 0.f, 1.f), std::clamp(tintG, 0.f, 1.f),
257 std::clamp(tintB, 0.f, 1.f));
258 defs_[id] = std::move(definition);
259 definitionViewDirty_ = true;
260 return true;
261}
262
263bool Card::removeCardDefinition(const std::string &id) {
264 if (defs_.erase(id) == 0) return false;
265 definitionViewDirty_ = true;
266 return true;
267}
268
270 auto it = defs_.find(id);
271 if (it == defs_.end())
273 eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "card definition was not found", id));
274 if (!condition.isValid())
276 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "card play condition is invalid", id));
277 it->second.playCondition = std::move(condition);
279}
280
281const CardDefinition *Card::findDef(const std::string &id) const {
282 auto it = defs_.find(id);
283 return it == defs_.end() ? nullptr : &it->second;
284}
285
288 const auto *definition = findDef(const_cast<CardData *>(card)->identity()->definitionId);
290 return CardPlayConditionAdapter::evaluate(card, *definition, definition->playCondition, std::move(queries));
291}
292
293eve::Result<double> Card::getCardAttribute(CardData &card, std::string_view attribute) const {
294 if (!ownsCard(cards_, card))
296 "card does not belong to this Card facade", "card"));
297 return CardAttributeAdapter::read(card, attribute);
298}
299
300eve::Result<void> Card::setCardAttribute(CardData &card, std::string_view attribute, double value) const {
301 if (!ownsCard(cards_, card))
303 "card does not belong to this Card facade", "card"));
304 return CardAttributeAdapter::setBase(card, attribute, value);
305}
306
308 eve::SubjectRef subject) const {
309 if (!ownsCard(cards_, card))
311 eve::DiagnosticCode::StaleHandle, "card does not belong to this Card facade", "card"));
312 auto attributes = CardAttributeAdapter::ensure(card);
313 if (!attributes) return eve::Result<effects::EffectHandle>::failure(attributes.status());
314 return card.effects()->values.apply(definition, subject);
315}
316
318 std::size_t settled = 0;
319 for (const auto &handle : cards_) {
320 auto *card = resolve<CardData>(handle);
321 if (card == nullptr || card->effects()->values.count() == 0) continue;
322 auto updated = card->effects()->values.advance(simulationStep);
324 auto result = std::move(updated).takeValue();
326 static_cast<double>(card->effects()->values.target().health));
328 settled += result.settled;
329 }
332}
333
335 eve::resource::IResourceAccount &playerAccount,
336 CardPlayComposition composition,
337 std::string transactionId) {
338 if (!ownsCard(cards_, card))
340 eve::DiagnosticCode::StaleHandle, "card does not belong to this Card facade", "card"));
341 const auto *definition = findDef(card.identity()->definitionId);
342 if (definition == nullptr)
344 eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "card definition was not found", "definition"));
346 request.card = &card;
347 request.definition = definition;
348 request.playerAccount = &playerAccount;
349 request.composition = std::move(composition);
350 request.transactionId = std::move(transactionId);
351 return CardPlayPaymentAdapter::play(std::move(request));
352}
353
354std::string Card::getCardDefinitionName(const std::string &id) {
355 const auto *d = findDef(id);
356 return d ? d->name : std::string{};
357}
358
359std::string Card::getCardDefinitionKind(const std::string &id) {
360 const auto *d = findDef(id);
361 return d ? d->kind : std::string{};
362}
363
364int Card::getCardDefinitionCost(const std::string &id) {
365 const auto *d = findDef(id);
366 return d ? d->cost : 0;
367}
368
369int Card::getCardDefinitionAttack(const std::string &id) {
370 const auto *d = findDef(id);
371 return d ? d->attack : 0;
372}
373
374int Card::getCardDefinitionHealth(const std::string &id) {
375 const auto *d = findDef(id);
376 return d ? d->health : 0;
377}
378
379float Card::getCardDefinitionTintR(const std::string &id) {
380 const auto *d = findDef(id);
381 return d ? d->tint.r : 0.f;
382}
383
384float Card::getCardDefinitionTintG(const std::string &id) {
385 const auto *d = findDef(id);
386 return d ? d->tint.g : 0.f;
387}
388
389float Card::getCardDefinitionTintB(const std::string &id) {
390 const auto *d = findDef(id);
391 return d ? d->tint.b : 0.f;
392}
393
394// ---------------------------------------------------------------------------
395// 工厂
396// ---------------------------------------------------------------------------
397
399 auto cfg = std::make_unique<LayoutConfig>();
400 LayoutConfig *raw = cfg.get();
401 configs_.push_back(std::move(cfg));
402 if (!activeConfig_) activeConfig_ = raw;
403 return raw;
404}
405
406CardData *Card::newCard(const std::string &defId) {
407 const CardDefinition *d = findDef(defId);
408 if (!d) return nullptr;
410 c->identity()->id = defId + "#" + std::to_string(nextInstance_++);
411 c->identity()->definitionId = defId;
412 c->identity()->name = d->name;
413 c->identity()->kind = d->kind;
414 c->stats()->cost = d->cost;
415 c->stats()->attack = d->attack;
416 c->stats()->health = d->health;
417 c->visual()->tint = d->tint;
418 auto attributes = CardAttributeAdapter::ensure(*c);
419 if (!attributes) {
420 attributes.ignore("Card::newCard could not seed canonical attributes");
421 c->release();
422 return nullptr;
423 }
424 if (d->health > 0) {
425 auto target = c->effects()->values.initializeTarget(CardEffectTarget{d->health, d->health, 0, 0});
426 if (!target) {
427 target.ignore("Card::newCard could not seed the effect target");
428 c->release();
429 return nullptr;
430 }
431 }
432 cards_.push_back(ecs::handle_of(c));
433 return c;
434}
435
438 decks_.push_back(ecs::handle_of(d));
439 activeDeck_ = d;
440 return d;
441}
442
443Zone *Card::newZone(const std::string &id, const std::string &label, float x, float y, float w, float h) {
445 auto *R = z->rect().operator->();
446 R->id = id;
447 R->label = label;
448 R->x = x;
449 R->y = y;
450 R->w = w;
451 R->h = h;
452 zones_.push_back(ecs::handle_of(z));
453 return z;
454}
455
458 h->meta()->config = cfg;
459 hands_.push_back(ecs::handle_of(h));
460 return h;
461}
462
464 auto mapper = std::make_unique<CardPlaneMapper>();
465 CardPlaneMapper *raw = mapper.get();
466 planeMappers_.push_back(std::move(mapper));
467 return raw;
468}
469
470// ---------------------------------------------------------------------------
471// 游戏状态
472// ---------------------------------------------------------------------------
473
475 if (cfg) activeConfig_ = cfg;
476}
477
478LayoutConfig *Card::getConfig() const { return activeConfig_; }
479
480int Card::handCount() const { return static_cast<int>(hands_.size()); }
481
483 if (index < 0 || static_cast<size_t>(index) >= hands_.size()) return nullptr;
484 return resolve<Hand>(hands_[static_cast<size_t>(index)]);
485}
486
487Hand *Card::findHand(const std::string &owner) const {
488 for (const auto &h : hands_) {
489 Hand *hand = resolve<Hand>(h);
490 if (hand && hand->meta()->owner == owner) return hand;
491 }
492 return nullptr;
493}
494
495int Card::zoneCount() const { return static_cast<int>(zones_.size()); }
496
498 if (index < 0 || static_cast<size_t>(index) >= zones_.size()) return nullptr;
499 return resolve<Zone>(zones_[static_cast<size_t>(index)]);
500}
501
502Deck *Card::getDeck() const { return activeDeck_; }
503
504CardData *Card::drawCard(const std::string &handOwner) {
505 Hand *h = findHand(handOwner);
506 if (!h || !activeDeck_) return nullptr;
507 CardData *c = activeDeck_->draw();
508 if (!c) return nullptr;
509 if (activeConfig_) {
510 c->layout()->x = activeConfig_->deckX;
511 c->layout()->y = activeConfig_->deckY;
512 }
513 c->state()->phase = CardState::Deck;
514 h->addCard(c);
515 return c;
516}
517
519 presentation_.clear();
520 presentation_.reserve(cards_.size());
521 for (const auto &handle : cards_) {
522 CardData *card = resolve<CardData>(handle);
523 if (!card) continue;
524 const auto *identity = card->identity().operator->();
525 const auto *layout = card->layout().operator->();
526 const auto *state = card->state().operator->();
527 const auto *visual = card->visual().operator->();
528 presentation_.push_back({identity->id,
529 identity->definitionId,
530 cardStateName(state->phase),
531 layout->x,
532 layout->y,
533 layout->w,
534 layout->h,
535 layout->angle,
536 layout->scale,
537 layout->alpha,
538 state->hovered,
539 state->dragging,
540 visual->disabled,
541 visual->faceUp});
542 }
543 return static_cast<int>(presentation_.size());
544}
545
546int Card::getPresentationCount() const { return static_cast<int>(presentation_.size()); }
547
549 if (index < 0 || static_cast<size_t>(index) >= presentation_.size()) return nullptr;
550 return &presentation_[static_cast<size_t>(index)];
551}
552
553// ---------------------------------------------------------------------------
554// 每帧
555// ---------------------------------------------------------------------------
556
557void Card::update(float dt, float mx, float my, bool down) {
558 std::vector<Zone *> zonePtrs;
559 zonePtrs.reserve(zones_.size());
560 for (auto &h : zones_) {
561 if (Zone *z = resolve<Zone>(h)) zonePtrs.push_back(z);
562 }
563 for (auto &h : hands_) {
564 if (Hand *hand = resolve<Hand>(h)) hand->update(dt, mx, my, down, zonePtrs, events_);
565 }
566}
567
569 if (!builtInVisuals_)
570 return;
571 if (activeConfig_ && activeConfig_->showZones) {
572 for (auto &h : zones_) {
573 if (Zone *z = resolve<Zone>(h)) z->render(gfx, true);
574 }
575 }
576 for (auto &h : hands_) {
577 if (Hand *hand = resolve<Hand>(h)) hand->render(gfx);
578 }
579}
580
581void Card::beginTargeting(const std::string &sourceId, float x, float y) {
582 targetingActive_ = true;
583 targetingValid_ = false;
584 targetingSource_ = sourceId;
585 targetingId_.clear();
586 targetingStartX_ = targetingX_ = x;
587 targetingStartY_ = targetingY_ = y;
588}
589
590void Card::updateTargeting(float x, float y, const std::string &targetId, bool valid) {
591 if (!targetingActive_)
592 return;
593 targetingX_ = x;
594 targetingY_ = y;
595 targetingId_ = targetId;
596 targetingValid_ = valid;
597}
598
599void Card::cancelTargeting() {
600 targetingActive_ = false;
601 targetingValid_ = false;
602 targetingSource_.clear();
603 targetingId_.clear();
604}
605
606void Card::renderTargeting(graphics::Graphics *gfx) {
607 if (!gfx || !targetingActive_)
608 return;
609 const float dx = targetingX_ - targetingStartX_;
610 const float dy = targetingY_ - targetingStartY_;
611 const float length = std::sqrt(dx * dx + dy * dy);
612 if (length < 2.f)
613 return;
614 constexpr float radiansToDegrees = 57.2957795131f;
615 const float angle = std::atan2(dy, dx) * radiansToDegrees;
616 const graphics::Color color = targetingValid_ ? graphics::Color(0.15f, 1.f, 0.25f, 0.9f)
617 : graphics::Color(1.f, 0.12f, 0.06f, 0.9f);
618 gfx->drawSolidRectRotated(targetingStartX_ + dx * 0.5f, targetingStartY_ + dy * 0.5f,
619 length, 12.f, angle, color);
620 gfx->drawSolidRectRotated(targetingX_ - std::cos((angle - 28.f) / radiansToDegrees) * 12.f,
621 targetingY_ - std::sin((angle - 28.f) / radiansToDegrees) * 12.f,
622 32.f, 10.f, angle - 28.f, color);
623 gfx->drawSolidRectRotated(targetingX_ - std::cos((angle + 28.f) / radiansToDegrees) * 12.f,
624 targetingY_ - std::sin((angle + 28.f) / radiansToDegrees) * 12.f,
625 32.f, 10.f, angle + 28.f, color);
626}
627
629 if (!activeDeck_ || !activeConfig_) return;
630 const LayoutConfig &cfg = *activeConfig_;
631 const int c = activeDeck_->count();
632 if (c <= 0) return;
633 const float w = cfg.cardW * 0.9f;
634 const float h = cfg.cardH * 0.9f;
635 for (int i = 0; i < 3 && i < c; ++i) {
636 const float off = static_cast<float>(i) * 3.f;
637 renderCardBack(gfx, cfg.deckX - w * 0.5f + off, cfg.deckY - h * 0.5f - off, w, h, 0.f, 1.f);
638 }
639 if (gfx->getFont())
640 printCentered(gfx, std::to_string(c), cfg.deckX, cfg.deckY - h * 0.5f - 12.f, 1.2f,
641 glm::vec4(0.95f, 0.9f, 0.8f, 1.f));
642}
643
644// ---------------------------------------------------------------------------
645// 事件
646// ---------------------------------------------------------------------------
647
648void Card::clearEvents() { events_.clear(); }
649
650int Card::getEventCount() const { return static_cast<int>(events_.size()); }
651
652std::string Card::getEventType(int index) const {
653 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
654 return events_[static_cast<size_t>(index)].type;
655}
656
657std::string Card::getEventHand(int index) const {
658 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
659 return events_[static_cast<size_t>(index)].hand;
660}
661
662std::string Card::getEventZone(int index) const {
663 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
664 return events_[static_cast<size_t>(index)].zoneId;
665}
666
667std::string Card::getEventCardId(int index) const {
668 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
669 return events_[static_cast<size_t>(index)].cardId;
670}
671
672std::string Card::getEventReason(int index) const {
673 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
674 return events_[static_cast<size_t>(index)].reason;
675}
676
677// ---------------------------------------------------------------------------
678// 脚本绑定
679// ---------------------------------------------------------------------------
680
681void Card::expose(ssq::Table &table) {
682 const auto vm = table.getHandle();
683 auto cls = table.addClass(name, Card::create, false);
684 expose(cls);
685
686 // LayoutConfig —— 全部布局参数(UiCard Configs)
687 auto cfgCls = table.addClass<LayoutConfig>(
688 "LayoutConfig", std::function<LayoutConfig *()>([]() -> LayoutConfig * { return nullptr; }), false);
689 cfgCls.addFunc("getCardW", [](LayoutConfig *c) -> float { return c ? c->cardW : 0.f; });
690 cfgCls.addFunc("setCardW", [](LayoutConfig *c, float v) { if (c) c->cardW = v; });
691 cfgCls.addFunc("getCardH", [](LayoutConfig *c) -> float { return c ? c->cardH : 0.f; });
692 cfgCls.addFunc("setCardH", [](LayoutConfig *c, float v) { if (c) c->cardH = v; });
693 cfgCls.addFunc("getSpacing", [](LayoutConfig *c) -> float { return c ? c->spacing : 0.f; });
694 cfgCls.addFunc("setSpacing", [](LayoutConfig *c, float v) { if (c) c->spacing = v; });
695 cfgCls.addFunc("getHandX", [](LayoutConfig *c) -> float { return c ? c->handX : 0.f; });
696 cfgCls.addFunc("setHandX", [](LayoutConfig *c, float v) { if (c) c->handX = v; });
697 cfgCls.addFunc("getHandY", [](LayoutConfig *c) -> float { return c ? c->handY : 0.f; });
698 cfgCls.addFunc("setHandY", [](LayoutConfig *c, float v) { if (c) c->handY = v; });
699 cfgCls.addFunc("getArcHeight", [](LayoutConfig *c) -> float { return c ? c->arcHeight : 0.f; });
700 cfgCls.addFunc("setArcHeight", [](LayoutConfig *c, float v) { if (c) c->arcHeight = v; });
701 cfgCls.addFunc("getRotationAngle", [](LayoutConfig *c) -> float { return c ? c->rotationAngle : 0.f; });
702 cfgCls.addFunc("setRotationAngle", [](LayoutConfig *c, float v) { if (c) c->rotationAngle = v; });
703 cfgCls.addFunc("getHoverRotation", [](LayoutConfig *c) -> bool { return c ? c->hoverRotation : false; });
704 cfgCls.addFunc("setHoverRotation", [](LayoutConfig *c, bool v) { if (c) c->hoverRotation = v; });
705 cfgCls.addFunc("getHoverScale", [](LayoutConfig *c) -> float { return c ? c->hoverScale : 0.f; });
706 cfgCls.addFunc("setHoverScale", [](LayoutConfig *c, float v) { if (c) c->hoverScale = v; });
707 cfgCls.addFunc("getHoverLift", [](LayoutConfig *c) -> float { return c ? c->hoverLift : 0.f; });
708 cfgCls.addFunc("setHoverLift", [](LayoutConfig *c, float v) { if (c) c->hoverLift = v; });
709 cfgCls.addFunc("getHoverSpeed", [](LayoutConfig *c) -> float { return c ? c->hoverSpeed : 0.f; });
710 cfgCls.addFunc("setHoverSpeed", [](LayoutConfig *c, float v) { if (c) c->hoverSpeed = v; });
711 cfgCls.addFunc("getMotionSpeed", [](LayoutConfig *c) -> float { return c ? c->motionSpeed : 0.f; });
712 cfgCls.addFunc("setMotionSpeed", [](LayoutConfig *c, float v) { if (c) c->motionSpeed = v; });
713 cfgCls.addFunc("getDisabledAlpha", [](LayoutConfig *c) -> float { return c ? c->disabledAlpha : 0.f; });
714 cfgCls.addFunc("setDisabledAlpha", [](LayoutConfig *c, float v) { if (c) c->disabledAlpha = v; });
715 cfgCls.addFunc("getShowZones", [](LayoutConfig *c) -> bool { return c ? c->showZones : false; });
716 cfgCls.addFunc("setShowZones", [](LayoutConfig *c, bool v) { if (c) c->showZones = v; });
717 cfgCls.addFunc("getDeckX", [](LayoutConfig *c) -> float { return c ? c->deckX : 0.f; });
718 cfgCls.addFunc("setDeckX", [](LayoutConfig *c, float v) { if (c) c->deckX = v; });
719 cfgCls.addFunc("getDeckY", [](LayoutConfig *c) -> float { return c ? c->deckY : 0.f; });
720 cfgCls.addFunc("setDeckY", [](LayoutConfig *c, float v) { if (c) c->deckY = v; });
721 cfgCls.addFunc("getDragThreshold", [](LayoutConfig *c) -> float { return c ? c->dragThreshold : 0.f; });
722 cfgCls.addFunc("setDragThreshold", [](LayoutConfig *c, float v) { if (c) c->dragThreshold = v; });
723
724 auto mapperCls = table.addClass<CardPlaneMapper>(
725 "CardPlaneMapper", std::function<CardPlaneMapper *()>([]() -> CardPlaneMapper * {
726 return nullptr;
727 }), false);
728 mapperCls.addFunc("setLogicalRect", &CardPlaneMapper::setLogicalRect);
729 mapperCls.addFunc("setPlane", &CardPlaneMapper::setPlane);
730 mapperCls.addFunc("mapRay", &CardPlaneMapper::mapRay);
731 mapperCls.addFunc("mapLayout", &CardPlaneMapper::mapLayout);
732 mapperCls.addFunc("getLogicalX", &CardPlaneMapper::getLogicalX);
733 mapperCls.addFunc("getLogicalY", &CardPlaneMapper::getLogicalY);
734 mapperCls.addFunc("getWorldX", &CardPlaneMapper::getWorldX);
735 mapperCls.addFunc("getWorldY", &CardPlaneMapper::getWorldY);
736 mapperCls.addFunc("getWorldZ", &CardPlaneMapper::getWorldZ);
737
738 // CardData
739 auto cardCls = table.addClass<CardData>(
740 "CardData", std::function<CardData *()>([]() -> CardData * { return nullptr; }), false);
741 registerCppEntityClassForScript<CardData>(cardCls);
742 cardCls.addFunc("getId", [](CardData *c) -> std::string { return c ? c->identity()->id : std::string{}; });
743 cardCls.addFunc("getInstanceId", [](CardData *c) -> std::string {
744 return c ? c->identity()->id : std::string{};
745 });
746 cardCls.addFunc("getDefinitionId", [](CardData *c) -> std::string {
747 return c ? c->identity()->definitionId : std::string{};
748 });
749 cardCls.addFunc("setId", [](CardData *c, const std::string &v) { if (c) c->identity()->id = v; });
750 cardCls.addFunc("getName", [](CardData *c) -> std::string { return c ? c->identity()->name : std::string{}; });
751 cardCls.addFunc("setName", [](CardData *c, const std::string &v) { if (c) c->identity()->name = v; });
752 cardCls.addFunc("getKind", [](CardData *c) -> std::string { return c ? c->identity()->kind : std::string{}; });
753 cardCls.addFunc("setKind", [](CardData *c, const std::string &v) { if (c) c->identity()->kind = v; });
754 cardCls.addFunc("getCost", [](CardData *c) -> int { return c ? c->stats()->cost : 0; });
755 cardCls.addFunc("setCost", [](CardData *c, int v) { if (c) c->stats()->cost = v; });
756 cardCls.addFunc("getAttack", [](CardData *c) -> int { return c ? c->stats()->attack : 0; });
757 cardCls.addFunc("setAttack", [](CardData *c, int v) { if (c) c->stats()->attack = v; });
758 cardCls.addFunc("getHealth", [](CardData *c) -> int { return c ? c->stats()->health : 0; });
759 cardCls.addFunc("setHealth", [](CardData *c, int v) { if (c) c->stats()->health = v; });
760 cardCls.addFunc("configureSettlementRulesJson", [vm](CardData* value, const std::string& json) {
761 if (!value)
764 eve::DiagnosticCode::InvalidArgument, "CardData receiver must not be null", "card", {},
765 "card.squirrel")));
767 if (!rules)
770 value->effects()->values.configureSettlementRules(rules.value()));
771 });
772 cardCls.addFunc("isFaceUp", [](CardData *c) -> bool { return c ? c->visual()->faceUp : true; });
773 cardCls.addFunc("setFaceUp", [](CardData *c, bool v) { if (c) c->visual()->faceUp = v; });
774 cardCls.addFunc("isDisabled", [](CardData *c) -> bool { return c ? c->visual()->disabled : false; });
775 cardCls.addFunc("setDisabled", [](CardData *c, bool v) { if (c) c->visual()->disabled = v; });
776 cardCls.addFunc("getState", [](CardData *c) -> std::string {
777 return c ? cardStateName(c->state()->phase) : std::string{};
778 });
779 cardCls.addFunc("setState", [](CardData *c, const std::string &v) {
780 if (!c) return;
781 auto *st = c->state().operator->();
782 if (v == "deck") st->phase = CardState::Deck;
783 else if (v == "hand") st->phase = CardState::Hand;
784 else if (v == "hovered") st->phase = CardState::Hovered;
785 else if (v == "dragging") st->phase = CardState::Dragging;
786 else if (v == "returning") st->phase = CardState::Returning;
787 else if (v == "played") st->phase = CardState::Played;
788 else if (v == "discarded") st->phase = CardState::Discarded;
789 else if (v == "disabled") st->phase = CardState::Disabled;
790 });
791 cardCls.addFunc("getTintR", [](CardData *c) -> float { return c ? c->visual()->tint.r : 0.f; });
792 cardCls.addFunc("getTintG", [](CardData *c) -> float { return c ? c->visual()->tint.g : 0.f; });
793 cardCls.addFunc("getTintB", [](CardData *c) -> float { return c ? c->visual()->tint.b : 0.f; });
794 cardCls.addFunc("setTint", [](CardData *c, float r, float g, float b) {
795 if (c) c->visual()->tint = glm::vec3(r, g, b);
796 });
797 cardCls.addFunc("setArt", [](CardData *c, graphics::Texture *t) { if (c) c->visual()->texture = t; });
798 cardCls.addFunc("getArt", [](CardData *c) -> graphics::Texture * { return c ? c->visual()->texture : nullptr; });
799 cardCls.addFunc("getX", [](CardData *c) -> float { return c ? c->layout()->x : 0.f; });
800 cardCls.addFunc("getY", [](CardData *c) -> float { return c ? c->layout()->y : 0.f; });
801 cardCls.addFunc("getW", [](CardData *c) -> float { return c ? c->layout()->w : 0.f; });
802 cardCls.addFunc("getH", [](CardData *c) -> float { return c ? c->layout()->h : 0.f; });
803 cardCls.addFunc("getAngle", [](CardData *c) -> float { return c ? c->layout()->angle : 0.f; });
804 cardCls.addFunc("getScale", [](CardData *c) -> float { return c ? c->layout()->scale : 0.f; });
805 cardCls.addFunc("getAlpha", [](CardData *c) -> float { return c ? c->layout()->alpha : 0.f; });
806 cardCls.addFunc("isHovered", [](CardData *c) -> bool { return c ? c->state()->hovered : false; });
807 cardCls.addFunc("isDragging", [](CardData *c) -> bool { return c ? c->state()->dragging : false; });
808 cardCls.addFunc("hit", [](CardData *c, float px, float py) -> bool { return c && c->hit(px, py); });
809 cardCls.addFunc("describe", [](CardData *c) -> std::string { return c ? c->describe() : std::string{}; });
810
811 // Deck
812 auto deckCls = table.addClass<Deck>(
813 "Deck", std::function<Deck *()>([]() -> Deck * { return nullptr; }), false);
814 registerCppEntityClassForScript<Deck>(deckCls);
815 deckCls.addFunc("push", &Deck::push);
816 deckCls.addFunc("draw", &Deck::draw);
817 deckCls.addFunc("peek", &Deck::peek);
818 deckCls.addFunc("count", &Deck::count);
819 deckCls.addFunc("isEmpty", &Deck::isEmpty);
820 deckCls.addFunc("clear", &Deck::clear);
821 deckCls.addFunc("shuffle", &Deck::shuffle);
822 deckCls.addFunc("getCard", &Deck::get);
823
824 // Zone
825 auto zoneCls = table.addClass<Zone>(
826 "Zone", std::function<Zone *()>([]() -> Zone * { return nullptr; }), false);
827 registerCppEntityClassForScript<Zone>(zoneCls);
828 zoneCls.addFunc("getId", [](Zone *z) -> std::string { return z ? z->rect()->id : std::string{}; });
829 zoneCls.addFunc("setId", [](Zone *z, const std::string &v) { if (z) z->rect()->id = v; });
830 zoneCls.addFunc("getLabel", [](Zone *z) -> std::string { return z ? z->rect()->label : std::string{}; });
831 zoneCls.addFunc("setLabel", [](Zone *z, const std::string &v) { if (z) z->rect()->label = v; });
832 zoneCls.addFunc("getX", [](Zone *z) -> float { return z ? z->rect()->x : 0.f; });
833 zoneCls.addFunc("getY", [](Zone *z) -> float { return z ? z->rect()->y : 0.f; });
834 zoneCls.addFunc("getW", [](Zone *z) -> float { return z ? z->rect()->w : 0.f; });
835 zoneCls.addFunc("getH", [](Zone *z) -> float { return z ? z->rect()->h : 0.f; });
836 zoneCls.addFunc("setRect", [](Zone *z, float x, float y, float w, float h) {
837 if (!z) return;
838 auto *R = z->rect().operator->();
839 R->x = x; R->y = y; R->w = w; R->h = h;
840 });
841 zoneCls.addFunc("getColorR", [](Zone *z) -> float { return z ? z->rect()->color.r : 0.f; });
842 zoneCls.addFunc("getColorG", [](Zone *z) -> float { return z ? z->rect()->color.g : 0.f; });
843 zoneCls.addFunc("getColorB", [](Zone *z) -> float { return z ? z->rect()->color.b : 0.f; });
844 zoneCls.addFunc("setColor", [](Zone *z, float r, float g, float b) {
845 if (z) z->rect()->color = glm::vec3(r, g, b);
846 });
847 zoneCls.addFunc("getAlpha", [](Zone *z) -> float { return z ? z->rect()->alpha : 0.f; });
848 zoneCls.addFunc("setAlpha", [](Zone *z, float v) { if (z) z->rect()->alpha = v; });
849 zoneCls.addFunc("isEnabled", [](Zone *z) -> bool { return z ? z->rect()->enabled : false; });
850 zoneCls.addFunc("setEnabled", [](Zone *z, bool v) { if (z) z->rect()->enabled = v; });
851 zoneCls.addFunc("addAcceptKind", [](Zone *z, const std::string &k) { if (z) z->filter()->acceptKinds.push_back(k); });
852 zoneCls.addFunc("clearAcceptKinds", [](Zone *z) { if (z) z->filter()->acceptKinds.clear(); });
853 zoneCls.addFunc("accepts", [](Zone *z, CardData *c) -> bool { return z && z->accepts(c); });
854 zoneCls.addFunc("contains", [](Zone *z, float px, float py) -> bool { return z && z->contains(px, py); });
855 zoneCls.addFunc("render", [](Zone *z, graphics::Graphics *gfx, bool showLabel) {
856 if (z) z->render(gfx, showLabel);
857 });
858
859 // Hand
860 auto handCls = table.addClass<Hand>(
861 "Hand", std::function<Hand *()>([]() -> Hand * { return nullptr; }), false);
862 registerCppEntityClassForScript<Hand>(handCls);
863 handCls.addFunc("getOwner", [](Hand *h) -> std::string { return h ? h->meta()->owner : std::string{}; });
864 handCls.addFunc("setOwner", [](Hand *h, const std::string &v) { if (h) h->meta()->owner = v; });
865 handCls.addFunc("getConfig", [](Hand *h) -> LayoutConfig * { return h ? h->meta()->config : nullptr; });
866 handCls.addFunc("setConfig", [](Hand *h, LayoutConfig *c) { if (h) h->meta()->config = c; });
867 handCls.addFunc("isFaceDown", [](Hand *h) -> bool { return h ? h->meta()->faceDown : false; });
868 handCls.addFunc("setFaceDown", [](Hand *h, bool v) { if (h) h->meta()->faceDown = v; });
869 handCls.addFunc("isPeek", [](Hand *h) -> bool { return h ? h->meta()->peek : false; });
870 handCls.addFunc("setPeek", [](Hand *h, bool v) { if (h) h->meta()->peek = v; });
871 handCls.addFunc("isInteractive", [](Hand *h) -> bool { return h ? h->meta()->interactive : true; });
872 handCls.addFunc("setInteractive", [](Hand *h, bool v) { if (h) h->meta()->interactive = v; });
873 handCls.addFunc("addCard", &Hand::addCard);
874 handCls.addFunc("removeCard", &Hand::removeCard);
875 handCls.addFunc("clear", &Hand::clear);
876 handCls.addFunc("count", &Hand::count);
877 handCls.addFunc("getCard", &Hand::get);
878 handCls.addFunc("findCard", &Hand::find);
879 handCls.addFunc("pickCard", &Hand::pick);
880 handCls.addFunc("render", [](Hand *h, graphics::Graphics *gfx) { if (h) h->render(gfx); });
881
882 auto snapshotCls = table.addClass<CardPresentationSnapshot>(
883 "CardPresentationSnapshot",
884 std::function<CardPresentationSnapshot *()>([]() -> CardPresentationSnapshot * {
885 return nullptr;
886 }), false);
887 snapshotCls.addFunc("getInstanceId", [](CardPresentationSnapshot *s) { return s ? s->instanceId : std::string{}; });
888 snapshotCls.addFunc("getDefinitionId", [](CardPresentationSnapshot *s) { return s ? s->definitionId : std::string{}; });
889 snapshotCls.addFunc("getState", [](CardPresentationSnapshot *s) { return s ? s->state : std::string{}; });
890 snapshotCls.addFunc("getX", [](CardPresentationSnapshot *s) { return s ? s->x : 0.f; });
891 snapshotCls.addFunc("getY", [](CardPresentationSnapshot *s) { return s ? s->y : 0.f; });
892 snapshotCls.addFunc("getW", [](CardPresentationSnapshot *s) { return s ? s->width : 0.f; });
893 snapshotCls.addFunc("getH", [](CardPresentationSnapshot *s) { return s ? s->height : 0.f; });
894 snapshotCls.addFunc("getAngle", [](CardPresentationSnapshot *s) { return s ? s->angle : 0.f; });
895 snapshotCls.addFunc("getScale", [](CardPresentationSnapshot *s) { return s ? s->scale : 0.f; });
896 snapshotCls.addFunc("getAlpha", [](CardPresentationSnapshot *s) { return s ? s->alpha : 0.f; });
897 snapshotCls.addFunc("isHovered", [](CardPresentationSnapshot *s) { return s && s->hovered; });
898 snapshotCls.addFunc("isDragging", [](CardPresentationSnapshot *s) { return s && s->dragging; });
899 snapshotCls.addFunc("isDisabled", [](CardPresentationSnapshot *s) { return s && s->disabled; });
900 snapshotCls.addFunc("isFaceUp", [](CardPresentationSnapshot *s) { return s && s->faceUp; });
901}
902
903void Card::expose(ssq::Class &cls) {
904 cls.addFunc("registerCardsFromJson", &Card::registerCardsFromJson);
905 cls.addFunc("clearCardDefinitions", &Card::clearCardDefinitions);
906 cls.addFunc("getCardDefinitionCount", &Card::getCardDefinitionCount);
907 cls.addFunc("getCardDefinitionId", &Card::getCardDefinitionId);
908 cls.addFunc("hasCardDefinition", &Card::hasCardDefinition);
909 cls.addFunc("setCardDefinition", &Card::setCardDefinition);
910 cls.addFunc("removeCardDefinition", &Card::removeCardDefinition);
911 cls.addFunc("getCardDefinitionName", &Card::getCardDefinitionName);
912 cls.addFunc("getCardDefinitionKind", &Card::getCardDefinitionKind);
913 cls.addFunc("getCardDefinitionCost", &Card::getCardDefinitionCost);
914 cls.addFunc("getCardDefinitionAttack", &Card::getCardDefinitionAttack);
915 cls.addFunc("getCardDefinitionHealth", &Card::getCardDefinitionHealth);
916 cls.addFunc("getCardDefinitionTintR", &Card::getCardDefinitionTintR);
917 cls.addFunc("getCardDefinitionTintG", &Card::getCardDefinitionTintG);
918 cls.addFunc("getCardDefinitionTintB", &Card::getCardDefinitionTintB);
919 cls.addFunc("newConfig", &Card::newConfig);
920 cls.addFunc("newCard", &Card::newCard);
921 cls.addFunc("newDeck", &Card::newDeck);
922 cls.addFunc("newZone", &Card::newZone);
923 cls.addFunc("newHand", &Card::newHand);
924 cls.addFunc("newPlaneMapper", &Card::newPlaneMapper);
925 cls.addFunc("setConfig", &Card::setConfig);
926 cls.addFunc("getConfig", &Card::getConfig);
927 cls.addFunc("handCount", &Card::handCount);
928 cls.addFunc("getHand", &Card::getHand);
929 cls.addFunc("findHand", &Card::findHand);
930 cls.addFunc("zoneCount", &Card::zoneCount);
931 cls.addFunc("getZone", &Card::getZone);
932 cls.addFunc("getDeck", &Card::getDeck);
933 cls.addFunc("drawCard", &Card::drawCard);
934 cls.addFunc("capturePresentation", &Card::capturePresentation);
935 cls.addFunc("getPresentationCount", &Card::getPresentationCount);
936 cls.addFunc("getPresentation", &Card::getPresentation);
937 cls.addFunc("update", &Card::update);
938 cls.addFunc("render", &Card::render);
939 cls.addFunc("setBuiltInVisuals", &Card::setBuiltInVisuals);
940 cls.addFunc("getBuiltInVisuals", &Card::getBuiltInVisuals);
941 cls.addFunc("beginTargeting", &Card::beginTargeting);
942 cls.addFunc("updateTargeting", &Card::updateTargeting);
943 cls.addFunc("cancelTargeting", &Card::cancelTargeting);
944 cls.addFunc("renderTargeting", &Card::renderTargeting);
945 cls.addFunc("isTargeting", &Card::isTargeting);
946 cls.addFunc("isTargetValid", &Card::isTargetValid);
947 cls.addFunc("getTargetSource", &Card::getTargetSource);
948 cls.addFunc("getTargetId", &Card::getTargetId);
949 cls.addFunc("renderDeck", &Card::renderDeck);
950 cls.addFunc("clearEvents", &Card::clearEvents);
951 cls.addFunc("getEventCount", &Card::getEventCount);
952 cls.addFunc("getEventType", &Card::getEventType);
953 cls.addFunc("getEventHand", &Card::getEventHand);
954 cls.addFunc("getEventZone", &Card::getEventZone);
955 cls.addFunc("getEventCardId", &Card::getEventCardId);
956 cls.addFunc("getEventReason", &Card::getEventReason);
957
958 // 把手牌发布到共享玩法协议(`eve_gameplay` / MCP)。返回 {ok, message}:
959 // 失败原因(非规范持久 id、重复实例、空 hand)不被丢弃。account 可为 null,
960 // 此时 `card:play` 走"未绑定支付"边界:零费卡照常出牌,收费卡得到明确诊断。
961 cls.addFunc("publishGameplay", [vm = cls.getHandle()](Card *self, const std::string &instanceId,
962 const std::string &ownerId, Hand *hand) {
963 ssq::Table result(vm);
964 if (self == nullptr || hand == nullptr) {
965 result.set("ok", false);
966 result.set("message", std::string("publishGameplay needs the card module and a hand"));
967 return result;
968 }
969 const auto published = self->publishGameplay(instanceId, ownerId, hand, nullptr);
970 result.set("ok", published.ok());
971 result.set("message", published.ok() ? std::string("published") : published.status().describe());
972 return result;
973 });
974 cls.addFunc("unpublishGameplay", [vm = cls.getHandle()](Card *self, const std::string &instanceId) {
975 ssq::Table result(vm);
976 const auto unpublished = self == nullptr ? eve::Result<void>::failure(eve::Diagnostic::error(
977 eve::DiagnosticCode::Failed, "card module unavailable", "self"))
978 : self->unpublishGameplay(instanceId);
979 result.set("ok", unpublished.ok());
980 result.set("message", unpublished.ok() ? std::string("unpublished") : unpublished.status().describe());
981 return result;
982 });
983 cls.addFunc("clearGameplayControls", &Card::clearGameplayControls);
984 cls.addFunc("getGameplayControlCount", &Card::gameplayControlCount);
985}
986
987} // namespace eve::card
LogicalId target
double value
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
int root
Definition AnimSmr.cpp:119
Vec3 relative
Definition AnimSmr.cpp:164
int subject
Definition AnimSmr.cpp:163
const std::string & s
Selective canonical attributes for card combat values.
float uv
Vec3 projected
Definition CaveMesh.cpp:122
float length
Definition CaveMesh.cpp:94
float py
struct SQVM * HSQUIRRELVM
eve::resource::CostSpec cost
eve::resource::IResourceAccount * account
std::string label
eve::Value condition
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
std::uint64_t sourceId
std::string layout
const GltfImportRequest & request
tensor::Graph g
Definition GpuGraph.cpp:7
wgpu::PopErrorScopeStatus status
glm::vec4 tint
float u
Definition Grass.cpp:233
glm::vec3 n
Definition Grass.cpp:63
double r
float v
std::int32_t c
int h
std::vector< Colorf > px
std::uint32_t height
std::uint32_t width
TokenKind kind
std::string name
bool valid
MeleePoint3 b
Definition MeleeHit.cpp:41
Texture * normal
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::array< std::uint64_t, kPixelChunkSize *kPixelChunkSize > updated
std::string id
Definition PlayHost.cpp:108
std::uint32_t targetId
PrimitiveHandle handle
float d
float t
RoadLaneDirection direction
std::string string
float dz
float dy
float dx
The single Squirrel projection for common Result, Status and Value.
Stable reference to a runtime gameplay subject.
uint32_t index
double oy
double ox
float vz
float vy
float vx
float angle
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
Strong, domain-neutral reference to a runtime subject.
Definition SubjectRef.h:26
static SubjectRef fromPersistentId(PersistentId id) noexcept
Wrap a persistent identity without changing its bytes.
Definition SubjectRef.h:32
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
static eve::Result< void > ensure(CardData &card)
Bind and seed the card's selected attributes exactly once.
static constexpr std::string_view healthAttribute
static eve::Result< double > read(CardData &card, std::string_view attribute)
Read a selected final card attribute and refresh compatibility fields.
static eve::Result< void > setBase(CardData &card, std::string_view attribute, double value)
Set a selected canonical base and refresh the legacy projection.
单张卡牌:ECS 实体,数据拆成 Identity / Stats / Visual / Layout / State。
Definition CardTypes.h:94
static CardData * createCard()
创建并触摸全部组件。
Maps a logical card canvas to a 3D parallelogram without depending on graphics.
Definition Card.h:55
float getWorldZ() const
Return the most recently mapped world Z coordinate.
Definition Card.h:75
void setLogicalRect(float x, float y, float width, float height)
Configure the logical rectangle represented by the world plane.
Definition Card.cpp:23
bool mapLayout(float x, float y)
Map a logical point to the configured world plane.
Definition Card.cpp:61
float getLogicalY() const
Return the most recently mapped logical Y coordinate.
Definition Card.h:69
bool mapRay(float ox, float oy, float oz, float dx, float dy, float dz)
Intersect a world ray and store its logical and world hit coordinates.
Definition Card.cpp:37
float getWorldY() const
Return the most recently mapped world Y coordinate.
Definition Card.h:73
void setPlane(float ox, float oy, float oz, float ux, float uy, float uz, float vx, float vy, float vz)
Configure world origin plus full-width U and full-height V vectors.
Definition Card.cpp:30
float getLogicalX() const
Return the most recently mapped logical X coordinate.
Definition Card.h:67
float getWorldX() const
Return the most recently mapped world X coordinate.
Definition Card.h:71
static decision::ConditionResult evaluate(const CardData *card, const CardDefinition &definition, const decision::Condition &condition, CardPlayConditionQueries queries={})
Evaluate a card definition's play condition against one instance.
Definition CardPlay.cpp:68
static eve::Result< eve::transaction::TransactionReceipt > play(CardPlayRequest request)
Execute condition, movement, card effect and Mana as one transaction.
Definition CardPlay.cpp:332
卡牌模块入口(eve.Card):定义注册、对象工厂与每帧 update/render。
Definition Card.h:91
Card()
Declared out of line so the incomplete CardControl member needs no deleter here.
int getCardDefinitionCost(const std::string &id)
Returns the card definition cost.
Definition Card.cpp:364
float getCardDefinitionTintB(const std::string &id)
Returns the card definition tint b.
Definition Card.cpp:389
int zoneCount() const
Zone count.
Definition Card.cpp:495
void renderDeck(graphics::Graphics *gfx)
Renders deck.
Definition Card.cpp:628
LayoutConfig * getConfig() const
Returns the config.
Definition Card.cpp:478
CardData * drawCard(const std::string &handOwner)
从牌库抽一张牌加入指定手牌;无牌时返回 nullptr。
Definition Card.cpp:504
eve::Result< void > setCardPlayCondition(const std::string &id, decision::Condition condition)
Replace the side-effect-free condition required to play a definition.
Definition Card.cpp:269
void setBuiltInVisuals(bool enabled)
Enable or disable the built-in card visuals while retaining layout and interaction.
Definition Card.h:271
decision::ConditionResult evaluatePlay(const CardData *card, CardPlayConditionQueries queries={}) const
Evaluate a card's pure play condition through the shared protocol.
Definition Card.cpp:286
int getPresentationCount() const
Return the number of entries in the most recently captured buffer.
Definition Card.cpp:546
int registerCardsFromJson(const std::string &json)
从 JSON 注册卡牌类型;返回成功注册数量。
Definition Card.cpp:208
void render(graphics::Graphics *gfx)
绘制手牌/落牌区(与牌库)。
Definition Card.cpp:568
int handCount() const
Hand count.
Definition Card.cpp:480
bool getBuiltInVisuals() const
Return whether Card::render draws the built-in card faces.
Definition Card.h:273
bool hasCardDefinition(const std::string &id)
卡牌类型查询。
Definition Card.cpp:244
LayoutConfig * newConfig()
工厂:对象由 ECS 表持有,脚本持有的是非拥有句柄。
Definition Card.cpp:398
void update(float dt, float mx, float my, bool down)
每帧更新布局与交互。
Definition Card.cpp:557
eve::Result< void > setCardAttribute(CardData &card, std::string_view attribute, double value) const
Set one canonical combat attribute through the Card facade.
Definition Card.cpp:300
std::vector< std::string > gameplayInstances() const
已发布的玩法实例标识(发布顺序)。
Definition Card.cpp:197
Hand * newHand(LayoutConfig *cfg)
创建一个手牌布局。
Definition Card.cpp:456
eve::Result< effects::EffectHandle > applyEffect(CardData &card, const CardEffectDefinition &definition, eve::SubjectRef subject) const
Apply a domain card effect to the card-owned lifecycle component.
Definition Card.cpp:307
float getCardDefinitionTintG(const std::string &id)
Returns the card definition tint g.
Definition Card.cpp:384
void setConfig(LayoutConfig *cfg)
游戏状态:当前布局、手牌、落牌区、牌库。
Definition Card.cpp:474
eve::Result< eve::transaction::TransactionReceipt > play(CardData &card, eve::resource::IResourceAccount &playerAccount, CardPlayComposition composition={}, std::string transactionId={})
Play a card through the facade's condition, container and payment transaction.
Definition Card.cpp:334
int getCardDefinitionHealth(const std::string &id)
Returns the card definition health.
Definition Card.cpp:374
eve::Result< void > unpublishGameplay(const std::string &instanceId)
取消发布一个实例;该实例未发布(或 id 非法)时返回诊断。
Definition Card.cpp:180
eve::Result< void > publishGameplay(const std::string &instanceId, const std::string &ownerId, Hand *hand, eve::resource::IResourceAccount *account=nullptr)
把一副手牌发布到共享玩法协议(eve_gameplay / MCP)。
Definition Card.cpp:163
Hand * findHand(const std::string &owner) const
Finds hand.
Definition Card.cpp:487
void clearGameplayControls()
取消发布本模块持有的全部玩法实例。
Definition Card.cpp:191
CardPlaneMapper * newPlaneMapper()
Create a reusable logical-card-canvas to 3D plane mapper.
Definition Card.cpp:463
int gameplayControlCount() const
已发布的玩法实例数量。
Definition Card.cpp:195
Hand * getHand(int index) const
Returns the hand.
Definition Card.cpp:482
int getCardDefinitionCount()
已注册卡牌类型数量。
Definition Card.cpp:229
Deck * getDeck() const
Returns the deck.
Definition Card.cpp:502
bool removeCardDefinition(const std::string &id)
Remove one definition by stable identifier.
Definition Card.cpp:263
int getCardDefinitionAttack(const std::string &id)
Returns the card definition attack.
Definition Card.cpp:369
std::string getCardDefinitionId(int index) const
Return a definition ID in deterministic sorted order.
Definition Card.cpp:231
int capturePresentation()
Capture all live cards into a contiguous presentation snapshot buffer.
Definition Card.cpp:518
eve::Result< std::size_t > step(const eve::SimulationStep &step)
Advance all card-owned effects and project current health.
Definition Card.cpp:317
bool setCardDefinition(const std::string &id, const std::string &name, const std::string &kind, int cost, int attack, int health, float tintR, float tintG, float tintB)
Insert or replace one definition for project-owned authoring tools.
Definition Card.cpp:246
float getCardDefinitionTintR(const std::string &id)
Returns the card definition tint r.
Definition Card.cpp:379
Deck * newDeck()
Creates a deck. @ownership Caller deletes unless documented otherwise.
Definition Card.cpp:436
std::string getCardDefinitionName(const std::string &id)
Definition Card.cpp:354
void clearCardDefinitions()
清空全部卡牌类型定义。
Definition Card.cpp:223
Zone * getZone(int index) const
Returns the zone.
Definition Card.cpp:497
Zone * newZone(const std::string &id, const std::string &label, float x, float y, float w, float h)
创建一个落牌区。
Definition Card.cpp:443
CardData * newCard(const std::string &defId)
Creates a card. @ownership Caller deletes unless documented otherwise.
Definition Card.cpp:406
CardPresentationSnapshot * getPresentation(int index)
Return an entry from the most recently captured buffer, or nullptr.
Definition Card.cpp:548
std::string getCardDefinitionKind(const std::string &id)
Returns the card definition kind.
Definition Card.cpp:359
eve::Result< double > getCardAttribute(CardData &card, std::string_view attribute) const
Read one canonical combat attribute through the Card facade.
Definition Card.cpp:293
牌库(栈顶在末尾)。
Definition CardTypes.h:188
CardData * get(int index)
CardData * peek()
查看栈顶卡牌(不弹出)。
void push(CardData *c)
将卡牌压入栈顶(末尾)。
Definition CardTypes.h:207
void shuffle()
洗牌。
CardData * draw()
弹出栈顶卡牌(末尾);空牌库返回 nullptr。
void clear()
清空牌库。
Definition CardTypes.h:213
static Deck * createDeck()
创建并触摸 Membership。
int count()
牌库数量/是否为空/按下标取牌。
Definition CardTypes.h:217
手牌:扇形布局 + 悬浮 + 拖拽 + 落区判定 + 渲染。
Definition CardTypes.h:273
CardData * get(int index)
static Hand * createHand()
创建并触摸全部组件。
bool removeCard(CardData *c)
CardData * pick(float px, float py)
命中检测:返回 (px,py) 处最上层卡牌。
void addCard(CardData *c)
手牌增删与查询。
CardData * find(const std::string &id)
落牌区(手牌区 / 出牌区 / 弃牌区),用于拖放命中判定。
Definition CardTypes.h:223
static Zone * createZone()
创建并触摸组件。
Explain one condition evaluation in a UI- and log-friendly form.
Definition Condition.h:129
static ConditionResult failed(ConditionReasonCode reason, Value evidence={}, Value details=Value::Object{})
Construct a rejected result with a stable reason and explanation.
Immutable condition AST node.
Definition Condition.h:195
static std::optional< Id128 > parse(std::string_view text) noexcept
Parses canonical UUID text.
Definition Identity.h:151
Font * getFont() const
Returns the font.
Definition Graphics.h:1629
EVENGINE_API_FOUNDATION public API.
Definition Json.h:136
bool valid() const
Valid.
Definition Json.h:157
static Document parse(const std::string &text, std::string *error=nullptr)
Parse.
Definition Json.cpp:581
Value root() const
Root.
Definition Json.h:159
EVENGINE_API_FOUNDATION public API.
Definition Json.h:38
Provider-neutral resource account contract.
static eve::Result< SettlementRuleSet > fromJson(std::string_view json)
Decode and compile a strict versioned JSON rule document without mutating an existing rule set.
void renderCardBack(graphics::Graphics *gfx, float x, float y, float w, float h, float angle, float a)
绘制牌背。
const char * cardStateName(CardState state)
状态枚举的字符串名(用于脚本/调试)。
Definition CardTypes.cpp:12
void printCentered(graphics::Graphics *gfx, const std::string &text, float cx, float cy, float scale, const glm::vec4 &color)
渲染辅助(也供 Zone / Deck 复用)。
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
std::unordered_map< std::string, SkillDefinition > & table()
Definition Skill.cpp:65
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
void registerCppEntityView(const ssq::Class &cls, CppEntityViewFn fn)
Registers cpp entity view.
Definition ECS.cpp:861
glm::vec4 Color
Render-neutral RGBA color shared by graphics-facing modules.
Definition RenderTypes.h:8
One deterministic fixed-step emitted by SimulationClock.
Definition Time.h:158
卡牌类型定义(registerCardsFromJson 注册)。
Definition CardTypes.h:79
std::vector< std::string > tags
Definition tags available to HasTag nodes.
Definition CardTypes.h:90
Strong card definition projected into the common effect definition.
Definition CardEffects.h:40
Mutable card combat state changed by the card effect executor.
Definition CardEffects.h:32
Optional cross-domain operations that belong to one card play.
Definition CardPlay.h:147
Read-only extension points used while evaluating a card play.
Definition CardPlay.h:29
Complete caller-owned input for one atomic card play.
Definition CardPlay.h:163
Immutable presentation data captured from one card for external 2D/3D adapters.
Definition Card.h:37
UiCard 风格的布局配置(脚本可实时修改,对应 UiCard 的 Configs 面板)。
Definition CardTypes.h:46
float cardW
卡牌宽/高(像素)。
Definition CardTypes.h:48
float deckX
牌库堆绘制位置。
Definition CardTypes.h:72
bool showZones
是否绘制落牌区。
Definition CardTypes.h:70
glm::vec4 color