/*
* statistics.cpp
* Player statistics
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* Permission to use, modify and distribute is granted via the
* Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
* Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
* Contributions by Tim Callahan, Jonathan Hseu
* Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
*
*/
#include "mud.h"
#include "commands.h"
#include <iomanip>
//*********************************************************************
// LevelInfo
//*********************************************************************
LevelInfo::LevelInfo(int pLevel, int pHp, int pMp, int pStat, int pSave, time_t pTime) {
level = pLevel;
hpGain = pHp;
mpGain = pMp;
statUp = pStat;
saveGain = pSave;
levelTime = pTime;
}
LevelInfo::LevelInfo(const LevelInfo* l) {
level = l->level;;
hpGain = l->hpGain;
mpGain = l->mpGain;
statUp = l->statUp;
saveGain = l->saveGain;
levelTime = l->levelTime;
}
LevelInfo::LevelInfo(xmlNodePtr rootNode) {
level = 0;
hpGain = 0;
mpGain = 0;
statUp = 0;
saveGain = 0;
levelTime = 0;
xmlNodePtr childNode = rootNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Level")) xml::copyToNum(level, childNode);
else if(NODE_NAME(childNode, "HpGain")) xml::copyToNum(hpGain, childNode);
else if(NODE_NAME(childNode, "MpGain")) xml::copyToNum(mpGain, childNode);
else if(NODE_NAME(childNode, "StatUp")) xml::copyToNum(statUp, childNode);
else if(NODE_NAME(childNode, "SaveGain")) xml::copyToNum(saveGain, childNode);
else if(NODE_NAME(childNode, "LevelTime")) xml::copyToNum(levelTime, childNode);
childNode = childNode->next;
}
if(level == 0)
throw std::exception();
}
void LevelInfo::save(xmlNodePtr rootNode) {
xmlNodePtr curNode = xml::newStringChild(rootNode, "LevelInfo");
xml::saveNonZeroNum(curNode, "Level", level);
xml::saveNonZeroNum(curNode, "HpGain", hpGain);
xml::saveNonZeroNum(curNode, "MpGain", mpGain);
xml::saveNonZeroNum(curNode, "StatUp", statUp);
xml::saveNonZeroNum(curNode, "SaveGain", saveGain);
xml::saveNonZeroNum(curNode, "LevelTime", levelTime);
}
void Statistics::setLevelInfo(int level, LevelInfo* levelInfo) {
LevelInfoMap::iterator it = levelHistory.find(level);
if(it != levelHistory.end()) {
levelHistory.erase(it);
}
levelHistory.insert(LevelInfoMap::value_type(level, levelInfo));
}
LevelInfo* Statistics::getLevelInfo(int level) {
LevelInfoMap::iterator it = levelHistory.find(level);
if(it == levelHistory.end())
return(NULL);
return(it->second);
}
int LevelInfo::getLevel() { return(level); }
int LevelInfo::getHpGain() { return(hpGain); }
int LevelInfo::getMpGain() { return(mpGain); }
int LevelInfo::getStatUp() { return(statUp); }
int LevelInfo::getSaveGain() { return(saveGain); }
time_t LevelInfo::getLevelTime() { return(levelTime); }
//*********************************************************************
// StringStatistic
//*********************************************************************
StringStatistic::StringStatistic() {
reset();
}
//*********************************************************************
// save
//*********************************************************************
void StringStatistic::save(xmlNodePtr rootNode, bstring nodeName) const {
if(!value && name == "")
return;
xmlNodePtr curNode = xml::newStringChild(rootNode, nodeName);
xml::saveNonZeroNum(curNode, "Value", value);
xml::saveNonNullString(curNode, "Name", name);
}
//*********************************************************************
// load
//*********************************************************************
void StringStatistic::load(xmlNodePtr curNode) {
xmlNodePtr childNode = curNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Value")) xml::copyToNum(value, childNode);
else if(NODE_NAME(childNode, "Name")) xml::copyToBString(name, childNode);
childNode = childNode->next;
}
}
//*********************************************************************
// update
//*********************************************************************
void StringStatistic::update(unsigned long num, bstring with) {
if(num > value) {
value = num;
name = stripColor(with);
}
}
//*********************************************************************
// reset
//*********************************************************************
void StringStatistic::reset() {
value = 0;
name = "";
}
//*********************************************************************
// Statistics
//*********************************************************************
Statistics::Statistics() {
track = true;
numPkWon = numPkIn = 0;
reset();
}
Statistics::Statistics(Statistics& cr) {
doCopy(cr);
}
Statistics::Statistics(const Statistics& cr) {
doCopy(cr);
}
Statistics& Statistics::operator=(const Statistics& cr) {
doCopy(cr);
return(*this);
}
Statistics::~Statistics() {
reset();
}
void Statistics::doCopy(const Statistics& st) {
start = st.start;
// combat
numSwings = st.numSwings;
numHits = st.numHits;
numMisses = st.numMisses;
numFumbles = st.numFumbles;
numDodges = st.numDodges;
numCriticals = st.numCriticals;
numTimesHit = st.numTimesHit;
numTimesMissed = st.numTimesMissed;
numTimesFled = st.numTimesFled;
numPkIn = st.numPkIn;
numPkWon = st.numPkWon;
// magic
numCasts = st.numCasts;
numOffensiveCasts = st.numOffensiveCasts;
numHealingCasts = st.numHealingCasts;
numWandsUsed = st.numWandsUsed;
numTransmutes = st.numTransmutes;
numPotionsDrank = st.numPotionsDrank;
// death
numKills = st.numKills;
numDeaths = st.numDeaths;
expLost = st.expLost; // New
lastExpLoss = st.lastExpLoss; // New
// other
numThefts = st.numThefts;
numAttemptedThefts = st.numAttemptedThefts;
numSaves = st.numSaves;
numAttemptedSaves = st.numAttemptedSaves;
numRecalls = st.numRecalls;
numLagouts = st.numLagouts;
numFishCaught = st.numFishCaught;
numItemsCrafted = st.numItemsCrafted;
numCombosOpened = st.numCombosOpened;
levelHistoryStart = st.levelHistoryStart;
// most
mostGroup = st.mostGroup;
mostExperience = st.mostExperience; // New
mostMonster = st.mostMonster;
mostAttackDamage = st.mostAttackDamage;
mostMagicDamage = st.mostMagicDamage;
// so we can reference
parent = st.parent;
LevelInfoMap::const_iterator it;
LevelInfo* lInfo;
for(it = st.levelHistory.begin() ; it != st.levelHistory.end() ; it++) {
lInfo = new LevelInfo((*it).second);
levelHistory[(*it).first] = lInfo;
}
}
//*********************************************************************
// reset
//*********************************************************************
void Statistics::reset() {
numSwings = numHits = numMisses = numFumbles = numDodges =
numCriticals = numTimesHit = numTimesMissed = numTimesFled =
numCasts = numOffensiveCasts = numHealingCasts = numKills =
numDeaths = numThefts = numAttemptedThefts = numSaves =
numAttemptedSaves = numRecalls = numLagouts = numWandsUsed =
numPotionsDrank = numItemsCrafted = numFishCaught = numCombosOpened =
mostGroup = numPkIn = numPkWon = numTransmutes = lastExpLoss = expLost = 0;
levelHistoryStart = 0;
mostMonster.reset();
mostAttackDamage.reset();
mostMagicDamage.reset();
mostExperience.reset();
long t = time(0);
start = ctime(&t);
start = start.trim();
LevelInfoMap::iterator it;
for(it = levelHistory.begin() ; it != levelHistory.end() ; ) {
delete (*it++).second;
}
levelHistory.clear();
}
//*********************************************************************
// StartLevelHistoryTracking
//*********************************************************************
// Timing of level history after this point in time should be accurate
void Statistics::startLevelHistoryTracking() {
levelHistoryStart = time(0);
}
//*********************************************************************
// getLevelHistoryStart
//*********************************************************************
time_t Statistics::getLevelHistoryStart() {
return(levelHistoryStart);
}
//*********************************************************************
// displayLevelHistory
//*********************************************************************
void Statistics::displayLevelHistory(const Player* viewer) {
bstring padding;
std::ostringstream oStr;
// set left aligned
oStr.setf(std::ios::right, std::ios::adjustfield);
oStr.imbue(std::locale(""));
oStr << "Leveling history times valid since ^C" << ctime(&levelHistoryStart) << "^x\n";
LevelInfo *lInfo;
for(LevelInfoMap::value_type p : levelHistory) {
lInfo = p.second;
time_t levelTime = lInfo->getLevelTime();
bstring levelTimeStr = ctime(&levelTime);
levelTimeStr.Remove('\n');
oStr << "Level ^C" << std::setfill('0') << std::setw(2) << lInfo->getLevel() << "^x Date: ^C" << levelTimeStr << "^x";
oStr << " Gains - HP: ^C" << std::setfill('0') << std::setw(2) << lInfo->getHpGain() << "^x MP: ^C";
oStr << std::setfill('0') << std::setw(2) << lInfo->getMpGain() << "^x Stat: ^C";
oStr << getStatName(lInfo->getStatUp()) << "^x Save: ^C" << getSaveName(lInfo->getSaveGain()) << "^x\n";
}
viewer->printColor("%s\n", oStr.str().c_str());
}
//*********************************************************************
// display
//*********************************************************************
void Statistics::display(const Player* viewer, bool death) {
bstring padding;
std::ostringstream oStr;
// set left aligned
oStr.setf(std::ios::left, std::ios::adjustfield);
oStr.imbue(std::locale(""));
if(death) {
// if death = true, player will always be the owner
oStr << "^WGeneral player statistics:^x\n"
<< " Level: ^C" << parent->getLevel() << "^x\n"
<< " Total Experience: ^C" << parent->getExperience() << "^x\n"
<< " Time Played: ^C" << parent->getTimePlayed() << "^x\n"
<< "\n";
}
oStr << "Tracking statistics since: ^C" << start << "\n";
if( numSwings ||
numDodges ||
numTimesHit ||
numTimesMissed ||
numDeaths ||
numKills ||
numPkIn
)
oStr << "^WCombat^x\n";
if(numSwings) {
oStr << " Swings: ^C" << numSwings << "^x\n";
if(numHits)
oStr << " Hits: ^C" << numHits << " (" << (numHits * 100 / numSwings) << "%)^x\n";
if(numMisses)
oStr << " Misses: ^C" << numMisses << " (" << (numMisses * 100 / numSwings) << "%)^x\n";
if(numFumbles)
oStr << " Fumbles: ^C" << numFumbles << " (" << (numFumbles * 100 / numSwings) << "%)^x\n";
if(numCriticals)
oStr << " Criticals: ^C" << numCriticals << " (" << (numCriticals * 100 / numSwings) << "%)^x\n";
}
if(numDodges)
oStr << " Dodges: ^C" << numDodges << "^x\n";
if(numTimesHit)
oStr << " Times Hit: ^C" << numTimesHit << "^x\n";
if(numTimesMissed)
oStr << " Times Missed: ^C" << numTimesMissed << "^x\n";
// Don't want to see this info after all
//if(numTimesFled)
// oStr << " Times Fled: ^C" << numTimesFled << "^x\n";
if(numDeaths)
oStr << " Deaths: ^C" << numDeaths << "^x\n";
if(numKills)
oStr << " Kills: ^C" << numKills << "^x\n";
if(numPkIn)
oStr << " Player kills: ^C" << numPkWon << "/" << numPkIn << " (" << (numPkWon * 100 / numPkIn) << "%)^x\n";
padding = (numTransmutes > 0 ? " " : "");
if( numCasts ||
numOffensiveCasts ||
numHealingCasts ||
numWandsUsed ||
numPotionsDrank ||
numTransmutes
)
oStr << "\n^WMagic^x\n";
if(numHealingCasts)
oStr << " Spells cast: ^C" << padding << numCasts << "^x\n";
if(numCasts) {
if(numOffensiveCasts)
oStr << " Offensive Spells: ^C" << numOffensiveCasts << " (" << (numOffensiveCasts * 100 / numCasts) << "%)^x\n";
if(numHealingCasts)
oStr << " Healing Spells: ^C" << numHealingCasts << " (" << (numHealingCasts * 100 / numCasts) << "%)^x\n";
}
if(numWandsUsed)
oStr << " Wands used: ^C" << padding << numWandsUsed << "^x\n";
if(numTransmutes)
oStr << " Wands transmuted: ^C" << padding << numTransmutes << "^x\n";
if(numPotionsDrank)
oStr << " Potions used: ^C" << padding << numPotionsDrank << "^x\n";
if( mostGroup ||
mostMonster.value ||
mostAttackDamage.value ||
mostMagicDamage.value
)
oStr << "\n^WMost / Largest^x\n";
if(mostGroup)
oStr << " Largest group: ^C" << mostGroup << "^x\n";
if(mostMonster.value)
oStr << " Toughest monster killed: ^C" << mostMonster.name << "^x\n";
if(mostExperience.value)
oStr << " Highest experience gained: ^C" << mostExperience.value << " from " << mostExperience.name << "^x\n";
if(mostAttackDamage.value)
oStr << " Most damage in one attack: ^C" << mostAttackDamage.value << " with " << mostAttackDamage.name << "^x\n";
if(mostMagicDamage.value)
oStr << " Most damage in one spell: ^C" << mostMagicDamage.value << " with " << mostMagicDamage.name << "^x\n";
if(expLost)
oStr << " Experience Lost: ^C" << expLost << "^x\n";
int rooms = parent->numDiscoveredRooms();
int numRecipes = parent->recipes.size();
if( (numThefts && numAttemptedThefts) ||
(numSaves && numAttemptedSaves) ||
numRecalls ||
numLagouts ||
numFishCaught ||
numItemsCrafted ||
numRecipes ||
numCombosOpened ||
rooms
)
oStr << "\n^WOther^x\n";
if(numThefts && numAttemptedThefts)
oStr << " Items stolen: ^C" << numThefts << "/" << numAttemptedThefts << " (" << (numThefts * 100 / numAttemptedThefts) << "%)^x\n";
if(numSaves && numAttemptedSaves)
oStr << " Saving throws made: ^C" << numSaves << "/" << numAttemptedSaves << " (" << (numSaves * 100 / numAttemptedSaves) << "%)^x\n";
if(numRecalls)
oStr << " Hazies/word-of-recalls used: ^C" << numRecalls << "^x\n";
if(numLagouts)
oStr << " Lagouts: ^C" << numLagouts << "^x\n";
if(numFishCaught)
oStr << " Fish caught: ^C" << numFishCaught << "^x\n";
if(numItemsCrafted)
oStr << " Items crafted: ^C" << numItemsCrafted << "^x\n";
if(numRecipes)
oStr << " Recipes known: ^C" << numRecipes << "^x\n";
if(numCombosOpened)
oStr << " Combinations opened: ^C" << numCombosOpened << "^x\n";
if(rooms)
oStr << " Special rooms discovered: ^C" << rooms << "^x\n";
viewer->printColor("%s\n", oStr.str().c_str());
}
//*********************************************************************
// calcToughness
//*********************************************************************
unsigned long Statistics::calcToughness(Creature* target) {
unsigned long t = 0;
if(target->isMonster()) {
const Monster* monster = target->getAsConstMonster();
t += target->hp.getMax();
t += target->getAttackPower();
t += target->getWeaponSkill();
t += target->getDefenseSkill();
// level is weighted
t += target->getLevel() * 2;
// only a percentage of their mana counts
t += (target->mp.getMax() * monster->getCastChance() / 100);
} else {
t = target->getLevel() * 10;
}
return(t);
}
//*********************************************************************
// damageWith
//*********************************************************************
bstring Statistics::damageWith(const Player* player, const Object* weapon) {
if(weapon)
return(weapon->getObjStr(NULL, INV | MAG, 1));
return((bstring)"your " + player->getUnarmedWeaponSkill() + "s");
}
//*********************************************************************
// pkDemographics
//*********************************************************************
unsigned long Statistics::pkDemographics() const {
if(numPkIn == numPkWon)
return(0);
return(pkRank());
}
//*********************************************************************
// getTime
//*********************************************************************
bstring Statistics::getTime() {
return(start);
}
//*********************************************************************
// save
//*********************************************************************
void Statistics::save(xmlNodePtr rootNode, bstring nodeName) const {
xmlNodePtr curNode = xml::newStringChild(rootNode, nodeName);
xml::newNumChild(curNode, "Track", track);
xml::saveNonNullString(curNode, "Start", start);
xml::saveNonZeroNum(curNode, "NumSwings", numSwings);
xml::saveNonZeroNum(curNode, "NumHits", numHits);
xml::saveNonZeroNum(curNode, "NumMisses", numMisses);
xml::saveNonZeroNum(curNode, "NumFumbles", numFumbles);
xml::saveNonZeroNum(curNode, "NumDodges", numDodges);
xml::saveNonZeroNum(curNode, "NumCriticals", numCriticals);
xml::saveNonZeroNum(curNode, "NumTimesHit", numTimesHit);
xml::saveNonZeroNum(curNode, "NumTimesMissed", numTimesMissed);
xml::saveNonZeroNum(curNode, "NumTimesFled", numTimesFled);
xml::saveNonZeroNum(curNode, "NumPkIn", numPkIn);
xml::saveNonZeroNum(curNode, "NumPkWon", numPkWon);
xml::saveNonZeroNum(curNode, "NumCasts", numCasts);
xml::saveNonZeroNum(curNode, "NumOffensiveCasts", numOffensiveCasts);
xml::saveNonZeroNum(curNode, "NumHealingCasts", numHealingCasts);
xml::saveNonZeroNum(curNode, "NumKills", numKills);
xml::saveNonZeroNum(curNode, "NumDeaths", numDeaths);
xml::saveNonZeroNum(curNode, "NumThefts", numThefts);
xml::saveNonZeroNum(curNode, "NumAttemptedThefts", numAttemptedThefts);
xml::saveNonZeroNum(curNode, "NumSaves", numSaves);
xml::saveNonZeroNum(curNode, "NumAttemptedSaves", numAttemptedSaves);
xml::saveNonZeroNum(curNode, "NumRecalls", numRecalls);
xml::saveNonZeroNum(curNode, "NumLagouts", numLagouts);
xml::saveNonZeroNum(curNode, "NumWandsUsed", numWandsUsed);
xml::saveNonZeroNum(curNode, "NumTransmutes", numTransmutes);
xml::saveNonZeroNum(curNode, "NumPotionsDrank", numPotionsDrank);
xml::saveNonZeroNum(curNode, "NumFishCaught", numFishCaught);
xml::saveNonZeroNum(curNode, "NumItemsCrafted", numItemsCrafted);
xml::saveNonZeroNum(curNode, "NumCombosOpened", numCombosOpened);
xml::saveNonZeroNum(curNode, "MostGroup", mostGroup);
xml::saveNonZeroNum(curNode, "ExpLost", expLost);
xml::saveNonZeroNum(curNode, "LastExpLoss", lastExpLoss);
mostMonster.save(curNode, "MostMonster");
mostAttackDamage.save(curNode, "MostAttackDamage");
mostMagicDamage.save(curNode, "MostMagicDamage");
mostExperience.save(curNode, "MostExperience");
xml::saveNonZeroNum(curNode, "LevelHistoryStart", levelHistoryStart);
xmlNodePtr historyNode = xml::newStringChild(curNode, "LevelHistory", "");
LevelInfoMap::const_iterator it;
for( it = levelHistory.begin() ; it != levelHistory.end() ; it++) {
(*it).second->save(historyNode);
}
// for(LevelInfoMap::value_type p : levelHistory) {
// p.second->save(historyNode);
// }
}
//*********************************************************************
// load
//*********************************************************************
void Statistics::load(xmlNodePtr curNode) {
xmlNodePtr childNode = curNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Track")) xml::copyToBool(track, childNode);
else if(NODE_NAME(childNode, "Start")) xml::copyToBString(start, childNode);
else if(NODE_NAME(childNode, "NumSwings")) xml::copyToNum(numSwings, childNode);
else if(NODE_NAME(childNode, "NumHits")) xml::copyToNum(numHits, childNode);
else if(NODE_NAME(childNode, "NumMisses")) xml::copyToNum(numMisses, childNode);
else if(NODE_NAME(childNode, "NumFumbles")) xml::copyToNum(numFumbles, childNode);
else if(NODE_NAME(childNode, "NumDodges")) xml::copyToNum(numDodges, childNode);
else if(NODE_NAME(childNode, "NumCriticals")) xml::copyToNum(numCriticals, childNode);
else if(NODE_NAME(childNode, "NumTimesHit")) xml::copyToNum(numTimesHit, childNode);
else if(NODE_NAME(childNode, "NumTimesMissed")) xml::copyToNum(numTimesMissed, childNode);
else if(NODE_NAME(childNode, "NumTimesFled")) xml::copyToNum(numTimesFled, childNode);
else if(NODE_NAME(childNode, "NumPkIn")) xml::copyToNum(numPkIn, childNode);
else if(NODE_NAME(childNode, "NumPkWon")) xml::copyToNum(numPkWon, childNode);
else if(NODE_NAME(childNode, "NumCasts")) xml::copyToNum(numCasts, childNode);
else if(NODE_NAME(childNode, "NumOffensiveCasts")) xml::copyToNum(numOffensiveCasts, childNode);
else if(NODE_NAME(childNode, "NumHealingCasts")) xml::copyToNum(numHealingCasts, childNode);
else if(NODE_NAME(childNode, "NumKills")) xml::copyToNum(numKills, childNode);
else if(NODE_NAME(childNode, "NumDeaths")) xml::copyToNum(numDeaths, childNode);
else if(NODE_NAME(childNode, "NumThefts")) xml::copyToNum(numThefts, childNode);
else if(NODE_NAME(childNode, "NumAttemptedThefts")) xml::copyToNum(numAttemptedThefts, childNode);
else if(NODE_NAME(childNode, "NumSaves")) xml::copyToNum(numSaves, childNode);
else if(NODE_NAME(childNode, "NumAttemptedSaves")) xml::copyToNum(numAttemptedSaves, childNode);
else if(NODE_NAME(childNode, "NumRecalls")) xml::copyToNum(numRecalls, childNode);
else if(NODE_NAME(childNode, "NumLagouts")) xml::copyToNum(numLagouts, childNode);
else if(NODE_NAME(childNode, "NumWandsUsed")) xml::copyToNum(numWandsUsed, childNode);
else if(NODE_NAME(childNode, "NumTransmutes")) xml::copyToNum(numTransmutes, childNode);
else if(NODE_NAME(childNode, "NumPotionsDrank")) xml::copyToNum(numPotionsDrank, childNode);
else if(NODE_NAME(childNode, "NumFishCaught")) xml::copyToNum(numFishCaught, childNode);
else if(NODE_NAME(childNode, "NumItemsCrafted")) xml::copyToNum(numItemsCrafted, childNode);
else if(NODE_NAME(childNode, "NumCombosOpened")) xml::copyToNum(numCombosOpened, childNode);
else if(NODE_NAME(childNode, "MostGroup")) xml::copyToNum(mostGroup, childNode);
else if(NODE_NAME(childNode, "MostMonster")) mostMonster.load(childNode);
else if(NODE_NAME(childNode, "MostAttackDamage")) mostAttackDamage.load(childNode);
else if(NODE_NAME(childNode, "MostMagicDamage")) mostMagicDamage.load(childNode);
else if(NODE_NAME(childNode, "MostExperience")) mostExperience.load(childNode);
else if(NODE_NAME(childNode, "ExpLost")) xml::copyToNum(expLost, childNode);
else if(NODE_NAME(childNode, "LastExpLoss")) xml::copyToNum(lastExpLoss, childNode);
else if(NODE_NAME(childNode, "LevelHistoryStart")) xml::copyToNum(levelHistoryStart, childNode);
else if(NODE_NAME(childNode, "LevelHistory")) {
xmlNodePtr infoNode = childNode->children;
while(infoNode) {
try {
LevelInfo *info = new LevelInfo(infoNode);
levelHistory.insert(LevelInfoMap::value_type(info->getLevel(), info));
} catch (...) {
}
infoNode = infoNode->next;
}
}
childNode = childNode->next;
}
}
//*********************************************************************
// swing
//*********************************************************************
void Statistics::swing() { if(track) numSwings++; }
//*********************************************************************
// hit
//*********************************************************************
void Statistics::hit() { if(track) numHits++; }
//*********************************************************************
// miss
//*********************************************************************
void Statistics::miss() { if(track) numMisses++; }
//*********************************************************************
// fumble
//*********************************************************************
void Statistics::fumble() { if(track) numFumbles++; }
//*********************************************************************
// dodge
//*********************************************************************
void Statistics::dodge() { if(track) numDodges++; }
//*********************************************************************
// critical
//*********************************************************************
void Statistics::critical() { if(track) numCriticals++; }
//*********************************************************************
// wasHit
//*********************************************************************
void Statistics::wasHit() { if(track) numTimesHit++; }
//*********************************************************************
// wasMissed
//*********************************************************************
void Statistics::wasMissed() { if(track) numTimesMissed++; }
//*********************************************************************
// flee
//*********************************************************************
void Statistics::flee() { if(track) numTimesFled++; }
//*********************************************************************
// winPk
//*********************************************************************
// because these two stats are older, they're always tracked
void Statistics::winPk() { numPkIn++; numPkWon++; }
//*********************************************************************
// losePk
//*********************************************************************
void Statistics::losePk() { numPkIn++; }
//*********************************************************************
// cast
//*********************************************************************
void Statistics::cast() { if(track) numCasts++; }
//*********************************************************************
// offensiveCast
//*********************************************************************
void Statistics::offensiveCast() { if(track) numOffensiveCasts++; }
//*********************************************************************
// healingCast
//*********************************************************************
void Statistics::healingCast() { if(track) numHealingCasts++; }
//*********************************************************************
// kill
//*********************************************************************
void Statistics::kill() { if(track) numKills++; }
//*********************************************************************
// die
//*********************************************************************
void Statistics::die() { if(track) numDeaths++; }
//*********************************************************************
// experienceLost
//*********************************************************************
void Statistics::experienceLost(unsigned long amt) {
// We only track the total if they're tracking statistics
if (track)
expLost += amt;
// However, we always track the last exp loss (For resurrect)
lastExpLoss = amt;
}
void Statistics::setExperienceLost(unsigned long amt) {
expLost = amt;
}
//*********************************************************************
// steal
//*********************************************************************
void Statistics::steal() { if(track) numThefts++; }
//*********************************************************************
// attemptSteal
//*********************************************************************
void Statistics::attemptSteal() { if(track) numAttemptedThefts++; }
//*********************************************************************
// save
//*********************************************************************
void Statistics::save() { if(track) numSaves++; }
//*********************************************************************
// attemptSave
//*********************************************************************
void Statistics::attemptSave() { if(track) numAttemptedSaves++; }
//*********************************************************************
// recall
//*********************************************************************
void Statistics::recall() { if(track) numRecalls++; }
//*********************************************************************
// lagout
//*********************************************************************
void Statistics::lagout() { if(track) numLagouts++; }
//*********************************************************************
// wand
//*********************************************************************
void Statistics::wand() { if(track) numWandsUsed++; }
//*********************************************************************
// transmute
//*********************************************************************
void Statistics::transmute() { if(track) numTransmutes++; }
//*********************************************************************
// potion
//*********************************************************************
void Statistics::potion() { if(track) numPotionsDrank++; }
//*********************************************************************
// fish
//*********************************************************************
void Statistics::fish() { if(track) numFishCaught++; }
//*********************************************************************
// craft
//*********************************************************************
void Statistics::craft() { if(track) numItemsCrafted++; }
//*********************************************************************
// combo
//*********************************************************************
void Statistics::combo() { if(track) numCombosOpened++; }
//*********************************************************************
// group
//*********************************************************************
void Statistics::group(unsigned long num) { if(track) mostGroup = MAX(num, mostGroup); }
//*********************************************************************
// monster
//*********************************************************************
void Statistics::monster(Monster* monster) {
if(!track || monster->isPet())
return;
mostMonster.update(calcToughness(monster), monster->getCName());
}
//*********************************************************************
// experience
//*********************************************************************
void Statistics::experience(unsigned long num, bstring with) {
if(track) mostExperience.update(num, with);
}
//*********************************************************************
// attackDamage
//*********************************************************************
void Statistics::attackDamage(unsigned long num, bstring with) {
if(track) mostAttackDamage.update(num, with);
}
//*********************************************************************
// magicDamage
//*********************************************************************
void Statistics::magicDamage(unsigned long num, bstring with) {
if(track) mostMagicDamage.update(num, with);
}
//*********************************************************************
// setParent
//*********************************************************************
void Statistics::setParent(Player* player) { parent = player; }
//*********************************************************************
// pkRank
//*********************************************************************
// This function returns the rank of the player based on how many
// pkills they has been in, and how many they have won
unsigned long Statistics::pkRank() const {
if(!numPkWon || !numPkIn)
return(0);
return(numPkWon * 100 / numPkIn);
}
//*********************************************************************
// getPkin
//*********************************************************************
unsigned long Statistics::getPkin() const { return(numPkIn); }
//*********************************************************************
// getPkwon
//*********************************************************************
unsigned long Statistics::getPkwon() const { return(numPkWon); }
//*********************************************************************
// getLostExperience
//*********************************************************************
unsigned long Statistics::getLostExperience() const { return(expLost); }
//*********************************************************************
// getLastExperienceLoss
//*********************************************************************
unsigned long Statistics::getLastExperienceLoss() const { return(lastExpLoss); }
//*********************************************************************
// setPkin
//*********************************************************************
// remove when all players are up to 2.42i
void Statistics::setPkin(unsigned long p) { numPkIn = p; }
//*********************************************************************
// setPkwon
//*********************************************************************
void Statistics::setPkwon(unsigned long p) { numPkWon = p; }
//*********************************************************************
// cmdLevelHistory
//*********************************************************************
int cmdLevelHistory(Player* player, cmd* cmnd) {
Player* target = player;
bool online=true;
if(player->isDm() && cmnd->num > 1) {
cmnd->str[1][0] = up(cmnd->str[1][0]);
target = gServer->findPlayer(cmnd->str[1]);
if(!target) {
loadPlayer(cmnd->str[1], &target);
online = false;
// If the player is offline, init() won't be run and the statistics object won't
// get its parent set. Do so now.
if(target)
target->statistics.setParent(target);
}
if(!target) {
player->print("That player does not exist.\n");
return(0);
}
player->printColor("^W%s's Level History\n", target->getCName());
}
target->statistics.displayLevelHistory(player);
if(!online)
free_crt(target);
return(0);
}
//*********************************************************************
// cmdStatistics
//*********************************************************************
int cmdStatistics(Player* player, cmd* cmnd) {
Player* target = player;
bool online=true;
if(!strcmp(cmnd->str[1], "reset")) {
player->statistics.reset();
player->print("Your statistics have been reset.\n");
player->print("Note that player kill statistics are always tracked and cannot be reset.\n");
return(0);
}
if(player->isDm() && cmnd->num > 1) {
cmnd->str[1][0] = up(cmnd->str[1][0]);
target = gServer->findPlayer(cmnd->str[1]);
if(!target) {
loadPlayer(cmnd->str[1], &target);
online = false;
// If the player is offline, init() won't be run and the statistics object won't
// get its parent set. Do so now.
if(target)
target->statistics.setParent(target);
}
if(!target) {
player->print("That player does not exist.\n");
return(0);
}
player->printColor("^W%s's Statistics\n", target->getCName());
}
target->statistics.display(player);
if(target == player) {
*player << ColorOn << "You may type ^Wstats reset^x to reset your statistic counts to zero.\n" << ColorOff;
*player << "You may use the set, clear, and toggle commands to control tracking of statistics.\n";
}
if(!online)
free_crt(target);
return(0);
}