载入中...
搜索中...
未找到
Card.cpp
浏览该文件的文档.
1#include "card/Card.h"
2
3#include "common/Json.h"
4#include "graphics/Graphics.h"
5
6#include <simplesquirrel/simplesquirrel.hpp>
7#include <squirrel.h>
8
9#include <algorithm>
10#include <cstdint>
11
12namespace eve::card {
13
15
16namespace {
17
19
20bool parseDefinition(Value o, std::unordered_map<std::string, CardDefinition> &defs) {
21 std::string id = o.getString("id");
22 if (id.empty()) return false;
24 def.id = id;
25 def.name = o.getString("name", id);
26 def.kind = o.getString("kind", "creature");
27 def.cost = o.getInt("cost");
28 def.attack = o.getInt("attack");
29 def.health = o.getInt("health");
30 auto tint = o.getFloatArray("tint");
31 if (tint.size() >= 3) def.tint = glm::vec3(tint[0], tint[1], tint[2]);
32 defs[id] = def;
33 return true;
34}
35
36template <typename T>
37T *resolve(const ecs::EntityHandle &h) {
38 return static_cast<T *>(ecs::try_get(h));
39}
40
41void destroyHandles(std::vector<ecs::EntityHandle> &hs) {
42 for (auto &h : hs) {
43 if (ecs::Entity *e = ecs::try_get(h)) ecs::DestroyEntity(e);
44 }
45 hs.clear();
46}
47
48template <typename T>
49void registerCppEntityClassForScript() {
50 eve::registerCppEntityView(typeid(T *).hash_code(), [](ssq::Array &out) {
51 HSQUIRRELVM vm = out.getHandle();
52 sq_pushobject(vm, out.getRaw());
53 ecs::Table *table = ecs::current();
54 if (table == nullptr) {
55 sq_pop(vm, 1);
56 return;
57 }
58 ecs::IComponentManager &cm = table->getOrCreateManager<T>();
59 auto *reg = cm.getOrCreateRegistryComponentBuffer<T>();
60 std::vector<ecs::IComponentBuffer *> stack;
61 stack.push_back(reg);
62 while (!stack.empty()) {
63 ecs::IComponentBuffer *buf = stack.back();
64 stack.pop_back();
65 auto *r = dynamic_cast<ecs::IRegistryComponentBuffer *>(buf);
66 if (r != nullptr) {
67 for (uint32_t i = 0; i < r->entity_count(); ++i) {
68 ecs::Entity *ent = r->entity_at(i);
69 if (ent != nullptr && ecs::is_entity_visible(ent)) {
70 ssq::detail::pushByPtr<T>(vm, static_cast<T *>(ent));
71 sq_arrayappend(vm, -2);
72 }
73 }
74 }
75 if (buf->children != nullptr) stack.push_back(buf->children);
76 if (buf->next != nullptr) stack.push_back(buf->next);
77 }
78 sq_pop(vm, 1);
79 });
80}
81
82} // namespace
83
85 destroyHandles(hands_);
86 destroyHandles(decks_);
87 destroyHandles(zones_);
88 destroyHandles(cards_);
89 activeDeck_ = nullptr;
90 activeConfig_ = nullptr;
91}
92
93// ---------------------------------------------------------------------------
94// 卡牌类型定义
95// ---------------------------------------------------------------------------
96
97int Card::registerCardsFromJson(const std::string &json) {
99 if (!doc.valid()) return 0;
100 const Value root = doc.root();
101 int n = 0;
102 if (root.isArray()) {
103 for (size_t i = 0; i < root.size(); ++i)
104 if (parseDefinition(root.at(i), defs_)) ++n;
105 } else if (root.isObject()) {
106 if (parseDefinition(root, defs_)) ++n;
107 }
108 return n;
109}
110
111void Card::clearCardDefinitions() { defs_.clear(); }
112
113int Card::getCardDefinitionCount() { return static_cast<int>(defs_.size()); }
114
115bool Card::hasCardDefinition(const std::string &id) { return defs_.count(id) != 0; }
116
117const CardDefinition *Card::findDef(const std::string &id) const {
118 auto it = defs_.find(id);
119 return it == defs_.end() ? nullptr : &it->second;
120}
121
122std::string Card::getCardDefinitionName(const std::string &id) {
123 const auto *d = findDef(id);
124 return d ? d->name : std::string{};
125}
126
127std::string Card::getCardDefinitionKind(const std::string &id) {
128 const auto *d = findDef(id);
129 return d ? d->kind : std::string{};
130}
131
132int Card::getCardDefinitionCost(const std::string &id) {
133 const auto *d = findDef(id);
134 return d ? d->cost : 0;
135}
136
137int Card::getCardDefinitionAttack(const std::string &id) {
138 const auto *d = findDef(id);
139 return d ? d->attack : 0;
140}
141
142int Card::getCardDefinitionHealth(const std::string &id) {
143 const auto *d = findDef(id);
144 return d ? d->health : 0;
145}
146
147float Card::getCardDefinitionTintR(const std::string &id) {
148 const auto *d = findDef(id);
149 return d ? d->tint.r : 0.f;
150}
151
152float Card::getCardDefinitionTintG(const std::string &id) {
153 const auto *d = findDef(id);
154 return d ? d->tint.g : 0.f;
155}
156
157float Card::getCardDefinitionTintB(const std::string &id) {
158 const auto *d = findDef(id);
159 return d ? d->tint.b : 0.f;
160}
161
162// ---------------------------------------------------------------------------
163// 工厂
164// ---------------------------------------------------------------------------
165
167 auto cfg = std::make_unique<LayoutConfig>();
168 LayoutConfig *raw = cfg.get();
169 configs_.push_back(std::move(cfg));
170 if (!activeConfig_) activeConfig_ = raw;
171 return raw;
172}
173
174CardData *Card::newCard(const std::string &defId) {
175 const CardDefinition *d = findDef(defId);
176 if (!d) return nullptr;
178 c->identity()->id = defId + "#" + std::to_string(nextInstance_++);
179 c->identity()->name = d->name;
180 c->identity()->kind = d->kind;
181 c->stats()->cost = d->cost;
182 c->stats()->attack = d->attack;
183 c->stats()->health = d->health;
184 c->visual()->tint = d->tint;
185 cards_.push_back(ecs::handle_of(c));
186 return c;
187}
188
191 decks_.push_back(ecs::handle_of(d));
192 activeDeck_ = d;
193 return d;
194}
195
196Zone *Card::newZone(const std::string &id, const std::string &label, float x, float y, float w, float h) {
198 auto *R = z->rect().operator->();
199 R->id = id;
200 R->label = label;
201 R->x = x;
202 R->y = y;
203 R->w = w;
204 R->h = h;
205 zones_.push_back(ecs::handle_of(z));
206 return z;
207}
208
211 h->meta()->config = cfg;
212 hands_.push_back(ecs::handle_of(h));
213 return h;
214}
215
216// ---------------------------------------------------------------------------
217// 游戏状态
218// ---------------------------------------------------------------------------
219
221 if (cfg) activeConfig_ = cfg;
222}
223
224LayoutConfig *Card::getConfig() const { return activeConfig_; }
225
226int Card::handCount() const { return static_cast<int>(hands_.size()); }
227
228Hand *Card::getHand(int index) const {
229 if (index < 0 || static_cast<size_t>(index) >= hands_.size()) return nullptr;
230 return resolve<Hand>(hands_[static_cast<size_t>(index)]);
231}
232
233Hand *Card::findHand(const std::string &owner) const {
234 for (const auto &h : hands_) {
235 Hand *hand = resolve<Hand>(h);
236 if (hand && hand->meta()->owner == owner) return hand;
237 }
238 return nullptr;
239}
240
241int Card::zoneCount() const { return static_cast<int>(zones_.size()); }
242
243Zone *Card::getZone(int index) const {
244 if (index < 0 || static_cast<size_t>(index) >= zones_.size()) return nullptr;
245 return resolve<Zone>(zones_[static_cast<size_t>(index)]);
246}
247
248Deck *Card::getDeck() const { return activeDeck_; }
249
250CardData *Card::drawCard(const std::string &handOwner) {
251 Hand *h = findHand(handOwner);
252 if (!h || !activeDeck_) return nullptr;
253 CardData *c = activeDeck_->draw();
254 if (!c) return nullptr;
255 if (activeConfig_) {
256 c->layout()->x = activeConfig_->deckX;
257 c->layout()->y = activeConfig_->deckY;
258 }
259 c->state()->phase = CardState::Deck;
260 h->addCard(c);
261 return c;
262}
263
264// ---------------------------------------------------------------------------
265// 每帧
266// ---------------------------------------------------------------------------
267
268void Card::update(float dt, float mx, float my, bool down) {
269 std::vector<Zone *> zonePtrs;
270 zonePtrs.reserve(zones_.size());
271 for (auto &h : zones_) {
272 if (Zone *z = resolve<Zone>(h)) zonePtrs.push_back(z);
273 }
274 for (auto &h : hands_) {
275 if (Hand *hand = resolve<Hand>(h)) hand->update(dt, mx, my, down, zonePtrs, events_);
276 }
277}
278
280 if (activeConfig_ && activeConfig_->showZones) {
281 for (auto &h : zones_) {
282 if (Zone *z = resolve<Zone>(h)) z->render(gfx, true);
283 }
284 }
285 for (auto &h : hands_) {
286 if (Hand *hand = resolve<Hand>(h)) hand->render(gfx);
287 }
288}
289
291 if (!activeDeck_ || !activeConfig_) return;
292 const LayoutConfig &cfg = *activeConfig_;
293 const int c = activeDeck_->count();
294 if (c <= 0) return;
295 const float w = cfg.cardW * 0.9f;
296 const float h = cfg.cardH * 0.9f;
297 for (int i = 0; i < 3 && i < c; ++i) {
298 const float off = static_cast<float>(i) * 3.f;
299 renderCardBack(gfx, cfg.deckX - w * 0.5f + off, cfg.deckY - h * 0.5f - off, w, h, 0.f, 1.f);
300 }
301 if (gfx->getFont())
302 printCentered(gfx, std::to_string(c), cfg.deckX, cfg.deckY - h * 0.5f - 12.f, 1.2f,
303 glm::vec4(0.95f, 0.9f, 0.8f, 1.f));
304}
305
306// ---------------------------------------------------------------------------
307// 事件
308// ---------------------------------------------------------------------------
309
310void Card::clearEvents() { events_.clear(); }
311
312int Card::getEventCount() const { return static_cast<int>(events_.size()); }
313
314std::string Card::getEventType(int index) const {
315 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
316 return events_[static_cast<size_t>(index)].type;
317}
318
319std::string Card::getEventHand(int index) const {
320 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
321 return events_[static_cast<size_t>(index)].hand;
322}
323
324std::string Card::getEventZone(int index) const {
325 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
326 return events_[static_cast<size_t>(index)].zoneId;
327}
328
329std::string Card::getEventCardId(int index) const {
330 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
331 return events_[static_cast<size_t>(index)].cardId;
332}
333
334std::string Card::getEventReason(int index) const {
335 if (index < 0 || static_cast<size_t>(index) >= events_.size()) return {};
336 return events_[static_cast<size_t>(index)].reason;
337}
338
339// ---------------------------------------------------------------------------
340// 脚本绑定
341// ---------------------------------------------------------------------------
342
343void Card::expose(ssq::Table &table) {
344 auto cls = table.addClass(name, Card::create, false);
345 expose(cls);
346
347 registerCppEntityClassForScript<CardData>();
348 registerCppEntityClassForScript<Hand>();
349 registerCppEntityClassForScript<Deck>();
350 registerCppEntityClassForScript<Zone>();
351
352 // LayoutConfig —— 全部布局参数(UiCard Configs)
353 auto cfgCls = table.addClass<LayoutConfig>(
354 "LayoutConfig", std::function<LayoutConfig *()>([]() -> LayoutConfig * { return nullptr; }), false);
355 cfgCls.addFunc("getCardW", [](LayoutConfig *c) -> float { return c ? c->cardW : 0.f; });
356 cfgCls.addFunc("setCardW", [](LayoutConfig *c, float v) { if (c) c->cardW = v; });
357 cfgCls.addFunc("getCardH", [](LayoutConfig *c) -> float { return c ? c->cardH : 0.f; });
358 cfgCls.addFunc("setCardH", [](LayoutConfig *c, float v) { if (c) c->cardH = v; });
359 cfgCls.addFunc("getSpacing", [](LayoutConfig *c) -> float { return c ? c->spacing : 0.f; });
360 cfgCls.addFunc("setSpacing", [](LayoutConfig *c, float v) { if (c) c->spacing = v; });
361 cfgCls.addFunc("getHandX", [](LayoutConfig *c) -> float { return c ? c->handX : 0.f; });
362 cfgCls.addFunc("setHandX", [](LayoutConfig *c, float v) { if (c) c->handX = v; });
363 cfgCls.addFunc("getHandY", [](LayoutConfig *c) -> float { return c ? c->handY : 0.f; });
364 cfgCls.addFunc("setHandY", [](LayoutConfig *c, float v) { if (c) c->handY = v; });
365 cfgCls.addFunc("getArcHeight", [](LayoutConfig *c) -> float { return c ? c->arcHeight : 0.f; });
366 cfgCls.addFunc("setArcHeight", [](LayoutConfig *c, float v) { if (c) c->arcHeight = v; });
367 cfgCls.addFunc("getRotationAngle", [](LayoutConfig *c) -> float { return c ? c->rotationAngle : 0.f; });
368 cfgCls.addFunc("setRotationAngle", [](LayoutConfig *c, float v) { if (c) c->rotationAngle = v; });
369 cfgCls.addFunc("getHoverRotation", [](LayoutConfig *c) -> bool { return c ? c->hoverRotation : false; });
370 cfgCls.addFunc("setHoverRotation", [](LayoutConfig *c, bool v) { if (c) c->hoverRotation = v; });
371 cfgCls.addFunc("getHoverScale", [](LayoutConfig *c) -> float { return c ? c->hoverScale : 0.f; });
372 cfgCls.addFunc("setHoverScale", [](LayoutConfig *c, float v) { if (c) c->hoverScale = v; });
373 cfgCls.addFunc("getHoverLift", [](LayoutConfig *c) -> float { return c ? c->hoverLift : 0.f; });
374 cfgCls.addFunc("setHoverLift", [](LayoutConfig *c, float v) { if (c) c->hoverLift = v; });
375 cfgCls.addFunc("getHoverSpeed", [](LayoutConfig *c) -> float { return c ? c->hoverSpeed : 0.f; });
376 cfgCls.addFunc("setHoverSpeed", [](LayoutConfig *c, float v) { if (c) c->hoverSpeed = v; });
377 cfgCls.addFunc("getMotionSpeed", [](LayoutConfig *c) -> float { return c ? c->motionSpeed : 0.f; });
378 cfgCls.addFunc("setMotionSpeed", [](LayoutConfig *c, float v) { if (c) c->motionSpeed = v; });
379 cfgCls.addFunc("getDisabledAlpha", [](LayoutConfig *c) -> float { return c ? c->disabledAlpha : 0.f; });
380 cfgCls.addFunc("setDisabledAlpha", [](LayoutConfig *c, float v) { if (c) c->disabledAlpha = v; });
381 cfgCls.addFunc("getShowZones", [](LayoutConfig *c) -> bool { return c ? c->showZones : false; });
382 cfgCls.addFunc("setShowZones", [](LayoutConfig *c, bool v) { if (c) c->showZones = v; });
383 cfgCls.addFunc("getDeckX", [](LayoutConfig *c) -> float { return c ? c->deckX : 0.f; });
384 cfgCls.addFunc("setDeckX", [](LayoutConfig *c, float v) { if (c) c->deckX = v; });
385 cfgCls.addFunc("getDeckY", [](LayoutConfig *c) -> float { return c ? c->deckY : 0.f; });
386 cfgCls.addFunc("setDeckY", [](LayoutConfig *c, float v) { if (c) c->deckY = v; });
387 cfgCls.addFunc("getDragThreshold", [](LayoutConfig *c) -> float { return c ? c->dragThreshold : 0.f; });
388 cfgCls.addFunc("setDragThreshold", [](LayoutConfig *c, float v) { if (c) c->dragThreshold = v; });
389
390 // CardData
391 auto cardCls = table.addClass<CardData>(
392 "CardData", std::function<CardData *()>([]() -> CardData * { return nullptr; }), false);
393 cardCls.addFunc("getId", [](CardData *c) -> std::string { return c ? c->identity()->id : std::string{}; });
394 cardCls.addFunc("setId", [](CardData *c, const std::string &v) { if (c) c->identity()->id = v; });
395 cardCls.addFunc("getName", [](CardData *c) -> std::string { return c ? c->identity()->name : std::string{}; });
396 cardCls.addFunc("setName", [](CardData *c, const std::string &v) { if (c) c->identity()->name = v; });
397 cardCls.addFunc("getKind", [](CardData *c) -> std::string { return c ? c->identity()->kind : std::string{}; });
398 cardCls.addFunc("setKind", [](CardData *c, const std::string &v) { if (c) c->identity()->kind = v; });
399 cardCls.addFunc("getCost", [](CardData *c) -> int { return c ? c->stats()->cost : 0; });
400 cardCls.addFunc("setCost", [](CardData *c, int v) { if (c) c->stats()->cost = v; });
401 cardCls.addFunc("getAttack", [](CardData *c) -> int { return c ? c->stats()->attack : 0; });
402 cardCls.addFunc("setAttack", [](CardData *c, int v) { if (c) c->stats()->attack = v; });
403 cardCls.addFunc("getHealth", [](CardData *c) -> int { return c ? c->stats()->health : 0; });
404 cardCls.addFunc("setHealth", [](CardData *c, int v) { if (c) c->stats()->health = v; });
405 cardCls.addFunc("isFaceUp", [](CardData *c) -> bool { return c ? c->visual()->faceUp : true; });
406 cardCls.addFunc("setFaceUp", [](CardData *c, bool v) { if (c) c->visual()->faceUp = v; });
407 cardCls.addFunc("isDisabled", [](CardData *c) -> bool { return c ? c->visual()->disabled : false; });
408 cardCls.addFunc("setDisabled", [](CardData *c, bool v) { if (c) c->visual()->disabled = v; });
409 cardCls.addFunc("getState", [](CardData *c) -> std::string {
410 return c ? cardStateName(c->state()->phase) : std::string{};
411 });
412 cardCls.addFunc("setState", [](CardData *c, const std::string &v) {
413 if (!c) return;
414 auto *st = c->state().operator->();
415 if (v == "deck") st->phase = CardState::Deck;
416 else if (v == "hand") st->phase = CardState::Hand;
417 else if (v == "hovered") st->phase = CardState::Hovered;
418 else if (v == "dragging") st->phase = CardState::Dragging;
419 else if (v == "returning") st->phase = CardState::Returning;
420 else if (v == "played") st->phase = CardState::Played;
421 else if (v == "discarded") st->phase = CardState::Discarded;
422 else if (v == "disabled") st->phase = CardState::Disabled;
423 });
424 cardCls.addFunc("getTintR", [](CardData *c) -> float { return c ? c->visual()->tint.r : 0.f; });
425 cardCls.addFunc("getTintG", [](CardData *c) -> float { return c ? c->visual()->tint.g : 0.f; });
426 cardCls.addFunc("getTintB", [](CardData *c) -> float { return c ? c->visual()->tint.b : 0.f; });
427 cardCls.addFunc("setTint", [](CardData *c, float r, float g, float b) {
428 if (c) c->visual()->tint = glm::vec3(r, g, b);
429 });
430 cardCls.addFunc("setArt", [](CardData *c, graphics::Texture *t) { if (c) c->visual()->texture = t; });
431 cardCls.addFunc("getArt", [](CardData *c) -> graphics::Texture * { return c ? c->visual()->texture : nullptr; });
432 cardCls.addFunc("getX", [](CardData *c) -> float { return c ? c->layout()->x : 0.f; });
433 cardCls.addFunc("getY", [](CardData *c) -> float { return c ? c->layout()->y : 0.f; });
434 cardCls.addFunc("getW", [](CardData *c) -> float { return c ? c->layout()->w : 0.f; });
435 cardCls.addFunc("getH", [](CardData *c) -> float { return c ? c->layout()->h : 0.f; });
436 cardCls.addFunc("getScale", [](CardData *c) -> float { return c ? c->layout()->scale : 0.f; });
437 cardCls.addFunc("getAlpha", [](CardData *c) -> float { return c ? c->layout()->alpha : 0.f; });
438 cardCls.addFunc("isHovered", [](CardData *c) -> bool { return c ? c->state()->hovered : false; });
439 cardCls.addFunc("isDragging", [](CardData *c) -> bool { return c ? c->state()->dragging : false; });
440 cardCls.addFunc("hit", [](CardData *c, float px, float py) -> bool { return c && c->hit(px, py); });
441 cardCls.addFunc("describe", [](CardData *c) -> std::string { return c ? c->describe() : std::string{}; });
442
443 // Deck
444 auto deckCls = table.addClass<Deck>(
445 "Deck", std::function<Deck *()>([]() -> Deck * { return nullptr; }), false);
446 deckCls.addFunc("push", &Deck::push);
447 deckCls.addFunc("draw", &Deck::draw);
448 deckCls.addFunc("peek", &Deck::peek);
449 deckCls.addFunc("count", &Deck::count);
450 deckCls.addFunc("isEmpty", &Deck::isEmpty);
451 deckCls.addFunc("clear", &Deck::clear);
452 deckCls.addFunc("shuffle", &Deck::shuffle);
453 deckCls.addFunc("getCard", &Deck::get);
454
455 // Zone
456 auto zoneCls = table.addClass<Zone>(
457 "Zone", std::function<Zone *()>([]() -> Zone * { return nullptr; }), false);
458 zoneCls.addFunc("getId", [](Zone *z) -> std::string { return z ? z->rect()->id : std::string{}; });
459 zoneCls.addFunc("setId", [](Zone *z, const std::string &v) { if (z) z->rect()->id = v; });
460 zoneCls.addFunc("getLabel", [](Zone *z) -> std::string { return z ? z->rect()->label : std::string{}; });
461 zoneCls.addFunc("setLabel", [](Zone *z, const std::string &v) { if (z) z->rect()->label = v; });
462 zoneCls.addFunc("getX", [](Zone *z) -> float { return z ? z->rect()->x : 0.f; });
463 zoneCls.addFunc("getY", [](Zone *z) -> float { return z ? z->rect()->y : 0.f; });
464 zoneCls.addFunc("getW", [](Zone *z) -> float { return z ? z->rect()->w : 0.f; });
465 zoneCls.addFunc("getH", [](Zone *z) -> float { return z ? z->rect()->h : 0.f; });
466 zoneCls.addFunc("setRect", [](Zone *z, float x, float y, float w, float h) {
467 if (!z) return;
468 auto *R = z->rect().operator->();
469 R->x = x; R->y = y; R->w = w; R->h = h;
470 });
471 zoneCls.addFunc("getColorR", [](Zone *z) -> float { return z ? z->rect()->color.r : 0.f; });
472 zoneCls.addFunc("getColorG", [](Zone *z) -> float { return z ? z->rect()->color.g : 0.f; });
473 zoneCls.addFunc("getColorB", [](Zone *z) -> float { return z ? z->rect()->color.b : 0.f; });
474 zoneCls.addFunc("setColor", [](Zone *z, float r, float g, float b) {
475 if (z) z->rect()->color = glm::vec3(r, g, b);
476 });
477 zoneCls.addFunc("getAlpha", [](Zone *z) -> float { return z ? z->rect()->alpha : 0.f; });
478 zoneCls.addFunc("setAlpha", [](Zone *z, float v) { if (z) z->rect()->alpha = v; });
479 zoneCls.addFunc("isEnabled", [](Zone *z) -> bool { return z ? z->rect()->enabled : false; });
480 zoneCls.addFunc("setEnabled", [](Zone *z, bool v) { if (z) z->rect()->enabled = v; });
481 zoneCls.addFunc("addAcceptKind", [](Zone *z, const std::string &k) { if (z) z->filter()->acceptKinds.push_back(k); });
482 zoneCls.addFunc("clearAcceptKinds", [](Zone *z) { if (z) z->filter()->acceptKinds.clear(); });
483 zoneCls.addFunc("accepts", [](Zone *z, CardData *c) -> bool { return z && z->accepts(c); });
484 zoneCls.addFunc("contains", [](Zone *z, float px, float py) -> bool { return z && z->contains(px, py); });
485 zoneCls.addFunc("render", [](Zone *z, graphics::Graphics *gfx, bool showLabel) {
486 if (z) z->render(gfx, showLabel);
487 });
488
489 // Hand
490 auto handCls = table.addClass<Hand>(
491 "Hand", std::function<Hand *()>([]() -> Hand * { return nullptr; }), false);
492 handCls.addFunc("getOwner", [](Hand *h) -> std::string { return h ? h->meta()->owner : std::string{}; });
493 handCls.addFunc("setOwner", [](Hand *h, const std::string &v) { if (h) h->meta()->owner = v; });
494 handCls.addFunc("getConfig", [](Hand *h) -> LayoutConfig * { return h ? h->meta()->config : nullptr; });
495 handCls.addFunc("setConfig", [](Hand *h, LayoutConfig *c) { if (h) h->meta()->config = c; });
496 handCls.addFunc("isFaceDown", [](Hand *h) -> bool { return h ? h->meta()->faceDown : false; });
497 handCls.addFunc("setFaceDown", [](Hand *h, bool v) { if (h) h->meta()->faceDown = v; });
498 handCls.addFunc("isPeek", [](Hand *h) -> bool { return h ? h->meta()->peek : false; });
499 handCls.addFunc("setPeek", [](Hand *h, bool v) { if (h) h->meta()->peek = v; });
500 handCls.addFunc("isInteractive", [](Hand *h) -> bool { return h ? h->meta()->interactive : true; });
501 handCls.addFunc("setInteractive", [](Hand *h, bool v) { if (h) h->meta()->interactive = v; });
502 handCls.addFunc("addCard", &Hand::addCard);
503 handCls.addFunc("removeCard", &Hand::removeCard);
504 handCls.addFunc("clear", &Hand::clear);
505 handCls.addFunc("count", &Hand::count);
506 handCls.addFunc("getCard", &Hand::get);
507 handCls.addFunc("findCard", &Hand::find);
508 handCls.addFunc("pickCard", &Hand::pick);
509 handCls.addFunc("render", [](Hand *h, graphics::Graphics *gfx) { if (h) h->render(gfx); });
510}
511
512void Card::expose(ssq::Class &cls) {
513 cls.addFunc("registerCardsFromJson", &Card::registerCardsFromJson);
514 cls.addFunc("clearCardDefinitions", &Card::clearCardDefinitions);
515 cls.addFunc("getCardDefinitionCount", &Card::getCardDefinitionCount);
516 cls.addFunc("hasCardDefinition", &Card::hasCardDefinition);
517 cls.addFunc("getCardDefinitionName", &Card::getCardDefinitionName);
518 cls.addFunc("getCardDefinitionKind", &Card::getCardDefinitionKind);
519 cls.addFunc("getCardDefinitionCost", &Card::getCardDefinitionCost);
520 cls.addFunc("getCardDefinitionAttack", &Card::getCardDefinitionAttack);
521 cls.addFunc("getCardDefinitionHealth", &Card::getCardDefinitionHealth);
522 cls.addFunc("getCardDefinitionTintR", &Card::getCardDefinitionTintR);
523 cls.addFunc("getCardDefinitionTintG", &Card::getCardDefinitionTintG);
524 cls.addFunc("getCardDefinitionTintB", &Card::getCardDefinitionTintB);
525 cls.addFunc("newConfig", &Card::newConfig);
526 cls.addFunc("newCard", &Card::newCard);
527 cls.addFunc("newDeck", &Card::newDeck);
528 cls.addFunc("newZone", &Card::newZone);
529 cls.addFunc("newHand", &Card::newHand);
530 cls.addFunc("setConfig", &Card::setConfig);
531 cls.addFunc("getConfig", &Card::getConfig);
532 cls.addFunc("handCount", &Card::handCount);
533 cls.addFunc("getHand", &Card::getHand);
534 cls.addFunc("findHand", &Card::findHand);
535 cls.addFunc("zoneCount", &Card::zoneCount);
536 cls.addFunc("getZone", &Card::getZone);
537 cls.addFunc("getDeck", &Card::getDeck);
538 cls.addFunc("drawCard", &Card::drawCard);
539 cls.addFunc("update", &Card::update);
540 cls.addFunc("render", &Card::render);
541 cls.addFunc("renderDeck", &Card::renderDeck);
542 cls.addFunc("clearEvents", &Card::clearEvents);
543 cls.addFunc("getEventCount", &Card::getEventCount);
544 cls.addFunc("getEventType", &Card::getEventType);
545 cls.addFunc("getEventHand", &Card::getEventHand);
546 cls.addFunc("getEventZone", &Card::getEventZone);
547 cls.addFunc("getEventCardId", &Card::getEventCardId);
548 cls.addFunc("getEventReason", &Card::getEventReason);
549}
550
551} // namespace eve::card
struct SQVM * HSQUIRRELVM
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
std::string type
std::string id
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int h
int w
std::vector< Colorf > px
uint32_t b
uint32_t c
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:24
const char * name
Definition RockMesh.cpp:21
int d
int v
单张卡牌:ECS 实体,数据拆成 Identity / Stats / Visual / Layout / State。
Definition CardTypes.h:84
static CardData * createCard()
创建并触摸全部组件。
卡牌模块入口(eve.Card):定义注册、对象工厂与每帧 update/render。
Definition Card.h:26
std::string getEventReason(int index) const
Definition Card.cpp:334
std::string getEventType(int index) const
Definition Card.cpp:314
int getCardDefinitionCost(const std::string &id)
Definition Card.cpp:132
float getCardDefinitionTintB(const std::string &id)
Definition Card.cpp:157
int zoneCount() const
Definition Card.cpp:241
void renderDeck(graphics::Graphics *gfx)
Definition Card.cpp:290
void clearEvents()
交互事件队列(抽牌/出牌/拖拽等)。
Definition Card.cpp:310
LayoutConfig * getConfig() const
Definition Card.cpp:224
CardData * drawCard(const std::string &handOwner)
从牌库抽一张牌加入指定手牌;无牌时返回 nullptr。
Definition Card.cpp:250
int registerCardsFromJson(const std::string &json)
从 JSON 注册卡牌类型;返回成功注册数量。
Definition Card.cpp:97
void render(graphics::Graphics *gfx)
绘制手牌/落牌区(与牌库)。
Definition Card.cpp:279
int handCount() const
Definition Card.cpp:226
std::string getEventCardId(int index) const
Definition Card.cpp:329
bool hasCardDefinition(const std::string &id)
卡牌类型查询。
Definition Card.cpp:115
LayoutConfig * newConfig()
工厂:对象由 ECS 表持有,脚本持有的是非拥有句柄。
Definition Card.cpp:166
void update(float dt, float mx, float my, bool down)
每帧更新布局与交互。
Definition Card.cpp:268
Hand * newHand(LayoutConfig *cfg)
创建一个手牌布局。
Definition Card.cpp:209
float getCardDefinitionTintG(const std::string &id)
Definition Card.cpp:152
~Card() override
Definition Card.cpp:84
std::string getEventZone(int index) const
Definition Card.cpp:324
void setConfig(LayoutConfig *cfg)
游戏状态:当前布局、手牌、落牌区、牌库。
Definition Card.cpp:220
int getCardDefinitionHealth(const std::string &id)
Definition Card.cpp:142
std::string getEventHand(int index) const
Definition Card.cpp:319
Hand * findHand(const std::string &owner) const
Definition Card.cpp:233
Hand * getHand(int index) const
Definition Card.cpp:228
int getCardDefinitionCount()
已注册卡牌类型数量。
Definition Card.cpp:113
Deck * getDeck() const
Definition Card.cpp:248
int getCardDefinitionAttack(const std::string &id)
Definition Card.cpp:137
int getEventCount() const
Definition Card.cpp:312
float getCardDefinitionTintR(const std::string &id)
Definition Card.cpp:147
Deck * newDeck()
Definition Card.cpp:189
std::string getCardDefinitionName(const std::string &id)
Definition Card.cpp:122
void clearCardDefinitions()
清空全部卡牌类型定义。
Definition Card.cpp:111
Zone * getZone(int index) const
Definition Card.cpp:243
Zone * newZone(const std::string &id, const std::string &label, float x, float y, float w, float h)
创建一个落牌区。
Definition Card.cpp:196
CardData * newCard(const std::string &defId)
Definition Card.cpp:174
std::string getCardDefinitionKind(const std::string &id)
Definition Card.cpp:127
牌库(栈顶在末尾)。
Definition CardTypes.h:142
CardData * get(int index)
CardData * peek()
查看栈顶卡牌(不弹出)。
void push(CardData *c)
将卡牌压入栈顶(末尾)。
Definition CardTypes.h:159
void shuffle()
洗牌。
CardData * draw()
弹出栈顶卡牌(末尾);空牌库返回 nullptr。
void clear()
清空牌库。
Definition CardTypes.h:165
static Deck * createDeck()
创建并触摸 Membership。
int count()
牌库数量/是否为空/按下标取牌。
Definition CardTypes.h:169
手牌:扇形布局 + 悬浮 + 拖拽 + 落区判定 + 渲染。
Definition CardTypes.h:223
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:175
static Zone * createZone()
创建并触摸组件。
Font * getFont() const
Definition Graphics.h:691
bool valid() const
Definition Json.h:111
static Document parse(const std::string &text, std::string *error=nullptr)
Definition Json.cpp:449
Value root() const
Definition Json.h:112
std::string getString(const char *key, const std::string &fallback={}) const
Definition Json.cpp:390
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:10
void printCentered(graphics::Graphics *gfx, const std::string &text, float cx, float cy, float scale, const glm::vec4 &color)
渲染辅助(也供 Zone / Deck 复用)。
void registerCppEntityView(size_t typeHash, CppEntityViewFn fn)
Definition ECS.cpp:590
卡牌类型定义(registerCardsFromJson 注册)。
Definition CardTypes.h:73
UiCard 风格的布局配置(脚本可实时修改,对应 UiCard 的 Configs 面板)。
Definition CardTypes.h:40
float cardW
卡牌宽/高(像素)。
Definition CardTypes.h:42
float deckX
牌库堆绘制位置。
Definition CardTypes.h:66
bool showZones
是否绘制落牌区。
Definition CardTypes.h:64