diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 6572012bc..0b93306f1 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -63,8 +63,7 @@ void Corpse::SendLootReqErrorPacket(Client* client, uint8 response) { safe_delete(outapp); } -Corpse* Corpse::LoadFromDBData(uint32 in_dbid, uint32 in_charid, std::string in_charname, float in_x, float in_y, float in_z, float in_heading, std::string time_of_death, bool rezzed, bool was_at_graveyard) -{ +Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, float in_x, float in_y, float in_z, float in_heading, std::string time_of_death, bool rezzed, bool was_at_graveyard){ uint32 item_count = database.GetCharacterCorpseItemCount(in_dbid); char *buffer = new char[sizeof(PlayerCorpse_Struct) + (item_count * sizeof(player_lootitem::ServerLootItem_Struct))]; PlayerCorpse_Struct *pcs = (PlayerCorpse_Struct*)buffer; @@ -105,11 +104,11 @@ Corpse* Corpse::LoadFromDBData(uint32 in_dbid, uint32 in_charid, std::string in_ pcs->exp, // uint32 in_rezexp was_at_graveyard // bool wasAtGraveyard ); - if (pcs->locked) + if (pcs->locked){ pc->Lock(); + } /* Load Item Tints */ - // memcpy(pc->item_tint, pcs->item_tint, sizeof(pc->item_tint)); pc->item_tint[0].color = pcs->item_tint[0].color; pc->item_tint[1].color = pcs->item_tint[1].color; pc->item_tint[2].color = pcs->item_tint[2].color; @@ -118,8 +117,7 @@ Corpse* Corpse::LoadFromDBData(uint32 in_dbid, uint32 in_charid, std::string in_ pc->item_tint[5].color = pcs->item_tint[5].color; pc->item_tint[6].color = pcs->item_tint[6].color; pc->item_tint[7].color = pcs->item_tint[7].color; - pc->item_tint[8].color = pcs->item_tint[8].color; - + pc->item_tint[8].color = pcs->item_tint[8].color; /* Load Physical Appearance */ pc->haircolor = pcs->haircolor; @@ -231,15 +229,15 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP corpse_decay_timer.SetTimer(RuleI(NPC,EmptyNPCCorpseDecayTimeMS)+1000); } + if(in_npc->HasPrivateCorpse()) { corpse_delay_timer.SetTimer(corpse_decay_timer.GetRemainingTime() + 1000); } - // Added By Hogie -- End for (int i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; } - this->rezzexp = 0; + this->rez_experience = 0; } Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( @@ -317,8 +315,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( } is_corpse_changed = true; - rezzexp = in_rezexp; - can_rez = true; + rez_experience = in_rezexp; + can_corpse_be_rezzed = true; is_player_corpse = true; is_locked = false; being_looted_by = 0xFFFFFFFF; @@ -386,9 +384,9 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( // this was mainly for client profile state reflection..should match db player inventory entries now. iter_queue it; - for(it=client->GetInv().cursor_begin(),i=8001; it!=client->GetInv().cursor_end(); ++it,i++) { + for (it = client->GetInv().cursor_begin(), i = 8001; it != client->GetInv().cursor_end(); ++it, i++) { item = *it; - if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) { + if ((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) { std::list slot_list = MoveItemToCorpse(client, item, i); removed_list.merge(slot_list); cursor = true; @@ -397,16 +395,17 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( } database.TransactionBegin(); - if(removed_list.size() != 0) { + if (removed_list.size() != 0) { std::stringstream ss(""); ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID(); ss << " AND ("; std::list::const_iterator iter = removed_list.begin(); bool first = true; - while(iter != removed_list.end()) { - if(first) { + while (iter != removed_list.end()) { + if (first) { first = false; - } else { + } + else { ss << " OR "; } ss << "slotid=" << (*iter); @@ -416,8 +415,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( database.QueryDatabase(ss.str().c_str()); } - if(cursor) { // all cursor items should be on corpse (client < SoF or RespawnFromHover = false) - while(!client->GetInv().CursorEmpty()) + if (cursor) { // all cursor items should be on corpse (client < SoF or RespawnFromHover = false) + while (!client->GetInv().CursorEmpty()) client->DeleteItemInInventory(MainCursor, 0, false, false); } else { // only visible cursor made it to corpse (client >= Sof and RespawnFromHover = true) @@ -451,13 +450,13 @@ std::list Corpse::MoveItemToCorpse(Client *client, ItemInst *item, int16 returnlist.push_back(equipslot); // Qualified bag slot iterations. processing bag slots that don't exist is probably not a good idea. - if(item->IsType(ItemClassContainer) && ((equipslot >= EmuConstants::GENERAL_BEGIN && equipslot <= MainCursor))) { - for(bagindex = SUB_BEGIN; bagindex <= EmuConstants::ITEM_CONTAINER_SIZE; bagindex++) { + if (item->IsType(ItemClassContainer) && ((equipslot >= EmuConstants::GENERAL_BEGIN && equipslot <= MainCursor))) { + for (bagindex = SUB_BEGIN; bagindex <= EmuConstants::ITEM_CONTAINER_SIZE; bagindex++) { // For empty bags in cursor queue, slot was previously being resolved as SLOT_INVALID (-1) interior_slot = Inventory::CalcSlotId(equipslot, bagindex); interior_item = client->GetInv().GetItem(interior_slot); - if(interior_item) { + if (interior_item) { AddItem(interior_item->GetItem()->ID, interior_item->GetCharges(), interior_slot, interior_item->GetAugmentItemID(0), interior_item->GetAugmentItemID(1), interior_item->GetAugmentItemID(2), interior_item->GetAugmentItemID(3), interior_item->GetAugmentItemID(4)); returnlist.push_back(Inventory::CalcSlotId(equipslot, bagindex)); client->DeleteItemInInventory(interior_slot, 0, true, false); @@ -554,7 +553,7 @@ Corpse::Corpse(uint32 in_dbid, uint32 in_charid, const char* in_charname, ItemLi this->gold = in_gold; this->platinum = in_plat; - rezzexp = in_rezexp; + rez_experience = in_rezexp; for (int i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; @@ -564,7 +563,7 @@ Corpse::Corpse(uint32 in_dbid, uint32 in_charid, const char* in_charname, ItemLi Corpse::~Corpse() { if (is_player_corpse && !(player_corpse_depop && corpse_db_id == 0)) { - Save(); + Save(); } ItemList::iterator cur,end; cur = itemlist.begin(); @@ -618,7 +617,7 @@ bool Corpse::Save() { dbpc->level = level; dbpc->texture = this->texture; dbpc->helmtexture = this->helmtexture; - dbpc->exp = rezzexp; + dbpc->exp = rez_experience; memcpy(dbpc->item_tint, item_tint, sizeof(dbpc->item_tint)); dbpc->haircolor = haircolor; @@ -664,10 +663,10 @@ void Corpse::Delete() { } void Corpse::Bury() { - if (IsPlayerCorpse() && corpse_db_id != 0) + if (IsPlayerCorpse() && corpse_db_id != 0){ database.BuryCharacterCorpse(corpse_db_id); + } corpse_db_id = 0; - player_corpse_depop = true; } @@ -677,7 +676,7 @@ void Corpse::Depop() { } void Corpse::DepopCorpse() { - player_corpse_depop = true; + player_corpse_depop = true; } uint32 Corpse::CountItems() { @@ -689,7 +688,9 @@ void Corpse::AddItem(uint32 itemnum, uint16 charges, int16 slot, uint32 aug1, ui return; is_corpse_changed = true; + ServerLootItem_Struct* item = new ServerLootItem_Struct; + memset(item, 0, sizeof(ServerLootItem_Struct)); item->item_id = itemnum; item->charges = charges; @@ -705,7 +706,6 @@ void Corpse::AddItem(uint32 itemnum, uint16 charges, int16 slot, uint32 aug1, ui ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct** bag_item_data) { ServerLootItem_Struct *sitem = 0, *sitem2; - // find the item ItemList::iterator cur,end; cur = itemlist.begin(); end = itemlist.end(); @@ -721,9 +721,9 @@ ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct** cur = itemlist.begin(); end = itemlist.end(); - for(; cur != end; ++cur) { + for (; cur != end; ++cur) { sitem2 = *cur; - if(sitem2->equip_slot >= bagstart && sitem2->equip_slot < bagstart + 10) { + if (sitem2->equip_slot >= bagstart && sitem2->equip_slot < bagstart + 10) { bag_item_data[sitem2->equip_slot - bagstart] = sitem2; } } @@ -753,7 +753,7 @@ void Corpse::RemoveItem(uint16 lootslot) { ItemList::iterator cur,end; cur = itemlist.begin(); end = itemlist.end(); - for(; cur != end; ++cur) { + for (; cur != end; ++cur) { ServerLootItem_Struct* sitem = *cur; if (sitem->lootslot == lootslot) { RemoveItem(sitem); @@ -812,7 +812,7 @@ bool Corpse::Process() { return false; } - if(corpse_delay_timer.Check()) { + if (corpse_delay_timer.Check()) { for (int i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; } @@ -820,8 +820,8 @@ bool Corpse::Process() { return true; } - if(corpse_graveyard_timer.Check()) { - if(zone->HasGraveyard()) { + if (corpse_graveyard_timer.Check()) { + if (zone->HasGraveyard()) { Save(); player_corpse_depop = true; database.SendCharacterCorpseToGraveyard(corpse_db_id, zone->graveyard_zoneid(), @@ -849,7 +849,7 @@ bool Corpse::Process() { */ /* This is when a corpse hits decay timer and does checks*/ - if(corpse_decay_timer.Check()) { + if (corpse_decay_timer.Check()) { /* NPC */ if (IsNPCCorpse()){ corpse_decay_timer.Disable(); @@ -860,7 +860,7 @@ bool Corpse::Process() { Delete(); } else { - if(database.BuryCharacterCorpse(corpse_db_id)) { + if (database.BuryCharacterCorpse(corpse_db_id)) { Save(); player_corpse_depop = true; corpse_db_id = 0; @@ -887,7 +887,7 @@ void Corpse::SetDecayTimer(uint32 decaytime) { bool Corpse::CanPlayerLoot(int charid) { uint8 looters = 0; - for(int i = 0; i < MAX_LOOTERS; i++) { + for (int i = 0; i < MAX_LOOTERS; i++) { if (allowed_looters[i] != 0){ looters++; } @@ -933,31 +933,49 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a return; } - if(being_looted_by == 0) { being_looted_by = 0xFFFFFFFF; } + if(being_looted_by == 0) { + being_looted_by = 0xFFFFFFFF; + } if(this->being_looted_by != 0xFFFFFFFF) { // lets double check.... Entity* looter = entity_list.GetID(this->being_looted_by); - if(looter == 0) { this->being_looted_by = 0xFFFFFFFF; } + if(looter == 0) { + this->being_looted_by = 0xFFFFFFFF; + } } - uint8 tCanLoot = 1; + uint8 Loot_Request_Type = 1; bool loot_coin = false; if(database.GetVariable("LootCoin", tmp, 9)) { loot_coin = (atoi(tmp) == 1); } - if(this->being_looted_by != 0xFFFFFFFF && this->being_looted_by != client->GetID()) { + if (this->being_looted_by != 0xFFFFFFFF && this->being_looted_by != client->GetID()) { SendLootReqErrorPacket(client, 0); - tCanLoot = 0; + Loot_Request_Type = 0; + } + else if (IsPlayerCorpse() && char_id == client->CharacterID()) { + Loot_Request_Type = 2; + } + else if ((IsNPCCorpse() || become_npc) && CanPlayerLoot(client->CharacterID())) { + Loot_Request_Type = 2; + } + else if (GetPKItem() == -1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot all items, variable cash */ + Loot_Request_Type = 3; + } + else if (GetPKItem() == 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 item, variable cash */ + Loot_Request_Type = 4; + } + else if (GetPKItem() > 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 set item, variable cash */ + Loot_Request_Type = 5; } - else if(IsPlayerCorpse() && char_id == client->CharacterID()) { tCanLoot = 2; } - else if((IsNPCCorpse() || become_npc) && CanPlayerLoot(client->CharacterID())) { tCanLoot = 2; } - else if(GetPKItem() == -1 && CanPlayerLoot(client->CharacterID())) { tCanLoot = 3; } //pvp loot all items, variable cash - else if(GetPKItem() == 1 && CanPlayerLoot(client->CharacterID())) { tCanLoot = 4; } //pvp loot 1 item, variable cash - else if(GetPKItem() > 1 && CanPlayerLoot(client->CharacterID())) { tCanLoot = 5; } //pvp loot 1 set item, variable cash - if(tCanLoot == 1) { if(client->Admin() < 100 || !client->GetGM()) { SendLootReqErrorPacket(client, 2); } } + if (Loot_Request_Type == 1) { + if (client->Admin() < 100 || !client->GetGM()) { + SendLootReqErrorPacket(client, 2); + } + } - if(tCanLoot >= 2 || (tCanLoot == 1 && client->Admin() >= 100 && client->GetGM())) { + if(Loot_Request_Type >= 2 || (Loot_Request_Type == 1 && client->Admin() >= 100 && client->GetGM())) { this->being_looted_by = client->GetID(); EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct)); moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer; @@ -965,8 +983,9 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a d->response = 1; d->unknown1 = 0x42; d->unknown2 = 0xef; - if(tCanLoot == 2 || (tCanLoot >= 3 && loot_coin)) { // dont take the coin off if it's a gm peeking at the corpse + /* Dont take the coin off if it's a gm peeking at the corpse */ + if(Loot_Request_Type == 2 || (Loot_Request_Type >= 3 && loot_coin)) { if(!IsPlayerCorpse() && client->IsGrouped() && client->AutoSplitEnabled() && client->GetGroup()) { d->copper = 0; d->silver = 0; @@ -990,7 +1009,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a outapp->priority = 6; client->QueuePacket(outapp); safe_delete(outapp); - if(tCanLoot == 5) { + if(Loot_Request_Type == 5) { int pkitem = GetPKItem(); const Item_Struct* item = database.GetItem(pkitem); ItemInst* inst = database.CreateItem(item, item->MaxCharges); @@ -1019,7 +1038,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a // Dont display the item if it's in a bag // Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse. - if(!IsPlayerCorpse() || item_data->equip_slot <= MainCursor || item_data->equip_slot == MainPowerSource || tCanLoot>=3 || + if(!IsPlayerCorpse() || item_data->equip_slot <= MainCursor || item_data->equip_slot == MainPowerSource || Loot_Request_Type>=3 || (item_data->equip_slot >= 8000 && item_data->equip_slot <= 8999)) { if(i < corpselootlimit) { item = database.GetItem(item_data->item_id); @@ -1398,7 +1417,7 @@ bool Corpse::Summon(Client* client, bool spell, bool CheckDistance) { } void Corpse::CompleteRezz(){ - rezzexp = 0; + rez_experience = 0; is_corpse_changed = true; this->Save(); } diff --git a/zone/corpse.h b/zone/corpse.h index 4f0e96d05..9fe6a899a 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -36,7 +36,7 @@ public: Corpse(Client* client, int32 in_rezexp); Corpse(uint32 in_corpseid, uint32 in_charid, const char* in_charname, ItemList* in_itemlist, uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_plat, float in_x, float in_y, float in_z, float in_heading, float in_size, uint8 in_gender, uint16 in_race, uint8 in_class, uint8 in_deity, uint8 in_level, uint8 in_texture, uint8 in_helmtexture, uint32 in_rezexp, bool wasAtGraveyard = false); ~Corpse(); - static Corpse* LoadFromDBData(uint32 in_dbid, uint32 in_charid, std::string in_charname, float in_x, float in_y, float in_z, float in_heading, std::string time_of_death, bool rezzed, bool was_at_graveyard); + static Corpse* LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, float in_x, float in_y, float in_z, float in_heading, std::string time_of_death, bool rezzed, bool was_at_graveyard); //abstract virtual function implementations requird by base abstract class virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) { return true; } @@ -109,7 +109,7 @@ public: char orgname[64]; uint32 GetEquipment(uint8 material_slot) const; // returns item id uint32 GetEquipmentColor(uint8 material_slot) const; - inline int GetRezzExp() { return rezzexp; } + inline int GetRezzExp() { return rez_experience; } // these are a temporary work-around until corpse inventory is removed from the database blob static int16 ServerToCorpseSlot(int16 server_slot); // encode @@ -119,30 +119,31 @@ protected: std::list MoveItemToCorpse(Client *client, ItemInst *item, int16 equipslot); private: - bool is_player_corpse; - bool is_corpse_changed; - bool is_locked; - int32 player_kill_item; - uint32 corpse_db_id; - uint32 char_id; - ItemList itemlist; - uint32 copper; + bool is_player_corpse; /* Determines if Player Corpse or not */ + bool is_corpse_changed; /* Determines if corpse has changed or not */ + bool is_locked; /* Determines if corpse is locked */ + int32 player_kill_item; /* Determines if Player Kill Item */ + uint32 corpse_db_id; /* Corpse Database ID (Player Corpse) */ + uint32 char_id; /* Character ID */ + ItemList itemlist; /* Internal Item list used for corpses */ + uint32 copper; uint32 silver; uint32 gold; uint32 platinum; - bool player_corpse_depop; - uint32 being_looted_by; - uint32 rezzexp; + bool player_corpse_depop; /* Sets up Corpse::Process to depop the player corpse */ + uint32 being_looted_by; /* Determines what the corpse is being looted by internally for logic */ + uint32 rez_experience; /* Amount of experience that the corpse would rez for */ bool rez; - bool can_rez; + bool can_corpse_be_rezzed; /* Bool declaring whether or not a corpse can be rezzed */ bool become_npc; - int allowed_looters[MAX_LOOTERS]; // People allowed to loot the corpse, character id - Timer corpse_decay_timer; - Timer corpse_res_timer; - Timer corpse_delay_timer; + int allowed_looters[MAX_LOOTERS]; /* People allowed to loot the corpse, character id */ + Timer corpse_decay_timer; /* The amount of time in millseconds in which a corpse will take to decay (Depop/Poof) */ + Timer corpse_res_timer; /* The amount of time in millseconds in which a corpse can be rezzed */ + Timer corpse_delay_timer; Timer corpse_graveyard_timer; - Timer loot_cooldown_timer; + Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */ Color_Struct item_tint[9]; + }; #endif diff --git a/zone/npc.h b/zone/npc.h index 71e6596ad..a88ae9176 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -359,8 +359,9 @@ public: const bool GetCombatEvent() const { return combat_event; } void SetCombatEvent(bool b) { combat_event = b; } - //The corpse we make can only be looted by people who got credit for the kill + /* Only allows players that killed corpse to loot */ const bool HasPrivateCorpse() const { return NPCTypedata->private_corpse; } + const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; } const char* GetRawNPCTypeName() const { return NPCTypedata->name; } diff --git a/zone/spells.cpp b/zone/spells.cpp index 69ded563c..bcd2150c6 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3806,7 +3806,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r void Corpse::CastRezz(uint16 spellid, Mob* Caster) { - _log(SPELLS__REZ, "Corpse::CastRezz spellid %i, Rezzed() is %i, rezzexp is %i", spellid,IsRezzed(),rezzexp); + _log(SPELLS__REZ, "Corpse::CastRezz spellid %i, Rezzed() is %i, rezzexp is %i", spellid,IsRezzed(),rez_experience); if(IsRezzed()){ if(Caster && Caster->IsClient()) @@ -3838,7 +3838,7 @@ void Corpse::CastRezz(uint16 spellid, Mob* Caster) rezz->unknown020 = 0x00000000; rezz->unknown088 = 0x00000000; // We send this to world, because it needs to go to the player who may not be in this zone. - worldserver.RezzPlayer(outapp, rezzexp, corpse_db_id, OP_RezzRequest); + worldserver.RezzPlayer(outapp, rez_experience, corpse_db_id, OP_RezzRequest); _pkt(SPELLS__REZ, outapp); safe_delete(outapp); } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 8794f3570..4ffd70625 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3784,7 +3784,7 @@ Corpse* ZoneDatabase::SummonBuriedCharacterCorpses(uint32 char_id, uint32 dest_z auto results = QueryDatabase(query); for (auto row = results.begin(); row != results.end(); ++row) { - NewCorpse = Corpse::LoadFromDBData( + NewCorpse = Corpse::LoadCharacterCorpseEntity( atoll(row[0]), // uint32 in_dbid char_id, // uint32 in_charid row[1], // char* in_charname @@ -3826,7 +3826,7 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id results = QueryDatabase(query); for (auto row = results.begin(); row != results.end(); ++row) { - NewCorpse = Corpse::LoadFromDBData( + NewCorpse = Corpse::LoadCharacterCorpseEntity( atoll(row[0]), char_id, row[1], @@ -3871,7 +3871,7 @@ Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) { ); auto results = QueryDatabase(query); for (auto row = results.begin(); row != results.end(); ++row) { - NewCorpse = Corpse::LoadFromDBData( + NewCorpse = Corpse::LoadCharacterCorpseEntity( atoll(row[0]), // id uint32 in_dbid atoll(row[1]), // charid uint32 in_charid row[2], // char_name @@ -3911,7 +3911,7 @@ bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) { // std::cout << row[9] << std::endl; entity_list.AddCorpse( - Corpse::LoadFromDBData( + Corpse::LoadCharacterCorpseEntity( atoll(row[0]), // id uint32 in_dbid atoll(row[1]), // charid uint32 in_charid row[2], // char_name