/* /daemon/race.c
* from the Dead Souls Object Library
* handles race configuration and administration
* created by Descartes of Borg 960108
* Version: @(#) races.c 1.4@(#)
* Last modified: 96/11/10
*/
#include <lib.h>
#include <save.h>
#include <privs.h>
#include "include/races.h"
inherit LIB_DAEMON;
private mapping Races = ([]);
static private mapping Resistances = ([]);
static private mapping Armours = ([]);
static void create() {
string array lines;
daemon::create();
if( unguarded((: file_size(SAVE_RACES __SAVE_EXTENSION__) :)) > 0 )
unguarded((: restore_object(SAVE_RACES) :));
if( !Races ) Races = ([]);
// Hocus pocus to load armour and resistance info
lines = explode(read_file("/include/armour_types.h"), "\n");
foreach(string line in lines) {
string type;
if( sscanf(line, "#define %s %*s", type) == 2 ) {
string file = DIR_DAEMONS "/tmp/" + type + ".c";
if( type == "A_MAX_ARMOUR_BIT" ) {
continue;
}
if( !file_exists(file) ) {
unguarded((: write_file($(file), "#include <armour_types.h>\n"
"int armour() { return " +
$(type) + "; }\n") :));
}
Armours[type] = call_other(file, "armour");
}
}
lines = explode(read_file("/include/damage_types.h"), "\n");
foreach(string line in lines) {
string type;
if( sscanf(line, "#define %s %*s", type) == 2 ) {
string file = DIR_DAEMONS "/tmp/" + type + ".c";
if( type == "MAX_DAMAGE_BIT" ) {
continue;
}
if( !file_exists(file) ) {
unguarded((: write_file($(file), "#include <damage_types.h>\n"
"int damage() { return " +
$(type) + "; }\n") :));
}
Resistances[type] = call_other(file, "damage");
}
}
}
static private void validate() {
if( !((int)master()->valid_apply(({ PRIV_ASSIST }))) )
error("Illegal attempt to modify race data");
}
void AddRace(string file, int player) {
class Race res;
string array lines, tmp;
string race;
validate();
if( !file_exists(file) ) error("No such file: " + file);
lines = explode(read_file(file), "\n");
lines = filter(lines, function(string str) {
if( strlen(str) == 0 ) {
return 0;
}
if( str[0] == '#' ) {
return 0;
}
if( str[0] == ' ' || str[0] == '\t' ) {
return 0;
}
return 1;
});
race = lines[0];
if( Races[race] ) error("Race already exists");
res = new(class Race);
res->Sensitivity = map(explode(lines[1], ":"), (: to_int :));
res->Language = lines[2];
lines = lines[3..];
res->Resistance = ([]);
while(sizeof(tmp = explode(lines[0], ":")) == 2) {
int x = to_int(tmp[0]);
if( x == 0 && tmp[0] != "0" ) x = GetResistance(tmp[0]);
res->Resistance[x] = tmp[1];
lines = lines[1..];
}
res->Stats = ([]);
while(sizeof(tmp = explode(lines[0], ":")) == 3) {
class Stat s = new (class Stat);
s->Average = to_int(tmp[1]);
s->Class = to_int(tmp[2]);
res->Stats[tmp[0]] = s;
lines = lines[1..];
}
res->Limbs = ({});
while(sizeof(tmp = explode(lines[0], ":")) == 4) {
mixed array limb = allocate(4);
limb[0] = tmp[0];
limb[1] = (tmp[1] == "0" ? 0 : tmp[1]);
limb[2] = to_int(tmp[2]);
limb[3] = map(explode(tmp[3], ","), function(string str) {
int x = to_int(str);
if( x == 0 && str != "0" )
return GetArmour(str);
return x;
});
res->Limbs = ({ res->Limbs..., limb });
if( sizeof(lines) > 1 ) lines = lines[1..];
else {
lines = ({});
break;
}
}
res->Fingers = ([]);
if( sizeof(lines) ) {
foreach(string hand in lines) {
string array parts = explode(hand, ":");
res->Fingers[parts[0]] = to_int(parts[1]);
}
}
res->Complete = 1;
if( player ) {
res->PlayerFlag = 1;
}
else {
res->PlayerFlag = 0;
}
Races[race] = res;
save_object(SAVE_RACES);
}
void RemoveRace(string race) {
validate();
map_delete(Races, race);
save_object(SAVE_RACES);
}
int GetArmour(string str) {
string file = DIR_DAEMONS "/tmp/" + str + ".c";
if( !unguarded((: file_exists($(file)) :)) ) {
unguarded((: write_file($(file), "#include <armour_types.h>\n" +
"int armour() { return " + $(str) + "; }\n") :));
}
return call_other(file, "armour");
}
int GetResistance(string str) {
string file = DIR_DAEMONS "/tmp/" + str + ".c";
if( !unguarded((: file_exists($(file)) :)) ) {
unguarded((: write_file($(file), "#include <damage_types.h>\n" +
"int damage() { return " + $(str) + "; }\n") :));
}
return call_other(file, "damage");
}
mapping GetRemoteRaces() {
mapping mp = ([]);
foreach(string race, class Race res in Races) {
mapping stats = ([]);
mp[race] = ([]);
mp[race]["limbs"] = res->Limbs;
mp[race]["resistance"] = res->Resistance;
foreach(string stat, class Stat st in res->Stats) {
stats[stat] = ([]);
stats[stat]["class"] = st->Class;
stats[stat]["average"] = st->Average;
}
mp[race]["stats"] = stats;
mp[race]["fingers"] = res->Fingers;
mp[race]["sensitivity"] = res->Sensitivity;
mp[race]["player"] = res->PlayerFlag;
mp[race]["language"] = res->Language;
}
return mp;
}
void SetComplete(string race) {
class Race res;
validate();
if( !Races[race] ) error("No such race");
else res = Races[race];
res->Complete = 1;
save_object(SAVE_RACES);
}
void SetLightSensitivity(string race, int array sensitivity) {
class Race res;
validate();
if( !Races[race] ) error("No such race");
else res = Races[race];
if( sensitivity[0] < 1 ) error("Invalid sensitivity value");
if( sensitivity[1] > 99 ) error("Invalid sensitivity value");
if( sensitivity[0] > sensitivity[1] ) error("Invalid sensitivity value");
res->Sensitivity = sensitivity;
save_object(SAVE_RACES);
}
void SetCharacterLimbs(string race, mixed array args) {
class Race res = Races[race];
mixed array tmp = ({});
if( !res || !res->Complete || sizeof(args) != 2 ) return;
args[0] = copy(res->Limbs);
foreach(string finger, int count in res->Fingers)
tmp = ({ tmp..., ({ finger, count }) });
args[1] = tmp;
}
void SetCharacterRace(string race, mixed array args) {
class Race res = Races[race];
mixed array tmp;
if( !res || !res->Complete || sizeof(args) != 4 ) return;
tmp = ({});
foreach(int key, string val in res->Resistance)
tmp = ({ tmp..., ({ key, val }) });
args[0] = tmp;
tmp = ({});
foreach(string key, class Stat stat in res->Stats)
tmp = ({ tmp..., ({ key, stat->Average, stat->Class }) });
args[1] = tmp;
args[2] = res->Language;
args[3] = ({ res->Sensitivity[0], res->Sensitivity[1] });
}
varargs string array GetRaces(int player_only) {
return filter(keys(Races), function(string race, int player_only) {
class Race res = Races[race];
if( !res->Complete ) return 0;
if( player_only && !res->PlayerFlag )
return 0;
return 1;
}, player_only);
}
string GetHelp(string race) {
class Race res = Races[race];
string array limbs;
string help = "Race: " + race + "\n\n";
string tmp;
int x;
if( !res ) return 0;
limbs = map(res->Limbs, (: $1[0] :));
help += "Limbs:\n";
help += capitalize(item_list(map(limbs, (: add_article :)))) + ".\n";
help += "\nFingered limbs:\n";
foreach(string finger, int count in res->Fingers)
help += "\t" + finger + " (" + count + ")\n";
limbs = regexp(limbs, ".* wing");
if( sizeof(limbs) ) {
help += "\nFlying\n";
}
else {
help += "\nNon-flying\n";
}
x = res->Sensitivity[0];
if( x < 11 ) tmp = "excellent";
else if( x < 16 ) tmp = "above average";
else if( x < 21 ) tmp = "good";
else if( x < 26 ) tmp = "average";
else if( x < 31 ) tmp = "below average";
else if( x < 36 ) tmp = "very poor";
else tmp = "extremely poor";
help += "\nNight vision: " + tmp + "\n";
x = res->Sensitivity[1];
if( x < 61 ) tmp = "extremely poor";
else if( x < 66 ) tmp = "very poor";
else if( x < 71 ) tmp = "below average";
else if( x < 76 ) tmp = "average";
else if( x < 81 ) tmp = "good";
else if( x < 86 ) tmp = "above average";
else tmp = "excellent";
help += "Day vision: " + tmp + "\n\n";
return help;
}
public mapping GetResistances() {
return copy(Resistances);
}
public mapping GetArmours() {
return copy(Armours);
}