/* * $Id: btechstats.c,v 1.8 2005/06/27 19:27:30 gregtaylor Exp $ * * Author: Markus Stenberg <fingon@iki.fi> * * Copyright (c) 1996 Markus Stenberg * Copyright (c) 1998-2002 Thomas Wouters * Copyright (c) 2000-2002 Cord Awtry * Copyright (c) 1999-2005 Kevin Stevens * All rights reserved * * Last modified: Tue Sep 8 09:54:45 1998 fingon * */ /* Mostly rewritten btech stat routines, only calling scheme is same. */ #include "config.h" #include <stdio.h> #include <math.h> #define BTECHSTATS #include "mech.h" #include "coolmenu.h" #include "mycool.h" #include "mech.events.h" #define BTECHSTATS_C #include "btmacros.h" #include "btechstats.h" #include "mux_tree.h" #include "htab.h" #include "create.h" #include "muxevent.h" #include "glue.h" #include "p.mechfile.h" #include "p.mech.utils.h" #include "p.mech.partnames.h" #include "p.mech.update.h" #include "p.bsuit.h" #include "p.map.obj.h" #include "p.mech.combat.h" #include "p.mech.combat.misc.h" #include "p.mech.pickup.h" #include "p.mech.tag.h" #include "p.functions.h" Tree skill_tree = NULL; extern dbref pilot_override; dbref cached_target_char = -1; int cached_skill; int cached_result; extern char *get_uptime_to_string(int); static int char_xp_bonus(PSTATS * s, int code); static int char_getstatvalue(PSTATS * s, char *name); static PSTATS *retrieve_stats(dbref player, int modes); static void clear_player(PSTATS * s); static void store_stats(dbref player, PSTATS * s, int modes); char *silly_get_uptime_to_string(int i) { static char buf[MBUF_SIZE]; char *c; c = get_uptime_to_string(i); strcpy(buf, c); free_sbuf(c); return buf; } static int char_getskilltargetbycode_base(dbref player, PSTATS * s, int code, int modifier, int use_xp); static int char_getskilltargetbycode_noxp(dbref player, int code, int modifier); static int figure_xp_bonus(dbref player, PSTATS * s, int code) { int t = char_values[code].xpthreshold; int tx, bon, btar; if (t <= 0) return 0; /* KLUDGE */ s->xp[code] = s->xp[code] % XP_MAX; /* reset exp modifier - this probably _was_ cached */ btar = char_getskilltargetbycode_base(player, s, code, 0, 0); while (btar > 4) { btar--; t = t / 3; } while (btar < 4) { btar++; t = t * 3; } if (t < 1) t = 1; tx = s->xp[code] % XP_MAX; bon = 0; while (tx > t) { bon++; tx -= t; t = t * 3; } return bon; } static int figure_xp_to_next_level(dbref target, int code) { int xpthresh = char_values[code].xpthreshold; int start_skill, target_skill, counter, running_total = 1; if (xpthresh <= 0) return -1; target_skill = char_getskilltargetbycode(target, code, 0); start_skill = char_getskilltargetbycode_noxp(target, code, 0); counter = start_skill; while (counter > 4) { counter--; xpthresh /= 3; } while (counter < 4) { counter++; xpthresh *= 3; } if (xpthresh < 1) xpthresh = 1; while (target_skill <= start_skill) { start_skill--; running_total += xpthresh; xpthresh *= 3; } return running_total; } /* Right now applies to only very few select skills */ static int char_xp_bonus(PSTATS * s, int code) { #if 0 int count = 1; int xp; if (t <= 0) return 0; xp = s->xp[code]; while (xp > (t * count)) { xp -= t * count * (mudconf.btech_ic ? 1 : 4); count++; } return count - 1; #endif return s->xp[code] / XP_MAX; } /*****************************/ /* list commands */ /*****************************/ void list_charvaluestuff(dbref player, int flag) { int found = 0, ok, type; int i; char buf[80]; if (flag == -1) notify(player, "List of charvalues available:"); if (flag >= 0) { notify(player, tprintf("List of %s available:", btech_charvaluetype_names[flag])); } buf[0] = 0; for (i = 0; i < NUM_CHARVALUES; i++) { ok = 0; type = char_values[i].type; if (flag < 0) ok = 1; else if (type == flag) ok = 1; if (ok) { sprintf(buf + strlen(buf), "%-23s ", char_values[i].name); if (!((++found) % 3)) { notify(player, buf); strcpy(buf, " "); } } } if (found % 3) { notify(player, buf); } notify(player, " "); notify(player, tprintf("Total of %d things found.", found)); } /*****************************/ /* get code commands */ /*****************************/ HASHTAB playervaluehash, playervaluehash2; int char_getvaluecode(char *name) { int *ip; char *tmpbuf, *tmpc1, *tmpc2; tmpbuf = alloc_sbuf("getvaluecodefind"); for (tmpc1 = name, tmpc2 = tmpbuf; *tmpc1 && ((tmpbuf - tmpc2) < (SBUF_SIZE - 1)); tmpc1++, tmpc2++) *tmpc2 = ToLower(*tmpc1); *tmpc2 = 0; if ((ip = hashfind(tmpbuf, &playervaluehash)) == NULL) ip = hashfind(tmpbuf, &playervaluehash2); free_sbuf(tmpbuf); return ((int) ip) - 1; } /********************/ /* Roll the dice */ /********************/ int char_rollsaving(void) { int r1, r2, r3; int r12, r13, r23; r1 = char_rolld6(1); r2 = char_rolld6(1); r3 = char_rolld6(1); r12 = r1 + r2; r13 = r1 + r3; r23 = r2 + r3; if (r12 > r13) { if (r12 > r23) return r12; else return r23; } else { if (r13 > r23) return r13; else return r23; } } int char_rollunskilled(void) { int r1, r2, r3; int r12, r13, r23; r1 = char_rolld6(1); r2 = char_rolld6(1); r3 = char_rolld6(1); r12 = r1 + r2; r13 = r1 + r3; r23 = r2 + r3; if (r12 < r13) { if (r12 < r23) return r12; else return r23; } else { if (r13 < r23) return r13; else return r23; } } int char_rollskilled(void) { return char_rolld6(2); } int char_rolld6(int num) { int i, total = 0; for (i = 0; i < num; i++) total = total + (random() % 6) + 1; return (total); } /*****************************/ /* DB access commands */ /*****************************/ static int char_getstatvalue(PSTATS * s, char *name) { return char_getstatvaluebycode(s, char_getvaluecode(name)); } int char_getvalue(dbref player, char *name) { return char_getvaluebycode(player, char_getvaluecode(name)); } static void char_setstatvalue(PSTATS * s, char *name, int value) { char_setstatvaluebycode(s, char_getvaluecode(name), value); } void char_setvalue(dbref player, char *name, int value) { char_setvaluebycode(player, char_getvaluecode(name), value); } static int char_getskilltargetbycode_base(dbref player, PSTATS * s, int code, int modifier, int use_xp) { int val, skill; if (code == -1) return 18; if (char_values[code].type != CHAR_SKILL) return 18; if (use_xp && cached_target_char == player && cached_skill == code) return cached_result + modifier; if (char_values[code].flag & CHAR_ATHLETIC) val = char_gvalue(s, "build") + char_gvalue(s, "reflexes"); else if (char_values[code].flag & CHAR_PHYSICAL) val = char_gvalue(s, "reflexes") + char_gvalue(s, "intuition"); else if (char_values[code].flag & CHAR_MENTAL) val = char_gvalue(s, "intuition") + char_gvalue(s, "learn"); else if (char_values[code].flag & CHAR_PHYSICAL) val = char_gvalue(s, "reflexes") + char_gvalue(s, "intuition"); else if (char_values[code].flag & CHAR_SOCIAL) val = char_gvalue(s, "intuition") + char_gvalue(s, "charisma"); else return 18; if (use_xp) { skill = char_getstatvaluebycode(s, code); if (skill == -1) return 18; cached_target_char = player; cached_skill = code; cached_result = 18 - val - skill; return cached_result + modifier; } else { skill = s->values[code]; if (skill == -1) return (18); return 18 - val - skill; } } int char_getskilltargetbycode(dbref player, int code, int modifier) { PSTATS *s; s = retrieve_stats(player, VALUES_CO); return char_getskilltargetbycode_base(player, s, code, modifier, 1); } static int char_getskilltargetbycode_noxp(dbref player, int code, int modifier) { PSTATS *s; s = retrieve_stats(player, VALUES_CO); return char_getskilltargetbycode_base(player, s, code, modifier, 0); } int char_getskilltarget(dbref player, char *name, int modifier) { return char_getskilltargetbycode(player, char_getvaluecode(name), modifier); } int char_getxpbycode(dbref player, int code) { PSTATS *s; if (code < 0) return 0; s = retrieve_stats(player, VALUES_SKILLS); return s->xp[code] % XP_MAX; } int char_gainxpbycode(dbref player, int code, int amount) { PSTATS *s; if (code < 0) return 0; s = retrieve_stats(player, VALUES_SKILLS | VALUES_ATTRS); if (!((mudstate.now > (s->last_use[code] + 30)) || (char_values[code].flag & SK_XP))) return 0; s->last_use[code] = mudstate.now; s->xp[code] += amount; s->xp[code] = s->xp[code] % XP_MAX + XP_MAX * figure_xp_bonus(player, s, code); store_stats(player, s, VALUES_SKILLS); return 1; } int char_gainxp(dbref player, char *skill, int amount) { return char_gainxpbycode(player, char_getvaluecode(skill), amount); } int char_getskillsuccess(dbref player, char *name, int modifier, int loud) { int roll, val; int code; code = char_getvaluecode(name); val = char_getskilltargetbycode(player, code, modifier); if (char_getvaluebycode(player, code) == 0) roll = char_rollunskilled(); else roll = char_rollskilled(); if (loud) { notify(player, tprintf("You make a %s skill roll!", name)); notify(player, tprintf("Modified skill BTH : %d Roll : %d", val, roll)); } if (roll >= val) return (1); /* Success! */ else return (0); /* Failure */ } int char_getskillmargsucc(dbref player, char *name, int modifier) { int roll, val; int code; code = char_getvaluecode(name); val = char_getskilltargetbycode(player, code, modifier); if (char_getvaluebycode(player, code) == 0) roll = char_rollunskilled(); else roll = char_rollskilled(); return (roll - val); } int char_getopposedskill(dbref first, char *skill1, dbref second, char *skill2) { int per1, per2; per1 = char_getskillmargsucc(first, skill1, 0); per2 = char_getskillmargsucc(second, skill2, 0); if (per1 > per2) return (first); else if (per2 == per1) return (0); else return (second); } int char_getattrsave(dbref player, char *name) { int val = char_getvalue(player, name); if (val == -1) return (-1); else if (val > 9) return 0; else return (18 - 2 * val); } int char_getattrsavesucc(dbref player, char *name) { int roll, val = char_getattrsave(player, name); if (val == -1) return (-1); roll = char_rollskilled(); if (roll >= val) return (1); else return (0); } /************************/ /* Database Commands */ /************************/ void init_btechstats(void) { char *tmpbuf, *tmpc1, *tmpc2; int i, j; hashinit(&playervaluehash, 20 * HASH_FACTOR); hashinit(&playervaluehash2, 20 * HASH_FACTOR); tmpbuf = alloc_sbuf("getvaluecode"); for (i = 0; i < NUM_CHARVALUES; i++) { for (tmpc1 = char_values[i].name, tmpc2 = tmpbuf; *tmpc1; tmpc1++, tmpc2++) *tmpc2 = ToLower(*tmpc1); *tmpc2 = '\0'; hashadd(tmpbuf, (int *) (i + 1), &playervaluehash); tmpbuf[0] = '\0'; tmpc1 = tmpbuf; for (j = 0; char_values[i].name[j]; j++) { if (!isupper(char_values[i].name[j])) continue; strncpy(tmpc1, &char_values[i].name[j], 3); tmpc1 += 3; } *tmpc1 = '\0'; if (strlen(tmpbuf) <= 3) { strncpy(tmpbuf, char_values[i].name, 5); tmpbuf[5] = '\0'; } char_values_short[i] = strdup(tmpbuf); for (tmpc1 = tmpbuf; *tmpc1; tmpc1++) *tmpc1 = ToLower(*tmpc1); hashadd(tmpbuf, (int *) (i + 1), &playervaluehash2); } free_sbuf(tmpbuf); } static PSTATS *create_new_stats(void) { PSTATS *s; Create(s, PSTATS, 1); s->dbref = -1; clear_player(s); return s; } static void clear_player(PSTATS * s) { int i; for (i = 0; i < NUM_CHARVALUES; i++) { s->values[i] = (char_values[i].type == CHAR_ATTRIBUTE ? 1 : 0); s->xp[i] = 0; } char_slives(s, 1); } static void show_charstatus(dbref player, PSTATS * s, dbref thing) { char *p; int i, j; int notified; coolmenu *c = NULL; if (thing) { addmenu(tprintf("%%cgName %%c: %s (#%d)", Name(thing), thing)); if (*(p = silly_atr_get(thing, A_FACTION))) addmenu(tprintf("%%cgFaction %%c: %s", p)); #if 0 if ((p = get_rankname(thing))) addmenu(tprintf("%%cgRank %%c: %s", p)); if (*(p = silly_atr_get(thing, A_JOB))) addmenu(tprintf("%%cgJob %%c: %s", p)); #endif addline(); } if (thing) { addmenu(tprintf("%%cgBruise %%c: %d of %d", char_gbruise(s), char_gmaxbruise(s))); addmenu(tprintf("%%cgLethal %%c: %d of %d", char_glethal(s), char_gmaxlethal(s))); } addmenu(tprintf("%%cgLives %%c: %d", char_glives(s))); addempty(); addmenu("%cgAttributes"); addmenu("Characteristics"); addline(); addmenu(tprintf(" %-8s%1d (%d+)", "BLD", char_gvalue(s, "build"), 18 - (char_gvalue(s, "build") * 2))); addmenu(tprintf(" %-15s%2d+", "Athletic", 18 - (char_gvalue(s, "build") + char_gvalue(s, "reflexes")))); addmenu(tprintf(" %-8s%1d (%d+)", "REF", char_gvalue(s, "reflexes"), 18 - (char_gvalue(s, "reflexes") * 2))); addmenu(tprintf(" %-15s%2d+", "Physical", 18 - (char_gvalue(s, "reflexes") + char_gvalue(s, "intuition")))); addmenu(tprintf(" %-8s%1d (%d+) ", "INT", char_gvalue(s, "intuition"), 18 - (char_gvalue(s, "intuition") * 2))); addmenu(tprintf(" %-15s%2d+", "Mental", 18 - (char_gvalue(s, "learn") + char_gvalue(s, "intuition")))); addmenu(tprintf(" %-8s%1d (%d+) ", "LRN", char_gvalue(s, "learn"), 18 - (char_gvalue(s, "learn") * 2))); addmenu(tprintf(" %-15s%2d+", "Social", 18 - (char_gvalue(s, "charisma") + char_gvalue(s, "intuition")))); addmenu(tprintf(" %-8s%1d (%d+)", "CHA", char_gvalue(s, "charisma"), 18 - (char_gvalue(s, "charisma") * 2))); addempty(); notified = 0; for (i = 0; i < NUM_CHARVALUES; i++) { if (char_values[i].type != CHAR_ADVANTAGE) continue; if (!(j = s->values[i])) continue; notified = 1; } if (notified) { addmenu("%cgAdvantages"); addline(); for (i = 0; i < NUM_CHARVALUES; i++) { if (char_values[i].type != CHAR_ADVANTAGE) continue; if (!(j = s->values[i])) continue; switch (char_values[i].flag) { case CHAR_ADV_BOOL: addmenu(tprintf(" %s", char_values[i].name)); break; case CHAR_ADV_VALUE: addmenu(tprintf(" %s: %d", char_values[i].name, j)); break; case CHAR_ADV_EXCEPT: if (j & CHAR_BLD) addmenu(" Exceptional Attribute: Build"); if (j & CHAR_REF) addmenu(" Exceptional Attribute: Reflexes"); if (j & CHAR_INT) addmenu(" Exceptional Attribute: Intuition"); if (j & CHAR_LRN) addmenu(" Exceptional Attribute: Learn"); if (j & CHAR_CHA) addmenu(" Exceptional Attribute: Charisma"); } addempty(); } } addmenu("%cgSkills"); addline(); notified = 0; for (i = 0; i < NUM_CHARVALUES; i++) { if (!s->values[i]) continue; if (char_values[i].type != CHAR_SKILL) continue; addmenu(tprintf(" %-25.25s : %d (%d+)", char_values[i].name, s->values[i], char_getskilltargetbycode(thing, i, 0))); notified = 1; } if (!notified) addmenu(" None"); /* addempty(); */ ShowCoolMenu(player, c); KillCoolMenu(c); } /************************/ /* MUSE COMMANDS */ /************************/ void do_charstatus(dbref player, dbref cause, int key, char *arg1) { dbref thing; int dir = 0; PSTATS *s; if (WizR(player)) dir++; if (arg1 && *arg1) { thing = char_lookupplayer(player, player, 0, arg1); DOCHECK(thing == NOTHING, "I don't know who that is"); if (thing != player && !(WizR(player))) { notify(player, "You do not have the authority to check that players stats"); return; } } else thing = player; s = retrieve_stats(thing, VALUES_ALL); show_charstatus(player, s, thing); } void do_charclear(dbref player, dbref cause, int key, char *arg1) { dbref thing; DOCHECK(!WizR(player), "Sorry, only those with the real power may clear players stats"); DOCHECK(!arg1 || !*arg1, "Who do you want to clear the stats from?"); thing = char_lookupplayer(player, player, 0, arg1); DOCHECK(thing == NOTHING, "I don't know who that is"); silly_atr_set(thing, A_ATTRS, ""); silly_atr_set(thing, A_SKILLS, ""); silly_atr_set(thing, A_ADVS, ""); silly_atr_set(thing, A_HEALTH, ""); notify(player, tprintf("Player #%d stats cleared", thing)); } #if 0 /* Why, what the fuck? */ dbref char_lookupplayer(dbref player, dbref cause, int key, char *arg1) { dbref which; if (!arg1 || !*arg1) return NOTHING; if (!string_compare(arg1, "me") && (Typeof(player) == TYPE_PLAYER)) return player; if (arg1[0] == '#') { if (sscanf(arg1, "#%d", &which) == 1) if (which >= 0 && isPlayer(which)) return which; return NOTHING; } return lookup_player(NOTHING, arg1, 0); } #endif dbref char_lookupplayer(dbref player, dbref cause, int key, char *arg1) { return lookup_player(player, arg1, 0); } static int loc_mod(int loc) { switch (loc) { case HEAD: return 15; case CTORSO: return 50; case LTORSO: case RTORSO: return 35; case LARM: case RARM: return 30; case LLEG: case RLEG: return 35; } return 0; } void initialize_pc(dbref player, MECH * mech) { PSTATS *s; int bruise, lethal, playerBLD; int dam, tot; char *c; int cnt; char buf1[MBUF_SIZE]; char buf2[MBUF_SIZE]; char buf3[MBUF_SIZE]; char buf4[2]; int ammo1; int ammo2; int i, id, brand; int pc_loc_to_mech_loc[] = { HEAD, CTORSO, RARM, RLEG }; if (!(MechType(mech) == CLASS_MW && !(MechCritStatus(mech) & PC_INITIALIZED))) return; buf4[1] = 0; s = retrieve_stats(player, VALUES_HEALTH | VALUES_ATTRS | VALUES_SKILLS); playerBLD = char_gvalue(s, "build"); MechCritStatus(mech) |= PC_INITIALIZED; bruise = char_gbruise(s); lethal = char_glethal(s); tot = playerBLD * 20; dam = bruise + lethal; MechMaxSpeed(mech) = (playerBLD + char_gvalue(s, "reflexes") + char_gvalue(s, "running")) * MP1 / 9.0; #define PC_LOCS 4 for (i = 0; i < NUM_SECTIONS; i++) { SetSectArmor(mech, i, 0); SetSectOArmor(mech, i, 0); SetSectInt(mech, i, (loc_mod(i) * (tot - dam)) / 100 + 1); SetSectOInt(mech, i, (loc_mod(i) * (tot - dam)) / 100 + 1); } c = silly_atr_get(player, A_PCEQUIP); cnt = sscanf(c, "%s %s %s %d %d", buf1, buf2, buf3, &ammo1, &ammo2); switch (cnt) { case 5: case 4: case 3: if (strcmp(buf3, "-")) { if (!find_matching_vlong_part(buf3, NULL, &id, &brand)) { SendError(tprintf("Invalid PC weapon #1 for %s(#%d): %s", Name(player), player, buf3)); return; } if (IsWeapon(id)) { SetPartType(mech, LARM, 0, id); SetPartData(mech, LARM, 0, 0); SetPartFireMode(mech, LARM, 0, 0); SetPartAmmoMode(mech, LARM, 0, 0); if ((i = MechWeapons[Weapon2I(id)].ammoperton)) { SetPartType(mech, LARM, 1, I2Ammo(Weapon2I(id))); SetPartData(mech, LARM, 1, cnt >= 5 ? ammo2 : i); SetPartFireMode(mech, LARM, 1, 0); SetPartAmmoMode(mech, LARM, 1, 0); } } } case 2: if (strcmp(buf2, "-")) { if (!find_matching_vlong_part(buf2, NULL, &id, &brand)) { SendError(tprintf("Invalid PC weapon #1 for %s(#%d): %s", Name(player), player, buf2)); return; } if (IsWeapon(id)) { SetPartType(mech, RARM, 0, id); SetPartData(mech, RARM, 0, 0); SetPartFireMode(mech, RARM, 0, 0); SetPartAmmoMode(mech, RARM, 0, 0); if ((i = MechWeapons[Weapon2I(id)].ammoperton)) { SetPartType(mech, RARM, 1, I2Ammo(Weapon2I(id))); SetPartData(mech, RARM, 1, cnt >= 4 ? ammo1 : i); SetPartFireMode(mech, RARM, 1, 0); SetPartAmmoMode(mech, RARM, 1, 0); } } } case 1: if (strlen(buf1) != PC_LOCS) { SendError(tprintf("Invalid armor string for %s(#%d): %s", Name(player), player, buf1)); return; } for (i = 0; buf1[i]; i++) if (!isdigit(buf1[i])) { SendError(tprintf ("Invalid armor char for %s(#%d) in %s (pos %d,%c)", Name(player), player, buf1, i + 1, buf1[i])); return; } for (i = 0; buf1[i]; i++) { buf4[0] = buf1[i]; SetSectArmor(mech, pc_loc_to_mech_loc[i], atoi(buf4)); } } } void fix_pilotdamage(MECH * mech, dbref player) { PSTATS *s; int bruise, lethal, playerBLD; s = retrieve_stats(player, VALUES_HEALTH | VALUES_ATTRS); bruise = char_gbruise(s); lethal = char_glethal(s); playerBLD = char_gvalue(s, "build") * 2; if (playerBLD < 1 || playerBLD > 100) playerBLD = 10; MechPilotStatus(mech) = (bruise + lethal) / playerBLD; } int PilotStatusRollNeeded[] = { 0, 3, 5, 7, 10, 11 }; #define CHDAM(val,ret) if (playerhits >= ((val))) return ret * mod; int mw_ic_bth(MECH * mech) { int playerBLD; int bruise, playerhits; PSTATS *s; int mod = 1; s = retrieve_stats(MechPilot(mech), VALUES_ATTRS | VALUES_ADVS | VALUES_HEALTH); playerBLD = char_gvalue(s, "build"); bruise = char_gbruise(s); playerhits = 10 * playerBLD - bruise; if (char_gvalue(s, "toughness") == 1) mod = -1; if (playerhits >= (8 * playerBLD)) return 3 * mod; else if (playerhits >= (6 * playerBLD)) return 5 * mod; else if (playerhits >= (4 * playerBLD)) return 7 * mod; else if (playerhits >= (2 * playerBLD)) return 9 * mod; else if (playerhits >= -1) return 11 * mod; return 0; } int handlemwconc(MECH * mech, int initial) { int m, roll; if (In_Character(mech->mynum) && MechPilot(mech) > 0) m = mw_ic_bth(mech); else { if (initial) if (MechPilotStatus(mech) > 5) { mech_notify(mech, MECHPILOT, "You are killed from personal injuries!!"); MechPilot(mech) = -1; Destroy(mech); MechSpeed(mech) = 0.; MechDesiredSpeed(mech) = 0.; return 0; } m = PilotStatusRollNeeded[BOUNDED(0, (int) MechPilotStatus(mech), 4)]; } if (initial && Uncon(mech)) return 0; if (m < 0) /* Gets the saving roll for someone with toughness */ roll = char_rollsaving(); else roll = char_rollskilled(); if (MechPilot(mech) >= 0) { if (initial) { mech_notify(mech, MECHPILOT, "You attempt to keep consciousness!"); mech_notify(mech, MECHPILOT, tprintf("Retain Conciousness on: %d \tRoll: %d", abs(m), roll)); } else { mech_notify(mech, MECHPILOT, "You attempt to regain consciousness!"); mech_notify(mech, MECHPILOT, tprintf("Regain Consciousness on: %d \tRoll: %d", abs(m), roll)); } } if (roll < (abs(m))) { if (initial) mech_notify(mech, MECHPILOT, "Consciousness slips away from you as you enter a sea of darkness..."); ProlongUncon(mech, UNCONSCIOUS_TIME); return 0; } return 1; } void headhitmwdamage(MECH * mech, int dam) { PSTATS *s; dbref player; int damage, bruise, lethaldam, playerBLD; if (mech->mynum < 0) return; /* check to see if mech is IC */ if (!In_Character(mech->mynum) || !GotPilot(mech)) { MechPilotStatus(mech) += dam; handlemwconc(mech, 1); return; } player = MechPilot(mech); s = retrieve_stats(player, VALUES_ATTRS | VALUES_ADVS | VALUES_HEALTH); /* get the player_stats structure */ bruise = char_gbruise(s); /* gets the players bruise damage */ playerBLD = char_gvalue(s, "build"); /* get the player's BLD value */ damage = 2 * playerBLD * dam; /* the damage we are due */ bruise += damage; /* this part subtracts 10 from players lethal damage */ if (bruise > playerBLD * 10) { lethaldam = char_glethal(s); lethaldam += (bruise - playerBLD * 10); bruise = playerBLD * 10; if (lethaldam >= playerBLD * 10) { lethaldam = playerBLD * 10; char_slethal(s, playerBLD * 10 - 1); char_sbruise(s, playerBLD * 10); store_stats(player, s, VALUES_HEALTH); if (!Destroyed(mech)) { DestroyAndDump(mech); ChannelEmitKill(mech, mech); } KillMechContentsIfIC(mech->mynum); return; } char_slethal(s, lethaldam); } char_sbruise(s, bruise); store_stats(player, s, VALUES_HEALTH); handlemwconc(mech, 1); MechPilotStatus(mech) += dam; } void mwlethaldam(MECH * mech, int dam) { PSTATS *s; dbref player; int bruise, lethaldam, playerBLD; if (mech->mynum < 0) return; /* check to see if mech is IC */ if (!In_Character(mech->mynum) || !GotPilot(mech)) { MechPilotStatus(mech) += dam; handlemwconc(mech, 1); return; } player = MechPilot(mech); s = retrieve_stats(player, VALUES_ATTRS | VALUES_ADVS | VALUES_HEALTH); /* get the player_stats structure */ bruise = char_gbruise(s); playerBLD = char_gvalue(s, "build"); if (!playerBLD) playerBLD++; lethaldam = char_glethal(s); lethaldam += BOUNDED(10, dam * playerBLD, 40); if (lethaldam >= playerBLD * 10) { lethaldam = playerBLD * 10; char_slethal(s, lethaldam - 1); char_sbruise(s, lethaldam); store_stats(player, s, VALUES_HEALTH); if (!Destroyed(mech)) { DestroyAndDump(mech); ChannelEmitKill(mech, mech); } KillMechContentsIfIC(mech->mynum); return; } char_sbruise(s, playerBLD * 10 - 5); char_slethal(s, lethaldam); store_stats(player, s, VALUES_HEALTH); handlemwconc(mech, 1); MechPilotStatus(mech) += dam; } void lower_xp(dbref player, int promillage) { PSTATS *s; int i; s = retrieve_stats(player, VALUES_ALL); for (i = 0; i < NUM_CHARVALUES; i++) { if (!s->xp[i]) continue; if (s->xp[i] < 0) { s->xp[i] = 0; continue; } s->xp[i] = (s->xp[i] % XP_MAX) * promillage / 1000; s->xp[i] = s->xp[i] % XP_MAX + XP_MAX * figure_xp_bonus(player, s, i); } store_stats(player, s, VALUES_ALL); } void AccumulateTechXP(dbref pilot, MECH * mech, int reason) { char *skname; int xp; static char *techw = "technician-weapons"; if (mech) { if (!(skname = FindTechSkillName(mech))) return; } else skname = techw; xp = MAX(1, reason); /* Using Exile method of spliting the xp off to different * channels for monitoring. TechXP goes to MechTechXP */ if (char_gainxp(pilot, skname, xp)) SendTechXP(tprintf("%s gained %d %s XP (changing mech #%d)", Name(pilot), xp, skname, mech ? mech->mynum : -1)); /* if (char_gainxp(pilot, skname, xp)) SendXP(tprintf("%s gained %d %s XP (changing mech #%d)", Name(pilot), xp, skname, mech ? mech->mynum : -1)); */ } void AccumulateTechWeaponsXP(dbref pilot, MECH * mech, int reason) { char *skname; int xp; static char *techw = "technician-weapons"; skname = techw; xp = MAX(1, reason); /* Using Exile method of spliting the xp off to different * channels for monitoring. TechXP goes to MechTechXP */ if (char_gainxp(pilot, skname, xp)) SendTechXP(tprintf("%s gained %d %s XP (changing mech #%d)", Name(pilot), xp, skname, mech ? mech->mynum : -1)); /* if (char_gainxp(pilot, skname, xp)) SendXP(tprintf("%s gained %d %s XP (changing mech #%d)", Name(pilot), xp, skname, mech ? mech->mynum : -1)); */ } void AccumulateCommXP(dbref pilot, MECH * mech) { int xp; xp = 1; if (!RGotPilot(mech)) return; if (!In_Character(mech->mynum)) return; if (!Connected(pilot)) return; if (char_gainxp(pilot, "Comm-Conventional", xp)) SendXP(tprintf("%s gained %d %s XP (in #%d)", Name(pilot), xp, "Comm-Conventional", mech->mynum)); } void AccumulatePilXP(dbref pilot, MECH * mech, int reason, int addanyway) { char *skname; int xp; if (!In_Character(mech->mynum)) return; if (!RGotPilot(mech)) return; if (!(skname = FindPilotingSkillName(mech))) return; if (!addanyway) { if (MechLX(mech) != MechX(mech) || MechLY(mech) != MechY(mech)) { MechLX(mech) = MechX(mech); MechLY(mech) = MechY(mech); } else return; } xp = MAX(1, reason); /* Switching to Exile method of tracking xp, where we split * Attacking and Piloting xp into two different channels */ if (char_gainxp(pilot, skname, xp)) SendPilotXP(tprintf("%s gained %d %s XP", Name(pilot), xp, skname)); /* if (char_gainxp(pilot, skname, xp)) SendXP(tprintf("%s gained %d %s XP", Name(pilot), xp, skname)); */ } void AccumulateSpotXP(dbref pilot, MECH * attacker, MECH * wounded) { int xp = 1; if (!In_Character(attacker->mynum)) return; if (!RGotPilot(attacker)) return; if (MechPilot(attacker) != pilot) return; if (attacker == wounded) return; if (Destroyed(wounded)) return; if (MechTeam(wounded) == MechTeam(attacker)) return; if (!In_Character(wounded->mynum)) return; if (char_gainxp(pilot, "Gunnery-Spotting", xp)) SendXP(tprintf("%s gained spotting XP", Name(pilot))); } int MadePerceptionRoll(MECH * mech, int modifier) { int pilot; if (!In_Character(mech->mynum)) return 0; if (!RGotGPilot(mech)) return 0; pilot = MechPilot(mech); if (pilot <= 0) return 0; if (!MechPer(mech)) MechPer(mech) = char_getskilltarget(pilot, "Perception", 2); if (Roll() < (MechPer(mech) + modifier)) return 0; char_gainxp(pilot, "Perception", 1); if (char_gainxp(pilot, "Perception", 1)) SendXP(tprintf("%s gained 1 perception XP", Name(pilot))); return 1; } void AccumulateArtyXP(dbref pilot, MECH * attacker, MECH * wounded) { int xp = 1; /* If not in character ie: like in simulator - no xp */ if (!In_Character(attacker->mynum)) return; if (!RGotGPilot(attacker)) return; if (GunPilot(attacker) != pilot) return; /* No xp for shooting yourself */ if (attacker == wounded) return; /* No xp for shooting destroyed units */ if (Destroyed(wounded)) return; /* No xp if both on same team */ if (MechTeam(wounded) == MechTeam(attacker)) return; /* If target not in character ie: in simulator - no xp */ if (!In_Character(wounded->mynum)) return; /* Switching to Exile method of tracking xp, where we split * Attacking and Piloting xp into two different channels */ if (char_gainxp(pilot, "Gunnery-Artillery", xp)) SendAttackXP(tprintf("%s gained %d artillery XP", Name(pilot), xp)); /* if (char_gainxp(pilot, "Gunnery-Artillery", xp)) SendXP(tprintf("%s gained %d artillery XP", Name(pilot), xp)); */ } void AccumulateComputerXP(dbref pilot, MECH * mech, int reason) { int xp; if (!mech) return; if (mech && In_Character(mech->mynum) && isPlayer(pilot)) if (char_gainxp(pilot, "computer", MAX(1, reason))) SendXP(tprintf("%s gained %d computer XP (mech #%d)", Name(pilot), reason, mech ? mech->mynum : -1)); } int HasBoolAdvantage(dbref player, const char *name) { PSTATS *s; char buf[SBUF_SIZE]; strcpy(buf, name); s = retrieve_stats(player, VALUES_ATTRS | VALUES_ADVS | VALUES_HEALTH); if (char_gvalue(s, buf) == 1) return 1; else return 0; } int bth_modifier[] = /* Starts from '3' , in 1/36's */ { /* 3 4 5 6 7 8 9 10 11 12 */ 1, 3, 6, 10, 15, 21, 26, 30, 33, 35, 0, 0, 0, 0 /* pad, just in case */ }; #define TonValue(mech) \ MAX(1, (MechTons(mech) / \ ((MechType(mech) != CLASS_MECH) ? 2 : 1) / \ ((MechMove(mech) == MOVE_NONE) ? 2 : 1))) static int t_mod(float sp) { if (sp <= MP2) return 0; if (sp <= MP4) return 1; if (sp <= MP6) return 2; if (sp <= MP9) return 3; return 4; /* No extra mods */ } #define MoveValue(mech) (t_mod(MMaxSpeed(mech)) + 2) #define NewMoveValue(mech) ((int) (MechMaxSpeed(mech)/MP1)) float getPilotBVMod(MECH * mech, int weapindx) { /* * What we do is we get the mod as if we had a 0+ piloting (baseline) * for the gun skill we want. Each '+' above zero subtracts .05 from * the result. Obviously, each '+' below adds .05. * * The first number in the array below corresponds to a 0+ 0+ person * and the last number in the array below corresponds to a 7+ 0+ person * (that's <gun skill>+ <pilot skill>+) */ int zeroPilotBaseSkills[] = { 2.05, 1.85, 1.65, 1.45, 1.25, 1.15, 1.05, .95 }; int myGSkill = FindPilotGunnery(mech, weapindx); int myPSkill = FindPilotPiloting(mech); float baseMod = 0.0; /* First we check if we have a totally off the wall GSkill, i.e., below * 0 or above 7. */ if (myGSkill < 0) { baseMod = zeroPilotBaseSkills[0] + (abs(myGSkill) * 0.20); } else if (myGSkill > 7) { baseMod = zeroPilotBaseSkills[7] - (myGSkill * 0.10); } else { baseMod = zeroPilotBaseSkills[myGSkill]; } return (baseMod - ((0 + myPSkill) * 0.05)); } void AccumulateGunXP(dbref pilot, MECH * attacker, MECH * wounded, int numOccurences, int multiplier, int weapindx, int bth) { int omul, xp, my_BV, th_BV, my_speed, th_speed; float myPilotBVMod = 1.0, theirPilotBVMod = 1.0; float missilemod; char *skname; char buf[MBUF_SIZE]; int damagemod; float vrtmod; missilemod = 1; if (mudconf.btech_oldxpsystem) { AccumulateGunXPold(pilot, attacker, wounded, numOccurences, multiplier, weapindx, bth); return; } /* Is attacker in character ie: not in simulator */ if (!In_Character(attacker->mynum)) return; if (!RGotGPilot(attacker)) return; if (GunPilot(attacker) != pilot) return; /* No xp for shooting yourself */ if (attacker == wounded) return; /* No xp for shooting destroyed mechs */ if (Destroyed(wounded)) return; /* No xp for shooting a teammate */ if (MechTeam(wounded) == MechTeam(attacker)) return; /* Is the target in character ie: in simulators */ if (!In_Character(wounded->mynum)) return; /* ? */ if (!(skname = FindGunnerySkillName(attacker, weapindx))) return; /* No xp for shooting mechwarriors if you not a mechwarrior */ if (MechType(wounded) == CLASS_MW && MechType(attacker) != CLASS_MW) return; /* bth to high so no way to hit */ if (!(bth <= 12)) return; multiplier = multiplier * mudconf.btech_xp_modifier; if (mudconf.btech_xp_bthmod) { if (!(bth >= 3 && bth <= 12)) return; /* sure hits aren't interesting */ multiplier = 2 * multiplier * bth_modifier[bth - 3] / 36; } omul = multiplier; /* Need to do a BV mod between the mechs */ my_BV = MechBV(attacker); th_BV = MechBV(wounded); if (mudconf.btech_xp_usePilotBVMod) { myPilotBVMod = getPilotBVMod(attacker, weapindx); theirPilotBVMod = getPilotBVMod(wounded, weapindx); my_BV = my_BV * myPilotBVMod; th_BV = th_BV * theirPilotBVMod; #ifdef XP_DEBUG SendDebug(tprintf ("Using skill modified battle value for mechs %d and %d " "with skill mods of %2.2f and %2.2f", attacker->mynum, wounded->mynum, myPilotBVMod, theirPilotBVMod)); #endif } my_speed = NewMoveValue(attacker) + 1; th_speed = NewMoveValue(wounded) + 1; if (MechWeapons[weapindx].type == TMISSILE) missilemod = mudconf.btech_xp_missilemod; else if (MechWeapons[weapindx].type == TAMMO) missilemod = mudconf.btech_xp_ammomod; if (mudconf.btech_defaultweapdam > 1) damagemod = numOccurences; else damagemod = 1; if (mudconf.btech_xp_vrtmod) vrtmod = (MechWeapons[weapindx].vrt < 30 ? sqrt((double) MechWeapons[weapindx].vrt / 30.0) : 1); else vrtmod = 1.0; multiplier = (vrtmod * missilemod * multiplier * sqrt((double) (th_BV + 1) * th_speed * mudconf.btech_defaultweapbv / mudconf.btech_defaultweapdam)) / (sqrt((double) (my_BV + 1) * my_speed * MechWeapons[weapindx].battlevalue / damagemod)); xp = BOUNDED(1, (multiplier * numOccurences / 100), 50); strcpy(buf, Name(wounded->mynum)); /* Switching to Exile method of tracking xp, where we split * Attacking and Piloting xp into two different channels */ if (char_gainxp(pilot, skname, xp)) SendAttackXP(tprintf("%s gained %d gun XP from feat of %d %% difficulty " "(%d occurences) against %s", Name(pilot), xp, multiplier, numOccurences, buf)); /* if (char_gainxp(pilot, skname, xp)) SendXP(tprintf("%s gained %d gun XP from feat of %d %% difficulty " "(%d occurences) against %s", Name(pilot), xp, multiplier, numOccurences, buf)); */ } void AccumulateGunXPold(dbref pilot, MECH * attacker, MECH * wounded, int numOccurences, int multiplier, int weapindx, int bth) { int omul, xp; char *skname; char buf[MBUF_SIZE]; /* Is the attacker in character ie: in simulators */ if (!In_Character(attacker->mynum)) return; if (!RGotGPilot(attacker)) return; if (GunPilot(attacker) != pilot) return; /* No xp for shooting yourself */ if (attacker == wounded) return; /* No xp for shooting destroyed units */ if (Destroyed(wounded)) return; /* No xp for shooting teammate */ if (MechTeam(wounded) == MechTeam(attacker)) return; /* if target is in character ie: in simulators or something */ if (!In_Character(wounded->mynum)) return; if (!(skname = FindGunnerySkillName(attacker, weapindx))) return; /* No xp for shooting a mechwarrior unless you a mechwarrior */ if (MechType(wounded) == CLASS_MW && MechType(attacker) != CLASS_MW) return; if (!(bth >= 3 && bth <= 12)) return; /* sure hits aren't interesting */ omul = multiplier; if (MechTons(attacker) > 0) multiplier = multiplier * BOUNDED(50, 100 * TonValue(wounded) / TonValue(attacker), 150); else { /* Bring this to the attention of the admins */ SendError(tprintf ("AccumulateGunXP: Weird tonnage for IC mech #%d (%s): %d", attacker->mynum, Name(attacker->mynum), (short) MechTons(attacker))); return; } /* Hmm.. we have to figure the speed differences as well */ { int my_speed = MoveValue(attacker); int th_speed = MoveValue(wounded); multiplier = multiplier * th_speed * th_speed / my_speed / my_speed; } multiplier = multiplier * bth_modifier[bth - 3] / 36; multiplier = multiplier * 2; /* For average shot */ if (Number(1, 50) > (multiplier * numOccurences)) return; /* Nothing for truly twinky stuff, occasionally */ xp = BOUNDED(1, (multiplier * numOccurences) / 100, 50); /*Hardcoded limit */ strcpy(buf, Name(wounded->mynum)); /* Switching to Exile method of tracking xp, where we split * Attacking and Piloting xp into two different channels */ if (char_gainxp(pilot, skname, xp)) SendAttackXP(tprintf("%s gained %d gun XP from feat of %d %% " "difficulty (%d occurences) against %s", Name(pilot), xp, multiplier, numOccurences, buf)); /* if (char_gainxp(pilot, skname, xp)) SendXP(tprintf ("%s gained %d gun XP from feat of %d %% difficulty (%d occurences) against %s", Name(pilot), xp, multiplier, numOccurences, buf)); */ } void fun_btgetcharvalue(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs) { /* fargs[0] = char id (#222) fargs[1] = value name / value loc # fargs[2] = flaggo (?) */ dbref target; int targetcode, flaggo; FUNCHECK((target = char_lookupplayer(player, cause, 0, fargs[0])) == NOTHING, "#-1 INVALID TARGET"); FUNCHECK(!Wiz(player), "#-1 PERMISSION DENIED!"); if (Readnum(targetcode, fargs[1])) targetcode = char_getvaluecode(fargs[1]); FUNCHECK(targetcode < 0 || targetcode >= NUM_CHARVALUES, "#-1 INVALID VALUE"); flaggo = atoi(fargs[2]); if (char_values[targetcode].type == CHAR_SKILL && flaggo == 4) { safe_tprintf_str(buff, bufc, "%d", figure_xp_to_next_level(target, targetcode)); return; } if (char_values[targetcode].type == CHAR_SKILL && flaggo == 3) { safe_tprintf_str(buff, bufc, "%d", retrieve_stats(target, VALUES_SKILLS)->values[targetcode]); return; } if (char_values[targetcode].type == CHAR_SKILL && flaggo == 2) { safe_tprintf_str(buff, bufc, "%d", char_getxpbycode(target, targetcode)); return; } if (char_values[targetcode].type == CHAR_SKILL && flaggo) { safe_tprintf_str(buff, bufc, "%d", char_getskilltargetbycode(target, targetcode, 0)); return; } safe_tprintf_str(buff, bufc, "%d", char_getvaluebycode(target, targetcode)); } void fun_btsetcharvalue(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs) { /* fargs[0] = char id (#222) fargs[1] = value name / value loc # fargs[2] = value to be set fargs[3] = flaggo (?) */ dbref target; int targetcode, targetvalue, flaggo; FUNCHECK((target = char_lookupplayer(player, cause, 0, fargs[0])) == NOTHING, "#-1 INVALID TARGET"); FUNCHECK(!Wiz(player), "#-1 PERMISSION DENIED!"); if (Readnum(targetcode, fargs[1])) targetcode = char_getvaluecode(fargs[1]); FUNCHECK(targetcode < 0 || targetcode >= NUM_CHARVALUES, "#-1 INVALID VALUE"); targetvalue = atoi(fargs[2]); flaggo = atoi(fargs[3]); /* We supposedly have everything at hand.. */ if (flaggo) { FUNCHECK(char_values[targetcode].type != CHAR_SKILL, "#-1 ONLY SKILLS CAN HAVE FLAG"); if (flaggo == 1) { /* Need to do some evil frobbage here */ char_setvaluebycode(target, targetcode, 0); targetvalue = char_getskilltargetbycode(target, targetcode, 0) - targetvalue; } else { if (flaggo != 3) { /* Add exp */ char_gainxpbycode(target, targetcode, targetvalue); SendXP(tprintf("#%d added %d more %s XP to #%d", player, targetvalue, char_values[targetcode].name, target)); safe_tprintf_str(buff, bufc, "%s gained %d more %s XP.", Name(target), targetvalue, char_values[targetcode].name); } else { /* Set the xp instead */ char_gainxpbycode(target, targetcode, targetvalue - char_getxpbycode(target, targetcode)); SendXP(tprintf("#%d set #%d's %s XP to %d", player, target, char_values[targetcode].name, targetvalue)); safe_tprintf_str(buff, bufc, "%s's %s XP set to %d.", Name(target), char_values[targetcode].name, targetvalue); } return; } } char_setvaluebycode(target, targetcode, targetvalue); safe_tprintf_str(buff, bufc, "%s's %s set to %d", Name(target), char_values[targetcode].name, char_getvaluebycode(target, targetcode)); } /* ---------------------------------------------------------------------- ** Syntax: btcharlist(skills|advantages|attributes[,targetplayer]) ** ** Given one of the three arguments above, btcharlist returns the ** listing of each in a space delimited list. This is basically a ** function version of +show. If the second argument is provided, only ** the skills/advantages that are learned or possessed will ** appear. For attributes the full list will be returned of since ** characters need all of them. */ void fun_btcharlist(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs) { int i; int type = 0; int first = 1; dbref target = 0; enum { CHSKI, CHADV, CHATT, }; static char *cmds[] = { "skills", "advantages", "attributes", NULL }; if (!fn_range_check("BTCHARLIST", nfargs, 1, 2, buff, bufc)) return; if (nfargs == 2) { target = char_lookupplayer(player, cause, 0, fargs[1]); if (target == NOTHING) { safe_str("#-1 FUNCTION (BTCHARLIST) INVALID TARGET", buff, bufc); return; } } switch (listmatch(cmds, fargs[0])) { case CHSKI: type = CHAR_SKILL; break; case CHADV: type = CHAR_ADVANTAGE; break; case CHATT: type = CHAR_ATTRIBUTE; break; default: safe_str("#-1 FUNCTION (BTCHARLIST) INVALID VALUE", buff, bufc); return; } for (i = 0; i < NUM_CHARVALUES; ++i) if (type == char_values[i].type) { if (nfargs == 2 && type != CHAR_ATTRIBUTE) { int targetcode = char_getvaluecode(char_values[i].name); if (char_getvaluebycode(target, targetcode) == 0) continue; } if (first) first = 0; else safe_str( " ", buff, bufc ); safe_str(char_values[i].name, buff, bufc); } return; } #define MAX_PLAYERS_ON 10000 void debug_xptop(dbref player, void *data, char *buffer) { int hm, i, j; dbref top[MAX_PLAYERS_ON]; int topv[MAX_PLAYERS_ON]; int count = 0, gt = 0; coolmenu *c = NULL; PSTATS *s; #if 0 notify(player, "Support discontinued. Bother a wiz if this bothers you."); return; #endif bzero(top, sizeof(top)); bzero(topv, sizeof(topv)); skipws(buffer); DOCHECK(!*buffer, "Invalid argument!"); DOCHECK((hm = char_getvaluecode(buffer)) < 0, "Invalid value name!"); DOCHECK(char_values[hm].type != CHAR_SKILL, "Only skills have XP (for now at least)"); DO_WHOLE_DB(i) { if (!isPlayer(i)) continue; if (Wiz(i)) continue; if (!(s = retrieve_stats(i, VALUES_SKILLS))) continue; if (!s->xp[hm]) continue; top[count] = i; topv[count] = (s->xp[hm] % XP_MAX); gt += topv[count]; count++; } for (i = 0; i < (count - 1); i++) for (j = i + 1; j < count; j++) { if (topv[j] > topv[i]) { topv[count] = topv[j]; topv[j] = topv[i]; topv[i] = topv[count]; top[count] = top[j]; top[j] = top[i]; top[i] = top[count]; } } addline(); for (i = 0; i < MIN(16, count); i++) { addmenu(tprintf("%3d. %s", i + 1, Name(top[i]))); addmenu(tprintf("%d (%.3f %%)", topv[i], (100.0 * topv[i]) / gt)); } addline(); if (gt) { addmenu(tprintf("Grand total: %d points", gt)); addline(); } ShowCoolMenu(player, c); KillCoolMenu(c); } static void store_health(dbref player, PSTATS * s) { silly_atr_set(player, A_HEALTH, tprintf("%d,%d", char_gvalue(s, "Bruise"), char_gvalue(s, "Lethal"))); } static void retrieve_health(dbref player, PSTATS * s) { char *c = silly_atr_get(player, A_HEALTH); PSTATS *s1; int i1, i2; if (sscanf(c, "%d,%d", &i1, &i2) != 2) { s1 = create_new_stats(); memcpy(s, s1, sizeof(PSTATS)); store_stats(player, s, VALUES_ALL); free((void *) s1); return; } char_svalue(s, "Bruise", i1); char_svalue(s, "Lethal", i2); } static void store_attrs(dbref player, PSTATS * s) { silly_atr_set(player, A_ATTRS, tprintf("%d,%d,%d,%d,%d", char_gvalue(s, "Build"), char_gvalue(s, "Reflexes"), char_gvalue(s, "Intuition"), char_gvalue(s, "Learn"), char_gvalue(s, "Charisma"))); } static void retrieve_attrs(dbref player, PSTATS * s) { char *c = silly_atr_get(player, A_ATTRS); PSTATS *s1; int i1, i2, i3, i4, i5; if (sscanf(c, "%d,%d,%d,%d,%d", &i1, &i2, &i3, &i4, &i5) != 5) { s1 = create_new_stats(); memcpy(s, s1, sizeof(PSTATS)); store_stats(player, s, VALUES_ALL); free((void *) s1); return; } char_svalue(s, "Build", i1); char_svalue(s, "Reflexes", i2); char_svalue(s, "Intuition", i3); char_svalue(s, "Learn", i4); char_svalue(s, "Charisma", i5); } static void generic_retrieve_stuff(dbref player, PSTATS * s, int attr) { char *c = silly_atr_get(player, attr), *e; char buf[512]; int i1, i2, i3, sn; if (!*c) return; while (1) { i2 = i3 = 0; e = strchr(c, '/'); if (sscanf(c, "%[A-Za-z_-]:%d,%d,%d", buf, &i1, &i2, &i3) < 2) return; /* Do the magic ;) */ sn = char_getvaluecode(buf); if (sn >= 0) { s->values[sn] = i1; if (i2) s->xp[sn] = i2; if (i3) s->last_use[sn] = i3; } if (!(c = e)) return; c++; if (!(*c)) return; } } static void generic_store_stuff(dbref player, PSTATS * s, int attr, int flag) { char buf[LBUF_SIZE]; int i; char *c; buf[0] = 0; c = buf; for (i = 0; i < NUM_CHARVALUES; i++) { if (!s->values[i] && !s->xp[i]) continue; if (flag) { if (char_values[i].type != CHAR_SKILL) continue; } else if (i != 5 && char_values[i].type != CHAR_ADVANTAGE) continue; if (s->xp[i]) sprintf(c, "%s:%d,%d,%d/", char_values_short[i], s->values[i], s->xp[i], (int) s->last_use[i]); else sprintf(c, "%s:%d/", char_values_short[i], s->values[i]); while (*(++c)); } if (*buf) silly_atr_set(player, attr, buf); else silly_atr_set(player, attr, ""); } static void retrieve_skills(dbref player, PSTATS * s) { generic_retrieve_stuff(player, s, A_SKILLS); } static void retrieve_advs(dbref player, PSTATS * s) { generic_retrieve_stuff(player, s, A_ADVS); } static void store_skills(dbref player, PSTATS * s) { generic_store_stuff(player, s, A_SKILLS, 1); } static void store_advs(dbref player, PSTATS * s) { generic_store_stuff(player, s, A_ADVS, 0); } static void store_stats(dbref player, PSTATS * s, int modes) { if (!isPlayer(player)) return; if (modes & VALUES_HEALTH) store_health(player, s); if (modes & VALUES_ATTRS) store_attrs(player, s); if (modes & VALUES_ADVS) { if (player == cached_target_char) cached_target_char = -1; store_advs(player, s); } if (modes & VALUES_SKILLS) { if (player == cached_target_char) cached_target_char = -1; store_skills(player, s); } } static PSTATS *retrieve_stats(dbref player, int modes) { static PSTATS s; bzero(&s, sizeof(PSTATS)); if (modes & VALUES_HEALTH) retrieve_health(player, &s); if (modes & VALUES_ADVS) retrieve_advs(player, &s); if (modes & VALUES_ATTRS) retrieve_attrs(player, &s); if (modes & VALUES_SKILLS) retrieve_skills(player, &s); return &s; } void debug_setxplevel(dbref player, void *data, char *buffer) { char *args[3]; int xpt, code; DOCHECK(mech_parseattributes(buffer, args, 3) != 2, "Invalid arguments!"); DOCHECK(Readnum(xpt, args[1]), "Invalid value!"); DOCHECK(xpt < 0, "Threshold needs to be >=0 (0 = no gains possible)"); DOCHECK((code = char_getvaluecode(args[0])) < 0, "That isn't any charvalue!"); DOCHECK(char_values[code].type != CHAR_SKILL, "That isn't any skill!"); char_values[code].xpthreshold = xpt; STARTLOG(LOG_ALWAYS, "WIZ", "CHANGE") { log_text(tprintf("Exp threshold for %s changed to %d by ", char_values[code].name, xpt)); log_name(player); ENDLOG; } } int btthreshold_func(char *skillname) { int code; if (!skillname || !*skillname) return -1; code = char_getvaluecode(skillname); if (code < 0) return -1; if (char_values[code].type != CHAR_SKILL) return -1; return char_values[code].xpthreshold; } #ifdef MENU_CHARGEN #include "chargen.c" #endif