EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Character.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, Bloody.Rabbit
24  Updates: Allan
25 */
26 
27 #include "eve-server.h"
28 
29 #include "Client.h"
30 #include "ConsoleCommands.h"
31 #include "EntityList.h"
32 #include "StaticDataMgr.h"
33 #include "StatisticMgr.h"
34 #include "account/AccountService.h"
35 #include "character/Character.h"
37 #include "fleet/FleetService.h"
39 #include "ship/Ship.h"
40 
41 /*
42  * CharacterTypeData
43  */
45  const char* _bloodlineName, uint8 _race, const char* _desc, const char* _maleDesc, const char* _femaleDesc, uint32 _corporationID, uint8 _perception, uint8 _willpower, uint8 _charisma, uint8 _memory, uint8 _intelligence, const char* _shortDesc, const char* _shortMaleDesc, const char* _shortFemaleDesc)
46 : bloodlineName(_bloodlineName),
47  race(_race),
48  description(_desc),
49  maleDescription(_maleDesc),
50  femaleDescription(_femaleDesc),
51  corporationID(_corporationID),
52  perception(_perception),
53  willpower(_willpower),
54  charisma(_charisma),
55  memory(_memory),
56  intelligence(_intelligence),
57  shortDescription(_shortDesc),
58  shortMaleDescription(_shortMaleDesc),
59  shortFemaleDescription(_shortFemaleDesc)
60 {
61 }
62 
63 /*
64  * CharacterType
65  */
66 CharacterType::CharacterType(uint16 _id, uint8 _bloodlineID, const Inv::TypeData& _data, const CharacterTypeData& _charData)
67 : ItemType(_id, _data),
68  m_bloodlineID(_bloodlineID),
69  m_bloodlineName(_charData.bloodlineName),
70  m_description(_charData.description),
71  m_maleDescription(_charData.maleDescription),
72  m_femaleDescription(_charData.femaleDescription),
73  m_corporationID(_charData.corporationID),
74  m_perception(_charData.perception),
75  m_willpower(_charData.willpower),
76  m_charisma(_charData.charisma),
77  m_memory(_charData.memory),
78  m_intelligence(_charData.intelligence),
79  m_shortDescription(_charData.shortDescription),
80  m_shortMaleDescription(_charData.shortMaleDescription),
81  m_shortFemaleDescription(_charData.shortFemaleDescription)
82 {
83  // check for consistency
84  assert(_data.race == _charData.race);
85 }
86 
88  return ItemType::Load<CharacterType>(typeID );
89 }
90 
91 /*
92  * CharacterAppearance
93  */
95 {
96  PyList* colors = data->GetItemString("colors")->AsList();
97  PyList::const_iterator color_cur = colors->begin();
98  for (; color_cur != colors->end(); ++color_cur) {
99  if ((*color_cur)->IsObjectEx()) {
100  PyObjectEx_Type2* color_obj = (PyObjectEx_Type2*)(*color_cur)->AsObjectEx();
101  PyTuple* color_tuple = color_obj->GetArgs()->AsTuple();
102  //color tuple data structure
103  //[0] PyToken
104  //[1] colorID
105  //[2] colorNameA
106  //[3] colorNameBC
107  //[4] weight
108  //[5] gloss
109 
110  m_db.SetAvatarColors(ownerID,
111  PyRep::IntegerValue(color_tuple->GetItem(1)),
112  PyRep::IntegerValue(color_tuple->GetItem(2)),
113  PyRep::IntegerValue(color_tuple->GetItem(3)),
114  color_tuple->GetItem(4)->AsFloat()->value(),
115  color_tuple->GetItem(5)->AsFloat()->value());
116  }
117  }
118 
119  PyObjectEx* appearance = data->GetItemString("appearance")->AsObjectEx();
120  PyObjectEx_Type2* app_obj = (PyObjectEx_Type2*)appearance;
121  PyTuple* app_tuple = app_obj->GetArgs()->AsTuple();
122 
123  m_db.SetAvatar(ownerID, app_tuple->GetItem(1));
124 
125  PyList* modifiers = data->GetItemString("modifiers")->AsList();
126  PyList::const_iterator modif_cur = modifiers->begin();
127  for (; modif_cur != modifiers->end(); ++modif_cur) {
128  if ((*modif_cur)->IsObjectEx()) {
129  PyObjectEx_Type2* modif_obj = (PyObjectEx_Type2*)(*modif_cur)->AsObjectEx();
130  PyTuple* modif_tuple = modif_obj->GetArgs()->AsTuple();
131 
132  //color tuple data structure
133  //[0] PyToken
134  //[1] modifierLocationID
135  //[2] paperdollResourceID
136  //[3] paperdollResourceVariation
137  m_db.SetAvatarModifiers(ownerID,
138  modif_tuple->GetItem(1),
139  modif_tuple->GetItem(2),
140  modif_tuple->GetItem(3));
141  }
142  }
143 
144  PyList* sculpts = data->GetItemString("sculpts")->AsList();
145  PyList::const_iterator sculpt_cur = sculpts->begin();
146  for (; sculpt_cur != sculpts->end(); sculpt_cur++) {
147  if ((*sculpt_cur)->IsObjectEx()) {
148  PyObjectEx_Type2* sculpt_obj = (PyObjectEx_Type2*)(*sculpt_cur)->AsObjectEx();
149  PyTuple* sculpt_tuple = sculpt_obj->GetArgs()->AsTuple();
150 
151  //sculpts tuple data structure
152  //[0] PyToken
153  //[1] sculptLocationID
154  //[2] weightUpDown
155  //[3] weightLeftRight
156  //[4] weightForwardBack
157  m_db.SetAvatarSculpts(ownerID,
158  sculpt_tuple->GetItem(1),
159  sculpt_tuple->GetItem(2),
160  sculpt_tuple->GetItem(3),
161  sculpt_tuple->GetItem(4));
162 
163  }
164  }
165 }
166 
167 
168 /*
169  * CharacterPortrait
170  */
171 
173 {
174  PortraitInfo info = PortraitInfo();
175 
176  info.backgroundID = PyRep::IntegerValue(data->GetItemString("backgroundID"));
177  info.lightColorID = PyRep::IntegerValue(data->GetItemString("lightColorID"));
178  info.lightID = PyRep::IntegerValue(data->GetItemString("lightID"));
179 
180  info.cameraFieldOfView = data->GetItemString("cameraFieldOfView")->AsFloat()->value();
181  info.lightIntensity = data->GetItemString("lightIntensity")->AsFloat()->value();
182 
183  PyTuple* cameraPoi = data->GetItemString("cameraPoi")->AsTuple();
184  info.cameraPoiX = cameraPoi->GetItem(0)->AsFloat()->value();
185  info.cameraPoiY = cameraPoi->GetItem(1)->AsFloat()->value();
186  info.cameraPoiZ = cameraPoi->GetItem(2)->AsFloat()->value();
187 
188  PyTuple* cameraPosition = data->GetItemString("cameraPosition")->AsTuple();
189  info.cameraX = cameraPosition->GetItem(0)->AsFloat()->value();
190  info.cameraY = cameraPosition->GetItem(1)->AsFloat()->value();
191  info.cameraZ = cameraPosition->GetItem(2)->AsFloat()->value();
192 
193  PyDict* poseData = data->GetItemString("poseData")->AsDict();
194  PyTuple* HeadLookTarget = poseData->GetItemString("HeadLookTarget")->AsTuple();
195  info.headLookTargetX = HeadLookTarget->GetItem(0)->AsFloat()->value();
196  info.headLookTargetY = HeadLookTarget->GetItem(1)->AsFloat()->value();
197  info.headLookTargetZ = HeadLookTarget->GetItem(2)->AsFloat()->value();
198 
199  info.browLeftCurl = poseData->GetItemString("BrowLeftCurl")->AsFloat()->value();
200  info.browLeftUpDown = poseData->GetItemString("BrowLeftUpDown")->AsFloat()->value();
201  info.browLeftTighten = poseData->GetItemString("BrowLeftTighten")->AsFloat()->value();
202  info.browRightCurl = poseData->GetItemString("BrowRightCurl")->AsFloat()->value();
203  info.browRightUpDown = poseData->GetItemString("BrowRightUpDown")->AsFloat()->value();
204  info.browRightTighten = poseData->GetItemString("BrowRightTighten")->AsFloat()->value();
205 
206  info.squintLeft = poseData->GetItemString("SquintLeft")->AsFloat()->value();
207  info.smileLeft = poseData->GetItemString("SmileLeft")->AsFloat()->value();
208  info.frownLeft = poseData->GetItemString("FrownLeft")->AsFloat()->value();
209  info.squintRight = poseData->GetItemString("SquintRight")->AsFloat()->value();
210  info.smileRight = poseData->GetItemString("SmileRight")->AsFloat()->value();
211  info.frownRight = poseData->GetItemString("FrownRight")->AsFloat()->value();
212 
213  info.jawUp = poseData->GetItemString("JawUp")->AsFloat()->value();
214  info.jawSideways = poseData->GetItemString("JawSideways")->AsFloat()->value();
215  info.headTilt = poseData->GetItemString("HeadTilt")->AsFloat()->value();
216  info.eyeClose = poseData->GetItemString("EyeClose")->AsFloat()->value();
217  info.eyesLookHorizontal = poseData->GetItemString("EyesLookHorizontal")->AsFloat()->value();
218  info.eyesLookVertical = poseData->GetItemString("EyesLookVertical")->AsFloat()->value();
219  info.orientChar = poseData->GetItemString("OrientChar")->AsFloat()->value();
220  info.portraitPoseNumber = poseData->GetItemString("PortraitPoseNumber")->AsFloat()->value();
221  info.puckerLips = poseData->GetItemString("PuckerLips")->AsFloat()->value();
222 
223  m_db.SetPortraitInfo(charID, info);
224 }
225 
226 
227 /*
228  * Character
229  */
231  uint32 _characterID,
232  // InventoryItem stuff:
233  const CharacterType &_charType,
234  const ItemData &_data,
235  // Character stuff:
236  const CharacterData &_charData,
237  const CorpData &_corpData)
238 : InventoryItem(_characterID, _charType, _data),
239  m_charData(_charData),
240  m_corpData(_corpData),
241  m_pClient(nullptr),
242  m_inTraining(nullptr),
243  m_loaded(false),
244  m_fleetData(CharFleetData()),
245  m_freePoints(0),
246  m_loginTime(0)
247 {
248  // enforce characters to be singletons
249  assert(isSingleton());
250 
251  if (!IsAgent(m_itemID)) {
252  m_loginTime = sEntityList.GetStamp();
254  }
255 }
256 
258 {
259  SaveBookMarks();
263 }
264 
266  return InventoryItem::Load<Character>( characterID );
267 }
268 
270  if (m_loaded)
271  return true;
272  if (IsAgent(m_itemID))
273  return true;
274 
275  if (!pInventory->LoadContents()) {
276  sLog.Error("Character::_Load","LoadContents returned false for char %u", m_itemID);
277  return (m_loaded = false);
278  }
280  sLog.Error("Character::_Load","LoadSkillQueue returned false for char %u", m_itemID);
281  return (m_loaded = false);
282  }
283  if (!m_skillQueue.empty()) {
284  SkillRef sRef = GetSkill(m_skillQueue.front().typeID);
285  if (sRef.get() != nullptr) {
286  sRef->SetFlag(flagSkillInTraining, false);
287  m_inTraining = sRef.get();
288  }
289  } else {
290  ClearSkillFlags();
291  }
292 
294 
295  if (m_loaded) {
296  m_certificates.clear();
298  sLog.Warning("Character::_Load","LoadCertificates returned false for char %u", m_itemID);
299  return (m_loaded = false);
300  }
301  }
302 
303  // load char personal bookmarks and folders ... corp shit will be done ???
304  LoadBookmarks();
305 
307 
308  return m_loaded;
309 }
310 
312 {
313  std::vector<InventoryItemRef> skills;
315  for (auto cur : skills) {
316  SkillRef::StaticCast(cur)->VerifyAttribs();
317  SkillRef::StaticCast(cur)->VerifySP();
318  }
319 }
320 
322  // make sure it's a character
323  const CharacterType *ct = sItemFactory.GetCharacterType(charData.typeID);
324  if (ct == nullptr)
325  return CharacterRef(nullptr);
326 
327  uint32 characterID(CharacterDB::NewCharacter(charData, corpData));
328  if (!IsCharacterID(characterID)) {
329  _log(CHARACTER__ERROR, "Failed to get itemID for new character.");
330  return CharacterRef(nullptr);
331  }
332 
333  return Character::Load(characterID);
334 }
335 
337 {
338 
341  if (!sConsole.IsShutdown())
343  sFltSvc.LeaveFleet(m_pClient);
344 
345  pInventory->Unload();
346 
347  if (!m_pClient->IsCharCreation()) {
348  sItemFactory.RemoveItem(m_itemID);
349  if (sDataMgr.IsStation(m_charData.locationID))
350  ; // do we need to do anything here?
351  }
352 }
353 
355  // delete contents
357  // delete character record
359  // let the parent care about the rest
361 }
362 
364 {
365  if (type == Account::CreditType::ISK) {
366  return m_charData.balance;
367  } else if (type == Account::CreditType::AURUM) {
368  return m_charData.aurBalance;
369  } else {
370  _log(ACCOUNT__ERROR, "Character::balance() - invalid type %u", type);
371  }
372  return 0.0f;
373 }
374 
375 bool Character::AlterBalance(float amount, uint8 type) {
376  if (amount == 0)
377  return true;
378 
379  // amount can be negative. check for funds to remove, if applicable
380  if ((balance(type) + amount) < 0) {
381  std::map<std::string, PyRep *> args;
382  args["amount"] = new PyFloat(-amount);
383  args["balance"] = new PyFloat(balance(type));
384  throw UserError ("NotEnoughMoney")
385  .AddISK ("amount", -amount)
386  .AddISK ("balance", balance (type));
387  }
388 
389  //adjust balance and send notification of change
390  OnAccountChange ac;
391  ac.ownerid = m_itemID;
392  if (type == Account::CreditType::ISK) {
393  m_charData.balance += amount;
394  // cap isk balance at one trillion
395  if (m_charData.balance > 1000000000000)
396  m_charData.balance = 1000000000000;
397  ac.balance = m_charData.balance;
398  ac.accountKey = "cash";
399  } else if (type == Account::CreditType::AURUM) {
400  m_charData.aurBalance += amount;
401  ac.balance = m_charData.aurBalance;
402  ac.accountKey = "AURUM";
403  }
404 
405  PyTuple *answer = ac.Encode();
406  m_pClient->SendNotification("OnAccountChange", "cash", &answer, false);
407 
408  SaveCharacter();
409  return true;
410 }
411 
412 void Character::SetLocation(uint32 stationID, SystemData& data) {
413  m_charData.locationID = (stationID == 0 ? data.systemID : stationID);
418  SaveCharacter();
419 }
420 
421 void Character::SetDescription(const char *newDescription) {
422  m_charData.description = newDescription;
423  SaveCharacter();
424 }
425 
427  // Add new employment history record -allan 25Mar14 update 20Jan15 update again 23May19
429  m_corpData = data;
433 }
434 
436 {
437  m_corpData.corpAccountKey = accountKey;
441 }
442 
444 {
449 }
450 
452 {
453  m_corpData = data;
455 }
456 
458 {
459  return m_db.PickAlternateShip(m_itemID, locationID);
460 }
461 
463 {
464  m_fleetData = fleet;
465  //if ((fleet.joinTime) and (m_fleetJoinTime != fleet.joinTime))
466  // m_fleetJoinTime = fleet.joinTime;
467 
469 }
470 
472 { // not used yet.
473 
474 }
475 
477 { // not used yet.
478  if (m_fleetData.fleetID == 0)
479  return;
480  // negative standings are NOT shared with fleet
481  if (newStanding < 0)
482  return;
483 }
484 
486 {
487  _log(EFFECTS__TRACE, "Character::ResetModifiers()");
488  ClearModifiers();
489  ResetAttributes();
490  std::vector<InventoryItemRef> allSkills;
491  pInventory->GetItemsByFlag(flagSkill, allSkills);
492  for (auto curSkill : allSkills) {
493  curSkill->ClearModifiers();
494  curSkill->ResetAttributes();
495  }
496 }
497 
499 {
500  _log(EFFECTS__TRACE, "Character::ProcessEffects()");
501  //ResetModifiers();
502 
503  // 427 total skills. this should be fairly fast...it is.
504  std::vector<InventoryItemRef> allSkills;
505  pInventory->GetItemsByFlag(flagSkill, allSkills);
506 
507  Effect curEffect = Effect();
508  std::vector<TypeEffects> typeFx;
509  for (auto curSkill : allSkills) {
510  typeFx.clear();
511  sFxDataMgr.GetTypeEffect(curSkill->typeID(), typeFx);
512  for (auto curFx : typeFx) {
513  curEffect = sFxDataMgr.GetEffect(curFx.effectID);
514  fxData data = fxData();
516  data.srcRef = curSkill;
517  sFxProc.ParseExpression(this, sFxDataMgr.GetExpression(curEffect.preExpression), data);
518  }
519  }
520  // apply processed char effects
521  sFxProc.ApplyEffects(this, this, pShip);
522 }
523 
524 /*
525  * SKILL__ERROR
526  * SKILL__WARNING
527  * SKILL__MESSAGE
528  * SKILL__INFO
529  * SKILL__DEBUG
530  * SKILL__TRACE
531  * SKILL__QUEUE
532  */
533 
534 void Character::GetSkillsList(std::vector<InventoryItemRef> &skills) const {
536 }
537 
538 bool Character::HasSkill(uint16 skillTypeID) const {
539  return (GetSkill(skillTypeID).get() != nullptr);
540 }
541 
543  return m_db.GetSkillHistory(m_itemID);
544 }
545 
547  _log(SKILL__QUEUE, "%s(%u): Saving skill queue.", name(), m_itemID );
549 }
550 
552 {
553  std::vector<InventoryItemRef> skills;
555  for (auto cur : skills)
556  cur->SetFlag(flagSkill, false);
557 }
558 
560 {
561  uint8 primary = GetAttribute(skill->GetAttribute(AttrPrimaryAttribute).get_uint32()).get_uint32();
562  uint8 secondary = GetAttribute(skill->GetAttribute(AttrSecondaryAttribute).get_uint32()).get_uint32();
563  return EvEMath::Skill::PointsPerMinute(primary, secondary);
564 }
565 
567 {
568  InventoryItemRef skill = pInventory->GetByTypeFlag( skillTypeID, flagSkill );
569  if (skill.get() == nullptr)
570  skill = pInventory->GetByTypeFlag( skillTypeID, flagSkillInTraining );
571 
572  return SkillRef::StaticCast( skill );
573 }
574 
575 int8 Character::GetSkillLevel(uint16 skillTypeID, bool zeroForNotInjected /*true*/) const {
576  SkillRef requiredSkill = GetSkill( skillTypeID );
577  // First, check for existence of skill trained or in training:
578  if (requiredSkill.get() == nullptr)
579  return (zeroForNotInjected ? 0 : -1);
580 
581  return (int8)requiredSkill->GetAttribute(AttrSkillLevel).get_uint32() ;
582 }
583 
584 bool Character::HasSkillTrainedToLevel(uint16 skillTypeID, uint8 skillLevel) const {
585  SkillRef requiredSkill = GetSkill( skillTypeID );
586  // First, check for existence of skill
587  if (requiredSkill.get() == nullptr)
588  return false;
589  // Second, check for required minimum level of skill, note it must already be trained to this level:
590  if (requiredSkill->GetAttribute(AttrSkillLevel) < skillLevel)
591  return false;
592  return true;
593 }
594 
596 {
597  /* this queries RAM skills and is used to display blueprints tab (S&I -> Blueprints)
598  * called by RamProxy::GetRelevantCharSkills()
599  *
600  * skillLevels, attributeValues = sm.GetService('manufacturing').GetRelevantCharSkills()
601  * maxManufacturingJobCount = int(attributeValues[const.attributeManufactureSlotLimit]) -AttrManufactureSlotLimit = 196,
602  * maxResearchJobCount = int(attributeValues[const.attributeMaxLaborotorySlots]) -AttrMaxLaborotorySlots = 467,
603  *
604  * skillLevels << this is a dict of max remote ram jobs
605  * attributeValues << this is a dict of max ram jobs
606  */
607 
608  PyDict* skillLevels = new PyDict();
611 
614  PyDict* attributeValues = new PyDict();
615  attributeValues->SetItem(new PyInt(AttrMaxLaborotorySlots), new PyInt(mLab));
616  attributeValues->SetItem(new PyInt(AttrManufactureSlotLimit), new PyInt(mSlot));
617 
618  PyTuple* tuple = new PyTuple(2);
619  tuple->SetItem(0, skillLevels);
620  tuple->SetItem(1, attributeValues);
621  return tuple;
622 }
623 
625  if (m_inTraining == nullptr)
626  return 0;
627 
628  // sanity check for skill training
629  if (m_skillQueue.empty()) {
630  sLog.Error("SkillQueue", "%s(%u) flagged as training but queue empty", \
633  m_inTraining = nullptr;
635  return 0;
636  }
637 
638  m_pClient->SetTrainingEndTime(m_skillQueue.front().endTime);
639  return m_skillQueue.front().endTime;
640 }
641 
643 {
644  SkillQueue::iterator itr = m_skillQueue.begin();
645  for (; itr != m_skillQueue.end(); ++itr) {
646  if (sRef->typeID() == itr->typeID)
647  if (sRef->GetAttribute(AttrSkillLevel).get_uint32() >= itr->level)
648  m_skillQueue.erase(itr);
649  }
650  SkillQueueLoop();
651 }
652 
653 void Character::ClearSkillQueue(bool update/*false*/)
654 {
655  CancelSkillInTraining(update);
656  m_skillQueue.clear();
657  _log(SKILL__QUEUE, "%s(%u) Skill Queue Cleared", name(), m_itemID);
658 }
659 
661  // get current skill queue
662  PyList *list = new PyList();
663  for (auto cur : m_skillQueue) {
664  SkillQueue_Element el;
665  el.typeID = cur.typeID;
666  el.level = cur.level;
667  list->AddItem( el.Encode() );
668  }
669 
670  // and encapsulate it in a tuple with the free points
671  PyTuple *tuple = new PyTuple(2);
672  tuple->SetItem(0, list);
673  tuple->SetItem(1, new PyInt(m_freePoints));
674  return tuple;
675 }
676 
678  // Loop through all skills trained and calculate total SP this character has trained
679  // this will also update charData for current SP
681  std::vector<InventoryItemRef> skills;
683  for (auto cur : skills)
684  m_charData.skillPoints += cur->GetAttribute( AttrSkillPoints ).get_uint32(); // much cleaner and more accurate -allan
685 
686  return m_charData.skillPoints;
687 }
688 
689 void Character::SaveSkillHistory(uint16 eventID, double logDate, uint32 characterID, uint16 skillTypeID, uint8 skillLevel, uint32 absolutePoints)
690 {
691  if (absolutePoints < 1)
692  return;
693  if (logDate < 1)
694  return;
695  if (!sDataMgr.IsSkillTypeID(skillTypeID))
696  return;
697  m_db.SaveSkillHistory(eventID, logDate, characterID, skillTypeID, skillLevel, absolutePoints);
698 }
699 
701  if (m_pClient == nullptr)
702  return 0;
703 
704  // returns
705  // 1=success, 2=prereqs, 3=already known, 4=split fail, 5=load fail
706 
707  SkillRef oldSkill = GetSkill( skill->typeID() );
708  if (oldSkill.get() != nullptr) {
710  m_pClient->SendNotifyMsg( "You already know this skill." );
711  return 3;
712  }
713 
718  if ( !skill->SkillPrereqsComplete( *this ) ) {
720  _log(SKILL__DEBUG, "%s(%u): Requested to inject %s (%u/%u) but prereq not complete.", \
721  name(), m_itemID, skill->name(), skill->typeID(), skill->itemID() );
722  m_pClient->SendNotifyMsg( "Injection failed. Skill prerequisites incomplete." );
723  return 2;
724  }
725 
726  // are we injecting from a stack of skills?
727  if ( skill->quantity() > 1 ) {
728  // split the stack to obtain single item
729  skill = SkillRef::StaticCast(skill->Split( 1 ));
730  if (skill.get() == nullptr ) {
731  _log( ITEM__ERROR, "%s (%u): Unable to split stack of %s (%u).", name(), m_itemID, skill->name(), skill->itemID() );
732  return 4;
733  }
734  }
735 
736  skill->ChangeSingleton(true);
737  skill->Move(m_itemID, flagSkill, true);
738  skill->SetAttribute(AttrSkillPoints, EvilZero.get_uint32());
739  skill->SetAttribute(AttrSkillLevel, EvilZero.get_uint32(), false);
740 
741  // 'EvESkill::Event::SkillInjected' shows as "Unknown" in PD>Skill>History
743  _log(SKILL__MESSAGE, "%s(%u) has injected %s(%u)", name(), m_itemID, skill->name(), skill->itemID());
744 
745  return 1;
746 }
747 
750 
751  CancelSkillInTraining(true);
752 
753  m_skillQueue.clear();
755  _log(SKILL__QUEUE, "%s(%u) Skill Queue Paused", name(), m_itemID);
756 }
757 
759 {
761 
762  if (m_skillQueue.empty())
763  return;
764 
765  Skill* skill(GetSkill(typeID).get());
766  if (typeID != m_skillQueue.front().typeID) {
767  // skill to start != first skill in queue...do we just start removing skills till we find this typeID?
768  _log(SKILL__WARNING, "LoadPausedSkillQueue() - type sent (%u) does not match first in queue (%u)",
769  typeID, m_skillQueue.front().typeID);
770  }
771 
772  // queue was paused. all endTimes are off, so reset using now as start time for first skill.
773  uint8 nextLvl(0);
774  uint32 currentSP(0), nextSP(0);
775  int64 startTime(GetFileTimeNow());
776  for (SkillQueue::iterator itr = m_skillQueue.begin(); itr != m_skillQueue.end(); ++itr) {
777  skill = GetSkill(itr->typeID).get();
778  if (skill == nullptr)
779  continue;
780  nextLvl = skill->GetAttribute(AttrSkillLevel).get_uint32() + 1;
781  if (nextLvl > EvESkill::MAXSKILLLEVEL)
782  nextLvl = EvESkill::MAXSKILLLEVEL;
783 
784  if (itr->level == nextLvl) {
785  currentSP = skill->GetCurrentSP(this, startTime);
786  } else {
787  currentSP = skill->GetSPForLevel(itr->level - 1);
788  }
789 
790  nextSP = skill->GetSPForLevel(itr->level);
791  itr->startTime = startTime;
792  itr->endTime = EvEMath::Skill::EndTime(currentSP, nextSP, GetSPPerMin(skill), startTime);
793  skill->SaveItem();
794  startTime = itr->endTime;
795  }
796 
797  // get first skill, add start history and send begin training packet
798  skill = GetSkill(m_skillQueue.front().typeID).get();
799  skill->SetFlag(flagSkillInTraining, true);
800  skill->SaveItem();
801 
802  OnSkillStartTraining osst;
803  osst.itemID = skill->itemID();
804  osst.endOfTraining = m_skillQueue.front().endTime;
805  PyTuple* tmp = osst.Encode();
807 
808  // do we save/show cancel/restart training for pause/resume?
810 
812 
813  _log(SKILL__QUEUE, "%s(%u) Paused Skill Queue Loaded and restarted", name(), m_itemID);
814 }
815 
816 void Character::CancelSkillInTraining(bool update/*false*/)
817 {
818  if (m_inTraining == nullptr)
819  return; //nothing to do...
820 
821  if (m_skillQueue.empty())
822  return;
823 
824  QueuedSkill qs = m_skillQueue.front();
826  if (nextLvl > EvESkill::MAXSKILLLEVEL)
827  nextLvl = EvESkill::MAXSKILLLEVEL;
828 
829  int64 curTime(GetFileTimeNow());
830  uint32 currentSP(0);
831 
832  // is skill in training first in queue?
833  if (qs.typeID != m_inTraining->typeID()) {
834  // nope
835  // not sure how to do this correctly...
836  currentSP = m_inTraining->GetCurrentSP(this);
838  // send training stopped packet
839  if (update) {
840  OnSkillTrainingStopped osst;
841  osst.itemID = m_inTraining->itemID();
842  osst.silent = true; // silent means 'disable neocom blink event'
843  PyTuple* tmp = osst.Encode();
845  }
846 
847  if (is_log_enabled(SKILL__INFO))
848  _log(SKILL__INFO, "%s:%s(%u/%u) Training canceled from skill not in queue.", \
850 
851  m_inTraining->SetAttribute(AttrSkillPoints, currentSP, update);
852  m_inTraining->SetFlag(flagSkill, update);
854  m_inTraining = nullptr;
855  // either way, training canceled.
856  return;
857  }
858 
859  // at this point, skill in training is first in queue
860  currentSP = m_inTraining->GetCurrentSP(this, qs.startTime);
861  if ((qs.endTime < curTime) or (currentSP >= m_inTraining->GetSPForLevel(nextLvl))) {
862  // this level has completed
863  // send training complete packet
864  if (update) {
865  OnSkillTrained ost;
866  ost.itemID = m_inTraining->itemID();
867  PyTuple* tmp = ost.Encode();
869  }
870 
871  // update attribs and save
872  m_inTraining->SetAttribute(AttrSkillLevel, nextLvl, false);
873  currentSP = m_inTraining->GetSPForLevel(nextLvl);
875 
876  if (is_log_enabled(SKILL__INFO))
877  _log(SKILL__INFO, "%s:%s(%u/%u) - CancelSkillInTraining - Training to level %u completed.", \
878  name(), m_inTraining->name(), m_inTraining->typeID(), m_inTraining->itemID(), nextLvl);
879  } else {
881  // send training stopped packet
882  if (update) {
883  OnSkillTrainingStopped osst;
884  osst.itemID = m_inTraining->itemID();
885  osst.silent = true; // silent means 'disable neocom blink event'
886  PyTuple* tmp = osst.Encode();
888  }
889 
890  if (is_log_enabled(SKILL__INFO))
891  _log(SKILL__INFO, "%s:%s(%u/%u) - Training to level %u canceled. CurrentSP: %u, nextSP: %u", \
892  name(), m_inTraining->name(), m_inTraining->typeID(), m_inTraining->itemID(), nextLvl, currentSP, m_inTraining->GetSPForLevel(nextLvl));
893  }
894 
895  m_inTraining->SetAttribute(AttrSkillPoints, currentSP, update);
896  m_inTraining->SetFlag(flagSkill, update);
898 
899  // remove from queue, if applicable
900  if (!m_skillQueue.empty())
901  if (m_inTraining->typeID() == m_skillQueue.front().typeID)
902  m_skillQueue.erase( m_skillQueue.begin() );
903 
904  m_inTraining = nullptr;
905 }
906 
908  Skill* skill(GetSkill(typeID).get());
909  if (skill == nullptr) {
910  // skill not found. cancel and return
911  _log(SKILL__QUEUE, "Cannot find Skill %u.", typeID);
912  m_pClient->SendErrorMsg("Cannot find skill to train.");
913  return;
914  }
915 
916  _log( SKILL__INFO, "Starting checks to add %s to training queue.", skill->name());
917 
918  uint8 nextLvl(skill->GetAttribute(AttrSkillLevel).get_uint32() + 1);
919  if (nextLvl > EvESkill::MAXSKILLLEVEL)
920  nextLvl = EvESkill::MAXSKILLLEVEL;
921 
922  int64 curTime(GetFileTimeNow());
923  uint32 currentSP(skill->GetCurrentSP(this)), nextSP(skill->GetSPForLevel(level));
924  if (level < nextLvl) {
925  // level to train is below current level. update client data and return.
926  SaveSkillHistory(EvESkill::Event::TaskMaster, curTime, m_itemID, typeID, level, currentSP);
927  skill->SetFlag(flagSkill, true);
928  skill->SaveItem();
929 
930  OnSkillTrained ost;
931  ost.itemID = skill->itemID();
932  PyTuple* tmp = ost.Encode();
934 
935  _log(SKILL__WARNING, "Trying to add level %u but current level is %u.", level, nextLvl -1);
936  return;
937  }
938 
939  if (level > nextLvl)
940  currentSP = skill->GetSPForLevel(level -1);
941 
942  // verify sp is below next level
943  if (currentSP >= nextSP) {
944  // it's not. update client data and return.
945  SaveSkillHistory(EvESkill::Event::TaskMaster, curTime, m_itemID, typeID, level, currentSP);
946  skill->SetFlag(flagSkill, true);
947  skill->SaveItem();
948 
949  OnSkillTrained ost;
950  ost.itemID = skill->itemID();
951  PyTuple* tmp = ost.Encode();
953 
954  _log(SKILL__WARNING, "Trying to add level %u at %u sp but current sp is %u.", level, nextSP, currentSP);
955  return;
956  }
957 
958  // current level trainable
959  QueuedSkill qs = QueuedSkill();
960  qs.typeID = typeID;
961  qs.level = level;
962 
963  if (m_skillQueue.empty()) {
964  // nothing in queue. begin training this skill
965  skill->SetFlag(flagSkillInTraining, true);
966  m_inTraining = skill;
967  qs.startTime = curTime;
968  qs.endTime = EvEMath::Skill::EndTime(currentSP, nextSP, GetSPPerMin(skill), curTime);
969  SaveSkillHistory(EvESkill::Event::TrainingStarted, curTime, m_itemID, typeID, level, nextSP);
970 
971  OnSkillStartTraining osst;
972  osst.itemID = skill->itemID();
973  osst.endOfTraining = qs.endTime;
974  PyTuple* tmp = osst.Encode();
976  } else {
977  qs.startTime = m_skillQueue.back().endTime +EvE::Time::Second;
978  qs.endTime = EvEMath::Skill::EndTime(currentSP, nextSP, GetSPPerMin(skill), qs.startTime);
979  }
980 
981  // add to queue and save
982  m_skillQueue.push_back( qs );
983  skill->SaveItem();
984 
985  float timeLeft = (qs.endTime - qs.startTime) / EvE::Time::Second;
986  const char* formatedTime = EvE::FormatTime(timeLeft);
987  _log(SKILL__QUEUE, "Added %s Level %u to queue with %s(%.1f) to train %uSP.", \
988  skill->name(), level, formatedTime, timeLeft, nextSP - currentSP);
989 }
990 
992  /* cleaned up code and reworked logic -allan 28Apr16 -- revisited 23Mar17 --updated code, logic and timers 16Nov17 -again 9jan18*/
993  // finally fixed. 22Jan18 --it wasnt 24Jan18 still not right 3Dec18 -again 4jan19 -another 6Aug19
994  // rewrote and FINALLY fixed. 10Aug19 --still wrong 23Aug20
995  // complete revamp and rename, this kept for notes -allan 12Oct20
996 }
997 
998 void Character::SkillQueueLoop(bool update/*true*/)
999 {
1000  double begin(GetTimeMSeconds());
1001  _log(SKILL__QUEUE, "%s(%u) calling SkillQueueLoop() - update %s", name(), m_itemID, update?"true":"false");
1002 
1003  // anything to do here?
1004  if (m_skillQueue.empty())
1005  if (m_inTraining == nullptr)
1006  return;
1007 
1008  if (m_inTraining->typeID() != m_skillQueue.front().typeID)
1009  CancelSkillInTraining(update);
1010 
1011  // at this point, there is a skill in training, and it is front of queue
1012  int64 curTime(GetFileTimeNow());
1013  if (m_skillQueue.front().endTime > curTime) {
1014  float timeLeft = (m_skillQueue.front().endTime - curTime) / EvE::Time::Second;
1015  const char* formatedTime = EvE::FormatTime(timeLeft);
1016  _log(SKILL__INFO, "%s still training. %s remaining.", m_inTraining->name(), formatedTime);
1018  return;
1019  }
1020 
1021  PyList* list = new PyList();
1022  bool sent(false), multiple(false);
1023  Skill* skill(nullptr);
1024  while (!m_skillQueue.empty()) {
1025  QueuedSkill qs = m_skillQueue.front();
1026  skill = GetSkill( qs.typeID ).get();
1027  if ((qs.typeID == 0) or (skill == nullptr)) {
1028  _log( SKILL__WARNING, "SkillID %u to train was not found. Erase and continue.", qs.typeID);
1029  m_skillQueue.erase( m_skillQueue.begin() );
1030  continue;
1031  }
1032 
1033  _log( SKILL__INFO, "Starting checks for %s.", skill->name());
1034 
1035  if (qs.endTime == 0) {
1036  // this should not hit at this point.
1037  _log(SKILL__ERROR, "endTime wasnt set. Erase from queue and continue.");
1038  skill->SetFlag(flagSkill, true);
1039  skill->SaveItem();
1040  m_skillQueue.erase( m_skillQueue.begin() );
1041  skill = nullptr;
1042  m_inTraining = nullptr;
1043  continue;
1044  }
1045 
1046  if (qs.endTime < curTime) {
1047  // skill training has completed.
1048  uint32 currentSP = skill->GetSPForLevel(qs.level);
1050 
1051  if (is_log_enabled(SKILL__INFO))
1052  _log(SKILL__INFO, "Queued Training completed for level: %u", qs.level);
1053 
1054  // update attribs and save
1055  skill->SetAttribute(AttrSkillLevel, qs.level, update);
1056  skill->SetAttribute(AttrSkillPoints, currentSP, update);
1057  skill->SetFlag(flagSkill, update);
1058  skill->SaveItem();
1059 
1060  // remove completed skill level from queue
1061  m_skillQueue.erase( m_skillQueue.begin() );
1062 
1063  // notify client
1064  if (update) {
1065  PyTuple* tmp(nullptr);
1066  if (m_skillQueue.empty()) {
1067  // only one skill to update
1068  OnSkillTrained ost;
1069  ost.itemID = skill->itemID();
1070  tmp = ost.Encode();
1071  } else {
1072  // another skill in the works. send combined update
1073  SkillRef sref = GetSkill(m_skillQueue.front().typeID);
1074  if (sref.get() == nullptr) {
1075  // that shit didnt work...revert to multiple packets
1076  OnSkillTrained ost;
1077  ost.itemID = skill->itemID();
1078  tmp = ost.Encode();
1079  } else {
1080  multiple = true;
1081  // queue skill switching uses the following to reduce data sent
1082  //def OnSkillSwitched(self, oldSkillID, newSkillID, ETA):
1083  OnSkillSwitched oss;
1084  oss.oldSkillID = skill->itemID();
1085  oss.newSkillID = sref->itemID();
1086  oss.ETA = m_skillQueue.front().endTime;
1087  tmp = oss.Encode();
1088  }
1089  }
1091  } else if (m_pClient->IsLogin())
1092  // for login, use OnMultipleSkillsTrained[]
1093  list->AddItemInt(skill->itemID());
1094 
1095  if (m_pClient->IsInSpace() and update) {
1096  switch (skill->groupID()) {
1101  ; // do nothing for these.
1102  } break;
1103  default: {
1104  if (!sent) {
1105  sent = true;
1106  m_pClient->SendInfoModalMsg("Completed Skill Training.<br>Your ship will update to the new level the next time you undock.");
1107  }
1108  } break;
1109  }
1110  }
1111 
1112  // clear variables and continue
1113  skill = nullptr;
1114  m_inTraining = nullptr;
1115  continue;
1116  }
1117 
1118  // at this point, there is at least one skill queued, and nothing currently training.
1119  uint32 nextSP(skill->GetSPForLevel(qs.level));
1121  skill->SetFlag(flagSkillInTraining, true);
1122  skill->SaveItem();
1123  m_inTraining = skill;
1124 
1125  if (is_log_enabled(SKILL__INFO)) {
1126  float timeLeft = (qs.endTime - curTime) / EvE::Time::Second;
1127  const char* formatedTime = EvE::FormatTime(timeLeft);
1128  _log(SKILL__INFO, "Training started. %s to train %u sp for level %u", \
1129  formatedTime, nextSP - skill->GetCurrentSP(this, qs.startTime), qs.level);
1130  }
1131 
1132  if (!multiple) {
1133  OnSkillStartTraining osst;
1134  osst.itemID = skill->itemID();
1135  osst.endOfTraining = qs.endTime;
1136  PyTuple* tmp = osst.Encode();
1138  }
1139 
1140  break;
1141  }
1142 
1144  SaveCharacter();
1145 
1146  if (m_pClient->IsLogin()) {
1147  PyTuple* tmp(nullptr);
1148  if (!list->empty()) {
1149  if (list->size() > 1) {
1150  OnMultipleSkillsTrained omst;
1151  omst.skillList = list;
1152  tmp = omst.Encode();
1153  }
1154  } else if (skill != nullptr) {
1155  OnSkillTrained ost;
1156  ost.itemID = skill->itemID();
1157  tmp = ost.Encode();
1158  }
1159 
1161  }
1162 
1163  _log(SKILL__QUEUE, "SkillQueueLoop() completed in %.4fms", (GetTimeMSeconds() - begin));
1164 }
1165 
1167 {
1168  if (m_skillQueue.empty()) {
1171  if (is_log_enabled(SKILL__TRACE))
1172  _log(SKILL__QUEUE, "%s(%u): UpdateSkillQueueEndTime() - Queue is empty.", name(), m_itemID);
1173  return;
1174  }
1175 
1176  // update client timer check for skill in training
1177  m_pClient->SetTrainingEndTime(m_skillQueue.front().endTime);
1179 
1180  SaveSkillQueue();
1181 }
1182 
1184  // this is char, skills, implants, boosters.
1185  if (!pInventory->ContentsLoaded())
1186  if (!pInventory->LoadContents()) {
1187  codelog(CHARACTER__ERROR, "%s (%u): Failed to load contents for GetCharInfo", name(), m_itemID);
1188  return nullptr;
1189  }
1190 
1191  Rsp_CommonGetInfo_Entry entry1;
1192  if (!Populate(entry1))
1193  return nullptr;
1194 
1195  PyDict *result = new PyDict();
1196  result->SetItem(new PyInt(m_itemID), new PyObject("util.KeyVal", entry1.Encode()));
1197 
1198  //now encode skills...
1199  std::vector<InventoryItemRef> skills;
1200  skills.clear();
1201  //find all the skills contained within ourself.
1202  pInventory->GetItemsByFlag(flagSkill, skills );
1204 
1207  //encode an entry for each one.
1208  for (auto cur : skills) {
1209  Rsp_CommonGetInfo_Entry entry;
1210  if (cur->Populate(entry)) {
1211  result->SetItem(new PyInt(cur->itemID()), new PyObject("util.KeyVal", entry.Encode()));
1212  } else {
1213  codelog(CHARACTER__ERROR, "%s (%u): Failed to load character item %u for GetCharInfo", name(), m_itemID, cur->itemID());
1214  }
1215  }
1216 
1219  return result;
1220 }
1221 
1223  util_Row row;
1224  row.header.push_back("description");
1225  row.line = new PyList();
1226  row.line->AddItemString( description().c_str() );
1227  return row.Encode();
1228 }
1229 
1231 {
1232  if (iRef.get() == nullptr)
1233  return;
1234 
1235  InventoryItem::AddItem(iRef);
1236 
1237  _log( CHARACTER__INFO, "%s(%u) has been added to %s with flag %i.", iRef->name(), iRef->itemID(), name(), (uint8)iRef->flag() );
1238 }
1239 
1241 {
1243  m_db.SetCurrentShip(m_itemID, shipID);
1244 }
1245 
1247 {
1248  m_charData.capsuleID = podID;
1249  m_db.SetCurrentPod(m_itemID, podID);
1250 }
1251 
1253 {
1255 }
1256 
1258  _log( CHARACTER__INFO, "Saving character info for %u.", m_itemID );
1259 
1260  // update skill points before save
1261  GetTotalSP();
1262  SetLogonMinutes();
1264 }
1265 
1267  _log( CHARACTER__INFO, "Saving full character info for %u.", m_itemID );
1268  //GetTotalSP();
1269  SaveCharacter();
1271  SaveAttributes();
1272 
1273  if (m_inTraining != nullptr) {
1274  m_inTraining->SetAttribute(AttrSkillPoints, m_inTraining->GetCurrentSP(this, m_skillQueue.front().startTime), false);
1276  }
1277 
1278  SaveSkillQueue();
1279 }
1280 
1282 {
1283  std::string reason = "Bounty for the killing of ";
1284  reason += cRef->itemName();
1286  // add data to StatisticMgr
1287  sStatMgr.Add(Stat::pcBounties, cRef->bounty());
1288 }
1289 
1291 {
1292  m_loginTime = sEntityList.GetStamp();
1294 }
1295 
1297 {
1298  double onlineTime = m_charData.loginTime - GetFileTimeNow();
1299  onlineTime /= 10000000;
1300  onlineTime -= 11644473600;
1301  onlineTime /= 60;
1302  return (uint16)onlineTime;
1303 }
1304 
1305 // called on 10m timer from client
1307  // get login time and set _logonMinutes -allan
1308  uint16 loginMinutes = (sEntityList.GetStamp() - m_loginTime) /60;
1309 
1310  // some checks are done < 1m, so if this check has no minutes, keep original time and exit
1311  if (loginMinutes > 0) {
1312  m_charData.logonMinutes += loginMinutes;
1313  m_loginTime = sEntityList.GetStamp();
1314  }
1315 }
1316 
1317 // certificate system
1318 bool Character::HasCertificate( uint32 certID ) const {
1319  CertMap::const_iterator itr = m_certificates.find(certID);
1320  return (itr != m_certificates.end());
1321 }
1322 
1324  crt = m_certificates;
1325 }
1326 
1328 {
1329  CharCerts cert = CharCerts();
1330  cert.certificateID = certID;
1331  cert.grantDate = GetFileTimeNow();
1332  cert.visibilityFlags = 0;
1333  m_certificates.emplace(certID, cert);
1334  m_cdb.AddCertificate(m_itemID, cert);
1335 }
1336 
1337 void Character::UpdateCertificate( uint32 certID, bool pub ) {
1338  m_cdb.UpdateCertificate(m_itemID, certID, pub);
1339 }
1340 
1342  _log( CHARACTER__INFO, "Saving Certificates of character %u", m_itemID );
1344 }
1345 
1346 // functions and methods for bookmark system (char mem maps)
1349 {
1350 
1351 }
1352 
1354 {
1355 
1356 }
1357 
1358 
1359 // functions and methods for standings system
1364 {
1365  if (toID == 0)
1366  toID = m_itemID;
1367  float res = StandingDB::GetStanding(fromID, toID);
1368  if (res < 0.0f) {
1369  res += ((10.0f + res) * (0.04f * GetSkillLevel(EvESkill::Diplomacy)));
1370  } else {
1371  res += ((10.0f - res) * (0.04f * GetSkillLevel(EvESkill::Connections)));
1372  }
1373  return res;
1374 }
1375 
1377  if (toID == 0)
1378  toID = m_itemID;
1379  float res = StandingDB::GetStanding(fromID, toID);
1380  if (res < 0.0f) {
1381  res += ((10.0f + res) * (0.04f * GetSkillLevel(EvESkill::Diplomacy)));
1382  } else {
1383  res += ((10.0f - res) * (0.04f * GetSkillLevel(EvESkill::Connections)));
1384  }
1385  return res;
1386 }
1387 
1388 void Character::SetStanding(uint32 fromID, uint32 toID, float standing) {
1389  StandingDB::SetStanding(fromID, toID, standing);
1390  PyTuple* payload = new PyTuple(0);
1391  m_pClient->SendNotification("OnStandingSet", "charid", payload, false);
1392 }
1393 
1394 // for map system
1395 void Character::VisitSystem(uint32 solarSystemID) {
1396  m_db.VisitSystem(solarSystemID, m_itemID);
1397 }
static float GetStanding(uint32 fromID, uint32 toID)
Definition: StandingDB.cpp:142
bool IsLogin()
Definition: Client.h:235
float cameraZ
Definition: CharacterDB.h:39
Base Python wire object.
Definition: PyRep.h:66
CharacterDB m_db
Definition: Character.h:434
void SetAccountKey(int32 accountKey)
Definition: Character.cpp:435
float jawSideways
Definition: CharacterDB.h:62
uint16 preExpression
Definition: EffectsData.h:26
PyTuple * AsTuple()
Definition: PyRep.h:138
unsigned __int8 uint8
Definition: eve-compat.h:46
bool LoadSkillQueue(uint32 charID, SkillQueue &into)
bool ContentsLoaded() const
Definition: Inventory.h:62
SkillRef GetSkill(uint16 skillTypeID) const
Definition: Character.cpp:566
#define sStatMgr
Definition: StatisticMgr.h:68
void SendNotification(const PyAddress &dest, EVENotificationStream &noti, bool seq=true)
Definition: Client.cpp:2245
double value() const
Definition: PyRep.h:309
bool LoadCertificates(uint32 characterID, CertMap &into)
void SendErrorMsg(const char *fmt,...)
Definition: Client.cpp:2719
void SetActiveShip(uint32 shipID)
Definition: Character.cpp:1240
#define _log(type, fmt,...)
Definition: logsys.h:124
static bool SaveCorpData(uint32 charID, const CorpData &data)
void SetAvatarColors(uint32 charID, uint32 colorID, uint32 colorNameA, uint32 colorNameBC, double weight, double gloss)
bool SaveSkillQueue(uint32 charID, SkillQueue &queue)
float smileLeft
Definition: CharacterDB.h:67
#define sConsole
PyRep * GetItem(size_t index) const
Returns Python object.
Definition: PyRep.h:602
uint32 PickAlternateShip(uint32 charID, uint32 locationID)
bool SaveCertificates(uint32 characterID, const CertMap &from)
PyRep * GetItemString(const char *key) const
Obtains database entry based on given key string.
Definition: PyRep.cpp:702
void SetAvatarModifiers(uint32 charID, PyRep *modifierLocationID, PyRep *paperdollResourceID, PyRep *paperdollResourceVariation)
void SetLocation(uint32 stationID, SystemData &data)
Definition: Character.cpp:412
float puckerLips
Definition: CharacterDB.h:64
float browRightTighten
Definition: CharacterDB.h:55
void SetTrainingEndTime(int64 endTime)
Definition: Client.h:331
Python's dictionary.
Definition: PyRep.h:719
void SetActivePod(uint32 podID)
Definition: Character.cpp:1246
bool IsCharCreation()
Definition: Client.h:433
bool SetFlag(EVEItemFlags flag, bool notify=false)
static bool SaveCharacter(uint32 charID, const CharacterData &data)
Definition: CharacterDB.cpp:66
uint8 GetSPPerMin(Skill *skill)
Definition: Character.cpp:559
void SetLogonMinutes()
Definition: Character.cpp:1306
virtual void AddItem(InventoryItemRef iRef)
CorpData m_corpData
Definition: Character.h:439
uint8 PointsPerMinute(uint8 pAttr, uint8 sAttr)
Definition: EvEMath.cpp:36
float frownLeft
Definition: CharacterDB.h:65
float eyeClose
Definition: CharacterDB.h:57
void UpdateFleetSession(CharFleetData &fleet)
Definition: Client.cpp:1992
void SaveSkillHistory(uint16 eventID, double logDate, uint32 characterID, uint16 skillTypeID, uint8 skillLevel, uint32 absolutePoints)
Definition: Character.cpp:689
void ClearSkillQueue(bool update=false)
Definition: Character.cpp:653
void ClearSkillFlags()
Definition: Character.cpp:551
void CancelSkillInTraining(bool update=false)
Definition: Character.cpp:816
float browRightUpDown
Definition: CharacterDB.h:56
#define IsAgent(itemID)
Definition: EVE_Defines.h:247
void AddItem(InventoryItemRef item)
Definition: Character.cpp:1230
uint8 level
Definition: CharacterDB.h:73
SkillQueue m_skillQueue
Definition: Character.h:445
void QueueDestinyEvent(PyTuple **multiEvent)
Definition: Client.cpp:2124
void GetCertificates(CertMap &crt)
Definition: Character.cpp:1323
static CharacterRef Spawn(CharacterData &charData, CorpData &corpData)
Definition: Character.cpp:321
uint32 skillPoints
PyTuple * SendSkillQueue()
Definition: Character.cpp:660
void SendInfoModalMsg(const char *fmt,...)
Definition: Client.cpp:2756
Python floating point number.
Definition: PyRep.h:292
void DeleteContents()
Definition: Inventory.cpp:273
InventoryItem for skill.
Definition: Skill.h:48
const_iterator begin() const
Definition: PyRep.h:660
float browRightCurl
Definition: CharacterDB.h:54
virtual bool _Load()
void UpdateCertificate(uint32 certificateID, bool pub)
Definition: Character.cpp:1337
#define sEntityList
Definition: EntityList.h:208
storage_type::const_iterator const_iterator
Definition: PyRep.h:644
PyObject * GetDescription() const
Definition: Character.cpp:1222
uint32 certificateID
float bounty() const
Definition: Character.h:287
uint32 shipID() const
Definition: Character.h:341
virtual void Delete()
Definition: Character.cpp:354
void UpdateCertificate(uint32 charID, uint32 certificateID, bool pub=false)
void UpdateSkillQueueEndTime(int64 endtime, uint32 charID)
void SetLogOffTime(uint32 charID)
const char * name()
bool IsInSpace()
Definition: Client.h:228
Character(uint32 _characterID, const CharacterType &_charType, const ItemData &_data, const CharacterData &_charData, const CorpData &_corpData)
Definition: Character.cpp:230
InventoryItemRef srcRef
Definition: EffectsData.h:78
PyRep * GetSkillHistory(uint32 charID)
void SendNotifyMsg(const char *fmt,...)
Definition: Client.cpp:2776
uint32 GetSPForLevel(uint8 level)
Definition: Skill.cpp:76
Python tuple.
Definition: PyRep.h:567
float headTilt
Definition: CharacterDB.h:49
RefPtr< Character > CharacterRef
Definition: ItemRef.h:63
uint32 GetTotalSP()
Definition: Character.cpp:677
signed __int8 int8
Definition: eve-compat.h:45
float eyesLookHorizontal
Definition: CharacterDB.h:59
std::map< uint16, CharCerts > CertMap
void UpdateSkillQueueEndTime()
Definition: Character.cpp:1166
EvilNumber EvilZero
Definition: EvilNumber.cpp:32
void AddItem(PyRep *i)
Definition: PyRep.h:701
void SafeDelete(T *&p)
Deletes and nullifies a pointer.
Definition: SafeMem.h:83
uint16 groupID() const
signed __int32 int32
Definition: eve-compat.h:49
UserError & AddISK(const char *name, double isk)
Shorthand method for adding an ISK amount.
void DeleteCharacter(uint32 charID)
* args
uint32 GetItemsByFlag(EVEItemFlags flag, std::vector< InventoryItemRef > &items) const
Definition: Inventory.cpp:458
void Unload()
Definition: Inventory.cpp:62
#define is_log_enabled(type)
Definition: logsys.h:78
#define sFltSvc
Definition: FleetService.h:147
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
float balance(uint8 type)
Definition: Character.cpp:363
uint32 m_freePoints
Definition: Character.h:446
int64 EndTime(uint32 currentSP, uint32 nextSP, uint8 SPMin, int64 timeNow)
Definition: EvEMath.cpp:46
float browLeftCurl
Definition: CharacterDB.h:51
int64 endTime
Definition: CharacterDB.h:75
bool isSingleton() const
Definition: InventoryItem.h:96
bool AlterBalance(float amount, uint8 type)
Definition: Character.cpp:375
bool SaveAttributes()
CharacterData m_charData
Definition: Character.h:440
Python extended object.
Definition: PyRep.h:861
void PayBounty(CharacterRef cRef)
Definition: Character.cpp:1281
void VisitSystem(uint32 solarSystemID)
Definition: Character.cpp:1395
void SetCurrentShip(uint32 charID, uint32 shipID)
void SetFleetData(CharFleetData &fleet)
Definition: Character.cpp:462
void SaveFullCharacter()
Definition: Character.cpp:1266
void AddToSkillQueue(uint16 typeID, uint8 level)
Definition: Character.cpp:907
bool SavePausedSkillQueue(uint32 charID, SkillQueue &queue)
float squintLeft
Definition: CharacterDB.h:60
uint32 stationID() const
Definition: Character.h:326
double GetTimeMSeconds()
Definition: utils_time.cpp:104
Python object.
Definition: PyRep.h:826
bool m_loaded
Definition: Character.h:450
void VisitSystem(uint32 solarSystemID, uint32 charID)
void SetBaseID(uint32 baseID)
Definition: Character.cpp:443
Inventory * pInventory
int64 GetEndOfTraining()
Definition: Character.cpp:624
#define codelog(type, fmt,...)
Definition: logsys.h:128
void SetItem(size_t index, PyRep *object)
Stores Python object.
Definition: PyRep.h:610
uint32 solarSystemID
float browLeftTighten
Definition: CharacterDB.h:52
uint32 lightID
Definition: CharacterDB.h:35
uint32 get_uint32()
Definition: EvilNumber.cpp:173
PyList * AsList()
Definition: PyRep.h:140
#define sFxDataMgr
std::string description
virtual bool _Load()
Definition: Character.cpp:269
float portraitPoseNumber
Definition: CharacterDB.h:48
float GetStandingModified(uint32 fromID, uint32 toID=0)
Definition: Character.cpp:1363
static void TranserFunds(uint32 fromID, uint32 toID, double amount, std::string reason="", uint8 entryTypeID=Journal::EntryType::Undefined, uint32 referenceID=0, uint16 fromKey=Account::KeyType::Cash, uint16 toKey=Account::KeyType::Cash, Client *pClient=nullptr)
Python integer.
Definition: PyRep.h:231
PyDict * AsDict()
Definition: PyRep.h:142
CertificateMgrDB m_cdb
Definition: Character.h:433
const uint8 MAXSKILLLEVEL
Definition: EvEMath.h:19
void UpdateCorpSession(CorpData &data)
Definition: Client.cpp:1970
float cameraFieldOfView
Definition: CharacterDB.h:40
void SetAttribute(uint16 attrID, int num, bool notify=true)
float frownRight
Definition: CharacterDB.h:66
float GetNPCCorpStanding(uint32 fromID, uint32 toID=0)
Definition: Character.cpp:1376
void SaveCharacter()
Definition: Character.cpp:1257
X * get() const
Definition: RefPtr.h:213
static CharacterType * Load(uint16 typeID)
Definition: Character.cpp:87
float orientChar
Definition: CharacterDB.h:50
void SaveCertificates()
Definition: Character.cpp:1341
void AddItemInt(int32 intval)
Definition: PyRep.h:702
void LogOut()
Definition: Character.cpp:336
uint32 constellationID
void SkillQueueLoop(bool update=true)
Definition: Character.cpp:998
CertMap m_certificates
Definition: Character.h:448
CharacterDB m_db
Definition: Character.h:205
bool Populate(Rsp_CommonGetInfo_Entry &into)
void ProcessEffects(ShipItem *pShip)
Definition: Character.cpp:498
#define IsCharacterID(itemID)
Definition: EVE_Defines.h:206
CharFleetData m_fleetData
Definition: Character.h:441
uint8 action
Definition: EffectsData.h:73
Python object "ccp_exceptions.UserError".
Definition: PyExceptions.h:121
uint32 lightColorID
Definition: CharacterDB.h:36
int64 startTime
Definition: CharacterDB.h:76
static RefPtr StaticCast(const RefPtr< Y > &oth)
Acts as static_cast from one RefPtr to another.
Definition: RefPtr.h:238
unsigned __int32 uint32
Definition: eve-compat.h:50
uint32 systemID
uint32 baseID
uint32 GetCurrentSP(Character *ch, int64 startTime=0)
Definition: Skill.cpp:80
Client * m_pClient
Definition: Character.h:437
bool HasCertificate(uint32 certificateID) const
Definition: Character.cpp:1318
uint32 regionID
float headLookTargetY
Definition: CharacterDB.h:45
void FleetShareMissionStandings(float newStanding)
Definition: Character.cpp:476
bool LoadPausedSkillQueue(uint32 charID, SkillQueue &into)
void ResetClone()
Definition: Character.cpp:1252
CharacterType(uint16 _id, uint8 _bloodlineID, const Inv::TypeData &_data, const CharacterTypeData &_charData)
Definition: Character.cpp:66
static void SetStanding(uint32 fromID, uint32 toID, float standing)
Definition: StandingDB.cpp:157
#define sFxProc
void Build(uint32 charID, PyDict *data)
Definition: Character.cpp:172
uint8 visibilityFlags
void VerifySP()
Definition: Character.cpp:311
uint32 logonMinutes
uint32 backgroundID
Definition: CharacterDB.h:34
RefPtr< InventoryItem > InventoryItemRef
Definition: ItemRef.h:52
uint32 corporationID
bool HasSkillTrainedToLevel(uint16 skillTypeID, uint8 skillLevel) const
Definition: Character.cpp:584
float smileRight
Definition: CharacterDB.h:68
void UpdateSkillQueue()
Definition: Character.cpp:991
Definition: Ship.h:46
double GetFileTimeNow()
Definition: utils_time.cpp:84
void GrantCertificate(uint32 certificateID)
Definition: Character.cpp:1327
void SetAvatarSculpts(uint32 charID, PyRep *sculptLocationID, PyRep *weightUpDown, PyRep *weightLeftRight, PyRep *weightForwardBack)
void SetPortraitInfo(uint32 charID, PortraitInfo &data)
void SetLogInTime(uint32 charID)
float cameraPoiX
Definition: CharacterDB.h:41
void AddCertificate(uint32 charID, CharCerts cert)
virtual ~Character()
Definition: Character.cpp:257
float browLeftUpDown
Definition: CharacterDB.h:53
Skill * m_inTraining
Definition: Character.h:444
signed __int64 int64
Definition: eve-compat.h:51
PyRep * GetSkillHistory()
Definition: Character.cpp:542
const_iterator end() const
Definition: PyRep.h:661
const std::string & itemName() const
int16 corpAccountKey
void Build(uint32 ownerID, PyDict *data)
Definition: Character.cpp:94
void SetAvatar(uint32 charID, PyRep *hairDarkness)
uint16 OnlineTime()
Definition: Character.cpp:1296
#define IsFleetID(itemID)
Definition: EVE_Defines.h:225
float cameraPoiZ
Definition: CharacterDB.h:43
void UpdateCorpData(CorpData &data)
Definition: Character.cpp:451
EvilNumber GetAttribute(const uint16 attrID) const
static uint32 NewCharacter(const CharacterData &data, const CorpData &corpData)
Definition: CharacterDB.cpp:33
uint16 typeID
Definition: CharacterDB.h:74
float headLookTargetZ
Definition: CharacterDB.h:46
PyRep * GetRAMSkills()
Definition: Character.cpp:595
void JoinCorporation(const CorpData &data)
Definition: Character.cpp:426
uint32 PickAlternateShip(uint32 locationID)
Definition: Character.cpp:457
bool LoadContents()
Definition: Inventory.cpp:113
void ResetModifiers()
Definition: Character.cpp:485
PyTuple * GetArgs() const
Definition: PyRep.cpp:947
static void AddEmployment(uint32 charID, uint32 corpID, uint32 oldCorpID=0)
int8 GetSkillLevel(uint16 skillTypeID, bool zeroForNotInjected=true) const
Definition: Character.cpp:575
CharacterTypeData(const char *_bloodlineName="", uint8 _race=0, const char *_desc="", const char *_maleDesc="", const char *_femaleDesc="", uint32 _corporationID=0, uint8 _perception=0, uint8 _willpower=0, uint8 _charisma=0, uint8 _memory=0, uint8 _intelligence=0, const char *_shortDesc="", const char *_shortMaleDesc="", const char *_shortFemaleDesc="")
Definition: Character.cpp:44
float cameraX
Definition: CharacterDB.h:37
CharacterDB m_db
Definition: Character.h:192
const char * FormatTime(int64 time=-1)
Definition: misc.cpp:204
void GetSkillsList(std::vector< InventoryItemRef > &skills) const
Definition: Character.cpp:534
size_t size() const
Definition: PyRep.h:663
int64 grantDate
float lightIntensity
Definition: CharacterDB.h:47
uint8 InjectSkillIntoBrain(SkillRef skill)
Definition: Character.cpp:700
virtual void Delete()
#define sItemFactory
Definition: ItemFactory.h:165
uint32 constellationID
PyDict * GetCharInfo()
Definition: Character.cpp:1183
const std::string & description() const
Definition: Character.h:284
static int64 IntegerValue(PyRep *pRep)
Definition: PyRep.cpp:118
void SetDescription(const char *newDescription)
Definition: Character.cpp:421
float headLookTargetX
Definition: CharacterDB.h:44
void LoadPausedSkillQueue(uint16 typeID)
Definition: Character.cpp:758
void LoadBookmarks()
Definition: Character.cpp:1348
float eyesLookVertical
Definition: CharacterDB.h:58
void SaveBookMarks()
Definition: Character.cpp:1353
PyFloat * AsFloat()
Definition: PyRep.h:126
void SetCurrentPod(uint32 charID, uint32 podID)
void RemoveFromQueue(SkillRef sRef)
Definition: Character.cpp:642
void SetStanding(uint32 fromID, uint32 toID, float standing)
Definition: Character.cpp:1388
unsigned __int16 uint16
Definition: eve-compat.h:48
PyObjectEx * AsObjectEx()
Definition: PyRep.h:154
static CharacterRef Load(uint32 characterID)
Definition: Character.cpp:265
InventoryItemRef GetByTypeFlag(uint32 typeID, EVEItemFlags flag) const
Definition: Inventory.cpp:444
void SetItem(PyRep *key, PyRep *value)
SetItem adds or sets a database entry.
Definition: PyRep.cpp:713
Wrapper class for PyObjectEx of type 2.
Definition: PyRep.h:938
float cameraPoiY
Definition: CharacterDB.h:42
void SetLoginTime()
Definition: Character.cpp:1290
uint32 m_loginTime
Definition: Character.h:452
void FleetShareMissionRewards()
Definition: Character.cpp:471
uint16 typeID() const
bool empty() const
Definition: PyRep.h:664
void PauseSkillQueue()
Definition: Character.cpp:748
float cameraY
Definition: CharacterDB.h:38
Python list.
Definition: PyRep.h:639
uint32 itemID() const
Definition: InventoryItem.h:98
float squintRight
Definition: CharacterDB.h:61
bool ChangeCloneType(uint32 charID, uint32 typeID)
bool HasSkill(uint16 skillTypeID) const
Definition: Character.cpp:538
#define sDataMgr
void SaveSkillQueue()
Definition: Character.cpp:546
void SaveSkillHistory(uint16 eventID, double logDate, uint32 characterID, uint32 skillTypeID, uint8 skillLevel, uint32 absolutePoints)