2010-04-02 19:52:46 -06:00
|
|
|
/*
|
|
|
|
www.sourceforge.net/projects/dfhack
|
|
|
|
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any
|
|
|
|
damages arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any
|
|
|
|
purpose, including commercial applications, and to alter it and
|
|
|
|
redistribute it freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must
|
|
|
|
not claim that you wrote the original software. If you use this
|
|
|
|
software in a product, an acknowledgment in the product documentation
|
|
|
|
would be appreciated but is not required.
|
|
|
|
|
|
|
|
2. Altered source versions must be plainly marked as such, and
|
|
|
|
must not be misrepresented as being the original software.
|
|
|
|
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
|
|
distribution.
|
|
|
|
*/
|
|
|
|
|
2010-05-26 04:24:45 -06:00
|
|
|
#include "Internal.h"
|
2011-04-10 02:19:15 -06:00
|
|
|
|
2011-04-23 18:49:49 -06:00
|
|
|
#include <stddef.h>
|
2011-04-10 02:19:15 -06:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <map>
|
|
|
|
#include <cstring>
|
|
|
|
using namespace std;
|
|
|
|
|
2010-05-26 04:24:45 -06:00
|
|
|
#include "ContextShared.h"
|
2010-04-02 19:52:46 -06:00
|
|
|
|
2010-08-20 06:10:05 -06:00
|
|
|
#include "dfhack/VersionInfo.h"
|
2010-05-25 22:48:23 -06:00
|
|
|
#include "dfhack/DFProcess.h"
|
|
|
|
#include "dfhack/DFVector.h"
|
|
|
|
#include "dfhack/DFError.h"
|
|
|
|
#include "dfhack/DFTypes.h"
|
2010-04-04 16:48:19 -06:00
|
|
|
|
2010-04-06 19:38:22 -06:00
|
|
|
// we connect to those
|
2010-05-26 00:42:09 -06:00
|
|
|
#include "dfhack/modules/Materials.h"
|
|
|
|
#include "dfhack/modules/Creatures.h"
|
2011-03-18 01:53:59 -06:00
|
|
|
#include "ModuleFactory.h"
|
2010-04-06 19:38:22 -06:00
|
|
|
|
2010-04-02 19:52:46 -06:00
|
|
|
using namespace DFHack;
|
2010-04-04 04:29:56 -06:00
|
|
|
|
2010-04-04 16:48:19 -06:00
|
|
|
struct Creatures::Private
|
|
|
|
{
|
|
|
|
bool Inited;
|
|
|
|
bool Started;
|
2010-09-02 18:15:09 -06:00
|
|
|
bool Ft_basic;
|
|
|
|
bool Ft_advanced;
|
|
|
|
bool Ft_jobs;
|
2011-04-03 13:27:47 -06:00
|
|
|
bool Ft_job_materials;
|
2010-09-02 18:15:09 -06:00
|
|
|
bool Ft_soul;
|
2011-04-03 13:27:47 -06:00
|
|
|
bool Ft_inventory;
|
2011-05-09 04:49:44 -06:00
|
|
|
bool Ft_owned_items;
|
2011-03-18 10:58:48 -06:00
|
|
|
struct t_offsets
|
|
|
|
{
|
|
|
|
// creature offsets
|
|
|
|
uint32_t vector;
|
|
|
|
uint32_t pos_offset;
|
|
|
|
uint32_t profession_offset;
|
|
|
|
uint32_t custom_profession_offset;
|
|
|
|
uint32_t race_offset;
|
|
|
|
int32_t civ_offset;
|
|
|
|
uint32_t flags1_offset;
|
|
|
|
uint32_t flags2_offset;
|
|
|
|
uint32_t name_offset;
|
|
|
|
uint32_t sex_offset;
|
|
|
|
uint32_t caste_offset;
|
|
|
|
uint32_t id_offset;
|
|
|
|
uint32_t labors_offset;
|
|
|
|
uint32_t happiness_offset;
|
|
|
|
uint32_t artifact_name_offset;
|
|
|
|
uint32_t physical_offset;
|
|
|
|
uint32_t mood_offset;
|
|
|
|
uint32_t mood_skill_offset;
|
|
|
|
uint32_t pickup_equipment_bit;
|
|
|
|
uint32_t soul_vector_offset;
|
|
|
|
uint32_t default_soul_offset;
|
|
|
|
uint32_t current_job_offset;
|
|
|
|
// soul offsets
|
|
|
|
uint32_t soul_skills_vector_offset;
|
|
|
|
// name offsets (needed for reading creature names)
|
|
|
|
uint32_t name_firstname_offset;
|
|
|
|
uint32_t name_nickname_offset;
|
|
|
|
uint32_t name_words_offset;
|
|
|
|
uint32_t soul_mental_offset;
|
|
|
|
uint32_t soul_traits_offset;
|
|
|
|
uint32_t appearance_vector_offset;
|
|
|
|
uint32_t birth_year_offset;
|
|
|
|
uint32_t birth_time_offset;
|
|
|
|
uint32_t inventory_offset;
|
2011-05-09 04:49:44 -06:00
|
|
|
uint32_t owned_items_offset;
|
2011-04-03 13:27:47 -06:00
|
|
|
// creature job stuff
|
|
|
|
int32_t job_type_offset;
|
|
|
|
int32_t job_id_offset;
|
|
|
|
int32_t job_materials_vector;
|
|
|
|
int32_t job_material_itemtype_o;
|
|
|
|
int32_t job_material_subtype_o;
|
|
|
|
int32_t job_material_subindex_o;
|
|
|
|
int32_t job_material_index_o;
|
|
|
|
int32_t job_material_flags_o;
|
|
|
|
// creature job material stuff
|
2011-03-18 10:58:48 -06:00
|
|
|
} creatures;
|
2010-04-04 16:48:19 -06:00
|
|
|
uint32_t creature_module;
|
2010-04-16 05:28:07 -06:00
|
|
|
uint32_t dwarf_race_index_addr;
|
2010-04-19 06:36:21 -06:00
|
|
|
uint32_t dwarf_civ_id_addr;
|
2011-04-11 04:32:53 -06:00
|
|
|
bool IdMapReady;
|
|
|
|
std::map<int32_t, int32_t> IdMap;
|
2010-04-18 06:56:09 -06:00
|
|
|
DfVector <uint32_t> *p_cre;
|
2010-05-26 04:24:45 -06:00
|
|
|
DFContextShared *d;
|
2010-04-18 13:30:02 -06:00
|
|
|
Process *owner;
|
2010-04-04 16:48:19 -06:00
|
|
|
};
|
|
|
|
|
2011-03-18 01:53:59 -06:00
|
|
|
Module* DFHack::createCreatures(DFContextShared * d)
|
|
|
|
{
|
|
|
|
return new Creatures(d);
|
|
|
|
}
|
|
|
|
|
2010-05-26 04:24:45 -06:00
|
|
|
Creatures::Creatures(DFContextShared* _d)
|
2010-04-02 19:52:46 -06:00
|
|
|
{
|
2010-04-04 16:48:19 -06:00
|
|
|
d = new Private;
|
|
|
|
d->d = _d;
|
2010-11-17 12:50:50 -07:00
|
|
|
d->owner = _d->p;
|
2010-04-04 16:48:19 -06:00
|
|
|
d->Inited = false;
|
|
|
|
d->Started = false;
|
2011-04-11 04:32:53 -06:00
|
|
|
d->IdMapReady = false;
|
2011-02-17 18:51:17 -07:00
|
|
|
d->p_cre = NULL;
|
2010-04-04 16:48:19 -06:00
|
|
|
d->d->InitReadNames(); // throws on error
|
2010-09-02 18:15:09 -06:00
|
|
|
VersionInfo * minfo = d->d->offset_descriptor;
|
|
|
|
OffsetGroup *OG_Creatures = minfo->getGroup("Creatures");
|
|
|
|
OffsetGroup *OG_creature = OG_Creatures->getGroup("creature");
|
|
|
|
OffsetGroup *OG_creature_ex = OG_creature->getGroup("advanced");
|
|
|
|
OffsetGroup *OG_soul = OG_Creatures->getGroup("soul");
|
|
|
|
OffsetGroup * OG_name = minfo->getGroup("name");
|
2011-04-03 13:27:47 -06:00
|
|
|
OffsetGroup * OG_jobs = OG_Creatures->getGroup("job");
|
|
|
|
OffsetGroup * OG_job_mats = OG_jobs->getGroup("material");
|
2011-05-09 04:49:44 -06:00
|
|
|
d->Ft_basic = d->Ft_advanced = d->Ft_jobs = d->Ft_soul = d->Ft_inventory = d->Ft_owned_items = d->Ft_job_materials = false;
|
2010-09-02 18:15:09 -06:00
|
|
|
|
2011-03-18 10:58:48 -06:00
|
|
|
Private::t_offsets &creatures = d->creatures;
|
2010-04-02 19:52:46 -06:00
|
|
|
try
|
|
|
|
{
|
2010-09-02 18:15:09 -06:00
|
|
|
// Creatures
|
|
|
|
creatures.vector = OG_Creatures->getAddress ("vector");
|
|
|
|
d->dwarf_race_index_addr = OG_Creatures->getAddress("current_race");
|
|
|
|
d->dwarf_civ_id_addr = OG_Creatures->getAddress("current_civ");
|
|
|
|
// Creatures/creature
|
|
|
|
creatures.name_offset = OG_creature->getOffset ("name");
|
|
|
|
creatures.custom_profession_offset = OG_creature->getOffset ("custom_profession");
|
|
|
|
creatures.profession_offset = OG_creature->getOffset ("profession");
|
|
|
|
creatures.race_offset = OG_creature->getOffset ("race");
|
|
|
|
creatures.pos_offset = OG_creature->getOffset ("position");
|
|
|
|
creatures.flags1_offset = OG_creature->getOffset ("flags1");
|
|
|
|
creatures.flags2_offset = OG_creature->getOffset ("flags2");
|
|
|
|
creatures.sex_offset = OG_creature->getOffset ("sex");
|
|
|
|
creatures.caste_offset = OG_creature->getOffset ("caste");
|
|
|
|
creatures.id_offset = OG_creature->getOffset ("id");
|
|
|
|
creatures.civ_offset = OG_creature->getOffset ("civ");
|
|
|
|
// name struct
|
|
|
|
creatures.name_firstname_offset = OG_name->getOffset("first");
|
|
|
|
creatures.name_nickname_offset = OG_name->getOffset("nick");
|
|
|
|
creatures.name_words_offset = OG_name->getOffset("second_words");
|
|
|
|
d->Ft_basic = true;
|
|
|
|
try
|
2010-08-29 16:08:17 -06:00
|
|
|
{
|
2010-09-02 18:15:09 -06:00
|
|
|
creatures.pickup_equipment_bit = OG_creature_ex->getOffset("pickup_equipment_bit");
|
|
|
|
creatures.mood_offset = OG_creature_ex->getOffset("mood");
|
|
|
|
// pregnancy
|
|
|
|
// pregnancy_ptr
|
|
|
|
creatures.birth_year_offset = OG_creature_ex->getOffset("birth_year");
|
|
|
|
creatures.birth_time_offset = OG_creature_ex->getOffset("birth_time");
|
|
|
|
creatures.current_job_offset = OG_creature_ex->getOffset("current_job");
|
|
|
|
creatures.mood_skill_offset = OG_creature_ex->getOffset("current_job_skill");
|
|
|
|
creatures.physical_offset = OG_creature_ex->getOffset("physical");
|
|
|
|
creatures.appearance_vector_offset = OG_creature_ex->getOffset("appearance_vector");
|
|
|
|
creatures.artifact_name_offset = OG_creature_ex->getOffset("artifact_name");
|
|
|
|
creatures.labors_offset = OG_creature_ex->getOffset ("labors");
|
|
|
|
creatures.happiness_offset = OG_creature_ex->getOffset ("happiness");
|
|
|
|
d->Ft_advanced = true;
|
2011-04-03 13:27:47 -06:00
|
|
|
}catch(Error::All&){};
|
|
|
|
try
|
|
|
|
{
|
|
|
|
creatures.inventory_offset = OG_creature_ex->getOffset("inventory_vector");
|
|
|
|
d->Ft_inventory = true;
|
2010-09-02 19:01:37 -06:00
|
|
|
}
|
|
|
|
catch(Error::All&){};
|
|
|
|
try
|
2011-05-09 04:49:44 -06:00
|
|
|
{
|
|
|
|
creatures.owned_items_offset = OG_creature_ex->getOffset("owned_items_vector");
|
|
|
|
d->Ft_owned_items = true;
|
|
|
|
}
|
|
|
|
catch(Error::All&){};
|
|
|
|
try
|
2010-09-02 19:01:37 -06:00
|
|
|
{
|
|
|
|
creatures.soul_vector_offset = OG_creature_ex->getOffset("soul_vector");
|
|
|
|
creatures.default_soul_offset = OG_creature_ex->getOffset("current_soul");
|
|
|
|
creatures.soul_mental_offset = OG_soul->getOffset("mental");
|
|
|
|
creatures.soul_skills_vector_offset = OG_soul->getOffset("skills_vector");
|
|
|
|
creatures.soul_traits_offset = OG_soul->getOffset("traits");
|
|
|
|
d->Ft_soul = true;
|
2010-08-29 16:08:17 -06:00
|
|
|
}
|
2010-09-02 18:15:09 -06:00
|
|
|
catch(Error::All&){};
|
2011-04-03 13:27:47 -06:00
|
|
|
try
|
|
|
|
{
|
|
|
|
creatures.job_type_offset = OG_jobs->getOffset("type");
|
|
|
|
creatures.job_id_offset = OG_jobs->getOffset("id");
|
|
|
|
d->Ft_jobs = true;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
creatures.job_materials_vector = OG_jobs->getOffset("materials_vector");
|
|
|
|
creatures.job_material_itemtype_o = OG_job_mats->getOffset("maintype");
|
|
|
|
creatures.job_material_subtype_o = OG_job_mats->getOffset("sectype1");
|
|
|
|
creatures.job_material_subindex_o = OG_job_mats->getOffset("sectype2");
|
|
|
|
creatures.job_material_index_o = OG_job_mats->getOffset("sectype3");
|
|
|
|
creatures.job_material_flags_o = OG_job_mats->getOffset("flags");
|
|
|
|
d->Ft_job_materials = true;
|
|
|
|
}
|
|
|
|
catch(Error::All&){};
|
|
|
|
}
|
|
|
|
catch(Error::All&){};
|
2010-04-02 19:52:46 -06:00
|
|
|
}
|
2010-09-02 18:15:09 -06:00
|
|
|
catch(Error::All&){};
|
|
|
|
d->Inited = true;
|
2010-04-02 19:52:46 -06:00
|
|
|
}
|
|
|
|
|
2010-04-04 16:48:19 -06:00
|
|
|
Creatures::~Creatures()
|
2010-04-02 19:52:46 -06:00
|
|
|
{
|
2010-04-04 16:48:19 -06:00
|
|
|
if(d->Started)
|
|
|
|
Finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::Start( uint32_t &numcreatures )
|
|
|
|
{
|
2011-02-17 18:51:17 -07:00
|
|
|
if(d->Ft_basic)
|
|
|
|
{
|
|
|
|
d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector);
|
|
|
|
d->Started = true;
|
|
|
|
numcreatures = d->p_cre->size();
|
2011-04-11 04:32:53 -06:00
|
|
|
d->IdMapReady = false;
|
2011-02-17 18:51:17 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2010-04-04 16:48:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::Finish()
|
|
|
|
{
|
|
|
|
if(d->p_cre)
|
|
|
|
{
|
|
|
|
delete d->p_cre;
|
|
|
|
d->p_cre = 0;
|
|
|
|
}
|
|
|
|
d->Started = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::ReadCreature (const int32_t index, t_creature & furball)
|
|
|
|
{
|
|
|
|
if(!d->Started) return false;
|
2010-09-02 19:01:37 -06:00
|
|
|
memset(&furball, 0, sizeof(t_creature));
|
2010-04-04 16:48:19 -06:00
|
|
|
// SHM fast path
|
2010-04-18 13:30:02 -06:00
|
|
|
Process * p = d->owner;
|
2010-06-17 17:17:46 -06:00
|
|
|
|
2010-04-02 19:52:46 -06:00
|
|
|
// read pointer from vector at position
|
2011-05-07 19:21:34 -06:00
|
|
|
uint32_t addr_cr = d->p_cre->at (index);
|
|
|
|
furball.origin = addr_cr;
|
2011-03-18 10:58:48 -06:00
|
|
|
Private::t_offsets &offs = d->creatures;
|
2010-06-17 17:17:46 -06:00
|
|
|
|
2010-04-02 19:52:46 -06:00
|
|
|
//read creature from memory
|
2010-09-02 19:01:37 -06:00
|
|
|
if(d->Ft_basic)
|
2010-04-26 05:23:57 -06:00
|
|
|
{
|
2010-09-02 19:01:37 -06:00
|
|
|
// name
|
2011-05-07 19:21:34 -06:00
|
|
|
d->d->readName(furball.name,addr_cr + offs.name_offset);
|
2010-09-02 19:01:37 -06:00
|
|
|
|
|
|
|
// basic stuff
|
2011-05-07 19:21:34 -06:00
|
|
|
p->readDWord (addr_cr + offs.id_offset, furball.id);
|
|
|
|
p->read (addr_cr + offs.pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really
|
|
|
|
p->readDWord (addr_cr + offs.race_offset, furball.race);
|
|
|
|
furball.civ = p->readDWord (addr_cr + offs.civ_offset);
|
|
|
|
p->readByte (addr_cr + offs.sex_offset, furball.sex);
|
|
|
|
p->readWord (addr_cr + offs.caste_offset, furball.caste);
|
|
|
|
p->readDWord (addr_cr + offs.flags1_offset, furball.flags1.whole);
|
|
|
|
p->readDWord (addr_cr + offs.flags2_offset, furball.flags2.whole);
|
2010-09-02 19:01:37 -06:00
|
|
|
// custom profession
|
2011-05-07 19:21:34 -06:00
|
|
|
p->readSTLString(addr_cr + offs.custom_profession_offset, furball.custom_profession, sizeof(furball.custom_profession));
|
2010-09-02 19:01:37 -06:00
|
|
|
// profession
|
2011-05-07 19:21:34 -06:00
|
|
|
furball.profession = p->readByte (addr_cr + offs.profession_offset);
|
2010-04-26 05:23:57 -06:00
|
|
|
}
|
2010-09-02 19:01:37 -06:00
|
|
|
if(d->Ft_advanced)
|
2010-04-26 05:23:57 -06:00
|
|
|
{
|
2010-09-02 19:01:37 -06:00
|
|
|
// happiness
|
2011-05-07 19:21:34 -06:00
|
|
|
p->readDWord (addr_cr + offs.happiness_offset, furball.happiness);
|
2010-09-02 19:01:37 -06:00
|
|
|
|
|
|
|
// physical attributes
|
2011-05-07 19:21:34 -06:00
|
|
|
p->read(addr_cr + offs.physical_offset,
|
2010-09-02 19:01:37 -06:00
|
|
|
sizeof(t_attrib) * NUM_CREATURE_PHYSICAL_ATTRIBUTES,
|
|
|
|
(uint8_t *)&furball.strength);
|
|
|
|
|
|
|
|
// mood stuff
|
2011-05-07 19:21:34 -06:00
|
|
|
furball.mood = (int16_t) p->readWord (addr_cr + offs.mood_offset);
|
|
|
|
furball.mood_skill = p->readWord (addr_cr + offs.mood_skill_offset);
|
|
|
|
d->d->readName(furball.artifact_name, addr_cr + offs.artifact_name_offset);
|
2010-09-02 19:01:37 -06:00
|
|
|
|
|
|
|
// labors
|
2011-05-07 19:21:34 -06:00
|
|
|
p->read (addr_cr + offs.labors_offset, NUM_CREATURE_LABORS, furball.labors);
|
2011-04-03 13:27:47 -06:00
|
|
|
|
2011-05-07 19:21:34 -06:00
|
|
|
furball.birth_year = p->readDWord (addr_cr + offs.birth_year_offset );
|
|
|
|
furball.birth_time = p->readDWord (addr_cr + offs.birth_time_offset );
|
2010-09-02 19:01:37 -06:00
|
|
|
/*
|
|
|
|
* p->readDWord(temp + offs.creature_pregnancy_offset, furball.pregnancy_timer);
|
|
|
|
*/
|
|
|
|
|
|
|
|
// appearance
|
2011-05-07 19:21:34 -06:00
|
|
|
DfVector <uint32_t> app(p, addr_cr + offs.appearance_vector_offset);
|
2010-09-02 19:01:37 -06:00
|
|
|
furball.nbcolors = app.size();
|
|
|
|
if(furball.nbcolors>MAX_COLORS)
|
|
|
|
furball.nbcolors = MAX_COLORS;
|
|
|
|
for(uint32_t i = 0; i < furball.nbcolors; i++)
|
|
|
|
{
|
|
|
|
furball.color[i] = app[i];
|
|
|
|
}
|
2010-04-02 19:52:46 -06:00
|
|
|
|
2010-09-02 19:01:37 -06:00
|
|
|
//likes
|
|
|
|
/*
|
|
|
|
DfVector <uint32_t> likes(d->p, temp + offs.creature_likes_offset);
|
|
|
|
furball.numLikes = likes.getSize();
|
|
|
|
for(uint32_t i = 0;i<furball.numLikes;i++)
|
|
|
|
{
|
|
|
|
uint32_t temp2 = *(uint32_t *) likes[i];
|
|
|
|
p->read(temp2,sizeof(t_like),(uint8_t *) &furball.likes[i]);
|
|
|
|
}*/
|
2010-04-02 19:52:46 -06:00
|
|
|
}
|
2010-09-02 19:01:37 -06:00
|
|
|
if(d->Ft_soul)
|
2010-04-02 19:52:46 -06:00
|
|
|
{
|
2010-09-02 19:01:37 -06:00
|
|
|
/*
|
|
|
|
// enum soul pointer vector
|
|
|
|
DfVector <uint32_t> souls(p,temp + offs.creature_soul_vector_offset);
|
|
|
|
*/
|
2011-05-07 19:21:34 -06:00
|
|
|
uint32_t soul = p->readDWord(addr_cr + offs.default_soul_offset);
|
2010-09-02 19:01:37 -06:00
|
|
|
furball.has_default_soul = false;
|
|
|
|
|
|
|
|
if(soul)
|
|
|
|
{
|
|
|
|
furball.has_default_soul = true;
|
|
|
|
// get first soul's skills
|
|
|
|
DfVector <uint32_t> skills(p, soul + offs.soul_skills_vector_offset);
|
|
|
|
furball.defaultSoul.numSkills = skills.size();
|
2010-04-02 19:52:46 -06:00
|
|
|
|
2010-09-02 19:01:37 -06:00
|
|
|
for (uint32_t i = 0; i < furball.defaultSoul.numSkills;i++)
|
|
|
|
{
|
|
|
|
uint32_t temp2 = skills[i];
|
|
|
|
// a byte: this gives us 256 skills maximum.
|
|
|
|
furball.defaultSoul.skills[i].id = p->readByte (temp2);
|
|
|
|
furball.defaultSoul.skills[i].rating =
|
|
|
|
p->readByte (temp2 + offsetof(t_skill, rating));
|
|
|
|
furball.defaultSoul.skills[i].experience =
|
|
|
|
p->readWord (temp2 + offsetof(t_skill, experience));
|
|
|
|
}
|
2010-06-15 17:55:12 -06:00
|
|
|
|
2010-09-02 19:01:37 -06:00
|
|
|
// mental attributes are part of the soul
|
|
|
|
p->read(soul + offs.soul_mental_offset,
|
|
|
|
sizeof(t_attrib) * NUM_CREATURE_MENTAL_ATTRIBUTES,
|
|
|
|
(uint8_t *)&furball.defaultSoul.analytical_ability);
|
2010-06-15 17:55:12 -06:00
|
|
|
|
2010-09-02 19:01:37 -06:00
|
|
|
// traits as well
|
|
|
|
p->read(soul + offs.soul_traits_offset,
|
|
|
|
sizeof (uint16_t) * NUM_CREATURE_TRAITS,
|
|
|
|
(uint8_t *) &furball.defaultSoul.traits);
|
2010-04-12 19:11:26 -06:00
|
|
|
}
|
2010-04-06 18:46:46 -06:00
|
|
|
}
|
2010-09-02 19:01:37 -06:00
|
|
|
if(d->Ft_jobs)
|
2010-05-05 06:08:18 -06:00
|
|
|
{
|
2011-05-07 19:21:34 -06:00
|
|
|
furball.current_job.occupationPtr = p->readDWord (addr_cr + offs.current_job_offset);
|
2010-09-02 19:01:37 -06:00
|
|
|
if(furball.current_job.occupationPtr)
|
|
|
|
{
|
|
|
|
furball.current_job.active = true;
|
2011-04-03 13:27:47 -06:00
|
|
|
furball.current_job.jobType = p->readByte (furball.current_job.occupationPtr + offs.job_type_offset );
|
2011-04-03 13:43:16 -06:00
|
|
|
furball.current_job.jobId = p->readWord (furball.current_job.occupationPtr + offs.job_id_offset);
|
2010-09-02 19:01:37 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
furball.current_job.active = false;
|
2010-09-02 19:01:37 -06:00
|
|
|
}
|
2010-05-05 06:08:18 -06:00
|
|
|
}
|
2011-05-07 19:21:34 -06:00
|
|
|
else
|
|
|
|
{
|
|
|
|
furball.current_job.active = false;
|
|
|
|
}
|
2010-04-02 19:52:46 -06:00
|
|
|
return true;
|
|
|
|
}
|
2010-04-04 16:48:19 -06:00
|
|
|
|
|
|
|
// returns index of creature actually read or -1 if no creature can be found
|
|
|
|
int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball,
|
|
|
|
const uint16_t x1, const uint16_t y1, const uint16_t z1,
|
|
|
|
const uint16_t x2, const uint16_t y2, const uint16_t z2)
|
|
|
|
{
|
2010-04-18 13:30:02 -06:00
|
|
|
if (!d->Started)
|
|
|
|
return -1;
|
2010-06-17 17:17:46 -06:00
|
|
|
|
2010-04-18 13:30:02 -06:00
|
|
|
Process *p = d->owner;
|
2011-04-03 13:27:47 -06:00
|
|
|
uint16_t coords[3];
|
|
|
|
uint32_t size = d->p_cre->size();
|
|
|
|
while (uint32_t(index) < size)
|
2010-04-04 16:48:19 -06:00
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
// read pointer from vector at position
|
|
|
|
uint32_t temp = d->p_cre->at(index);
|
|
|
|
p->read (temp + d->creatures.pos_offset, 3 * sizeof (uint16_t), (uint8_t *) &coords);
|
|
|
|
if (coords[0] >= x1 && coords[0] < x2)
|
2010-04-04 16:48:19 -06:00
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if (coords[1] >= y1 && coords[1] < y2)
|
2010-04-04 16:48:19 -06:00
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if (coords[2] >= z1 && coords[2] < z2)
|
2010-04-04 16:48:19 -06:00
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
ReadCreature (index, furball);
|
|
|
|
return index;
|
2010-04-04 16:48:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-03 13:27:47 -06:00
|
|
|
index++;
|
2010-04-04 16:48:19 -06:00
|
|
|
}
|
2011-04-03 13:27:47 -06:00
|
|
|
return -1;
|
2010-04-04 16:48:19 -06:00
|
|
|
}
|
|
|
|
|
2011-04-11 04:32:53 -06:00
|
|
|
int32_t Creatures::FindIndexById(int32_t creature_id)
|
|
|
|
{
|
|
|
|
if (!d->Started || !d->Ft_basic)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!d->IdMapReady)
|
|
|
|
{
|
|
|
|
d->IdMap.clear();
|
|
|
|
|
|
|
|
Process * p = d->owner;
|
|
|
|
Private::t_offsets &offs = d->creatures;
|
|
|
|
|
|
|
|
uint32_t size = d->p_cre->size();
|
|
|
|
for (uint32_t index = 0; index < size; index++)
|
|
|
|
{
|
|
|
|
uint32_t temp = d->p_cre->at(index);
|
|
|
|
int32_t id = p->readDWord (temp + offs.id_offset);
|
|
|
|
d->IdMap[id] = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<int32_t,int32_t>::iterator it;
|
|
|
|
it = d->IdMap.find(creature_id);
|
|
|
|
if(it == d->IdMap.end())
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
|
2010-04-06 19:38:22 -06:00
|
|
|
bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS])
|
2010-04-02 19:52:46 -06:00
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_advanced) return false;
|
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
|
|
|
|
p->write(temp + d->creatures.labors_offset, NUM_CREATURE_LABORS, labors);
|
|
|
|
uint32_t pickup_equip;
|
|
|
|
p->readDWord(temp + d->creatures.pickup_equipment_bit, pickup_equip);
|
|
|
|
pickup_equip |= 1u;
|
|
|
|
p->writeDWord(temp + d->creatures.pickup_equipment_bit, pickup_equip);
|
|
|
|
return true;
|
2010-06-14 17:59:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::WriteHappiness(const uint32_t index, const uint32_t happinessValue)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_advanced) return false;
|
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
p->writeDWord (temp + d->creatures.happiness_offset, happinessValue);
|
|
|
|
return true;
|
2010-04-02 19:52:46 -06:00
|
|
|
}
|
2010-04-06 19:38:22 -06:00
|
|
|
|
2010-06-15 10:28:05 -06:00
|
|
|
bool Creatures::WriteFlags(const uint32_t index,
|
2010-06-17 17:17:46 -06:00
|
|
|
const uint32_t flags1,
|
|
|
|
const uint32_t flags2)
|
2010-06-15 10:28:05 -06:00
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_basic) return false;
|
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
p->writeDWord (temp + d->creatures.flags1_offset, flags1);
|
2010-06-19 13:09:16 -06:00
|
|
|
p->writeDWord (temp + d->creatures.flags2_offset, flags2);
|
2010-06-17 17:17:46 -06:00
|
|
|
return true;
|
2010-06-15 10:28:05 -06:00
|
|
|
}
|
|
|
|
|
2010-06-15 17:19:19 -06:00
|
|
|
bool Creatures::WriteSkills(const uint32_t index, const t_soul &soul)
|
2010-06-15 15:23:24 -06:00
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_soul) return false;
|
2010-06-17 17:17:46 -06:00
|
|
|
|
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset);
|
|
|
|
|
|
|
|
if(!souloff)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-06-15 15:23:24 -06:00
|
|
|
DfVector<uint32_t> skills(p, souloff + d->creatures.soul_skills_vector_offset);
|
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
for (uint32_t i=0; i<soul.numSkills; i++)
|
2010-06-15 15:23:24 -06:00
|
|
|
{
|
|
|
|
uint32_t temp2 = skills[i];
|
2010-06-17 17:17:46 -06:00
|
|
|
p->writeByte(temp2 + offsetof(t_skill, rating), soul.skills[i].rating);
|
|
|
|
p->writeWord(temp2 + offsetof(t_skill, experience), soul.skills[i].experience);
|
2010-06-15 15:23:24 -06:00
|
|
|
}
|
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
return true;
|
2010-06-15 15:23:24 -06:00
|
|
|
}
|
|
|
|
|
2010-06-15 17:19:19 -06:00
|
|
|
bool Creatures::WriteAttributes(const uint32_t index, const t_creature &creature)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_advanced || !d->Ft_soul) return false;
|
2010-06-15 17:19:19 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset);
|
2010-06-15 17:19:19 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
if(!souloff)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-15 17:19:19 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
// physical attributes
|
|
|
|
p->write(temp + d->creatures.physical_offset,
|
|
|
|
sizeof(t_attrib) * NUM_CREATURE_PHYSICAL_ATTRIBUTES,
|
|
|
|
(uint8_t *)&creature.strength);
|
2010-06-15 17:19:19 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
// mental attributes are part of the soul
|
|
|
|
p->write(souloff + d->creatures.soul_mental_offset,
|
|
|
|
sizeof(t_attrib) * NUM_CREATURE_MENTAL_ATTRIBUTES,
|
|
|
|
(uint8_t *)&creature.defaultSoul.analytical_ability);
|
2010-06-15 17:19:19 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
return true;
|
2010-06-15 17:19:19 -06:00
|
|
|
}
|
|
|
|
|
2010-06-16 13:47:05 -06:00
|
|
|
bool Creatures::WriteSex(const uint32_t index, const uint8_t sex)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_basic ) return false;
|
2010-06-16 13:47:05 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
p->writeByte (temp + d->creatures.sex_offset, sex);
|
2010-11-17 12:50:50 -07:00
|
|
|
|
|
|
|
return true;
|
2010-06-16 13:47:05 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::WriteTraits(const uint32_t index, const t_soul &soul)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_soul) return false;
|
2010-06-17 17:17:46 -06:00
|
|
|
|
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset);
|
2010-06-16 13:47:05 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
if(!souloff)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-16 13:47:05 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
p->write(souloff + d->creatures.soul_traits_offset,
|
|
|
|
sizeof (uint16_t) * NUM_CREATURE_TRAITS,
|
|
|
|
(uint8_t *) &soul.traits);
|
2010-06-16 13:47:05 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
return true;
|
2010-06-16 13:47:05 -06:00
|
|
|
}
|
|
|
|
|
2010-06-17 16:18:01 -06:00
|
|
|
bool Creatures::WriteMood(const uint32_t index, const uint16_t mood)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_advanced) return false;
|
2010-06-17 16:18:01 -06:00
|
|
|
|
2010-06-17 17:17:46 -06:00
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
p->writeWord(temp + d->creatures.mood_offset, mood);
|
|
|
|
return true;
|
2010-06-17 16:18:01 -06:00
|
|
|
}
|
|
|
|
|
2010-06-22 10:21:09 -06:00
|
|
|
bool Creatures::WriteMoodSkill(const uint32_t index, const uint16_t moodSkill)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_advanced) return false;
|
2010-06-22 10:21:09 -06:00
|
|
|
|
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
p->writeWord(temp + d->creatures.mood_skill_offset, moodSkill);
|
|
|
|
return true;
|
2010-08-09 12:28:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::WriteJob(const t_creature * furball, std::vector<t_material> const& mat)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Inited || !d->Ft_job_materials) return false;
|
2010-08-09 12:28:35 -06:00
|
|
|
if(!furball->current_job.active) return false;
|
2011-04-03 13:27:47 -06:00
|
|
|
|
|
|
|
unsigned int i;
|
2010-08-09 12:28:35 -06:00
|
|
|
Process * p = d->owner;
|
2011-04-03 13:27:47 -06:00
|
|
|
Private::t_offsets & off = d->creatures;
|
|
|
|
DfVector <uint32_t> cmats(p, furball->current_job.occupationPtr + off.job_materials_vector);
|
2010-08-09 12:28:35 -06:00
|
|
|
|
|
|
|
for(i=0;i<cmats.size();i++)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
p->writeWord(cmats[i] + off.job_material_itemtype_o, mat[i].itemType);
|
|
|
|
p->writeWord(cmats[i] + off.job_material_subtype_o, mat[i].subType);
|
|
|
|
p->writeWord(cmats[i] + off.job_material_subindex_o, mat[i].subIndex);
|
|
|
|
p->writeDWord(cmats[i] + off.job_material_index_o, mat[i].index);
|
|
|
|
p->writeDWord(cmats[i] + off.job_material_flags_o, mat[i].flags);
|
2010-08-09 12:28:35 -06:00
|
|
|
}
|
|
|
|
return true;
|
2010-06-22 10:21:09 -06:00
|
|
|
}
|
|
|
|
|
2010-06-22 11:27:27 -06:00
|
|
|
bool Creatures::WritePos(const uint32_t index, const t_creature &creature)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started) return false;
|
2010-06-22 11:27:27 -06:00
|
|
|
|
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
2011-04-03 13:27:47 -06:00
|
|
|
p->write (temp + d->creatures.pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (creature.x));
|
|
|
|
return true;
|
2010-06-22 11:27:27 -06:00
|
|
|
}
|
|
|
|
|
2010-06-22 20:32:33 -06:00
|
|
|
bool Creatures::WriteCiv(const uint32_t index, const int32_t civ)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started) return false;
|
2010-06-22 20:32:33 -06:00
|
|
|
|
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
Process * p = d->owner;
|
|
|
|
p->writeDWord(temp + d->creatures.civ_offset, civ);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-04-16 05:28:07 -06:00
|
|
|
uint32_t Creatures::GetDwarfRaceIndex()
|
|
|
|
{
|
|
|
|
if(!d->Inited) return 0;
|
2010-04-18 13:30:02 -06:00
|
|
|
Process * p = d->owner;
|
|
|
|
return p->readDWord(d->dwarf_race_index_addr);
|
2010-04-16 05:28:07 -06:00
|
|
|
}
|
|
|
|
|
2010-04-19 06:36:21 -06:00
|
|
|
int32_t Creatures::GetDwarfCivId()
|
|
|
|
{
|
|
|
|
if(!d->Inited) return -1;
|
|
|
|
Process * p = d->owner;
|
|
|
|
return p->readDWord(d->dwarf_civ_id_addr);
|
|
|
|
}
|
2010-04-04 04:29:56 -06:00
|
|
|
/*
|
2010-04-18 13:30:02 -06:00
|
|
|
bool Creatures::getCurrentCursorCreature(uint32_t & creature_index)
|
2010-04-02 19:52:46 -06:00
|
|
|
{
|
|
|
|
if(!d->cursorWindowInited) return false;
|
2010-04-18 13:30:02 -06:00
|
|
|
Process * p = d->owner;
|
|
|
|
creature_index = p->readDWord(d->current_cursor_creature_offset);
|
2010-04-02 19:52:46 -06:00
|
|
|
return true;
|
|
|
|
}
|
2010-04-19 06:36:21 -06:00
|
|
|
*/
|
2010-04-26 05:23:57 -06:00
|
|
|
|
|
|
|
bool Creatures::ReadJob(const t_creature * furball, vector<t_material> & mat)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Inited || !d->Ft_job_materials) return false;
|
2010-04-26 05:23:57 -06:00
|
|
|
if(!furball->current_job.active) return false;
|
|
|
|
|
2011-04-03 13:27:47 -06:00
|
|
|
Process * p = d->owner;
|
|
|
|
Private::t_offsets & off = d->creatures;
|
|
|
|
DfVector <uint32_t> cmats(p, furball->current_job.occupationPtr + off.job_materials_vector);
|
2010-04-26 05:23:57 -06:00
|
|
|
mat.resize(cmats.size());
|
|
|
|
for(i=0;i<cmats.size();i++)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
mat[i].itemType = p->readWord(cmats[i] + off.job_material_itemtype_o);
|
|
|
|
mat[i].subType = p->readWord(cmats[i] + off.job_material_subtype_o);
|
|
|
|
mat[i].subIndex = p->readWord(cmats[i] + off.job_material_subindex_o);
|
|
|
|
mat[i].index = p->readDWord(cmats[i] + off.job_material_index_o);
|
|
|
|
mat[i].flags = p->readDWord(cmats[i] + off.job_material_flags_o);
|
2010-04-26 05:23:57 -06:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2010-08-17 07:21:54 -06:00
|
|
|
|
|
|
|
bool Creatures::ReadInventoryIdx(const uint32_t index, std::vector<uint32_t> & item)
|
|
|
|
{
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_inventory) return false;
|
2010-08-17 07:21:54 -06:00
|
|
|
uint32_t temp = d->p_cre->at (index);
|
2010-08-27 20:39:03 -06:00
|
|
|
return this->ReadInventoryPtr(temp, item);
|
2010-08-17 07:21:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::ReadInventoryPtr(const uint32_t temp, std::vector<uint32_t> & item)
|
|
|
|
{
|
2010-08-27 20:39:03 -06:00
|
|
|
unsigned int i;
|
2011-04-03 13:27:47 -06:00
|
|
|
if(!d->Started || !d->Ft_inventory) return false;
|
2010-08-17 07:21:54 -06:00
|
|
|
Process * p = d->owner;
|
|
|
|
|
2010-08-27 20:39:03 -06:00
|
|
|
DfVector <uint32_t> citem(p, temp + d->creatures.inventory_offset);
|
|
|
|
if(citem.size() == 0)
|
|
|
|
return false;
|
|
|
|
item.resize(citem.size());
|
2010-08-17 07:21:54 -06:00
|
|
|
for(i=0;i<citem.size();i++)
|
2010-08-27 20:39:03 -06:00
|
|
|
item[i] = p->readDWord(citem[i]);
|
2010-08-17 07:21:54 -06:00
|
|
|
return true;
|
2010-08-27 20:39:03 -06:00
|
|
|
}
|
2011-04-13 10:36:10 -06:00
|
|
|
|
2011-05-09 04:49:44 -06:00
|
|
|
bool Creatures::ReadOwnedItemsIdx(const uint32_t index, std::vector<int32_t> & item)
|
|
|
|
{
|
|
|
|
if(!d->Started || !d->Ft_owned_items) return false;
|
|
|
|
uint32_t temp = d->p_cre->at (index);
|
|
|
|
return this->ReadOwnedItemsPtr(temp, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Creatures::ReadOwnedItemsPtr(const uint32_t temp, std::vector<int32_t> & item)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
if(!d->Started || !d->Ft_owned_items) return false;
|
|
|
|
Process * p = d->owner;
|
|
|
|
|
|
|
|
DfVector <int32_t> citem(p, temp + d->creatures.owned_items_offset);
|
|
|
|
if(citem.size() == 0)
|
|
|
|
return false;
|
|
|
|
item.resize(citem.size());
|
|
|
|
for(i=0;i<citem.size();i++)
|
|
|
|
item[i] = citem[i];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-04-13 10:36:10 -06:00
|
|
|
void Creatures::CopyNameTo(t_creature &creature, uint32_t address)
|
|
|
|
{
|
|
|
|
Private::t_offsets &offs = d->creatures;
|
|
|
|
|
|
|
|
if(d->Ft_basic)
|
|
|
|
d->d->copyName(creature.origin + offs.name_offset, address);
|
|
|
|
}
|
|
|
|
|