mirror of
https://github.com/therealKyp/Earth-and-Beyond-server
synced 2026-08-13 22:23:03 -04:00
714 lines
No EOL
13 KiB
C++
714 lines
No EOL
13 KiB
C++
// ResourceClass.cpp
|
|
|
|
#include "Net7.h"
|
|
#include "MemoryHandler.h"
|
|
#include "ObjectClass.h"
|
|
#include "ResourceClass.h"
|
|
#include "ServerManager.h"
|
|
#include "ObjectManager.h"
|
|
#include <float.h>
|
|
|
|
Resource::Resource(long object_id) : Object (object_id)
|
|
{
|
|
m_Type = OT_RESOURCE;
|
|
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;
|
|
m_Field_Container = 0;
|
|
memset(m_Resource_contents, 0, MAX_ITEMS_PER_RESOURCE*sizeof(ContentSlot));
|
|
memset(&m_ObjectTimeSlot, 0, sizeof(m_ObjectTimeSlot));
|
|
}
|
|
|
|
Resource::Resource() : Object (0)
|
|
{
|
|
m_Type = OT_RESOURCE;
|
|
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));
|
|
}
|
|
|
|
Resource::~Resource()
|
|
{
|
|
// TODO: destroy everything
|
|
}
|
|
|
|
void Resource::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
|
|
}
|
|
|
|
static char *resource_name[] = {
|
|
"Asteroid", //0x71E
|
|
"Hydrocarbon Deposit", //0x726
|
|
"Crystalline Asteroid", //0x727
|
|
"Gas Cloud", //0x72a
|
|
"Tazeron Asteroid",
|
|
"Mordanite Asteroid",
|
|
"Hulk",
|
|
0
|
|
};
|
|
|
|
void Resource::SetTypeAndName(short basset)
|
|
{
|
|
short name_type = 0;
|
|
|
|
//check to see if this is an 'asteroid' type
|
|
AssetData *asset = g_ServerMgr->AssetList()->GetAssetData(basset);
|
|
if (strcmp(asset->m_CatName, "Asteroids") == 0)
|
|
{
|
|
//select name and main type based on sub type
|
|
switch (asset->m_SubCatName[0])
|
|
{
|
|
case 'R':
|
|
name_type = 0;
|
|
m_Resource_type = REACTIVE_ASTEROID;
|
|
break;
|
|
|
|
case 'M':
|
|
name_type = 0;
|
|
m_Resource_type = ROCKY_ASTEROID;
|
|
break;
|
|
|
|
case 'H':
|
|
name_type = 1;
|
|
m_Resource_type = HYDROCARBON;
|
|
break;
|
|
|
|
case 'G':
|
|
if (asset->m_SubCatName[1] == 'a')
|
|
{
|
|
name_type = 3;
|
|
m_Resource_type = GAS_CLOUD;
|
|
}
|
|
else
|
|
{
|
|
name_type = 2;
|
|
m_Resource_type = CRYSTALLINE_ASTEROID;
|
|
}
|
|
break;
|
|
|
|
case 'C':
|
|
name_type = 1;
|
|
m_Resource_type = CARBONACEOUS_ASTEROID;
|
|
break;
|
|
|
|
case 'N':
|
|
name_type = 0;
|
|
m_Resource_type = NICKEL_IRON;
|
|
break;
|
|
|
|
case 'D':
|
|
name_type = 1;
|
|
m_Resource_type = DIRTY_ICE_ASTEROID;
|
|
break;
|
|
|
|
default:
|
|
name_type = 3;
|
|
m_Resource_type = GAS_CLOUD;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (asset->m_SubCatName[0])
|
|
{
|
|
case 'I':
|
|
name_type = 6;
|
|
m_Resource_type = INORGANIC_HULK;
|
|
SetScale(3.0f);
|
|
break;
|
|
|
|
case 'O':
|
|
name_type = 6;
|
|
m_Resource_type = ORGANIC_HULK;
|
|
SetScale(3.0f);
|
|
break;
|
|
|
|
default:
|
|
name_type = 6;
|
|
m_Resource_type = INORGANIC_HULK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetBasset(basset);
|
|
SetName(resource_name[name_type]);
|
|
//LogMessage("0x%04x:%s\n", m_CreateInfo.BaseAsset, Name());
|
|
}
|
|
|
|
void Resource::SetBasset(short basset)
|
|
{
|
|
m_CreateInfo.BaseAsset = basset;
|
|
AssetData *asset = g_ServerMgr->AssetList()->GetAssetData(basset);
|
|
|
|
switch (asset->m_CatName[0])
|
|
{
|
|
case 'H':
|
|
//hulk
|
|
m_Type = OT_HULK;
|
|
if (asset->m_SubCatName[0] == 'I')
|
|
{
|
|
m_Resource_type = INORGANIC_HULK;
|
|
}
|
|
else
|
|
{
|
|
m_Resource_type = ORGANIC_HULK;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
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;
|
|
};
|
|
}
|
|
|
|
void Resource::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 resource already has this item
|
|
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;
|
|
|
|
SetRequiresReset(true);
|
|
}
|
|
|
|
ItemBase * Resource::GetItem(long slot)
|
|
{
|
|
if (slot >= 0 && slot < MAX_ITEMS_PER_RESOURCE)
|
|
{
|
|
return (m_Resource_contents[slot].item);
|
|
}
|
|
else
|
|
{
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
short Resource::GetStack(long slot)
|
|
{
|
|
if (slot >= 0 && slot < MAX_ITEMS_PER_RESOURCE)
|
|
{
|
|
return (m_Resource_contents[slot].stack);
|
|
}
|
|
else
|
|
{
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
float Resource::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 Resource::SetLevelFromHSV(float h1)
|
|
{
|
|
int colour = (int) h1;
|
|
|
|
switch (colour)
|
|
{
|
|
case 180:
|
|
m_Level = 1;
|
|
break;
|
|
case 120:
|
|
m_Level = 2;
|
|
break;
|
|
case 30:
|
|
m_Level = 3;
|
|
break;
|
|
case 20:
|
|
m_Level = 4;
|
|
break;
|
|
case 10:
|
|
m_Level = 5;
|
|
break;
|
|
case 0:
|
|
m_Level = 6;
|
|
break;
|
|
case -60:
|
|
m_Level = 7;
|
|
break;
|
|
case -70:
|
|
m_Level = 8;
|
|
break;
|
|
case -100:
|
|
m_Level = 9;
|
|
break;
|
|
case -110:
|
|
m_Level = 10;
|
|
break;
|
|
|
|
default:
|
|
m_Level = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Resource::ResetResource()
|
|
{
|
|
int x;
|
|
|
|
memset(m_Resource_contents, 0, MAX_ITEMS_PER_RESOURCE*sizeof(ContentSlot));
|
|
|
|
m_Content_count = 0;
|
|
|
|
if (Level() == 0) //haven't yet assigned a level to this object
|
|
{
|
|
LogMessage("WARNING: no level assigned to object '%s' [%d]\n", Name(), GameID());
|
|
SetLevel(1); //default to level 1
|
|
}
|
|
|
|
m_Resource_start_value = 0;
|
|
|
|
if (BaseAsset() == 0x726 && Level() == 10)
|
|
{
|
|
AddItem(g_ItemBaseMgr->GetItem(3009), 1); //grail water (quest)
|
|
}
|
|
else
|
|
{
|
|
//pick a number of slots
|
|
long random = rand()%25 + rand()%25 + rand()%25 + rand()%25 + 4;
|
|
long slots = 1;
|
|
|
|
if (random > 45) slots++;
|
|
if (random > 70) slots++;
|
|
if (random > 85) slots++;
|
|
if (random > 95) slots++;
|
|
if (random > 99) slots++;
|
|
|
|
for (x = 0; x < slots; x++)
|
|
{
|
|
short level = Level() - rand()%2;
|
|
short stack = rand()%5 + 1;
|
|
ItemBase *item_to_add;
|
|
|
|
if (level < 1) level = 1;
|
|
|
|
SectorManager * SMgr = GetSectorManager();
|
|
if (SMgr->GetSectorID() == 1052 && m_Resource_type == INORGANIC_HULK)
|
|
{
|
|
Sleep(1);
|
|
}
|
|
if (SMgr)
|
|
{
|
|
item_to_add = g_ItemBaseMgr->GetOreTemplate(level, m_Resource_type, SMgr->GetSectorID(), (Field*)m_Field_Container);
|
|
}
|
|
else
|
|
{
|
|
item_to_add = 0;
|
|
}
|
|
|
|
if (item_to_add)
|
|
{
|
|
if (item_to_add->MaxStack() == 1)
|
|
{
|
|
stack = 1;
|
|
}
|
|
else if (m_Resource_type == GAS_CLOUD && Level() < 7) //gas cloud
|
|
{
|
|
if (rand()%30 == 29)
|
|
{
|
|
stack = rand()%80 + 1;
|
|
}
|
|
else if (rand()%20 > 18)
|
|
{
|
|
stack = rand()%40 + 1;
|
|
}
|
|
else
|
|
{
|
|
stack = rand()%6 + 1;
|
|
}
|
|
}
|
|
AddItem(item_to_add, stack);
|
|
}
|
|
else
|
|
{
|
|
if (GetSectorManager())
|
|
{
|
|
long id = GetDatabaseUID();
|
|
if (m_Field_Container)
|
|
{
|
|
id = m_Field_Container->GetDatabaseUID();
|
|
}
|
|
LogMessage("--> ERROR: No ore found for Asteroid '%s', ID:%d level %d sector %d\n", Name(), id, Level(), GetSectorManager()->GetSectorID());
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_Resource_remains = 1.0f;
|
|
|
|
SetRespawnTick(0);
|
|
|
|
SetRequiresReset(true);
|
|
|
|
m_ToBeRemoved = false;
|
|
}
|
|
|
|
void Resource::SendObjectReset()
|
|
{
|
|
Player * p = 0;
|
|
u32 * sector_list = m_ObjectMgr->GetSectorList();
|
|
|
|
if (sector_list)
|
|
{
|
|
while (g_PlayerMgr->GetNextPlayerOnList(p, sector_list))
|
|
{
|
|
UnSetIndex(p->ResourceSendList());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Resource::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->SetResourceDrainLevel(this, slot);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_Resource_remains == 0)
|
|
{
|
|
DestroyResource();
|
|
}
|
|
}
|
|
|
|
void Resource::DestroyResource()
|
|
{
|
|
long destroy_timer = 2500;
|
|
long respawn_timer = 60000*15; //15mins //TODO: make this selectable from DASE data
|
|
|
|
if (BaseAsset() == 0x726 && Level() >= 9)
|
|
{
|
|
respawn_timer = 10000;
|
|
}
|
|
|
|
if (ObjectType() == OT_FLOATING_ORE)
|
|
{
|
|
m_ObjectMgr->DestroyObject(this, 0, -1);
|
|
}
|
|
else
|
|
{
|
|
switch (m_Resource_type)
|
|
{
|
|
case GAS_CLOUD:
|
|
m_ObjectMgr->DestroyObject(this, 0, respawn_timer);
|
|
break;
|
|
|
|
case INORGANIC_HULK:
|
|
case ORGANIC_HULK:
|
|
m_ObjectMgr->DestroyObject(this, 0, -1);
|
|
break;
|
|
|
|
case HYDROCARBON:
|
|
destroy_timer += 1500; //hydro's take longer to disintegrate
|
|
case REACTIVE_ASTEROID:
|
|
case ROCKY_ASTEROID:
|
|
case CRYSTALLINE_ASTEROID:
|
|
case CARBONACEOUS_ASTEROID:
|
|
case DIRTY_ICE_ASTEROID:
|
|
case NICKEL_IRON:
|
|
m_ObjectMgr->DestroyObject(this, destroy_timer, respawn_timer);
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_TargetOnCreate = 0;
|
|
}
|
|
|
|
//Send object to all players who can see this object. Currently used only for resource hijacks
|
|
void Resource::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 Resource::SendPosition(Player *player)
|
|
{
|
|
player->SendConstantPositionalUpdate(
|
|
GameID(),
|
|
PosX(),
|
|
PosY(),
|
|
PosZ(),
|
|
Orientation());
|
|
}
|
|
|
|
void Resource::SendAuxDataPacket(Player *player)
|
|
{
|
|
switch (CreateType())
|
|
{
|
|
case 38:
|
|
player->SendAuxNameResource(this);
|
|
break;
|
|
case 4:
|
|
player->SendResourceName(GameID(), Name());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//On creation of resource graphic object for Player
|
|
void Resource::OnCreate(Player *player)
|
|
{
|
|
|
|
}
|
|
|
|
//Called every time this resource is targeted.
|
|
void Resource::OnTargeted(Player *player)
|
|
{
|
|
player->BlankVerbs();
|
|
|
|
switch (ObjectType())
|
|
{
|
|
case OT_RESOURCE:
|
|
case OT_HULK:
|
|
if (player->Profession() == PROFESSION_EXPLORER)
|
|
{
|
|
player->AddVerb(VERBID_PROSPECT, float(player->ProspectRange()));
|
|
player->SendResourceLevel(GameID());
|
|
player->SendResourceContentsAUX(this);
|
|
}
|
|
break;
|
|
|
|
case OT_FLOATING_ORE:
|
|
player->AddVerb(VERBID_TRACTOR, 2000.0f);
|
|
break;
|
|
};
|
|
}
|
|
|
|
void Resource::SetDestroyTimer(long time_delay, long respawn_delay)
|
|
{
|
|
if (time_delay == 0)
|
|
{
|
|
//destroy now
|
|
Remove();
|
|
}
|
|
else
|
|
{
|
|
GetSectorManager()->AddTimedCallPNode(&m_ObjectTimeSlot, B_DESTROY_RESOURCE, time_delay, this, respawn_delay);
|
|
}
|
|
}
|
|
|
|
void Resource::RemoveDestroyTimer()
|
|
{
|
|
if (m_ObjectTimeSlot.event_time != 0)
|
|
{
|
|
GetSectorManager()->RemoveTimedCall(&m_ObjectTimeSlot, true);
|
|
}
|
|
} |