net7/trunk/Net7/HuskClass.cpp
2014-05-11 16:54:16 -04:00

516 lines
No EOL
10 KiB
C++

// HuskClass.cpp
#include "Net7.h"
#include "MemoryHandler.h"
#include "ObjectClass.h"
#include "HuskClass.h"
#include "ServerManager.h"
#include "ObjectManager.h"
#include <float.h>
Husk::Husk(long object_id) : Object (object_id)
{
m_Type = OT_HUSK;
m_Position_info.type = POSITION_CONSTANT;
m_Content_count = 0;
m_Resource_value = 0;
m_Respawn_tick = 0;
m_Resource_type = 0;
m_CreateInfo.Type = 38;
m_Resource_remains = 0.0f;
m_Resource_start_value = 0;
memset(m_Resource_contents, 0, MAX_ITEMS_PER_RESOURCE*sizeof(ContentSlot));
memset(&m_ObjectTimeSlot, 0, sizeof(m_ObjectTimeSlot));
m_HuskCredits = 0;
}
Husk::Husk() : Object (0)
{
m_Type = OT_HUSK;
m_Position_info.type = POSITION_CONSTANT;
m_Content_count = 0;
m_Resource_value = 0;
m_Respawn_tick = 0;
m_Resource_type = 0;
m_CreateInfo.Type = 38;
m_Resource_remains = 0.0f;
m_Resource_start_value = 0;
memset(m_Resource_contents, 0, MAX_ITEMS_PER_RESOURCE*sizeof(ContentSlot));
memset(&m_ObjectTimeSlot, 0, sizeof(m_ObjectTimeSlot));
m_HuskCredits = 0;
}
Husk::~Husk()
{
// TODO: destroy everything
}
void Husk::SetLevel(short level)
{
float obj_colour;
switch (level)
{
case 1:
obj_colour = 180.0f;
break;
case 2:
obj_colour = 120.0f;
break;
case 3:
obj_colour = 30.0f;
break;
case 4:
obj_colour = 20.0f;
break;
case 5:
obj_colour = 10.0f;
break;
case 6:
obj_colour = 0.0f;
break;
case 7:
obj_colour = -60.0f;
break;
case 8:
obj_colour = -70.0f;
break;
case 9:
obj_colour = -100.0f;
break;
case 10:
obj_colour = -110.0f;
break;
case 11:
obj_colour = -120.0f;
break;
default:
obj_colour = 180.0f;
level = 1;
break;
}
m_Level = level;
m_CreateInfo.HSV[0] = obj_colour; //NB: this can still be overriden easily with a SetColour
}
void Husk::SetBasset(short basset)
{
m_CreateInfo.BaseAsset = basset;
AssetData *asset = g_ServerMgr->AssetList()->GetAssetData(basset);
m_Type = OT_HUSK;
if (asset->m_Name[0] == 'O')
{
m_Resource_type = ORGANIC_HULK;
}
else
{
m_Resource_type = INORGANIC_HULK;
}
switch (m_CreateInfo.BaseAsset)
{
case 1822:
case 1823:
case 1824:
m_ObjectRadius = 800.0f;
break;
case 1825:
case 1826:
case 1827:
m_ObjectRadius = 630.0f;
break;
case 1828:
case 1829:
case 1830:
m_ObjectRadius = 510.0f;
break;
case 1831:
case 1832:
case 1833:
m_ObjectRadius = 750.0f;
break;
case 1834:
m_ObjectRadius = 0;
break;
default:
m_ObjectRadius = g_ServerMgr->BAssetRadii()->GetRadius(basset);
break;
};
}
//this should go into the object base class really, since it's used for resource class too
void Husk::AddItem(ItemBase *item, long stack)
{
int i;
int j;
if (item == (0) || stack == 0)
{
LogMessage("NULL item passed to AddItem\n");
return;
}
//locate first empty slot
for (i=0; i < MAX_ITEMS_PER_RESOURCE; i++)
{
if (m_Resource_contents[i].stack == 0)
{
break;
}
}
//see if Husk already has this
for (j=0; j < MAX_ITEMS_PER_RESOURCE; j++)
{
if (m_Resource_contents[j].item == item)
{
if ((stack + m_Resource_contents[j].stack) <= item->MaxStack())
{
m_Resource_contents[j].stack += (u16)stack;
m_Resource_start_value += (u16)stack;
}
else
{
m_Resource_start_value += (item->MaxStack() - m_Resource_contents[j].stack);
m_Resource_contents[j].stack = item->MaxStack();
}
m_Resource_value = m_Resource_start_value;
return;
}
}
if (i < MAX_ITEMS_PER_RESOURCE)
{
m_Resource_contents[i].item = item;
m_Resource_contents[i].stack = (u16)stack;
m_Content_count++;
m_Resource_start_value += (u16)stack;
}
m_Resource_value = m_Resource_start_value;
}
ItemBase * Husk::GetItem(long slot)
{
if (slot >= 0 && slot < MAX_ITEMS_PER_RESOURCE)
{
return (m_Resource_contents[slot].item);
}
else
{
return (0);
}
}
short Husk::GetStack(long slot)
{
if (slot >= 0 && slot < MAX_ITEMS_PER_RESOURCE)
{
return (m_Resource_contents[slot].stack);
}
else
{
return (0);
}
}
float Husk::RemoveItem(long slot_id, long stack)
{
float resource_remains = 0.0f;
float resource_remaining;
if (slot_id < MAX_ITEMS_PER_RESOURCE)
{
if (m_Resource_contents[slot_id].stack > (u16)stack)
{
m_Resource_contents[slot_id].stack -= (u16)stack;
}
else
{
m_Resource_contents[slot_id].stack = 0;
m_Resource_contents[slot_id].item = (0);
}
m_Resource_value -= (u16)stack;
resource_remaining = ( (float)(m_Resource_value) / (float)(m_Resource_start_value) );
resource_remains = 0.0f;
//roundings needed by client
if (resource_remaining > 0.0f)
{
resource_remains = 0.125f;
}
if (resource_remaining > 0.125f)
{
resource_remains = 0.25f;
}
if (resource_remaining > 0.25f)
{
resource_remains = 0.4f;
}
if (resource_remaining > 0.4f)
{
resource_remains = 0.5f;
}
if (resource_remaining > 0.5f)
{
resource_remains = 0.6f;
}
if (resource_remaining > 0.6f)
{
resource_remains = 0.88889f;
}
if (resource_remaining > 0.95f)
{
resource_remains = 1.0f;
}
}
else
{
LogMessage("ERROR: slot out of range for object '%s' id [%d]\n", Name(), GameID());
}
m_Resource_remains = resource_remains;
SendObjectDrain(slot_id);
return (resource_remains);
}
void Husk::PopulateHusk(long mob_type)
{
MOBData *mob_data = g_ServerMgr->MOBList()->GetMOBData(mob_type);
long loot_item_id;
short stack;
float chance_to_drop, drop_number;
long highest_count = mob_data->m_Loot.size();
//pick a number of slots
long random = rand()%25 + rand()%25 + rand()%25 + rand()%25 + 4;
long slots = 1;
if (random > 55) slots++;
if (random > 75) slots++;
if (random > 90) slots++;
if (random > 96) slots++;
if (random > 99) slots++;
if (highest_count != 0)
{
for (int x = 0; x < slots; x++)
{
int rand_item = (rand()%highest_count);
loot_item_id = mob_data->m_Loot[rand_item]->item_base_id;
if (loot_item_id == -1) continue;
//see if this item drops or not
chance_to_drop = mob_data->m_Loot[rand_item]->drop_chance;
drop_number = (float)(rand()%250 + rand()%250 + rand()%250 + rand()%250)/1000.0f;
if (chance_to_drop >= drop_number)
{
stack = rand()%(mob_data->m_Loot[rand_item]->quantity) + 1;
AddItem(g_ItemBaseMgr->GetItem(loot_item_id), stack);
}
}
}
else
{
LogMessage("Husk %s has no loot choice\n", Name());
}
if (m_Resource_start_value > 0)
{
m_Resource_remains = 1.0f;
}
else
{
m_Resource_remains = 0.0f;
}
SetRespawnTick(0);
m_ToBeRemoved = false;
}
void Husk::SendObjectReset()
{
Player * p = 0;
u32 * sector_list = m_ObjectMgr->GetSectorList();
if (sector_list)
{
while (g_PlayerMgr->GetNextPlayerOnList(p, sector_list))
{
UnSetIndex(p->ResourceSendList());
}
}
}
void Husk::SendObjectDrain(long slot)
{
PlayerList::iterator itrPList;
Player * p = 0;
u32 * sector_list = m_ObjectMgr->GetSectorList();
if (slot != -1 && sector_list)
{
while (g_PlayerMgr->GetNextPlayerOnList(p, sector_list))
{
if (GetIndex(p->ObjectRangeList()))
{
p->SetHuskDrainLevel(this, slot);
}
}
}
if (m_Resource_remains == 0)
{
RemoveDestroyTimer();
SetRespawnTick(-1);
Remove();
}
}
//Send object to all players who can see this object. Currently used only for resource hijacks
void Husk::SendToVisibilityList(bool include_player)
{
Player * p = 0;
u32 * sector_list = m_ObjectMgr->GetSectorList();
if (sector_list)
{
while (g_PlayerMgr->GetNextPlayerOnList(p, sector_list))
{
if (GetIndex(p->ObjectRangeList()))
{
p->SendAdvancedPositionalUpdate(GameID(), PosInfo());
}
}
}
}
void Husk::SetHuskName(char *name)
{
char buffer[128];
m_NameLen = _snprintf(buffer, 128, "Corpse of %s", name);
m_Name = g_StringMgr->GetStr(buffer);
}
void Husk::SendPosition(Player *player)
{
player->SendConstantPositionalUpdate(
GameID(),
PosX(),
PosY(),
PosZ(),
Orientation());
}
void Husk::SendAuxDataPacket(Player *player)
{
player->SendHuskName(this);
}
//On creation of resource graphic object for Player
void Husk::OnCreate(Player *player)
{
//if 'TargetOnCreate' is set for this object, we want a player to auto-target it
//when it comes into their view. (eg Husks).
/*if (player->GameID() == GetPlayerLootLock())
{
player->SendHuskContent(this);
player->SendPacketCache();
player->ShipIndex()->SetTargetGameID(GameID());
player->SendAuxShip();
player->BlankVerbs();
player->AddVerb(VERBID_LOOT, 2000.0f);
SetPlayerLootLock(0);
}*/
}
//Called every time this resource is targeted.
void Husk::OnTargeted(Player *player)
{
player->BlankVerbs();
player->SendHuskContent(this);
player->AddVerb(VERBID_LOOT, 6000.0f);
}
void Husk::SetDestroyTimer(long time_delay, long respawn_delay)
{
if (time_delay == 0)
{
//destroy now
Remove();
}
else
{
GetSectorManager()->AddTimedCallPNode(&m_ObjectTimeSlot, B_DESTROY_HUSK, time_delay, this, respawn_delay);
}
}
void Husk::RemoveDestroyTimer()
{
if (m_ObjectTimeSlot.event_time != 0)
{
GetSectorManager()->RemoveTimedCall(&m_ObjectTimeSlot, true);
}
}
void Husk::DestroyHusk()
{
Player *p = 0;
u32 * sector_list = m_ObjectMgr->GetSectorList();
SetRespawnTick(-1);
if (!Active()) return;
//have a little removal effect
ObjectEffect ObjExplosion;
ObjExplosion.Bitmask = 0x07;
ObjExplosion.GameID = GameID();
ObjExplosion.EffectDescID = 393; //orange shockwave
ObjExplosion.EffectID = m_ObjectMgr->GetAvailableSectorID();
ObjExplosion.TimeStamp = GetNet7TickCount();
ObjExplosion.Duration = 4000;
while (g_PlayerMgr->GetNextPlayerOnList(p, sector_list))
{
if (p)
{
if (GetIndex(p->ObjectRangeList()))
{
p->SendObjectEffect(&ObjExplosion);
}
}
}
Remove();
}
void Husk::SetLootTimer(long time_delay)
{
if (time_delay == 0)
{
m_LootTime = 0;
}
else
{
m_LootTime = GetNet7TickCount() + time_delay;
}
}