WIP port 4-d quest dialogue modules
This commit is contained in:
@@ -603,6 +603,19 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
keeper_update.attack_speed = 100;
|
||||
if (!c.Send(keeper) || !c.Send(keeper_info) || !c.Send(keeper_update))
|
||||
return Fail(name + ": send shopkeeper");
|
||||
GCCharacterAdd elder = keeper;
|
||||
elder.vid = kQuestVID;
|
||||
elder.x = kQuestX;
|
||||
elder.y = kQuestY;
|
||||
elder.race = kQuestRace;
|
||||
GCCharAddInfo elder_info = zeroed<GCCharAddInfo>();
|
||||
elder_info.header = HDR_GC_CHAR_ADDITIONAL_INFO;
|
||||
elder_info.vid = kQuestVID;
|
||||
std::strncpy(elder_info.name, "Oldster", sizeof(elder_info.name) - 1);
|
||||
GCCharacterUpdate elder_update = keeper_update;
|
||||
elder_update.vid = kQuestVID;
|
||||
if (!c.Send(elder) || !c.Send(elder_info) || !c.Send(elder_update))
|
||||
return Fail(name + ": send quest NPC");
|
||||
Event(name + ":burst_sent");
|
||||
|
||||
// A ping after the burst proves that GamePhase consumed every packet above and can reply.
|
||||
@@ -619,6 +632,20 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
bool shopping = false;
|
||||
std::int32_t gold = kStartGold;
|
||||
std::uint32_t bag0 = 0; // vnum in inventory cell 0 (the fake character starts with an empty bag)
|
||||
int quest_page = 0; // the quest dialogue's last page sent (1 question, 2 next, 3 done)
|
||||
// CQuestManager::SendScript: packet_script {header, size, skin, src_size} and the script text.
|
||||
auto send_script = [&](const std::string& script) {
|
||||
struct
|
||||
{
|
||||
DynHead head;
|
||||
std::uint8_t skin;
|
||||
std::uint16_t src_size;
|
||||
} __attribute__((packed)) head = {{HDR_GC_SCRIPT, static_cast<std::uint16_t>(sizeof(head) + script.size())}, 1 /* QUEST_SKIN_NORMAL */,
|
||||
static_cast<std::uint16_t>(script.size())};
|
||||
std::string bytes(reinterpret_cast<const char*>(&head), sizeof(head));
|
||||
bytes += script;
|
||||
return c.Send(bytes.data(), bytes.size());
|
||||
};
|
||||
for (;;)
|
||||
{
|
||||
std::uint8_t packet[1024] = {};
|
||||
@@ -759,6 +786,11 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
CGOnClick click;
|
||||
std::memcpy(&click, packet, sizeof(click));
|
||||
Event(name + ":click " + std::to_string(click.vid));
|
||||
// CHARACTER::OnClick → CQuestManager::Click: say(...) then select("Yes", "No") → GotoSelectState.
|
||||
if (click.vid == kQuestVID && !send_script("Greetings, young warrior.[ENTER]Shall I tell you a story?[ENTER][QUESTION 1;Yes|2;No]"))
|
||||
return Fail(name + ": send GC_SCRIPT question");
|
||||
if (click.vid == kQuestVID)
|
||||
quest_page = 1;
|
||||
if (click.vid == kShopVID && !shopping)
|
||||
{
|
||||
shopping = true;
|
||||
@@ -780,6 +812,25 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
return Fail(name + ": send GC_SHOP START");
|
||||
}
|
||||
}
|
||||
// CInputMain::ScriptAnswer: an answer above 250 is the [NEXT] button (CQuestManager::Resume), the rest pick
|
||||
// a [QUESTION] choice (CQuestManager::Select, 0-based).
|
||||
if (header == HDR_CG_SCRIPT_ANSWER)
|
||||
{
|
||||
const std::uint8_t answer = packet[1];
|
||||
Event(name + ":answer " + std::to_string(answer));
|
||||
if (quest_page == 1 && answer == 0)
|
||||
{
|
||||
quest_page = 2;
|
||||
if (!send_script("Long ago a dragon slept under this village.[ENTER][NEXT]"))
|
||||
return Fail(name + ": send GC_SCRIPT next");
|
||||
}
|
||||
else if (quest_page == 2 && answer > 250)
|
||||
{
|
||||
quest_page = 3;
|
||||
if (!send_script("It sleeps there still.[ENTER][DONE]"))
|
||||
return Fail(name + ": send GC_SCRIPT done");
|
||||
}
|
||||
}
|
||||
// CInputMain::Shop: END → CShop::RemoveGuest (GC_SHOP END); BUY → CShop::Buy (PointChange(POINT_GOLD), then
|
||||
// CItem::AddToCharacter's GC_ITEM_SET into the first empty cell); SELL2 → CShopManager::Sell (the cell empties
|
||||
// with the 42-byte header-20 packet, then PointChange(POINT_GOLD)).
|
||||
|
||||
@@ -37,6 +37,10 @@ public:
|
||||
static constexpr std::int32_t kShopX = kMobX + 400, kShopY = kMobY;
|
||||
static constexpr std::uint32_t kShopItemVnum = 27001, kShopItemPrice = 50;
|
||||
static constexpr std::int32_t kStartGold = 10000, kShopSellPrice = 9;
|
||||
// An old man (npclist 20009) 3 m east of the store whose click runs a quest dialogue the way CQuestManager
|
||||
// sends it: say + select ([QUESTION]), then a [NEXT] page, then a [DONE] page.
|
||||
static constexpr std::uint32_t kQuestVID = 0x00045678, kQuestRace = 20009;
|
||||
static constexpr std::int32_t kQuestX = kShopX + 300, kQuestY = kShopY;
|
||||
|
||||
~FakeLoginServer();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user