diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 8675703a..beef9204 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -1435,12 +1435,46 @@ static void server_command_edit(shared_ptr c, const std::string& args) { if (tokens.at(1) == "none") { p->disp.visual.extra_model = 0; p->disp.visual.validation_flags &= 0xFD; + // Restore saved fields, if any + if (p->disp.visual.unused[0] == 0x8D) { + p->disp.visual.char_class = p->disp.visual.unused[1]; + p->disp.visual.head = p->disp.visual.unused[2]; + p->disp.visual.hair = p->disp.visual.unused[3]; + p->disp.visual.unused.clear(0); + } } else { uint8_t npc = npc_for_name(tokens.at(1)); if (npc == 0xFF) { send_text_message(c, "$C6No such NPC"); return; } + + // Some NPCs can crash the client if the character's class is + // incorrect. To handle this, we save the affected fields in the unused + // bytes after extra_model. + int8_t replacement_class = -1; + switch (npc) { + case 1: // Rico (replace with HUnewearl) + case 6: // Elly (replace with HUnewearl) + replacement_class = 0x01; + break; + case 0: // Ninja (replace with HUmar) + case 5: // Flowen (replace with HUmar) + replacement_class = 0x00; + break; + } + if (replacement_class >= 0) { + if (p->disp.visual.unused[0] != 0x8D) { + p->disp.visual.unused[0] = 0x8D; + p->disp.visual.unused[1] = p->disp.visual.char_class; + p->disp.visual.unused[2] = p->disp.visual.head; + p->disp.visual.unused[3] = p->disp.visual.hair; + } + p->disp.visual.char_class = replacement_class; + p->disp.visual.head = 0x00; + p->disp.visual.hair = 0x00; + } + p->disp.visual.extra_model = npc; p->disp.visual.validation_flags |= 0x02; }