EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
InventoryDB.cpp
Go to the documentation of this file.
1 /*
2  ------------------------------------------------------------------------------------
3  LICENSE:
4  ------------------------------------------------------------------------------------
5  This file is part of EVEmu: EVE Online Server Emulator
6  Copyright 2006 - 2021 The EVEmu Team
7  For the latest information visit https://evemu.dev
8  ------------------------------------------------------------------------------------
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License along with
19  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20  Place - Suite 330, Boston, MA 02111-1307, USA, or go to
21  http://www.gnu.org/copyleft/lesser.txt.
22  ------------------------------------------------------------------------------------
23  Author: Zhur
24  Updates: Allan
25 */
26 
29 #include "eve-server.h"
30 
31 #include "Client.h"
32 #include "PyCallable.h"
33 #include "character/Character.h"
34 #include "inventory/ItemType.h"
36 #include "ship/Ship.h"
37 #include "station/Station.h"
38 #include "system/Asteroid.h"
39 #include "system/SolarSystem.h"
40 
42  DBQueryResult res;
43 
44  if(!sDatabase.RunQuery(res,
45  "SELECT"
46  " bloodlineName,"
47  " raceID,"
48  " description,"
49  " maleDescription,"
50  " femaleDescription,"
51  " corporationID,"
52  " perception,"
53  " willpower,"
54  " charisma,"
55  " memory,"
56  " intelligence,"
57  " shortDescription,"
58  " shortMaleDescription,"
59  " shortFemaleDescription "
60  " FROM chrBloodlines "
61  " WHERE bloodlineID = %u",
62  bloodlineID))
63  {
64  codelog(DATABASE__ERROR, "Failed to query bloodline %u: %s.", bloodlineID, res.error.c_str());
65  return false;
66  }
67 
68  DBResultRow row;
69  if(!res.GetRow(row)) {
70  _log(DATABASE__MESSAGE, "No data found for bloodline %u.", bloodlineID);
71  return false;
72  }
73 
74  into.bloodlineName = row.GetText(0);
75  into.race = row.GetUInt(1);
76  into.description = row.GetText(2);
77  into.maleDescription = row.GetText(3);
78  into.femaleDescription = row.GetText(4);
79  into.corporationID = row.GetUInt(5);
80  into.perception = row.GetUInt(6);
81  into.willpower = row.GetUInt(7);
82  into.charisma = row.GetUInt(8);
83  into.memory = row.GetUInt(9);
84  into.intelligence = row.GetUInt(10);
85  into.shortDescription = row.GetText(11);
86  into.shortMaleDescription = row.GetText(12);
87  into.shortFemaleDescription = row.GetText(13);
88  return true;
89 }
90 
91 bool InventoryDB::GetCharacterTypeByBloodline(uint8 bloodlineID, uint16& characterTypeID) {
92  DBQueryResult res;
93  if(!sDatabase.RunQuery(res, "SELECT typeID FROM bloodlineTypes WHERE bloodlineID = %u", bloodlineID)) {
94  codelog(DATABASE__ERROR, "Failed to query bloodline %u: %s.", bloodlineID, res.error.c_str());
95  return false;
96  }
97 
98  DBResultRow row;
99  if(!res.GetRow(row)) {
100  _log(DATABASE__MESSAGE, "No data for bloodline %u.", bloodlineID);
101  return false;
102  }
103 
104  characterTypeID = row.GetUInt(0);
105 
106  return true;
107 }
108 
109 bool InventoryDB::GetBloodlineByCharacterType(uint16 characterTypeID, uint8 &bloodlineID) {
110  DBQueryResult res;
111  if(!sDatabase.RunQuery(res, "SELECT bloodlineID FROM bloodlineTypes WHERE typeID = %u", characterTypeID)) {
112  codelog(DATABASE__ERROR, "Failed to query character type %u: %s.", characterTypeID, res.error.c_str());
113  return false;
114  }
115 
116  DBResultRow row;
117  if(!res.GetRow(row)) {
118  _log(DATABASE__MESSAGE, "No data for character type %u.", characterTypeID);
119  return false;
120  }
121 
122  bloodlineID = row.GetUInt(0);
123 
124  return true;
125 }
126 
127 bool InventoryDB::GetCharacterType(uint16 characterTypeID, uint8 &bloodlineID, CharacterTypeData &into) {
128  if(!GetBloodlineByCharacterType(characterTypeID, bloodlineID))
129  return false;
130  return GetCharacterType(bloodlineID, into);
131 }
132 
133 bool InventoryDB::GetCharacterTypeByBloodline(uint8 bloodlineID, uint16 &characterTypeID, CharacterTypeData &into) {
134  if(!GetCharacterTypeByBloodline(bloodlineID, characterTypeID))
135  return false;
136  return GetCharacterType(bloodlineID, into);
137 }
138 
139 /* this is only called by Inventory::LoadContents()
140  * it is optimized for specific calling objects, to avoid multiple db hits while loading,
141  * and to load only things needed for this object at the time of the call.
142  */
143 bool InventoryDB::GetItemContents(OwnerData &od, std::vector<uint32> &into) {
144  std::stringstream query;
145  query << "SELECT itemID FROM entity WHERE locationID = ";
146  query << od.locID;
147 
148  if (sDataMgr.IsSolarSystem(od.locID)) {
149  query << " AND ownerID = " << od.ownerID;
150  } else if (sDataMgr.IsStation(od.locID)) {
151  if (od.ownerID == 1) {
152  /* this will get agents in station */
153  query << " AND ownerID < " << maxNPCItem;
154  query << " AND itemID < " << maxNPCItem;
155  } else {
156  if (IsPlayerCorp(od.corpID)) {
157  // check for items owned by corp in players cargo/hangar
158  query << " AND ((ownerID = " << od.ownerID << ") OR (ownerID = " << od.corpID << "))";
159  } else {
160  query << " AND ownerID = " << od.ownerID;
161  }
162  }
163  } else if (IsCharacterID(od.locID)) {
164  if (od.ownerID == 1) {
165  // not sure what to do here....
166  } else if (IsPlayerCorp(od.corpID)) {
167  // check for items owned by corp in players cargo/hangar...this *should* work for cap ships' cargo, also
168  query << " AND ((ownerID = " << od.ownerID << ") OR (ownerID = " << od.corpID << "))";
169  } else {
170  query << " AND ownerID = " << od.ownerID;
171  }
172  } else if (IsOfficeID(od.locID)) {
173  // may not need this, as location is officeID, but items MAY be owned by players in corp hangar.
174  //query << " AND ownerID = " << od.ownerID;
175  }
176 
177  query << " ORDER BY itemID";
178 
179  DBQueryResult res;
180  if(!sDatabase.RunQuery(res,query.str().c_str() )) {
181  codelog(DATABASE__ERROR, "Error in GetItemContents query for locationID %u: %s", od.locID, res.error.c_str());
182  return false;
183  }
184 
185  _log(DATABASE__RESULTS, "GetItemContents: '%s' returned %u items", query.str().c_str(), res.GetRowCount());
186  DBResultRow row;
187  while( res.GetRow( row ) )
188  into.push_back( row.GetUInt( 0 ) );
189 
190  return true;
191 }
192 
193 /* not used? */
194 bool InventoryDB::GetItemContents(uint32 itemID, EVEItemFlags flag, std::vector<uint32> &into)
195 {
196  DBQueryResult res;
197 
198  if( !sDatabase.RunQuery( res,
199  "SELECT "
200  " itemID"
201  " FROM entity "
202  " WHERE locationID=%u"
203  " AND flag=%d",
204  itemID, (int)flag ) )
205  {
206  codelog(DATABASE__ERROR, "Error in GetItemContents query for item %u: %s", itemID, res.error.c_str());
207  return false;
208  }
209 
210  _log(DATABASE__RESULTS, "GetItemContents for item %u returned %u items", itemID, res.GetRowCount());
211  DBResultRow row;
212  while( res.GetRow( row ) )
213  into.push_back( row.GetUInt( 0 ) );
214 
215  return true;
216 }
217 
218 /* not used? */
219 bool InventoryDB::GetItemContents(uint32 itemID, EVEItemFlags flag, uint32 ownerID, std::vector<uint32> &into)
220 {
221  DBQueryResult res;
222 
223  if( !sDatabase.RunQuery( res,
224  "SELECT "
225  " itemID"
226  " FROM entity "
227  " WHERE locationID=%u"
228  " AND flag=%d"
229  " AND ownerID=%u",
230  itemID, (int)flag, ownerID ) )
231  {
232  codelog(DATABASE__ERROR, "Error in GetItemContents query for item %u with flag %u: %s", itemID, (int)flag, res.error.c_str());
233  return false;
234  }
235 
236  _log(DATABASE__RESULTS, "GetItemContents for item %u with flag %u returned %u items", itemID, flag, res.GetRowCount());
237  DBResultRow row;
238  while( res.GetRow( row ) )
239  into.push_back( row.GetUInt( 0 ) );
240 
241  return true;
242 }
243 
245 {
246  DBerror err;
247  sDatabase.RunQuery(err, "DELETE FROM entity WHERE customInfo LIKE '%Position Test%'"); // 90.63s on main, 0.037s on dev
248  //sDatabase.RunQuery(err, "DELETE FROM entity WHERE itemName LIKE '%Bubble%'"); // 66.75s on main, 0.036s on dev
249 }
250 
252  DBQueryResult res;
253 
254  if (IsAgent(characterID)) {
255  if(!sDatabase.RunQuery(res,
256  "SELECT"
257  " 0 as accountID,"
258  " title,"
259  " description,"
260  " gender,"
261  " bounty,"
262  " 0 as balance,"
263  " 0 as aurBalance,"
264  " securityRating,"
265  " 0 as logonMinutes,"
266  " stationID,"
267  " solarSystemID,"
268  " constellationID,"
269  " regionID,"
270  " ancestryID,"
271  " 0 AS bloodlineID,"
272  " 0 AS raceID,"
273  " careerID,"
274  " schoolID,"
275  " careerSpecialityID,"
276  " createDateTime,"
277  " 0 as shipID," // update this when agents are in space
278  " 0 as capsuleID,"
279  " flag,"
280  " name,"
281  " 0 AS skillPoints,"
282  " typeID"
283  " FROM chrNPCCharacters AS chr"
284  " WHERE characterID = %u", characterID)) {
285  codelog(DATABASE__ERROR, "Error in GetCharacter query: %s", res.error.c_str());
286  return false;
287  }
288  } else {
289  if(!sDatabase.RunQuery(res,
290  "SELECT"
291  " accountID,"
292  " title,"
293  " description,"
294  " gender,"
295  " bounty,"
296  " balance,"
297  " aurBalance,"
298  " securityRating,"
299  " logonMinutes,"
300  " stationID,"
301  " solarSystemID,"
302  " constellationID,"
303  " regionID,"
304  " ancestryID,"
305  " bloodlineID,"
306  " raceID,"
307  " careerID,"
308  " schoolID,"
309  " careerSpecialityID,"
310  " createDateTime,"
311  " shipID,"
312  " capsuleID,"
313  " flag,"
314  " characterName,"
315  " skillPoints,"
316  " typeID"
317  " FROM chrCharacters"
318  " WHERE characterID = %u", characterID))
319  {
320  codelog(DATABASE__ERROR, "Error in GetCharacter query: %s", res.error.c_str());
321  return false;
322  }
323  }
324 
325  DBResultRow row;
326  if(!res.GetRow(row)) {
327  _log(DATABASE__MESSAGE, "No data found for character %u.", characterID);
328  return false;
329  }
330 
331  into.accountID = row.IsNull( 0 ) ? 0 : row.GetUInt( 0 );
332  into.title = row.GetText( 1 );
333  into.description = row.GetText( 2 );
334  into.gender = row.GetInt( 3 ) ? true : false;
335  into.bounty = row.GetDouble( 4 );
336  into.balance = row.GetDouble( 5 );
337  into.aurBalance = row.GetDouble( 6 );
338  into.securityRating = row.GetDouble( 7 );
339  into.logonMinutes = row.GetUInt( 8 );
340  into.stationID = row.GetUInt( 9 );
341  into.solarSystemID = row.GetUInt( 10 );
342  into.locationID = (into.stationID == 0 ? into.solarSystemID : into.stationID);
343  into.constellationID = row.GetUInt( 11 );
344  into.regionID = row.GetUInt( 12 );
345  into.ancestryID = row.GetUInt( 13 );
346  into.bloodlineID = row.GetUInt( 14 );
347  into.raceID = row.GetUInt( 15 );
348  into.careerID =row.GetUInt( 16 );
349  into.schoolID = row.GetUInt( 17 );
350  into.careerSpecialityID = row.GetUInt( 18 );
351  into.createDateTime = row.GetInt64( 19 );
352  into.shipID = row.GetUInt( 20 );
353  into.capsuleID = row.GetUInt( 21 );
354  into.flag = row.GetUInt(22);
355  into.name = row.GetText(23);
356  into.skillPoints = row.GetUInt(24);
357  into.typeID = row.GetUInt(25);
358 
359  return true;
360 }
361 
362 bool InventoryDB::GetCorpData(uint32 characterID, CorpData &into) {
363  DBQueryResult res;
364  DBResultRow row;
365 
366  if (IsAgent(characterID)) {
367  into.corpAccountKey = 1001;
368 
369  if (!sDatabase.RunQuery(res,
370  "SELECT corporationID, locationID"
371  " FROM agtAgents"
372  " WHERE agentID = %u",
373  characterID))
374  {
375  codelog(DATABASE__ERROR, "Failed to query corp member info of character %u: %s.", characterID, res.error.c_str());
376  return false;
377  }
378 
379  if (!res.GetRow(row)) {
380  _log(DATABASE__MESSAGE, "No corp member info found for character %u.", characterID);
381  return false;
382  }
383  into.corporationID = row.GetInt(0);
384  into.baseID = row.GetInt(1);
385  } else {
386  if (!sDatabase.RunQuery(res,
387  "SELECT"
388  " startDateTime,"
389  " corporationID,"
390  " corpAccountKey,"
391  " corpRole,"
392  " rolesAtAll,"
393  " rolesAtBase,"
394  " rolesAtHQ,"
395  " rolesAtOther,"
396  " grantableRoles,"
397  " grantableRolesAtBase,"
398  " grantableRolesAtHQ,"
399  " grantableRolesAtOther,"
400  " baseID"
401  " FROM chrCharacters"
402  " WHERE characterID = %u",
403  characterID))
404  {
405  codelog(DATABASE__ERROR, "Failed to query corp member info of character %u: %s.", characterID, res.error.c_str());
406  return false;
407  }
408  if (!res.GetRow(row)) {
409  _log(DATABASE__MESSAGE, "No corp member info found for character %u.", characterID);
410  return false;
411  }
412 
413  into.startDateTime = row.GetInt64(0);
414  into.corporationID = row.GetInt(1);
415  into.corpAccountKey = row.GetInt(2);
416  into.corpRole = row.GetInt64(3);
417  into.rolesAtAll = row.GetInt64(4);
418  into.rolesAtBase = row.GetInt64(5);
419  into.rolesAtHQ = row.GetInt64(6);
420  into.rolesAtOther = row.GetInt64(7);
421  into.grantableRoles = row.GetInt64(8);
422  into.grantableRolesAtBase = row.GetInt64(9);
423  into.grantableRolesAtHQ = row.GetInt64(10);
424  into.grantableRolesAtOther = row.GetInt64(11);
425  into.baseID = row.GetInt(12);
426  }
427 
428  if(!sDatabase.RunQuery(res,
429  "SELECT"
430  " taxRate,"
431  " stationID,"
432  " allianceID,"
433  " warFactionID,"
434  " corporationName,"
435  " tickerName"
436  " FROM crpCorporation"
437  " WHERE corporationID = %u", into.corporationID))
438  {
439  codelog(DATABASE__ERROR, "Failed to query HQ of character's %u corporation %u: %s.", characterID, into.corporationID, res.error.c_str());
440  return false;
441  }
442 
443  if(!res.GetRow(row)) {
444  _log(DATABASE__MESSAGE, "No HQ found for character's %u corporation.", characterID);
445  return false;
446  }
447 
448  into.taxRate = row.GetDouble(0);
449  into.corpHQ = (row.IsNull(1) ? 0 : row.GetUInt(1));
450  into.allianceID = (row.IsNull(2) ? 0 : row.GetUInt(2));
451  into.warFactionID = (row.IsNull(3) ? 0 : row.GetUInt(3));
452  into.name = row.GetText(4);
453  into.ticker = row.GetText(5);
454 
455  return true;
456 }
457 
459  DBQueryResult res;
460 
461  if( IsStaticMapItem(celestialID)) {
462  // This Celestial object is a static celestial, so get its data from the 'mapDenormalize' table:
463  if(!sDatabase.RunQuery(res,
464  "SELECT"
465  " security, radius, celestialIndex, orbitIndex"
466  " FROM mapDenormalize"
467  " WHERE itemID = %u",
468  celestialID))
469  {
470  codelog(DATABASE__ERROR, "Failed to query celestial object %u: %s.", celestialID, res.error.c_str());
471  return false;
472  }
473 
474  DBResultRow row;
475  if(!res.GetRow(row)) {
476  _log(DATABASE__MESSAGE, "Static Celestial object %u not found.", celestialID);
477  return false;
478  }
479 
480  into.security = (row.IsNull(0) ? 0 : row.GetDouble(0));
481  into.radius = row.GetDouble(1);
482  into.celestialIndex = (row.IsNull(2) ? 0 : row.GetUInt(2));
483  into.orbitIndex = (row.IsNull(3) ? 0 : row.GetUInt(3));
484  } else {
485  // Quite possibly, this Celestial object is a dynamic one, so try to get its data from the 'entity' table,
486  // and if it's not there either, then flag an error.
487  if(!sDatabase.RunQuery(res,
488  "SELECT"
489  " entity.itemID, "
490  " invTypes.radius "
491  " FROM entity "
492  " LEFT JOIN invTypes USING (typeID)"
493  " WHERE entity.itemID = %u",
494  celestialID))
495  {
496  codelog(DATABASE__ERROR, "Failed to query celestial object %u: %s.", celestialID, res.error.c_str());
497  return false;
498  }
499 
500  DBResultRow row;
501  if(!res.GetRow(row)) {
502  _log(DATABASE__MESSAGE, "Dynamic Celestial object %u not found.", celestialID);
503  return false;
504  }
505 
506  into.security = 1.0;
507  into.radius = (row.IsNull(1) ? 1 : row.GetDouble(1));
508  into.celestialIndex = 0;
509  into.orbitIndex = 0;
510  }
511 
512  return true;
513 }
514 
516  DBQueryResult res;
517 
518  if(!sDatabase.RunQuery(res,
519  "SELECT"
520  " xMin, yMin, zMin,"
521  " xMax, yMax, zMax,"
522  " luminosity,"
523  " border, fringe, corridor, hub, international, regional, constellation,"
524  " security, factionID, radius, sunTypeID, securityClass"
525  " FROM mapSolarSystems"
526  " WHERE solarSystemID=%u", solarSystemID))
527  {
528  codelog(DATABASE__ERROR, "Error in GetSolarSystem query for system %u: %s.", solarSystemID, res.error.c_str());
529  return false;
530  }
531 
532  DBResultRow row;
533  if(!res.GetRow(row)) {
534  _log(DATABASE__MESSAGE, "No data found for solar system %u.", solarSystemID);
535  return false;
536  }
537 
538  into.minPosition = GPoint(row.GetDouble(0), row.GetDouble(1), row.GetDouble(2));
539  into.maxPosition = GPoint(row.GetDouble(3), row.GetDouble(4), row.GetDouble(5));
540  into.luminosity = row.GetDouble(6);
541 
542  into.border = row.GetBool(7);
543  into.fringe = row.GetBool(8);
544  into.corridor = row.GetBool(9);
545  into.hub = row.GetBool(10);
546  into.international = row.GetBool(11);
547  into.regional = row.GetBool(12);
548  into.constellation = row.GetBool(13);
549 
550  into.security = row.GetDouble(14);
551  into.factionID = (row.IsNull(15) ? 0 : row.GetUInt(15));
552  into.radius = row.GetDouble(16);
553  into.sunTypeID = row.GetUInt(17);
554  into.securityClass = (row.IsNull(18) ? (std::string("")) : row.GetText(18));
555 
556  return true;
557 }
std::string bloodlineName
Definition: Character.h:62
unsigned __int8 uint8
Definition: eve-compat.h:46
uint32 locID
#define sDatabase
Definition: dbcore.h:199
const char * GetText(uint32 index) const
Definition: dbcore.h:104
static bool GetCharacterTypeByBloodline(uint8 bloodlineID, uint16 &characterTypeID)
Definition: InventoryDB.cpp:91
#define _log(type, fmt,...)
Definition: logsys.h:124
int64 grantableRolesAtHQ
#define maxNPCItem
Definition: EVE_Defines.h:139
uint8 intelligence
Definition: Character.h:73
uint32 corpHQ
int32 GetInt(uint32 index) const
Definition: dbcore.cpp:635
bool GetCelestialObject(uint32 celestialID, CelestialObjectData &into)
double luminosity
Definition: SolarSystem.h:59
std::string shortDescription
Definition: Character.h:75
int64 startDateTime
uint32 GetUInt(uint32 index) const
Definition: dbcore.cpp:658
bool GetCharacterData(uint32 characterID, CharacterData &into)
double GetDouble(uint32 index) const
Definition: dbcore.cpp:693
int64 rolesAtHQ
#define IsAgent(itemID)
Definition: EVE_Defines.h:247
int64 rolesAtBase
EVEItemFlags
Definition: EVE_Flags.h:13
std::string femaleDescription
Definition: Character.h:66
GPoint maxPosition
Definition: SolarSystem.h:58
uint32 skillPoints
GPoint minPosition
Definition: SolarSystem.h:57
int64 rolesAtOther
bool GetCorpData(uint32 characterID, CorpData &into)
int64 createDateTime
bool GetRow(DBResultRow &into)
Definition: dbcore.cpp:552
bool GetBool(uint32 index) const
Definition: dbcore.cpp:647
float taxRate
Definition: gpoint.h:33
std::string name
std::string description
Definition: Character.h:64
uint32 corpID
bool GetItemContents(OwnerData &od, std::vector< uint32 > &into)
const char * c_str() const
Definition: dbcore.h:48
#define codelog(type, fmt,...)
Definition: logsys.h:128
uint32 solarSystemID
std::string description
int64 rolesAtAll
static void DeleteTrackingCans()
float securityRating
int32 allianceID
bool GetSolarSystem(uint32 solarSystemID, SolarSystemData &into)
uint32 corporationID
Definition: Character.h:67
std::string maleDescription
Definition: Character.h:65
bool IsNull(uint32 index) const
Definition: dbcore.h:102
uint32 ownerID
#define IsPlayerCorp(itemID)
Definition: EVE_Defines.h:241
uint32 constellationID
int64 corpRole
uint32 factionID
Definition: SolarSystem.h:71
#define IsCharacterID(itemID)
Definition: EVE_Defines.h:206
unsigned __int32 uint32
Definition: eve-compat.h:50
uint32 baseID
uint32 logonMinutes
uint32 corporationID
#define IsOfficeID(itemID)
Definition: EVE_Defines.h:253
DBerror error
Definition: dbcore.h:69
int16 corpAccountKey
std::string securityClass
Definition: SolarSystem.h:74
int32 warFactionID
#define IsStaticMapItem(itemID)
Definition: EVE_Defines.h:270
typeID Spawn an NPC with the specified type text Search for items matching the specified query() type()() itemID() copy() materialLevel()() itemID(attributeID)-Retrieves attribute value." ) COMMAND( setattr
size_t GetRowCount()
Definition: dbcore.h:72
uint32 sunTypeID
Definition: SolarSystem.h:73
int64 grantableRoles
std::string title
int64 grantableRolesAtBase
int64 GetInt64(uint32 index) const
Definition: dbcore.cpp:670
int64 grantableRolesAtOther
bool GetCharacterType(uint8 bloodlineID, CharacterTypeData &into)
Definition: InventoryDB.cpp:41
unsigned __int16 uint16
Definition: eve-compat.h:48
std::string ticker
std::string name
Definition: dbcore.h:39
std::string shortFemaleDescription
Definition: Character.h:77
std::string shortMaleDescription
Definition: Character.h:76
uint32 careerSpecialityID
bool GetBloodlineByCharacterType(uint16 characterTypeID, uint8 &bloodlineID)
#define sDataMgr