Batch 4-b: verify combat on the port route
The fake server spawns a stray dog outside the village's BANPK safe disc and answers CG_TARGET/CG_ATTACK with GC_TARGET/GC_DAMAGE_INFO/GC_DEAD. port.login_flow and python_game_render_test hold the left button on it (MBF_SMART -> __OnPressActor) until it dies. Adds the host/test helper PythonBoot::Evaluate / Metin2PythonHost.evaluate. python_3d_surface: emission is now multiplied by the texture, like D3D's emissive-then-MODULATE, which removes the grey click-glow quad and the grey wash on characters. Damage numbers wait on CPythonSystem (4-g). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6ea0fa9889
commit
85e176bdd5
@@ -563,6 +563,24 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
std::strncpy(ownership.owner, kCharacterName, sizeof(ownership.owner) - 1);
|
||||
if (!c.Send(ground) || !c.Send(ownership))
|
||||
return Fail(name + ": send ground item");
|
||||
// A monster in view: CHARACTER::EncodeInsertPacket sends ADDITIONAL_INFO only for PCs and NPCs, so a
|
||||
// CHAR_TYPE_MONSTER is ADD + UPDATE (the client names it from mob_proto).
|
||||
GCCharacterAdd mob = zeroed<GCCharacterAdd>();
|
||||
mob.header = HDR_GC_CHARACTER_ADD;
|
||||
mob.vid = kMobVID;
|
||||
mob.x = kMobX;
|
||||
mob.y = kMobY;
|
||||
mob.type = 0; // CHAR_TYPE_MONSTER
|
||||
mob.race = kMobRace;
|
||||
mob.moving_speed = 100;
|
||||
mob.attack_speed = 100;
|
||||
GCCharacterUpdate mob_update = zeroed<GCCharacterUpdate>();
|
||||
mob_update.header = HDR_GC_CHARACTER_UPDATE;
|
||||
mob_update.vid = kMobVID;
|
||||
mob_update.moving_speed = 100;
|
||||
mob_update.attack_speed = 100;
|
||||
if (!c.Send(mob) || !c.Send(mob_update))
|
||||
return Fail(name + ": send monster");
|
||||
Event(name + ":burst_sent");
|
||||
|
||||
// A ping after the burst proves that GamePhase consumed every packet above and can reply.
|
||||
@@ -575,6 +593,7 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
// Then hold the connection until the test stops us, reading what the game phase sends the way
|
||||
// CInputProcessor::Process frames it (static size or TDynamicSizePacketHeader, then the sequence
|
||||
// byte). A CG_MOVE (input_main.cpp CInputMain::Move) becomes "<name>:move <func> <arg> <rot> <x> <y>".
|
||||
int mob_hp = kMobHits;
|
||||
for (;;)
|
||||
{
|
||||
std::uint8_t packet[1024] = {};
|
||||
@@ -671,6 +690,36 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
if (!c.Send(chat) || !c.Send(line.c_str(), line.size() + 1))
|
||||
return Fail(name + ": send GC_CHAT");
|
||||
}
|
||||
// CInputMain::Target → CHARACTER::SetTarget → BroadcastTargetPacket: GC_TARGET with the monster's HP percent.
|
||||
if (header == HDR_CG_TARGET)
|
||||
{
|
||||
CGTarget target;
|
||||
std::memcpy(&target, packet, sizeof(target));
|
||||
Event(name + ":target " + std::to_string(target.vid));
|
||||
GCTarget out = {HDR_GC_TARGET, target.vid,
|
||||
static_cast<std::uint8_t>(target.vid == kMobVID ? mob_hp * 100 / kMobHits : 0)};
|
||||
if (!c.Send(out))
|
||||
return Fail(name + ": send GC_TARGET");
|
||||
}
|
||||
// CInputMain::Attack → battle_hit → CHARACTER::Damage: GC_DAMAGE_INFO to the attacker, the target HP
|
||||
// update, and at 0 HP CHARACTER::Dead's GC_DEAD.
|
||||
if (header == HDR_CG_ATTACK)
|
||||
{
|
||||
CGAttack attack;
|
||||
std::memcpy(&attack, packet, sizeof(attack));
|
||||
Event(name + ":attack " + std::to_string(attack.type) + " " + std::to_string(attack.victim_vid));
|
||||
if (attack.victim_vid == kMobVID && mob_hp > 0)
|
||||
{
|
||||
--mob_hp;
|
||||
GCDamageInfo damage = {HDR_GC_DAMAGE_INFO, kMobVID, 1 /* DAMAGE_NORMAL */, 100};
|
||||
GCTarget target = {HDR_GC_TARGET, kMobVID, static_cast<std::uint8_t>(mob_hp * 100 / kMobHits)};
|
||||
if (!c.Send(damage) || !c.Send(target))
|
||||
return Fail(name + ": send GC_DAMAGE_INFO");
|
||||
GCDead dead = {HDR_GC_DEAD, kMobVID};
|
||||
if (mob_hp == 0 && !c.Send(dead))
|
||||
return Fail(name + ": send GC_DEAD");
|
||||
}
|
||||
}
|
||||
if (header == HDR_CG_MOVE)
|
||||
{
|
||||
CGMove move;
|
||||
|
||||
Reference in New Issue
Block a user