// NPC statistic tracker for FR-Mud
// Radix - April 6, 1996
// Version 1.7
#include "timestuff.h"
#include "XP_adjust.h"
/* The data mappings...
([ "directory of death room" :
([ "filename" : ({
kills,
levels killed,
total xp killed/100,
last kill,
time averaged,
killed,
level killed by,
total xp killed/100 by,
xp awarded
lasted killed,
time averaged,
kill xp
}) ])
])
*/
inherit "/std/object.c";
#define SAVE "/save/"
#define PKHAND "/obj/handlers/pk"
mapping data;
int totaldif,diftimes;
void reset_screw_rate() {
totaldif = 0;
diftimes = 0;
}
int query_screw_rate() {
int num = diftimes;
int dif = totaldif;
write(num+"\n");
if(num > 20000) reset_screw_rate();
if(num <= 0) return 1; // Taniwha
return dif/num;
}
int query_number_screwed() { return diftimes; }
mapping query_data() { return data; }
void load_this_ob() {
if(!m_sizeof(data))
restore_object(SAVE+"death");
}
void save_this_ob() {
if(m_sizeof(data))
save_object(SAVE+"death",1);
}
create()
{
::create();
data = ([ ]);
load_this_ob();
}
void dest_me()
{
save_this_ob();
destruct(this_object());
}
string crop_string(string longpa, int howlong) {
string shorter;
shorter = longpa[sizeof(longpa)-howlong..sizeof(longpa)];
return shorter;
}
string environment_path(object obj)
{
string fname = file_name(environment(obj));
string *dom = explode(fname,"/");
dom -= ({ dom[sizeof(dom)-1] });
return implode(dom,"/");
}
mapping query_npcstats() {
load_this_ob();
return data;
}
mapping query_domain_npcstats( string dom ) {
load_this_ob();
if(data[dom]) return data[dom];
return 0;
}
mixed *query_npc_stat( string dom, string pathname ) {
load_this_ob();
if(data[dom]) {
if(data[dom][pathname]) return data[dom][pathname];
}
return 0;
}
void full_path_report(string dom) {
int i,j;
string outgoing;
string *indic;
load_this_ob();
outgoing = "\nfilename kills lvkls xpkls lakil tiavg killd lvkby "
"xpkb xpaw lakld tiavg kxp\n";
outgoing += "(XP in units of 100, time in player minutes)\n\n";
if(data[dom]) {
indic = m_indices(data[dom]);
for(i=0;i<m_sizeof(data[dom]);i++) {
outgoing += crop_string(indic[i],10)+" ";
for(j=0;j<sizeof(data[dom][indic[i]]);j++) {
outgoing += data[dom][indic[i]][j]+" ";
}
outgoing += "\n";
}
outgoing += "\n";
this_player()->more_string(outgoing);
}
}
void killed_awarded_ratio(string dom) {
int i,j;
int killed,kt,awarded,at;
float ratio;
string outgoing;
string *indic;
load_this_ob();
outgoing = "\nEnd of filename player xp killed / xp awarded \n";
outgoing += "(player xp in units of 100)\n\n";
if(data[dom]) {
indic = m_indices(data[dom]);
for(i=0;i<m_sizeof(data[dom]);i++) {
killed = data[dom][indic[i]][2];
awarded = data[dom][indic[i]][8];
kt+=killed;
at+=awarded;
outgoing += crop_string(indic[i],30)+" ";
if(awarded)
outgoing += (killed+0.0)/(awarded+0.0)+"\n";
else
outgoing += killed+" killed, never been killed.\n";
}
outgoing += "\nTOTAL "+(kt+0.0)/(at+0.0)+"\n\n";
this_player()->more_string(outgoing);
}
}
void full_domain_kar(string realdom) {
int i,j;
int killed,kt,awarded,at;
int tim, timt, timtt, time_now;
int ktt,att;
float ratio;
string dom, outgoing;
string *indic;
string *ind;
string *tmp;
load_this_ob();
time_now = TIMEKEEPER->query_running_time()/60.0;
outgoing = "\nDirectory pc xp killed/xp award awarded rate\n";
outgoing += "(player xp in units of 100, time in player hours)\n\n";
if(!mappingp(data)) data = ([ ]); // Taniwha
ind = m_indices(data);
for(i=0;i<sizeof(ind);i++) {
tmp = explode(ind[i],"/");
if(sizeof(tmp) < 2) continue;
if(tmp[1] == realdom) {
dom = ind[i];
indic = m_indices(data[dom]);
if(!m_sizeof(data[dom])) {
data = m_delete(data,data[dom]);
continue;
}
for(j=0;j<m_sizeof(data[dom]);j++) {
killed = data[dom][indic[j]][2];
awarded = data[dom][indic[j]][8];
if(((time_now - data[dom][indic[j]][3]) > BASE_WEEK/30.0
&& (time_now - data[dom][indic[j]][9]) > BASE_WEEK/30.0)
|| (time_now - data[dom][indic[j]][3]) < 0.0
|| (time_now - data[dom][indic[j]][9]) < 0.0)
{
data[dom] = m_delete(data[dom],indic[j]);
continue;
}
tim = data[dom][indic[j]][10];
if(tim > timt) timt = tim;
kt+=killed;
at+=awarded;
}
if(dom)
dom = dom[strlen(realdom)+3..1000]+"/";
if(at)
outgoing += sprintf("%-35s %15.4f ", dom, ((kt+0.0) / (at+0.0)));
else
outgoing += sprintf("%-35s %15.4f ", dom, 0.0);
if(timt)
outgoing += sprintf("%15.4f\n", ((at+0.0) * 60.0) / (timt+0.0));
else
outgoing += sprintf("%15.4f\n", 0.0);
ktt += kt;
att += at;
if(timt > timtt) timtt = timt;
at = 0;
kt = 0;
timt = 0;
}
}
if(att)
outgoing += "\nTOTAL "+(ktt+0.0)/(att+0.0)+" ";
if(timtt) outgoing += (att+0.0)*60.0/(timtt+0.0)+"\n";
else outgoing += " NKTT";
this_player()->more_string(outgoing);
}
void original_radix_data(string dom) {
int i,j;
int died,dt,kills,kt,timd,tmdt,timk,tmkt,levd,ldt,levk,lkt,xpd,
xdt,xpk,xkt,awded,awdt;
float ratio;
string outgoing;
string *indic;
load_this_ob();
outgoing = "\nfilename freqdied freqkills avglevd avglevk avgxpd"
" avgxpk rateawarded\n";
outgoing += "(player xp in units of 100, time in player hours)\n\n";
if(data[dom]) {
indic = m_indices(data[dom]);
for(i=0;i<m_sizeof(data[dom]);i++) {
died = data[dom][indic[i]][5];
dt += died;
kills = data[dom][indic[i]][0];
kt += kills;
timd = data[dom][indic[i]][10];
if(timd > tmdt) tmdt = timd;
timk = data[dom][indic[i]][4];
if(timk > tmkt) tmkt = timk;
levd = data[dom][indic[i]][6];
ldt += levd;
levk = data[dom][indic[i]][1];
lkt += levk;
xpd = data[dom][indic[i]][7];
xdt += xpd;
xpk = data[dom][indic[i]][2];
xkt += xpk;
awded = data[dom][indic[i]][8];
awdt += awded;
outgoing += crop_string(indic[i],20);
if(timd) outgoing += " "+(died+0.0)*60.0/(timd+0.0);
else outgoing += " NTD";
if(timk) outgoing += " "+(kills+0.0)*60.0/(timk+0.0);
else outgoing += " NTK";
if(died) outgoing += " "+(levd+0.0)/(died+0.0);
else outgoing += " ND";
if(kills) outgoing += " "+(levk+0.0)/(kills+0.0);
else outgoing += " NK";
if(died) outgoing += " "+(xpd+0.0)/(died+0.0);
else outgoing += " ND";
if(kills) outgoing += " "+(xpk+0.0)/(kills+0.0);
else outgoing += " NK";
if(timd) outgoing += " "+(awded+0.0)*60.0/(timd+0.0);
else outgoing += " NTD";
outgoing += "\n";
}
outgoing += "\nTOTAL";
if(tmdt) outgoing += " "+(dt+0.0)*60.0/(tmdt+0.0);
else outgoing += " NTD";
if(tmkt) outgoing += " "+(kt+0.0)*60.0/(tmkt+0.0);
else outgoing += " NTK";
if(dt) outgoing += " "+(ldt+0.0)/(dt+0.0);
else outgoing += " ND";
if(kt) outgoing += " "+(lkt+0.0)/(kt+0.0);
else outgoing += " NK";
if(dt) outgoing += " "+(xdt+0.0)/(dt+0.0);
else outgoing += " ND";
if(kt) outgoing += " "+(xkt+0.0)/(kt+0.0);
else outgoing += " NK";
if(tmdt) outgoing += " "+(awdt+0.0)*60.0/(tmdt+0.0);
else outgoing += " NTD";
outgoing += "\n\n";
this_player()->more_string(outgoing);
}
}
float get_real_rate(mixed vals, object npc)
{
float rateret;
if(sizeof(vals) < 12)
return -1;
if(vals[5] && vals[6] / vals[5] < 4) return -1;
if(vals[10] < BASE_WEEK/60 && vals[7] < 1000000000) return -1;
if (!vals[8]) {
if (vals[2]) return MAX_XP_BON;
else return -1;
}
rateret = (vals[2]+0.0)/(vals[8]+0.0)/BASE_KAR;
if(rateret*vals[11] > npc->query_level()*60*MAX_XP_BON)
rateret = MAX_XP_BON*(npc->query_level()+0.0)*60.0/(vals[11]+0.0);
if(rateret*vals[11] < npc->query_level()*60*MAX_XP_PEN)
{
rateret = MAX_XP_PEN*(npc->query_level()+0.0)*60.0/(vals[11]+0.0);
if(rateret > 1.0) rateret = 1.0;
}
return rateret;
}
float update_npc_died(object npc, object player)
{
mixed vals;
mapping tmp;
string domname, obname;
int i, temp;
int time_now, time_since, total_time, time_extra;
float rateret;
if(!(obname = real_filename(npc)))
return 1;
if(!(domname = environment_path(npc)))
return 1;
load_this_ob();
tmp = data[domname];
if(!tmp)
tmp = ([ ]);
vals = tmp[obname];
if(!vals) vals = ({0,0,0,0,0,0,0,0,0,0,0,0});
if(!(player->query_creator()) &&
strsrch(player->query_name(),"test") == -1) {
time_now = TIMEKEEPER->query_running_time()/60.0;
if(!vals[9]) vals[9] = time_now;
time_since = time_now - vals[9];
if(time_since < 0) time_since = 0;
if(time_since > BASE_WEEK/30.0) {
vals[5]=0;
vals[6]=0;
vals[7]=0;
vals[8]=0;
vals[9]=time_now;
vals[10]=time_since;
}
else {
total_time = vals[10]+time_since;
if(total_time > BASE_WEEK/30.0) {
time_extra = total_time - BASE_WEEK/30.0;
temp = vals[5]*((vals[10]-time_extra)*10.0/vals[10])/10;
vals[5] = temp;
temp = vals[6]*((vals[10]-time_extra)*10.0/vals[10])/10;
vals[6] = temp;
temp = vals[7]*((vals[10]-time_extra)*10.0/vals[10])/10;
vals[7] = temp;
temp = vals[8]*((vals[10]-time_extra)*10.0/vals[10])/10;
vals[8] = temp;
temp = BASE_WEEK/30.0;
vals[10] = temp;
}
else vals[10] = total_time;
vals[9] = time_now;
}
if(vals[10] < 0) vals[10] = BASE_WEEK/30;
vals[5] += 1;
vals[6] += player->query_level();
vals[7] += player->query_total_xp()/100;
vals[11] = npc->query_kill_xp();
vals[8] += vals[11];
if(vals[7] > 2000000000) {
temp=vals[5]*2000000000.0/vals[7];
vals[5]=temp;
temp=vals[6]*2000000000.0/vals[7];
vals[6] = temp;
temp=vals[8]*2000000000.0/vals[7];
vals[8] = temp;
temp=vals[10]*2000000000.0/vals[7];;
vals[10] = temp;
vals[7]=2000000000;
}
tmp[obname] = vals;
data[domname] = tmp;
save_this_ob();
}
// Made seperate function for other purposes - Radix
rateret = get_real_rate(vals, npc);
if(rateret == -1)
return 1.0;
if(!(player->query_creator()) &&
strsrch(player->query_name(),"test") == -1) {
totaldif += rateret*vals[11]-(npc->query_level()*60);
diftimes += 1;
}
if(rateret) return rateret;
return 1.0;
}
// Called from /global/creator/cmds/info.c
void info_npc(object npc)
{
mixed vals;
mapping tmp;
float rateret;
string domname, obname;
if(!(obname = real_filename(npc)) || !(domname = environment_path(npc)))
{
write("Invalid NPC object filename or environment path.\n");
return 0;
}
tmp = data[domname];
if(!tmp)
{
write("No data for NPC in this environment.\n");
return 0;
}
vals = tmp[obname];
rateret = get_real_rate(vals, npc);
if(rateret == -1)
rateret = 1.0;
write("Info Data for NPC: "+npc->query_short()+"\n");
write("Filename: "+obname+"\n");
write("Environment: "+domname+"\n");
write("----------------------------------------\n");
write("Kill xp: "+npc->query_kill_xp()+"\n");
write("Rate Return: "+rateret+"\n");
write("Total: "+npc->query_kill_xp() * rateret+"\n");
return;
}
void update_player_died(object npc, object player)
{
mixed vals;
mapping tmp;
string domname, obname;
int i, temp;
int time_now, time_since, total_time, time_extra;
if(player->query_creator() ||
strsrch(player->query_name(),"test") != -1) return;
if(!(obname = real_filename(npc)))
return;
if(!(domname = environment_path(npc)))
return;
load_this_ob();
tmp = data[domname];
if(!tmp)
tmp = ([ ]);
vals = tmp[obname];
if(!vals) vals = ({0,0,0,0,0,0,0,0,0,0,0,0});
time_now = TIMEKEEPER->query_running_time()/60.0;
if(!vals[3]) vals[3] = time_now;
time_since = time_now - vals[3];
if(time_since < 0) time_since = 0;
if(time_since > BASE_WEEK/30.0) {
vals[0]=0;
vals[1]=0;
vals[2]=0;
vals[3]=time_now;
vals[4]=time_since;
}
else {
total_time = vals[4]+time_since;
if(total_time > BASE_WEEK/30.0) {
time_extra = total_time - BASE_WEEK/30.0;
temp = vals[0]*((vals[4]-time_extra)*10.0/vals[4])/10;
vals[0] = temp;
temp = vals[1]*((vals[4]-time_extra)*10.0/vals[4])/10;
vals[1] = temp;
temp = vals[2]*((vals[4]-time_extra)*10.0/vals[4])/10;
vals[2] = temp;
temp = BASE_WEEK/30.0;
vals[4] = temp;
}
else vals[4] = total_time;
vals[3] = time_now;
}
if(vals[4] < 0) vals[4] = BASE_WEEK/30;
vals[0] += 1;
vals[1] += player->query_level();
vals[2] += player->query_total_xp()/100;
vals[11] = npc->query_kill_xp();
tmp[obname] = vals;
data[domname] = tmp;
save_this_ob();
return;
}
void domain_death(object victim, object enemy)
{
string *path = explode(file_name(environment(victim)),"/");
mixed mas;
if(sizeof(path) < 2 || (path[0] != "d" && path[0] != "w"))
return;
mas = "/"+path[0]+"/"+path[1]+"/master";
catch(mas->domain_death(victim, enemy));
}
void mud_death(object victim, object enemy)
{
string *path = explode(file_name(environment(victim)),"/");
mixed mas;
string *doms = get_dir("/d/");
int i;
for(i=0; i<sizeof(doms); i++)
{
mas = "/d/"+doms[i]+"/master";
catch(mas->mud_death(victim, enemy));
}
return;
}
float update_statistics(object victim, object enemy)
{
string create_name;
if(enemy && victim)
{
if(environment(enemy) && environment(victim))
{
domain_death(victim, enemy);
mud_death(victim, enemy);
}
if(interactive(victim) && enemy->query_npc()) {
update_player_died(enemy, victim);
return 1;
}
create_name = victim->query_create_me();
if(victim->query_npc() && interactive(enemy)) {
if(!enemy->query_creator())
if(create_name != "Object" && create_name != "Root")
log_file("CREATE_ME",real_filename(victim)+
" ["+victim->query_create_me()+"] killed by "+
enemy->query_cap_name()+" for "+
victim->query_kill_xp()+" :"+ctime(time())+"\n");
return update_npc_died(victim, enemy);
}
// PKing...
if(interactive(victim) && interactive(enemy))
catch(PKHAND->update_player_killed(victim, enemy));
}
return 1;
}