/* Proficiency list management
* List Management Functions - Kevin Reid <kpreid@attglobal.net>
* Everything else - Cris Jacobin (Muerte of CrodoMud)
* Telnet://crodomud.crodo.com:4000
*/
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "interpreter.h"
#include "screen.h"
#include "constants.h"
#include "profs.h"
/* External Functions */
char *how_good(int percent);
struct prof_data *prof_new_node(struct char_data *ch) {
struct prof_data *new_node;
if (ch == NULL)
return NULL;
new_node = malloc(sizeof(struct prof_data));
if (new_node == NULL)
return NULL;
new_node->type = PROF_TYPE_NONE;
new_node->key = 0;
new_node->value = 0;
new_node->next = PROFS(ch);
PROFS(ch) = new_node;
return new_node;
}
void prof_destroy_node(struct char_data *ch, struct prof_data *target) {
struct prof_data *tnext;
if (target == NULL)
return;
tnext = target->next;
if (tnext) {
*target = *tnext;
free(tnext);
} else if (PROFS(ch) == target) {
free(target);
PROFS(ch) = NULL;
} else {
struct prof_data *tprev;
for (tprev = PROFS(ch); tprev != NULL; tprev = tprev->next) {
if (tprev->next == target) {
tprev->next = target->next;
free(target);
}
}
}
}
struct prof_data * prof_get_node(struct char_data *ch, int look_type, int look_key) {
struct prof_data *i;
for (i = PROFS(ch); i != NULL; i = i->next) {
if (i->type != look_type) continue;
if (i->key != look_key) continue;
return i;
}
return NULL;
}
/*-------*/
PROF_VALUE_TYPE prof_get(struct char_data *ch, int look_type, int look_key) {
struct prof_data *node;
node = prof_get_node(ch, look_type, look_key);
if (node == NULL) return -1;
return node->value;
}
void prof_set(struct char_data *ch, int look_type, int look_key, PROF_VALUE_TYPE new_val) {
struct prof_data *node;
if (new_val > 100.00)
new_val = 100.00;
node = prof_get_node(ch, look_type, look_key);
if (node == NULL) {
/* If the node doesn't exist, and it's being set to <0, then don't bother
allocating one */
if (new_val < 0)
return;
node = prof_new_node(ch);
if (node == NULL)
return;
node->type = look_type;
node->key = look_key;
}
if (new_val < 0) {
prof_destroy_node(ch, node);
} else {
node->value = new_val;
}
}
void prof_destroy_all(struct char_data *ch) {
while (PROFS(ch)) {
prof_destroy_node(ch, PROFS(ch));
}
}
/* Load characters profs from disk*/
int load_profs(struct char_data *ch) {
FILE *fl;
char fname[MAX_STRING_LENGTH];
struct prof_file_elem prof;
/* Build the filename (/lib/plrprofs) */
if (!get_filename(GET_NAME(ch), fname, PROFS_FILE)) {
send_to_char("Filename error in load_profs!\r\n", ch);
return (1); }
/* Cannot open the file! */
if (!(fl = fopen(fname, "r+b"))) {
if (errno != ENOENT) { /* if it fails, NOT because of no file */
log("SYSERR: READING PROFS FILE %s : %s", fname, strerror(errno));
send_to_char("\r\n********************* NOTICE *********************\r\n"
"There was a problem loading your profs from disk.\r\n"
"Contact a God for assistance.\r\n", ch);
}
return (1);
}
/* Make sure we're at the beginning */
rewind(fl);
/* Begin adding profs */
while (!feof(fl)) {
fread(&prof, sizeof(struct prof_file_elem), 1, fl);
prof_set(ch, prof.type, prof.key, prof.value); }
/* Profs loaded and ready to go */
return (0);
}
/* Save character's profs to disk */
int save_profs(struct char_data *ch) {
struct prof_data *prof;
struct prof_file_elem prof_data;
FILE *fl;
char filename[MAX_INPUT_LENGTH];
int ferr = 0;
/* No profs, no reason to save (logging into game?) */
if (PROFS(ch) == NULL)
return (0);
if (IS_NPC(ch))
return (0);
if (!get_filename(GET_NAME(ch), filename, PROFS_FILE)) {
send_to_char("Filename Error in save profs\r\n", ch);
return (1); }
if (!(fl = fopen(filename, "wb"))) {
log("SYSERR: WRITING PROFS FILE %s : %s", filename, strerror(errno));
send_to_char("\r\n********************* NOTICE *********************\r\n"
"There was a problem writing your profs to disk.\r\n"
"Contact a God for assistance.\r\n", ch); }
rewind(fl);
prof = PROFS(ch);
/* Write profs to disk */
while (prof != NULL) {
prof_data.type = prof->type;
prof_data.key = prof->key;
prof_data.value = prof->value;
ferr = fwrite(&prof_data, sizeof(struct prof_file_elem), 1, fl);
if (ferr < 1) {
perror("SYSERR: error writing to file in save_profs");
return (1); }
prof = prof->next;
}
fclose(fl);
return (0);
}
ACMD(do_profs) {
struct prof_data *prof;
char buffer[MAX_STRING_LENGTH];
extern struct obj_data *obj_proto;
int int_value;
prof = PROFS(ch);
if (!GET_PROF_SLOTS(ch))
sprintf(buffer, "You have no proficiency slots remaining.\r\n");
else
sprintf(buffer, "You have %d proficiency slot%s remaining.\r\n\r\n",
GET_PROF_SLOTS(ch), (GET_PROF_SLOTS(ch) == 1 ? "" : "s"));
send_to_char(buffer, ch);
if (prof == NULL) {
send_to_char("You are not proficient in ANYTHING. You suck!\r\n", ch);
return; }
if (prof != NULL)
send_to_char("You are proficient in the following weapons.\r\n", ch);
while (prof != NULL) {
int_value = prof->value;
sprintf(buffer, "%s. Proficiency: %s\r\n",
obj_proto[real_object(prof->key)].short_description,
how_good(int_value));
send_to_char(buffer, ch);
prof = prof->next;
}
send_to_char("\r\n", ch);
}
float prof_adjust(struct char_data *ch) {
float value;
value = PROF_WEAP_ADJ;
/* Class based modifiers */
if (IS_WARRIOR(ch))
value *= 2;
else
if (IS_THIEF(ch))
value *= 1.5;
/* Add to the current prof */
value += GET_CUR_PROF(ch)->value;
return (value);
}
void prof_slot_gain(struct char_data *ch) {
int class;
if (IS_MULTI(ch))
class = GET_SECOND_CLASS(ch);
else
class = GET_FIRST_CLASS(ch);
switch (class) {
case CLASS_WARRIOR:
if ((GET_LEVEL(ch) == 3) || (GET_LEVEL(ch) == 6) ||
(GET_LEVEL(ch) == 9) || (GET_LEVEL(ch) == 12) ||
(GET_LEVEL(ch) == 15) || (GET_LEVEL(ch) == 18) ||
(GET_LEVEL(ch) == 21) || (GET_LEVEL(ch) == 24) ||
(GET_LEVEL(ch) == 27) || (GET_LEVEL(ch) == 30))
GET_PROF_SLOTS(ch)++;
break;
case CLASS_THIEF:
if ((GET_LEVEL(ch) == 4) || (GET_LEVEL(ch) == 8) ||
(GET_LEVEL(ch) == 12) || (GET_LEVEL(ch) == 16) ||
(GET_LEVEL(ch) == 20) || (GET_LEVEL(ch) == 24) ||
(GET_LEVEL(ch) == 28) || (GET_LEVEL(ch) == 24))
GET_PROF_SLOTS(ch)++;
break;
case CLASS_NECROMANCER:
if ((GET_LEVEL(ch) == 4) || (GET_LEVEL(ch) == 8) ||
(GET_LEVEL(ch) == 12) || (GET_LEVEL(ch) == 16) ||
(GET_LEVEL(ch) == 20) || (GET_LEVEL(ch) == 24) ||
(GET_LEVEL(ch) == 28) || (GET_LEVEL(ch) == 24))
GET_PROF_SLOTS(ch)++;
break;
case CLASS_SORCERER:
if ((GET_LEVEL(ch) == 6) || (GET_LEVEL(ch) == 12) ||
(GET_LEVEL(ch) == 18) || (GET_LEVEL(ch) == 24) ||
(GET_LEVEL(ch) == 30) || (GET_LEVEL(ch) == 24))
GET_PROF_SLOTS(ch)++;
break;
}
}
int prof_apply_thac0(struct char_data *ch) {
int class;
if (IS_MULTI(ch))
class = GET_SECOND_CLASS(ch);
else
class = GET_FIRST_CLASS(ch);
if (IS_NPC(ch))
class = CLASS_THIEF;
/* Not proficient in the current weapon */
if ((GET_CUR_PROF(ch) == NULL) ||
(GET_CUR_PROF(ch)->value <= 40)) {
switch (class) {
case CLASS_WARRIOR:
return (-2);
break;
case CLASS_THIEF:
return (-3);
break;
case CLASS_NECROMANCER:
return (-3);
break;
case CLASS_SORCERER:
return (-4);
break;
}
}
/* Char is specialized in this weapon */
if (GET_CUR_PROF(ch)->value >= 81)
return (1);
/* No bonus for just being proficient.
Chars assumed to be average with their
weapon of choice */
return (0);
}
int profs_delete_file(struct char_data *ch)
{
char filename[50];
FILE *fl;
if (!get_filename(GET_NAME(ch), filename, PROFS_FILE))
return (0);
if (!(fl = fopen(filename, "rb"))) {
if (errno != ENOENT) /* if it fails but NOT because of no file */
log("SYSERR: deleting profs file %s (1): %s", filename, strerror(errno));
return (0);
}
fclose(fl);
/* if it fails, NOT because of no file */
if (remove(filename) < 0 && errno != ENOENT)
log("SYSERR: deleting profs file %s (2): %s", filename, strerror(errno));
return (1);
}