|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum) |
|
|
|
09-19-2010, 05:51 AM
|
|
Demi-God
|
|
Join Date: May 2007
Location: b
Posts: 1,447
|
|
Destructable Objects
Here's a diff for it. HUGE thanks to Derision and Trevius for getting the packets figured out. This implements two database fields, which the SQL is listed below for as well.
destructable - this enables the object as being destructable
destructablestr - this is the object string that gets placed as an object. The only way to use this is if the client you are viewing it on has that eqg file, and if that client has that eqg file in its assets list. This is named qeynos_assets.txt for example, and contains a list of the object eqgs that contain the destructable object. The filename is what you put in destructablestr.
TODO: Make objects appear differently depending on a flag you set in the object itself. This is outlined in the diff comments and just requires a database field. This is so objects don't sink in the ground, or are too high above the ground.
TODO2: Add the object unknown opcode to perl.
NOTE: Objects' destructable appearance state depends on the appearance. This is outlined in the diff comments if you are curious about it.
SQL
Code:
ALTER TABLE `npc_types` ADD COLUMN `destructable` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '' AFTER
`unique_spawn_by_name`, ADD COLUMN `destructablestr` varchar(24) NOT NULL DEFAULT '' COMMENT '' AFTER `destructable`
Diff
Code:
Index: common/emu_oplist.h
===================================================================
--- common/emu_oplist.h (revision 1666)
+++ common/emu_oplist.h (working copy)
@@ -477,6 +477,7 @@
N(OP_TradeBusy),
N(OP_GuildUpdateURLAndChannel),
N(OP_CameraEffect),
+N(OP_DestructableRelated),
N(OP_SpellEffect),
N(OP_DzQuit),
N(OP_DzListTimers),
Index: common/eq_packet_structs.h
===================================================================
--- common/eq_packet_structs.h (revision 1666)
+++ common/eq_packet_structs.h (working copy)
@@ -313,6 +313,25 @@
/*0348*/ Color_Struct colors[MAX_MATERIALS]; // Array elements correspond to struct equipment_colors above
};
/*0384*/ uint8 lfg; // 0=off, 1=lfg on
+ bool DestructableObject;
+ char DestructableString1[64];
+ char DestructableString2[64];
+ char DestructableString3[64];
+ uint32 DestructableUnk1;
+ uint32 DestructableUnk2;
+ uint32 DestructableID1;
+ uint32 DestructableID2;
+ uint32 DestructableID3;
+ uint32 DestructableID4;
+ uint32 DestructableUnk3;
+ uint32 DestructableUnk4;
+ uint32 DestructableUnk5;
+ uint32 DestructableUnk6;
+ uint32 DestructableUnk7;
+ uint32 DestructableUnk8;
+ uint32 DestructableUnk9;
+ uint8 DestructableByte;
+
/*0385*/
};
Index: common/patches/SoD.cpp
===================================================================
--- common/patches/SoD.cpp (revision 1666)
+++ common/patches/SoD.cpp (working copy)
@@ -924,6 +924,29 @@
dest->FastQueuePacket(&in, ack_req);
}
+const char LiveTent[] =
+{
+0x61, 0x5f, 0x4d, 0x69, 0x6e, 0x6f, 0x68, 0x74, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6e, 0x74, 0x30,
+0x37, 0x00, 0xdb, 0x3b, 0x00, 0x00, 0x28, 0x00, 0x00, 0x20, 0x41, 0x01, 0x00, 0x00, 0x60, 0x1d,
+0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x4e,
+0x54, 0x5f, 0x47, 0x00, 0x61, 0x5f, 0x74, 0x65, 0x6e, 0x74, 0x00, 0x5a, 0x6f, 0x6e, 0x65, 0x41,
+0x63, 0x74, 0x6f, 0x72, 0x5f, 0x30, 0x31, 0x31, 0x38, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
+0x02, 0x00, 0x00, 0xb0, 0x07, 0x00, 0x00, 0xb1, 0x07, 0x00, 0x00, 0xb2, 0x07, 0x00, 0x00, 0xb3,
+0x07, 0x00, 0x00, 0x00, 0x9d, 0xf7, 0x13, 0x00, 0x00, 0x00, 0x00, 0x58, 0x9d, 0xf7, 0x13, 0x00,
+0x5b, 0xc5, 0x13, 0x60, 0x88, 0x12, 0x00, 0x66, 0x8f, 0x5a, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x08, 0x00,
+0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+0x00, 0x00, 0x3e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe1, 0x07, 0x00, 0x27, 0x83, 0x3a, 0x02, 0xf7, 0x02,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
ENCODE(OP_ZoneEntry){ ENCODE_FORWARD(OP_ZoneSpawns); }
ENCODE(OP_ZoneSpawns) {
@@ -967,7 +990,15 @@
if(strlen(emu->suffix))
PacketSize += strlen(emu->suffix) + 1;
-
+
+ if(emu->DestructableObject)
+ {
+ PacketSize = PacketSize - 4; // No bodytype
+ PacketSize += 53; // Fixed portion
+ PacketSize += strlen(emu->DestructableString1) + 1;
+ PacketSize += strlen(emu->DestructableString2) + 1;
+ PacketSize += strlen(emu->DestructableString3) + 1;
+ }
bool ShowName = 1;
if(emu->bodytype >= 66)
{
@@ -1000,7 +1031,15 @@
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spawnId);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
- VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height?
+ if(emu->DestructableObject)
+ {
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x41200000);
+ }
+ else
+ {
+ VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height?
+ }
+
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer;
@@ -1023,6 +1062,12 @@
Bitfields->showname = ShowName;
+ if(emu->DestructableObject)
+ {
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x1d600000);
+ Buffer = Buffer -4;
+ }
+
Bitfields->ispet = emu->is_pet;
Buffer += sizeof(structs::Spawn_Struct_Bitfields);
@@ -1035,10 +1080,48 @@
if(strlen(emu->suffix))
OtherData = OtherData | 0x08;
+ if(emu->DestructableObject)
+ OtherData = OtherData | 0xd1;
+
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
- VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3
+ if(emu->DestructableObject)
+ {
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000000);
+ }
+ else
+ {
+ VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3
+ }
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
+
+ if(emu->DestructableObject)
+ {
+ // Live has 0xe1 for OtherData
+ //
+ VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructableString1);
+ VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructableString2);
+ VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructableString3);
+
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk1);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk2);
+
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableID1);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableID2);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableID3);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableID4);
+
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk3);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk4);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk5);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk6);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk7);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk8);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructableUnk9);
+
+ VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->DestructableByte);
+ }
+
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->size);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->face);
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->walkspeed);
@@ -1056,8 +1139,16 @@
// Setting this next field to zero will cause a crash. Looking at ShowEQ, if it is zero, the bodytype field is not
// present. Will sort that out later.
- VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); // This is a properties count field
- VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->bodytype);
+
+ if(!emu->DestructableObject)
+ {
+ VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); // This is a properties count field
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->bodytype);
+ }
+ else
+ {
+ VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
+ }
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->curHp);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->haircolor);
@@ -1115,6 +1206,17 @@
Position->z = emu->z;
Position->deltaZ = emu->deltaZ;
+ if(emu->DestructableObject)
+ {
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000000);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000000);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x0007e1c3);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x023a8327);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x000002f7);
+
+ Buffer = Buffer -20;
+ }
+
Buffer += sizeof(structs::Spawn_Struct_Position);
if((emu->NPC == 0) || (emu->race <=12) || (emu->race == 128) || (emu ->race == 130) || (emu->race == 330) || (emu->race == 522))
@@ -1165,8 +1267,6 @@
}
Buffer += 33; // Unknown;
- //_log(NET__ERROR, "Sending zone spawn for %s", emu->name);
- //_hex(NET__ERROR, outapp->pBuffer, outapp->size);
dest->FastQueuePacket(&outapp, ack_req);
}
Index: zone/beacon.cpp
===================================================================
--- zone/beacon.cpp (revision 1666)
+++ zone/beacon.cpp (working copy)
@@ -45,7 +45,7 @@
:Mob
(
NULL, NULL, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,""
),
remove_timer(lifetime),
spell_timer(0)
Index: zone/client.cpp
===================================================================
--- zone/client.cpp (revision 1666)
+++ zone/client.cpp (working copy)
@@ -139,7 +139,9 @@
0, // qglobal
0, // slow_mitigation
0, // maxlevel
- 0 // scalerate
+ 0, // scalerate
+ 0, //destructableobject
+ "" //destructableobjectstr
),
//these must be listed in the order they appear in client.h
Index: zone/command.cpp
===================================================================
--- zone/command.cpp (revision 1666)
+++ zone/command.cpp (working copy)
@@ -860,6 +860,35 @@
void command_optest(Client *c, const Seperator *sep)
{
+ if(!c->GetTarget())
+ return;
+
+ EQApplicationPacket *outapp = new EQApplicationPacket(OP_DestructableRelated, 8);
+ char *Buffer = (char *)outapp->pBuffer;
+
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, c->GetTarget()->GetID());
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, atoi(sep->arg[1]));
+
+ /*
+ * EQApplicationPacket *outapp = new EQApplicationPacket(OP_TestBuff, 28);
+ char *Buffer = (char *)outapp->pBuffer;
+
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000039); // Effect type
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, c->GetTarget()->GetID());
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, c->GetTarget()->GetID());
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00001388);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000000);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000bb8);
+ VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x04990101);
+ */
+
+ DumpPacket(outapp);
+ c->QueuePacket(outapp);
+ safe_delete(outapp);
+ return;
+
+
+
if(sep->IsNumber(1))
{
switch(atoi(sep->arg[1]))
Index: zone/mob.cpp
===================================================================
--- zone/mob.cpp (revision 1666)
+++ zone/mob.cpp (working copy)
@@ -104,7 +104,9 @@
int8 in_qglobal,
float in_slow_mitigation, // Allows for mobs to mitigate how much they are slowed.
int8 in_maxlevel,
- int32 in_scalerate
+ int32 in_scalerate,
+ bool in_destructableobject,
+ const char * in_destructableobjectstr
) :
attack_timer(2000),
attack_dw_timer(2000),
@@ -371,6 +373,11 @@
nimbus_effect3 = 0;
flymode = FlyMode3;
+
+ destructableobject = in_destructableobject;
+
+ if(in_destructableobjectstr)
+ strncpy(destructableobjectstr,in_destructableobjectstr,24);
// Pathing
PathingLOSState = UnknownLOS;
PathingLoopCount = 0;
@@ -818,7 +826,71 @@
}
memset(ns->spawn.set_to_0xFF, 0xFF, sizeof(ns->spawn.set_to_0xFF));
+ if(IsNPC() && destructableobject)
+ {
+ ns->spawn.DestructableObject = true;
+ // Changing the first string made it vanish, so it has some significance.
+ if(destructableobjectstr)
+ sprintf(ns->spawn.DestructableString1, destructableobjectstr);
+ // Changing the second string made no visible difference
+ sprintf(ns->spawn.DestructableString2, "%s", ns->spawn.name);
+ // Putting a string in the final one that was previously empty had no visible effect.
+ sprintf(ns->spawn.DestructableString3, "");
+ // Unk1 is 0x00000000 for zombie catapult
+ // Changing it to 0x0000ffff made it invisvible / untargetable
+ // 0x00000001 Visible
+ // 0x00000005 not visible
+ // 0x00000004 not visible
+ // 0x00000002 visible, but only one of two endpieces showing and crosspiece at an odd angle
+ // Maybe this corresponds to the state set with the #appearance commands.
+ ns->spawn.DestructableUnk1 = 0x00000000; // Was 0x00000000
+ // Next one was originally 0x000001f5;
+ // Changing it to 0x00000000 made it look like a human
+ // Changing it to 0x000001f0 made it look like a catapult
+ // Changing it to 0x000001e0 made it look like a catapult
+ // Changing it to 0x00000100 made it look like a catapult
+ // Changing it to 0x00000001 made it look like a catapult
+ ns->spawn.DestructableUnk2 = 0x00000224;
+ // These next 4 are mostly always sequential
+ // Originally they were 633, 634, 635, 636
+ // Changing them all to 633 - no visible effect.
+ // Changing them all to 636 - no visible effect.
+ // #appearance 44 1 makes it jump but no visible damage
+ // #appearance 44 2 makes it look completely broken but still visible
+ // #appearnace 44 3 makes it jump but not visible difference to 3
+ // #appearance 44 4 makes it disappear altogether
+ // #appearance 44 5 makes the client sad.
+ //
+ // Reversing the order of these four numbers and then using #appearance gain had no visible change.
+ //
+ // There is an opcode 0x301d live, 0x5ea1 SoD that seems to change whether the object is targetable or not.
+ //
+ // Setting these four ids to zero had no visible effect when the catapult spawned, nor when #appearance was used.
+ ns->spawn.DestructableID1 = 1968;
+ ns->spawn.DestructableID2 = 1969;
+ ns->spawn.DestructableID3 = 1970;
+ ns->spawn.DestructableID4 = 1971;
+ // Next one was originally 0x1ce45008, changing it to 0x00000000 made no visible difference
+ ns->spawn.DestructableUnk3 = 0x13f79d00;
+ // Next one was originally 0x1a68fe30, changing it to 0x00000000 made no visible difference
+ ns->spawn.DestructableUnk4 = 0x00000000;
+ // Next one was already 0x00000000
+ ns->spawn.DestructableUnk5 = 0x13f79d58;
+ // Next one was originally 0x005a69ec, changing it to 0x00000000 made no visible difference.
+ ns->spawn.DestructableUnk6 = 0x13c55b00;
+ // Next one was originally 0x1a68fe30, changing it to 0x00000000 made no visible difference.
+ ns->spawn.DestructableUnk7 = 0x00128860;
+ // Next one was originally 0x0059de6d, changing it to 0x00000000 made no visible difference.
+ ns->spawn.DestructableUnk8 = 0x005a8f66;
+ // Next one was originally 0x00000201, changing it to 0x00000000 made no visible difference.
+ // For the Minohten tents, 0x00000000 had them up in the air, whil 0x201 put them on the ground.
+ // Changing it it 0x00000001 makes the tent sink into the ground.
+ ns->spawn.DestructableUnk9 = 0x00000201; // Needs to be 201 for tents
+ ns->spawn.DestructableByte = 0x00;
+
+ ns->spawn.flymode = 0;
+ }
}
void Mob::CreateDespawnPacket(EQApplicationPacket* app, bool Decay)
Index: zone/mob.h
===================================================================
--- zone/mob.h (revision 1666)
+++ zone/mob.h (working copy)
@@ -425,7 +425,9 @@
int8 in_qglobal,
float in_slow_mitigation, // Allows for mobs to mitigate how much they are slowed.
int8 in_maxlevel,
- int32 in_scalerate
+ int32 in_scalerate,
+ bool in_destructableobject,
+ const char* in_destructableobjectstr
);
virtual ~Mob();
@@ -1302,6 +1304,10 @@
bool m_hasPartialSpellRune;
bool m_hasDeathSaveChance;
int flymode;
+
+ bool destructableobject;
+ char destructableobjectstr[24];
+
int QGVarDuration(const char *fmt);
void InsertQuestGlobal(int charid, int npcid, int zoneid, const char *name, const char *value, int expdate);
Index: zone/npc.cpp
===================================================================
--- zone/npc.cpp (revision 1666)
+++ zone/npc.cpp (working copy)
@@ -109,7 +109,9 @@
d->qglobal,
d->slow_mitigation,
d->maxlevel,
- d->scalerate ),
+ d->scalerate ,
+ d->destructable,
+ d->destructablestr),
attacked_timer(CombatEventTimer_expire),
swarm_timer(100),
classattack_timer(1000),
@@ -343,6 +345,8 @@
ldon_trap_detected = 0;
}
qGlobals = NULL;
+ destructableobject = d->destructable;
+ strcpy(destructableobjectstr, d->destructablestr);
guard_x_saved = 0;
guard_y_saved = 0;
guard_z_saved = 0;
Index: zone/npc.h
===================================================================
--- zone/npc.h (revision 1666)
+++ zone/npc.h (working copy)
@@ -306,6 +306,8 @@
uint32 GetAdventureTemplate() const { return adventure_template_id; }
+ bool IsDestuctableObject() { return destructableobject; }
+
protected:
const NPCType* NPCTypedata;
Index: zone/PlayerCorpse.cpp
===================================================================
--- zone/PlayerCorpse.cpp (revision 1666)
+++ zone/PlayerCorpse.cpp (working copy)
@@ -198,7 +198,7 @@
in_npc->GetHeading(),in_npc->GetX(),in_npc->GetY(),in_npc->GetZ(),0,
in_npc->GetTexture(),in_npc->GetHelmTexture(),
0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0,0),
+ 0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0,0,0,""),
corpse_decay_timer(in_decaytime),
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
corpse_graveyard_timer(0),
@@ -303,7 +303,9 @@
0, // qglobal
0, // slow_mitigation
0, // maxlevel
- 0 // scalerate
+ 0, // scalerate
+ 0, //destr obj
+ "" //destr obj
),
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
@@ -413,7 +415,7 @@
: Mob("Unnamed_Corpse","",0,0,in_gender, in_race, in_class, BT_Humanoid, in_deity, in_level,0, in_size, 0, in_heading, in_x, in_y, in_z,0,in_texture,in_helmtexture,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0xff,
- 0,0,0,0,0,0,0,0,0,0),
+ 0,0,0,0,0,0,0,0,0,0,0,""),
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)),
Index: zone/zonedb.cpp
===================================================================
--- zone/zonedb.cpp (revision 1666)
+++ zone/zonedb.cpp (working copy)
@@ -1095,7 +1095,9 @@
"npc_types.maxlevel,"
"npc_types.scalerate,"
"npc_types.private_corpse,"
- "npc_types.unique_spawn_by_name";
+ "npc_types.unique_spawn_by_name,"
+ "npc_types.destructable,"
+ "npc_types.destructablestr";
MakeAnyLenString(&query, "%s FROM npc_types WHERE id=%d", basic_query, id);
@@ -1265,6 +1267,8 @@
tmpNPCType->scalerate = atoi(row[r++]);
tmpNPCType->private_corpse = atoi(row[r++]) == 1 ? true : false;
tmpNPCType->unique_spawn_by_name = atoi(row[r++]) == 1 ? true : false;
+ tmpNPCType->destructable = atoi(row[r++]) == 1 ? true : false;
+ strncpy(tmpNPCType->destructablestr, row[r++], 24);
// If NPC with duplicate NPC id already in table,
// free item we attempted to add.
Index: zone/zonedump.h
===================================================================
--- zone/zonedump.h (revision 1666)
+++ zone/zonedump.h (working copy)
@@ -117,6 +117,8 @@
int32 scalerate;
bool private_corpse;
bool unique_spawn_by_name;
+ bool destructable;
+ char destructablestr[24];
};
struct ZSDump_Spawn2 {
Last edited by trevius; 09-23-2011 at 06:43 AM..
|
|
|
|
09-19-2010, 05:53 AM
|
|
Demi-God
|
|
Join Date: May 2007
Location: b
Posts: 1,447
|
|
Here's a picture, just for laughs.
|
09-19-2010, 09:07 AM
|
Developer
|
|
Join Date: Mar 2009
Location: -
Posts: 228
|
|
Pft where is my thanks for complaining to Trev that I wanted destructible objects and then gm summoning him on top of where one should be to motivate him to figure out the opt codes!
Just joking! This is great news.
Kayen
GM Storm Haven
|
|
|
|
09-20-2010, 08:48 AM
|
|
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Haha, to be honest, I didn't do any of the work on Destructible items yet. I just asked Derision about the work he had done, as I was planning to see if I could help to get them working. I don't think there is too much left to do after seeing the work Derision has done. We just need to add in a few new DB fields and make some stuff to handle them properly.
I don't know much about destructible objects, but here are some points on what I have learned so far from messing with them:
1. Destructible objects have 5 states of appearances which can be seen by doing #appearance 44 0 to 4. Appearance 0 is the non-damaged version, and 4 is fully destroyed. Do not use appearance 5 or higher, as that will crash the client!
2. The new opcode named OP_DestructibleRelated changes the object from being targetable to being untargetable. This can be made into a Perl command, but we will also need some way for new players who zone in to see the object as untargetable as well. I think we will need to play with the struct a bit to see how to set the spawn to be untargetable from the start so we can set that field for new players zoning in after the object has been set this way. One cool thing about this new opcode is that it also works on normal NPCs. If it is used on a normal NPC, it removes them from your target and makes them untargetable. It is almost like they are toggled to bodytype 11 in real-time. If there is a way to change them back to being targetable again, I think this opcode could have some other potentially nice uses (maybe anti-hack stuff and possibly other uses).
3. The destruction animations can be done in any order, and also can be done in reverse.
4. These objects all have collision, which I think makes them more useful than some other types of zone objects.
5. Since the objects are essentially NPCs, they can be moved with a #summon. This is pretty cool. It makes me wonder what would happen if you set one on a pathing grid lol!
6. Each destructable object has 4 variable length string fields. I assume we can use the name and lastname field of normal NPCs for 2 of those strings, but we will probably need at least 1 or 2 new fields to be able to handle these properly. There are still at least a few fields we don't undertand yet, so there will probably need to be some other fields as well. I noticed a couple of fields that were set to 100, and I assume one of them may be object size.
At this point, I think the plan is to add destructible objects to the npc_types table. This makes sense, because they are essentially NPCs and even use the same opcode as NPCs do for spawning them. It is also the easiest way to manage them, since they need to be loaded like an NPC anyway.
Here are some notes on what I think we still need:
1. We need a way to set the damage states automatically based on HP percentages like maybe having them changes appearances every 25% (100% = 0, 75% = 1, 50% = 2, 25% = 3, 0% = 4). I believe that the appearance fields I added to NPCs a while back should be able to work for destructible objects as well, but will need to review that later to be sure. This should allow them to show the correct appearance state when new players zone in.
2. We need a way to set them non-targetable for new players zoning in after the OP_DestructibleRelated opcode is sent.
3. Optional would be to add a perl command to send the new OP_DestructibleRelated opcode (I can add this in like 2 seconds).
4. It may not be required, but we should try to identify some more of the unknown fields if possible.
I don't have a ton of time to work on this atm, but if no one else commits some stuff for destructible objects like what was submitted here, I will try to get to it when I have more time. I really appreciate Derision sharing the work he has done on them to this point. With his work, I think destructible objects should be functional and on the SVN pretty soon one way or another
EDIT: Wanted to note that the patch Secrets posted will probably break any existing corpses. So, for any servers that leave corpses with items on them, be warned that patching this will basically poof any existing corpses on your server (or make them inaccessible anyway).
Last edited by trevius; 09-20-2010 at 12:00 PM..
|
|
|
|
|
|
|
09-27-2010, 08:27 AM
|
|
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Seems like adding the code to replace existing objects in a zone with a destructible object should be easy enough to get going as it doesn't matter much what is set, it just takes over the object initially and everything looks ok. The only thing keeping this from being submitted is figuring out what is required to get new destructible objects that don't already exist to be able to spawn properly. So far, I haven't had too much luck in figuring those out completely. I was able to confirm that DestructableUnk1 is the setting for how damaged the object is. Unfortunately, for the example I was using (from oceangreenvillage), I wasn't able to get it to show up at all unless it was set to a value of 1 or higher (up to 4). That is one of the issues left to figure out.
The next issue is to figure out why they appear to be spawning about 5 units lower than they should, which puts them partially underground. I don't have any reference to how they should look on Live, but I am pretty sure they shouldn't be partially underground like that.
The final issue is to figure out why the collector may be collecting a size that is not the same size they should appear in-game. It is hard to be sure if this is really an issue or not though. I am using tents in mesa to compare as I spawned them to not replace the existing tents and they were all set to size 6 as they were collected, but the tents they are supposed to replace are actually size 5. This may just be due to SOE being lazy and using a generic setting since the size issue does not happen when they are actually replacing the existing objects as it takes on that object's attributes.
One other thing that I was able to confirm is that the last 2 fields are actually in the wrong order. It is an int8 then an int32, not int32 then int8. They are generally set like 0x01 and 0x00000002.
Either way, I am holding off on working on these more for a while. If anyone else wants to, feel free. My main concern with adding these is that we get all of the required fields added to the npc_types table so collects for them only need to be done once in order to have all of the info we will need for any destructible object. I know we will definitely need a new string field for the 3rd destructible string. I think we will need at least 1 or 2 other fields for the DestructableUnk1 and maybe the one noted as "// eye height?" in the normal part of the struct.
|
|
|
|
09-27-2010, 11:17 PM
|
Administrator
|
|
Join Date: Sep 2006
Posts: 1,348
|
|
Couldn't you just offset them 5 units above where they should be and figure it out later? =p
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 08:31 AM.
|
|
|
|
|
|
|
|
|
|
|
|
|