/* Save new/edited mob to memory. */ void medit_save_internally(struct descriptor_data *d) { int i; mob_rnum new_rnum; struct descriptor_data *dsc; struct char_data *mob; i = (real_mobile(OLC_NUM(d)) == NOBODY); if ((new_rnum = add_mobile(OLC_MOB(d), OLC_NUM(d))) == NOBODY) { log("medit_save_internally: add_mobile failed."); return; } /* Update triggers and free old proto list */ if (mob_proto[new_rnum].proto_script && mob_proto[new_rnum].proto_script != OLC_SCRIPT(d)) free_proto_script(&mob_proto[new_rnum], MOB_TRIGGER); mob_proto[new_rnum].proto_script = OLC_SCRIPT(d); /* this takes care of the mobs currently in-game */ for (mob = character_list; mob; mob = mob->next) { if (GET_MOB_RNUM(mob) != new_rnum) continue; /* remove any old scripts */ if (SCRIPT(mob)) extract_script(mob, MOB_TRIGGER); free_proto_script(mob, MOB_TRIGGER); copy_proto_script(&mob_proto[new_rnum], mob, MOB_TRIGGER); assign_triggers(mob, MOB_TRIGGER); } /* end trigger update */ if (!i) /* Only renumber on new mobiles. */ return; /* Update keepers in shops being edited and other mobs being edited. */ for (dsc = descriptor_list; dsc; dsc = dsc->next) { if (STATE(dsc) == CON_SEDIT) S_KEEPER(OLC_SHOP(dsc)) += (S_KEEPER(OLC_SHOP(dsc)) != NOTHING && S_KEEPER(OLC_SHOP(dsc)) >= new_rnum); else if (STATE(dsc) == CON_MEDIT) GET_MOB_RNUM(OLC_MOB(dsc)) += (GET_MOB_RNUM(OLC_MOB(dsc)) != NOTHING && GET_MOB_RNUM(OLC_MOB(dsc)) >= new_rnum); } /* Update other people in zedit too. From: C.Raehl 4/27/99 */ for (dsc = descriptor_list; dsc; dsc = dsc->next) if (STATE(dsc) == CON_ZEDIT) for (i = 0; OLC_ZONE(dsc)->cmd[i].command != 'S'; i++) if (OLC_ZONE(dsc)->cmd[i].command == 'M') if (OLC_ZONE(dsc)->cmd[i].arg1 >= new_rnum) OLC_ZONE(dsc)->cmd[i].arg1++; }
int delete_mobile(mob_rnum refpt) { struct char_data *live_mob; int vnum, counter, zone, cmd_no; if (refpt < 0 || refpt > top_of_mobt) { log("SYSERR: GenOLC: delete_mobile: Invalid rnum %d.", refpt); return FALSE; } vnum = mob_index[refpt].vnum; add_to_save_list(zone_table[real_zone_by_thing(vnum)].number, SL_MOB); extract_mobile_all(vnum); free_mobile_strings(&mob_proto[refpt]); for (counter = refpt; counter < top_of_mobt; counter++) { mob_index[counter] = mob_index[counter + 1]; mob_proto[counter] = mob_proto[counter + 1]; mob_proto[counter].nr--; } top_of_mobt--; RECREATE(mob_index, struct index_data, top_of_mobt + 1); RECREATE(mob_proto, struct char_data, top_of_mobt + 1); /* * Update live mobile rnums. */ for (live_mob = character_list; live_mob; live_mob = live_mob->next) GET_MOB_RNUM(live_mob) -= (GET_MOB_RNUM(live_mob) >= refpt); /* * Update zone table. */ for (zone = 0; zone <= top_of_zone_table; zone++) for (cmd_no = 0; ZCMD(zone, cmd_no).command != 'S'; cmd_no++) if (ZCMD(zone, cmd_no).command == 'M') ZCMD(zone, cmd_no).arg1 -= (ZCMD(zone, cmd_no).arg1 >= refpt); /* * Update shop keepers. */ if (shop_index) for (counter = 0; counter <= top_shop - top_shop_offset; counter++) SHOP_KEEPER(counter) -= (SHOP_KEEPER(counter) >= refpt); return TRUE; }
/* * Free a mobile structure that has been edited. * Take care of existing mobiles and their mob_proto! */ int free_mobile(struct char_data *mob) { int i; if (mob == NULL) return FALSE; /* * Non-prototyped mobile. Also known as new mobiles. */ if ((i = GET_MOB_RNUM(mob)) == NOBODY) free_mobile_strings(mob); else { /* Prototyped mobile. */ if (mob->player.name && mob->player.name != mob_proto[i].player.name) free(mob->player.name); if (mob->player.title && mob->player.title != mob_proto[i].player.title) free(mob->player.title); if (mob->player.short_descr && mob->player.short_descr != mob_proto[i].player.short_descr) free(mob->player.short_descr); if (mob->player.long_descr && mob->player.long_descr != mob_proto[i].player.long_descr) free(mob->player.long_descr); if (mob->player.description && mob->player.description != mob_proto[i].player.description) free(mob->player.description); } while (mob->affected) affect_remove(mob, mob->affected); free(mob); return TRUE; }
void medit_setup_new(struct descriptor_data *d) { struct char_data *mob; /* * Allocate a scratch mobile structure. */ CREATE(mob, struct char_data, 1); init_mobile(mob); GET_MOB_RNUM(mob) = -1; /* * Set up some default strings. */ GET_ALIAS(mob) = str_dup("mob unfinished"); GET_SDESC(mob) = str_dup("the unfinished mob"); GET_LDESC(mob) = str_dup("An unfinished mob stands here.\r\n"); GET_DDESC(mob) = str_dup("It looks unfinished.\r\n"); #if CONFIG_OASIS_MPROG OLC_MPROGL(d) = NULL; OLC_MPROG(d) = NULL; #endif OLC_MOB(d) = mob; /* Has changed flag. (It hasn't so far, we just made it.) */ OLC_VAL(d) = FALSE; medit_disp_menu(d); }
void do_mob_report (struct char_data *ch) { struct char_data *mob; FILE *reportfile; int i; if (!(reportfile = fopen("report.mob", "w"))) { mlog("SYSERR: Mob report file unavailable."); send_to_char ("Report.mob could not be generated.\r\n",ch); return; } sprintf(buf, "MOBS\n----\n"); for (i=0; i<top_of_mobt;i++) { mob=read_mobile(i, REAL); char_to_room(mob, 0); sprintf(buf+strlen(buf), "[%5d] %s Spec Proc: ", GET_MOB_VNUM(mob), GET_NAME(mob)); if (mob_index[GET_MOB_RNUM(mob)].func!=NULL) get_spec_name(GET_MOB_RNUM(mob), buf2,'m'); else sprintf(buf2, "none"); sprintf(buf+strlen(buf), "%s\n",buf2); sprintf(buf+strlen(buf),mob->player.description); sprintf(buf+strlen(buf),"Difficulty: %d XP: %d HP: %d Mana: %d Gold %d\n", GET_DIFFICULTY(mob), GET_EXP(mob), GET_MAX_HIT(mob), GET_MAX_MANA(mob), GET_GOLD(mob)); sprintf(buf+strlen(buf),"Passive Defense: %d Damage Reduction: %d ", GET_PD(mob), GET_REDUCTION(mob)); sprintf(buf+strlen(buf), "Attack Type: %s\n", attack_hit_text[mob->mob_specials.attack_type].singular); sprintbit(MOB_FLAGS(mob), action_bits, buf2, sizeof(buf2)); sprintf(buf+strlen(buf),"Flags: %s\n", buf2); sprintbit(AFF_FLAGS(mob), affected_bits, buf2, sizeof(buf2)); sprintf(buf+strlen(buf),"Affects: %s\n\n-------\n", buf2); extract_char(mob); fprintf(reportfile, buf); buf[0]='\0'; }/*for i=0...*/ fclose (reportfile); send_to_char ("report.mob printed\r\n",ch); }
/* search all over the world for a char num, and return a pointer if found */ struct char_data *get_char_num(mob_rnum nr) { struct char_data *i; for (i = character_list; i; i = i->next) if (GET_MOB_RNUM(i) == nr) return i; return NULL; }
int ok_damage_shopkeeper(struct char_data * ch, struct char_data * victim) { char buf[200]; int index; if (IS_NPC(victim) && (mob_index[GET_MOB_RNUM(victim)].func == shop_keeper)) for (index = 0; index < top_shop; index++) if ((GET_MOB_RNUM(victim) == SHOP_KEEPER(index)) && !SHOP_KILL_CHARS(index)) { do_action(victim, GET_NAME(ch), cmd_slap, 0); sprintf(buf, "%s %s", GET_NAME(ch), MSG_CANT_KILL_KEEPER); do_tell(victim, buf, cmd_tell, 0); if (GET_RACE(ch)==RACE_KENDER) do_gen_comm(victim, "Stinkin' Kender scum!", 0, SCMD_SHOUT); return (FALSE); } return (TRUE); }
void load_mtrigger(char_data *ch) { trig_data *t; int result = 0; if (!SCRIPT_CHECK(ch, MTRIG_LOAD)) return; for (t = TRIGGERS(SCRIPT(ch)); t; t = t->next) { if (TRIGGER_CHECK(t, MTRIG_LOAD) && (rand_number(1, 100) <= GET_TRIG_NARG(t))) { result = script_driver(&ch, t, MOB_TRIGGER, TRIG_NEW); break; } } if (result == SCRIPT_ERROR_CODE) { /* we have recursed beyond reasonable depth */ /* make sure this mob is the last one in the load chain */ if (GET_MOB_RNUM(ch) != NOBODY) { free_proto_script(&mob_proto[GET_MOB_RNUM(ch)], MOB_TRIGGER); } } }
/* * Save new/edited mob to memory. */ void medit_save_internally(struct descriptor_data *d) { int i; mob_rnum new_rnum; struct descriptor_data *dsc; i = (real_mobile(OLC_NUM(d)) == NOBODY); if ((new_rnum = add_mobile(OLC_MOB(d), OLC_NUM(d))) < 0) { log("medit_save_internally: add_object failed."); return; } if (!i) /* Only renumber on new mobiles. */ return; /* * Update keepers in shops being edited and other mobs being edited. */ for (dsc = descriptor_list; dsc; dsc = dsc->next) { if (STATE(dsc) == CON_SEDIT) S_KEEPER(OLC_SHOP(dsc)) += (S_KEEPER(OLC_SHOP(dsc)) >= new_rnum); else if (STATE(dsc) == CON_MEDIT) GET_MOB_RNUM(OLC_MOB(dsc)) += (GET_MOB_RNUM(OLC_MOB(dsc)) >= new_rnum); } /* * Update other people in zedit too. From: C.Raehl 4/27/99 */ for (dsc = descriptor_list; dsc; dsc = dsc->next) if (STATE(dsc) == CON_ZEDIT) for (i = 0; OLC_ZONE(dsc)->cmd[i].command != 'S'; i++) if (OLC_ZONE(dsc)->cmd[i].command == 'M') if (OLC_ZONE(dsc)->cmd[i].arg1 >= new_rnum) OLC_ZONE(dsc)->cmd[i].arg1++; }
/* control the fights going on. Called every 2 seconds from comm.c. */ void perform_violence(void) { struct char_data *ch; for (ch = combat_list; ch; ch = next_combat_list) { next_combat_list = ch->next_fighting; if (FIGHTING(ch) == NULL || (IN_ROOM(ch) != IN_ROOM(FIGHTING(ch))) || \ (!char_within_range_of_vict(ch, FIGHTING(ch)))) { stop_fighting(ch); continue; } if (IS_NPC(ch)) { if (GET_MOB_WAIT(ch) > 0) { GET_MOB_WAIT(ch) -= PULSE_VIOLENCE; continue; } GET_MOB_WAIT(ch) = 0; if (GET_POS(ch) < POS_FIGHTING) { GET_POS(ch) = POS_FIGHTING; act("$n scrambles to $s feet!", TRUE, ch, 0, 0, TO_ROOM); } } if (GET_POS(ch) < POS_FIGHTING) { send_to_char("You can't fight while sitting!!\r\n", ch); continue; } hit(ch, FIGHTING(ch), TYPE_UNDEFINED); /* XXX: Need to see if they can handle "" instead of NULL. */ if (MOB_FLAGGED(ch, MOB_SPEC) && mob_index[GET_MOB_RNUM(ch)].func != NULL) (mob_index[GET_MOB_RNUM(ch)].func) (ch, ch, 0, ""); } }
void medit_free_mobile(struct char_data *mob) { int i; /* * Non-prototyped mobile. Also known as new mobiles. */ if (!mob) return; else if (GET_MOB_RNUM(mob) == -1) { if (mob->player.name) free(mob->player.name); if (mob->player.title) free(mob->player.title); if (mob->player.short_descr) free(mob->player.short_descr); if (mob->player.long_descr) free(mob->player.long_descr); if (mob->player.description) free(mob->player.description); } else if ((i = GET_MOB_RNUM(mob)) > -1) { /* Prototyped mobile. */ if (mob->player.name && mob->player.name != mob_proto[i].player.name) free(mob->player.name); if (mob->player.title && mob->player.title != mob_proto[i].player.title) free(mob->player.title); if (mob->player.short_descr && mob->player.short_descr != mob_proto[i].player.short_descr) free(mob->player.short_descr); if (mob->player.long_descr && mob->player.long_descr != mob_proto[i].player.long_descr) free(mob->player.long_descr); if (mob->player.description && mob->player.description != mob_proto[i].player.description) free(mob->player.description); } while (mob->affected) affect_remove(mob, mob->affected, 0); free(mob); }
static void medit_setup_new(struct descriptor_data *d) { struct char_data *mob; /* Allocate a scratch mobile structure. */ CREATE(mob, struct char_data, 1); init_mobile(mob); GET_MOB_RNUM(mob) = NOBODY; /* Set up some default strings. */ GET_ALIAS(mob) = strdup("mob unfinished"); GET_SDESC(mob) = strdup("the unfinished mob"); GET_LDESC(mob) = strdup("An unfinished mob stands here.\r\n"); GET_DDESC(mob) = strdup("It looks unfinished.\r\n"); SCRIPT(mob) = NULL; mob->proto_script = OLC_SCRIPT(d) = NULL; OLC_MOB(d) = mob; /* Has changed flag. (It hasn't so far, we just made it.) */ OLC_VAL(d) = FALSE; OLC_ITEM_TYPE(d) = MOB_TRIGGER; }
static void extract_mobile_all(mob_vnum vnum) { struct char_data *next, *ch; int i; for (ch = character_list; ch; ch = next) { next = ch->next; if (GET_MOB_VNUM(ch) == vnum) { if ((i = GET_MOB_RNUM(ch)) != NOBODY) { if (ch->player.name && ch->player.name != mob_proto[i].player.name) free(ch->player.name); ch->player.name = NULL; if (ch->player.title && ch->player.title != mob_proto[i].player.title) free(ch->player.title); ch->player.title = NULL; if (ch->player.short_descr && ch->player.short_descr != mob_proto[i].player.short_descr) free(ch->player.short_descr); ch->player.short_descr = NULL; if (ch->player.long_descr && ch->player.long_descr != mob_proto[i].player.long_descr) free(ch->player.long_descr); ch->player.long_descr = NULL; if (ch->player.description && ch->player.description != mob_proto[i].player.description) free(ch->player.description); ch->player.description = NULL; /* free script proto list if it's not the prototype */ if (ch->proto_script && ch->proto_script != mob_proto[i].proto_script) free_proto_script(ch, MOB_TRIGGER); ch->proto_script = NULL; } extract_char(ch); } } }
void medit_parse(struct descriptor_data *d, char *arg) { int i = -1, j; char *oldtext = NULL; if (OLC_MODE(d) > MEDIT_NUMERICAL_RESPONSE) { i = atoi(arg); if (!*arg || (!isdigit(arg[0]) && ((*arg == '-') && !isdigit(arg[1])))) { write_to_output(d, "Try again : "); return; } } else { /* String response. */ if (!genolc_checkstring(d, arg)) return; } switch (OLC_MODE(d)) { case MEDIT_CONFIRM_SAVESTRING: /* Ensure mob has MOB_ISNPC set. */ SET_BIT_AR(MOB_FLAGS(OLC_MOB(d)), MOB_ISNPC); switch (*arg) { case 'y': case 'Y': /* Save the mob in memory and to disk. */ medit_save_internally(d); mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(d->character)), TRUE, "OLC: %s edits mob %d", GET_NAME(d->character), OLC_NUM(d)); if (CONFIG_OLC_SAVE) { medit_save_to_disk(zone_table[real_zone_by_thing(OLC_NUM(d))].number); write_to_output(d, "Mobile saved to disk.\r\n"); } else write_to_output(d, "Mobile saved to memory.\r\n"); cleanup_olc(d, CLEANUP_ALL); return; case 'n': case 'N': /* If not saving, we must free the script_proto list. We do so by * assigning it to the edited mob and letting free_mobile in * cleanup_olc handle it. */ OLC_MOB(d)->proto_script = OLC_SCRIPT(d); cleanup_olc(d, CLEANUP_ALL); return; default: write_to_output(d, "Invalid choice!\r\n"); write_to_output(d, "Do you wish to save your changes? : "); return; } break; case MEDIT_MAIN_MENU: i = 0; switch (*arg) { case 'q': case 'Q': if (OLC_VAL(d)) { /* Anything been changed? */ write_to_output(d, "Do you wish to save your changes? : "); OLC_MODE(d) = MEDIT_CONFIRM_SAVESTRING; } else cleanup_olc(d, CLEANUP_ALL); return; case '1': OLC_MODE(d) = MEDIT_SEX; medit_disp_sex(d); return; case '2': OLC_MODE(d) = MEDIT_KEYWORD; i--; break; case '3': OLC_MODE(d) = MEDIT_S_DESC; i--; break; case '4': OLC_MODE(d) = MEDIT_L_DESC; i--; break; case '5': OLC_MODE(d) = MEDIT_D_DESC; send_editor_help(d); write_to_output(d, "Enter mob description:\r\n\r\n"); if (OLC_MOB(d)->player.description) { write_to_output(d, "%s", OLC_MOB(d)->player.description); oldtext = strdup(OLC_MOB(d)->player.description); } string_write(d, &OLC_MOB(d)->player.description, MAX_MOB_DESC, 0, oldtext); OLC_VAL(d) = 1; return; case '6': OLC_MODE(d) = MEDIT_POS; medit_disp_positions(d); return; case '7': OLC_MODE(d) = MEDIT_DEFAULT_POS; medit_disp_positions(d); return; case '8': OLC_MODE(d) = MEDIT_ATTACK; medit_disp_attack_types(d); return; case '9': OLC_MODE(d) = MEDIT_STATS_MENU; medit_disp_stats_menu(d); return; case 'a': case 'A': OLC_MODE(d) = MEDIT_NPC_FLAGS; medit_disp_mob_flags(d); return; case 'b': case 'B': OLC_MODE(d) = MEDIT_AFF_FLAGS; medit_disp_aff_flags(d); return; case 'w': case 'W': write_to_output(d, "Copy what mob? "); OLC_MODE(d) = MEDIT_COPY; return; case 'x': case 'X': write_to_output(d, "Are you sure you want to delete this mobile? "); OLC_MODE(d) = MEDIT_DELETE; return; case 's': case 'S': OLC_SCRIPT_EDIT_MODE(d) = SCRIPT_MAIN_MENU; dg_script_menu(d); return; default: medit_disp_menu(d); return; } if (i == 0) break; else if (i == 1) write_to_output(d, "\r\nEnter new value : "); else if (i == -1) write_to_output(d, "\r\nEnter new text :\r\n] "); else write_to_output(d, "Oops...\r\n"); return; case MEDIT_STATS_MENU: i=0; switch(*arg) { case 'q': case 'Q': medit_disp_menu(d); return; case '1': /* Edit level */ OLC_MODE(d) = MEDIT_LEVEL; i++; break; case '2': /* Autoroll stats */ medit_autoroll_stats(d); medit_disp_stats_menu(d); OLC_VAL(d) = TRUE; return; case '3': OLC_MODE(d) = MEDIT_NUM_HP_DICE; i++; break; case '4': OLC_MODE(d) = MEDIT_SIZE_HP_DICE; i++; break; case '5': OLC_MODE(d) = MEDIT_ADD_HP; i++; break; case '6': OLC_MODE(d) = MEDIT_NDD; i++; break; case '7': OLC_MODE(d) = MEDIT_SDD; i++; break; case '8': OLC_MODE(d) = MEDIT_DAMROLL; i++; break; case 'a': case 'A': OLC_MODE(d) = MEDIT_AC; i++; break; case 'b': case 'B': OLC_MODE(d) = MEDIT_EXP; i++; break; case 'c': case 'C': OLC_MODE(d) = MEDIT_GOLD; i++; break; case 'd': case 'D': OLC_MODE(d) = MEDIT_HITROLL; i++; break; case 'e': case 'E': OLC_MODE(d) = MEDIT_ALIGNMENT; i++; break; case 'f': case 'F': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_STR; i++; break; case 'g': case 'G': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_INT; i++; break; case 'h': case 'H': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_WIS; i++; break; case 'i': case 'I': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_DEX; i++; break; case 'j': case 'J': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_CON; i++; break; case 'k': case 'K': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_CHA; i++; break; case 'l': case 'L': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_PARA; i++; break; case 'm': case 'M': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_ROD; i++; break; case 'n': case 'N': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_PETRI; i++; break; case 'o': case 'O': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_BREATH; i++; break; case 'p': case 'P': if (!CONFIG_MEDIT_ADVANCED) { write_to_output(d, "Invalid Choice!\r\nEnter Choice : "); return; } OLC_MODE(d) = MEDIT_SPELL; i++; break; default: medit_disp_stats_menu(d); return; } if (i == 0) break; else if (i == 1) write_to_output(d, "\r\nEnter new value : "); else if (i == -1) write_to_output(d, "\r\nEnter new text :\r\n] "); else write_to_output(d, "Oops...\r\n"); return; case OLC_SCRIPT_EDIT: if (dg_script_edit_parse(d, arg)) return; break; case MEDIT_KEYWORD: smash_tilde(arg); if (GET_ALIAS(OLC_MOB(d))) free(GET_ALIAS(OLC_MOB(d))); GET_ALIAS(OLC_MOB(d)) = str_udup(arg); break; case MEDIT_S_DESC: smash_tilde(arg); if (GET_SDESC(OLC_MOB(d))) free(GET_SDESC(OLC_MOB(d))); GET_SDESC(OLC_MOB(d)) = str_udup(arg); break; case MEDIT_L_DESC: smash_tilde(arg); if (GET_LDESC(OLC_MOB(d))) free(GET_LDESC(OLC_MOB(d))); if (arg && *arg) { char buf[MAX_INPUT_LENGTH]; snprintf(buf, sizeof(buf), "%s\r\n", arg); GET_LDESC(OLC_MOB(d)) = strdup(buf); } else GET_LDESC(OLC_MOB(d)) = strdup("undefined"); break; case MEDIT_D_DESC: /* * We should never get here. */ cleanup_olc(d, CLEANUP_ALL); mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: OLC: medit_parse(): Reached D_DESC case!"); write_to_output(d, "Oops...\r\n"); break; case MEDIT_NPC_FLAGS: if ((i = atoi(arg)) <= 0) break; else if ( (j = medit_get_mob_flag_by_number(i)) == -1) { write_to_output(d, "Invalid choice!\r\n"); write_to_output(d, "Enter mob flags (0 to quit) :"); return; } else if (j <= NUM_MOB_FLAGS) { TOGGLE_BIT_AR(MOB_FLAGS(OLC_MOB(d)), (j)); } medit_disp_mob_flags(d); return; case MEDIT_AFF_FLAGS: if ((i = atoi(arg)) <= 0) break; else if (i <= NUM_AFF_FLAGS) TOGGLE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), i); /* Remove unwanted bits right away. */ REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_CHARM); REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_POISON); REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_GROUP); REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_SLEEP); medit_disp_aff_flags(d); return; /* Numerical responses. */ case MEDIT_SEX: GET_SEX(OLC_MOB(d)) = LIMIT(i - 1, 0, NUM_GENDERS - 1); break; case MEDIT_HITROLL: GET_HITROLL(OLC_MOB(d)) = LIMIT(i, 0, 50); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_DAMROLL: GET_DAMROLL(OLC_MOB(d)) = LIMIT(i, 0, 50); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_NDD: GET_NDD(OLC_MOB(d)) = LIMIT(i, 0, 30); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_SDD: GET_SDD(OLC_MOB(d)) = LIMIT(i, 0, 127); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_NUM_HP_DICE: GET_HIT(OLC_MOB(d)) = LIMIT(i, 0, 30); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_SIZE_HP_DICE: GET_MANA(OLC_MOB(d)) = LIMIT(i, 0, 1000); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_ADD_HP: GET_MOVE(OLC_MOB(d)) = LIMIT(i, 0, 30000); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_AC: GET_AC(OLC_MOB(d)) = LIMIT(i, -200, 200); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_EXP: GET_EXP(OLC_MOB(d)) = LIMIT(i, 0, MAX_MOB_EXP); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_GOLD: GET_GOLD(OLC_MOB(d)) = LIMIT(i, 0, MAX_MOB_GOLD); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_STR: GET_STR(OLC_MOB(d)) = LIMIT(i, 11, 25); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_INT: GET_INT(OLC_MOB(d)) = LIMIT(i, 11, 25); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_WIS: GET_WIS(OLC_MOB(d)) = LIMIT(i, 11, 25); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_DEX: GET_DEX(OLC_MOB(d)) = LIMIT(i, 11, 25); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_CON: GET_CON(OLC_MOB(d)) = LIMIT(i, 11, 25); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_CHA: GET_CHA(OLC_MOB(d)) = LIMIT(i, 11, 25); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_PARA: GET_SAVE(OLC_MOB(d), SAVING_PARA) = LIMIT(i, 0, 100); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_ROD: GET_SAVE(OLC_MOB(d), SAVING_ROD) = LIMIT(i, 0, 100); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_PETRI: GET_SAVE(OLC_MOB(d), SAVING_PETRI) = LIMIT(i, 0, 100); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_BREATH: GET_SAVE(OLC_MOB(d), SAVING_BREATH) = LIMIT(i, 0, 100); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_SPELL: GET_SAVE(OLC_MOB(d), SAVING_SPELL) = LIMIT(i, 0, 100); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_POS: GET_POS(OLC_MOB(d)) = LIMIT(i - 1, 0, NUM_POSITIONS - 1); break; case MEDIT_DEFAULT_POS: GET_DEFAULT_POS(OLC_MOB(d)) = LIMIT(i - 1, 0, NUM_POSITIONS - 1); break; case MEDIT_ATTACK: GET_ATTACK(OLC_MOB(d)) = LIMIT(i, 0, NUM_ATTACK_TYPES - 1); break; case MEDIT_LEVEL: GET_LEVEL(OLC_MOB(d)) = LIMIT(i, 1, LVL_IMPL); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_ALIGNMENT: GET_ALIGNMENT(OLC_MOB(d)) = LIMIT(i, -1000, 1000); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; case MEDIT_COPY: if ((i = real_mobile(atoi(arg))) != NOWHERE) { medit_setup_existing(d, i); } else write_to_output(d, "That mob does not exist.\r\n"); break; case MEDIT_DELETE: if (*arg == 'y' || *arg == 'Y') { if (delete_mobile(GET_MOB_RNUM(OLC_MOB(d))) != NOBODY) write_to_output(d, "Mobile deleted.\r\n"); else write_to_output(d, "Couldn't delete the mobile!\r\n"); cleanup_olc(d, CLEANUP_ALL); return; } else if (*arg == 'n' || *arg == 'N') { medit_disp_menu(d); OLC_MODE(d) = MEDIT_MAIN_MENU; return; } else write_to_output(d, "Please answer 'Y' or 'N': "); break; default: /* We should never get here. */ cleanup_olc(d, CLEANUP_ALL); mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: OLC: medit_parse(): Reached default case!"); write_to_output(d, "Oops...\r\n"); break; } /* END OF CASE If we get here, we have probably changed something, and now want to return to main menu. Use OLC_VAL as a 'has changed' flag */ OLC_VAL(d) = TRUE; medit_disp_menu(d); }
int delete_mobile(mob_rnum refpt) { struct char_data *live_mob; struct char_data *proto; int counter, cmd_no; mob_vnum vnum; zone_rnum zone; #if CIRCLE_UNSIGNED_INDEX if (refpt == NOBODY || refpt > top_of_mobt) { #else if (refpt < 0 || refpt > top_of_mobt) { #endif log("SYSERR: GenOLC: delete_mobile: Invalid rnum %d.", refpt); return NOBODY; } vnum = mob_index[refpt].vnum; proto = &mob_proto[refpt]; extract_mobile_all(vnum); extract_char(proto); for (counter = refpt; counter < top_of_mobt; counter++) { mob_index[counter] = mob_index[counter + 1]; mob_proto[counter] = mob_proto[counter + 1]; mob_proto[counter].nr--; } top_of_mobt--; RECREATE(mob_index, struct index_data, top_of_mobt + 1); RECREATE(mob_proto, struct char_data, top_of_mobt + 1); /* Update live mobile rnums. */ for (live_mob = character_list; live_mob; live_mob = live_mob->next) GET_MOB_RNUM(live_mob) -= (GET_MOB_RNUM(live_mob) >= refpt); /* Update zone table. */ for (zone = 0; zone <= top_of_zone_table; zone++) for (cmd_no = 0; ZCMD(zone, cmd_no).command != 'S'; cmd_no++) if (ZCMD(zone, cmd_no).command == 'M'){ if (ZCMD(zone, cmd_no).arg1 == refpt) { delete_zone_command(&zone_table[zone], cmd_no); } else ZCMD(zone, cmd_no).arg1 -= (ZCMD(zone, cmd_no).arg1 > refpt); } /* Update shop keepers. */ if (shop_index) for (counter = 0; counter <= top_shop; counter++) SHOP_KEEPER(counter) -= (SHOP_KEEPER(counter) >= refpt); save_mobiles(real_zone_by_thing(vnum)); return refpt; } int copy_mobile_strings(struct char_data *t, struct char_data *f) { if (f->player.name) t->player.name = strdup(f->player.name); if (f->player.title) t->player.title = strdup(f->player.title); if (f->player.short_descr) t->player.short_descr = strdup(f->player.short_descr); if (f->player.long_descr) t->player.long_descr = strdup(f->player.long_descr); if (f->player.description) t->player.description = strdup(f->player.description); return TRUE; } int update_mobile_strings(struct char_data *t, struct char_data *f) { if (f->player.name) t->player.name = f->player.name; if (f->player.title) t->player.title = f->player.title; if (f->player.short_descr) t->player.short_descr = f->player.short_descr; if (f->player.long_descr) t->player.long_descr = f->player.long_descr; if (f->player.description) t->player.description = f->player.description; return TRUE; } int free_mobile_strings(struct char_data *mob) { if (mob->player.name) free(mob->player.name); if (mob->player.title) free(mob->player.title); if (mob->player.short_descr) free(mob->player.short_descr); if (mob->player.long_descr) free(mob->player.long_descr); if (mob->player.description) free(mob->player.description); return TRUE; } /* Free a mobile structure that has been edited. Take care of existing mobiles * and their mob_proto! */ int free_mobile(struct char_data *mob) { mob_rnum i; if (mob == NULL) return FALSE; /* Non-prototyped mobile. Also known as new mobiles. */ if ((i = GET_MOB_RNUM(mob)) == NOBODY) { free_mobile_strings(mob); /* free script proto list */ free_proto_script(mob, MOB_TRIGGER); } else { /* Prototyped mobile. */ if (mob->player.name && mob->player.name != mob_proto[i].player.name) free(mob->player.name); if (mob->player.title && mob->player.title != mob_proto[i].player.title) free(mob->player.title); if (mob->player.short_descr && mob->player.short_descr != mob_proto[i].player.short_descr) free(mob->player.short_descr); if (mob->player.long_descr && mob->player.long_descr != mob_proto[i].player.long_descr) free(mob->player.long_descr); if (mob->player.description && mob->player.description != mob_proto[i].player.description) free(mob->player.description); /* free script proto list if it's not the prototype */ if (mob->proto_script && mob->proto_script != mob_proto[i].proto_script) free_proto_script(mob, MOB_TRIGGER); } while (mob->affected) affect_remove(mob, mob->affected); /* free any assigned scripts */ if (SCRIPT(mob)) extract_script(mob, MOB_TRIGGER); free(mob); return TRUE; }
void medit_parse(struct descriptor_data *d, char *arg) { int number; int mob_number; // the RNUM switch(d->edit_mode) { case MEDIT_CONFIRM_EDIT: /* if player hits 'Y' then edit mob */ switch (*arg) { case 'y': case 'Y': medit_disp_menu(d); break; case 'n': case 'N': STATE(d) = CON_PLAYING; /* free up the editing mob */ if (d->edit_mob) Mem->DeleteCh(d->edit_mob); d->edit_mob = NULL; d->edit_number = 0; PLR_FLAGS(d->character).RemoveBit(PLR_EDITING); break; default: send_to_char("That's not a valid choice!\r\n", CH); send_to_char("Do you wish to edit it?\r\n", CH); break; } break; /* end of MEDIT_CONFIRM_EDIT */ case MEDIT_CONFIRM_SAVESTRING: switch(*arg) { case 'y': case 'Y': // first write to the internal tables if (!from_ip_zone(d->edit_number)) { sprintf(buf,"%s wrote new mob #%ld", GET_CHAR_NAME(d->character), d->edit_number); mudlog(buf, d->character, LOG_WIZLOG, TRUE); } mob_number = real_mobile(d->edit_number); if (mob_number > 0) { // first we go through the entire list of mobs to find out // which are pointing to this prototype; if it is, it gets // replaced struct char_data *i, *temp; int c; for (i = character_list; i; i = i->next) { if (mob_number == i->nr) { // alloc a temp mobile temp = Mem->GetCh(); *temp = *i; *i = *d->edit_mob; /* copy game-time dependent vars over */ i->in_room = temp->in_room; i->nr = mob_number; i->affected = temp->affected; i->carrying = temp->carrying; i->cyberware = temp->cyberware; i->bioware = temp->bioware; // any eq worn for (c = 0; c < NUM_WEARS; ++c) i->equipment[c] = temp->equipment[c]; i->next_in_room = temp->next_in_room; i->next = temp->next; i->next_fighting = temp->next_fighting; i->followers = temp->followers; i->master = temp->master; i->char_specials.fighting = temp->char_specials.fighting; i->char_specials.hunting = temp->char_specials.hunting; i->mob_specials.last_direction = temp->mob_specials.last_direction; i->mob_specials.memory = temp->mob_specials.memory; i->mob_specials.wait_state = temp->mob_specials.wait_state; Mem->ClearCh(temp); } // end if statement } // end for loop // now you can free the old prototype and put in the new one if (mob_proto[mob_number].player.physical_text.keywords) delete [] mob_proto[mob_number].player.physical_text.keywords; if (mob_proto[mob_number].player.title) delete [] mob_proto[mob_number].player.title; if (mob_proto[mob_number].player.physical_text.name) delete [] mob_proto[mob_number].player.physical_text.name; if (mob_proto[mob_number].player.physical_text.room_desc) delete [] mob_proto[mob_number].player.physical_text.room_desc; if (mob_proto[mob_number].player.physical_text.look_desc) delete [] mob_proto[mob_number].player.physical_text.look_desc; if (mob_proto[mob_number].mob_specials.arrive) delete [] mob_proto[mob_number].mob_specials.arrive; if (mob_proto[mob_number].mob_specials.leave) delete [] mob_proto[mob_number].mob_specials.leave; mob_proto[mob_number] = *d->edit_mob; mob_proto[mob_number].nr = mob_number; } else { // if not, we need to make a new spot in the list int counter; int found = FALSE; struct char_data *new_mob_proto; struct index_data *new_mob_index; struct char_data *temp_mob; // two because you are adding one and you need one over new_mob_index = new struct index_data[top_of_mobt + 2]; new_mob_proto = new struct char_data[top_of_mobt + 2]; // count through the tables for (counter = 0; counter < top_of_mobt + 1; counter++) { /* if we haven't found it */ if (!found) { /* check if current virtual is bigger than our virtual */ if (MOB_VNUM_RNUM(counter) > d->edit_number) { /* eureka. insert now */ /*---------*/ new_mob_index[counter].vnum = d->edit_number; new_mob_index[counter].number = 0; new_mob_index[counter].func = NULL; /*---------*/ new_mob_proto[counter] = *(d->edit_mob); new_mob_proto[counter].in_room = NOWHERE; /* it is now safe (and necessary!) to assign real number to * the edit_mob, which has been -1 all this time */ d->edit_mob->nr = counter; /* and assign to prototype as well */ new_mob_proto[counter].nr = counter; found = TRUE; /* insert the other proto at this point */ new_mob_index[counter + 1] = mob_index[counter]; new_mob_proto[counter + 1] = mob_proto[counter]; new_mob_proto[counter + 1].nr = counter + 1; } else { /* just copy from old to new, no num change */ new_mob_proto[counter] = mob_proto[counter]; new_mob_index[counter] = mob_index[counter]; } } else { // if !found else /* we HAVE already found it.. therefore copy to mobile + 1 */ new_mob_index[counter + 1] = mob_index[counter]; new_mob_proto[counter + 1] = mob_proto[counter]; new_mob_proto[counter + 1].nr = counter + 1; } } // for loop through list /* if we STILL haven't found it, means the mobile was > than all * the other mobs.. so insert at end */ if (!found) { new_mob_index[top_of_mobt + 1].vnum = d->edit_number; new_mob_index[top_of_mobt + 1].number = 0; new_mob_index[top_of_mobt + 1].func = NULL; clear_char(new_mob_proto + top_of_mobt + 1); new_mob_proto[top_of_mobt + 1] = *(d->edit_mob); new_mob_proto[top_of_mobt + 1].in_room = NOWHERE; new_mob_proto[top_of_mobt + 1].nr = top_of_mobt + 1; /* it is now safe (and necessary!) to assign real number to * the edit_mob, which has been -1 all this time */ d->edit_mob->nr = top_of_mobt + 1; } top_of_mobt++; /* we also have to renumber all the mobiles currently * * existing in the world. This is because when I start * * extracting mobiles, bad things will happen! */ for (temp_mob = character_list; temp_mob; temp_mob = temp_mob->next) if (GET_MOB_RNUM (temp_mob) >= d->edit_mob->nr) GET_MOB_RNUM (temp_mob)++; /* free and replace old tables */ delete [] mob_proto; delete [] mob_index; mob_proto = new_mob_proto; mob_index = new_mob_index; /* RENUMBER ZONE TABLES HERE, only * * because I ADDED a mobile! * * This code shamelessly ripped off from db.c */ int zone, cmd_no; for (zone = 0; zone <= top_of_zone_table; zone++) for (cmd_no = 0; cmd_no < zone_table[zone].num_cmds; cmd_no++) { switch (ZCMD.command) { case 'M': ZCMD.arg1 = (ZCMD.arg1 >= d->edit_mob->nr ? ZCMD.arg1 + 1 : ZCMD.arg1); break; } } } // finally done putting the mobile into memory send_to_char("Writing mobile to disk...", CH); write_mobs_to_disk(d->character->player_specials->saved.zonenum); // again, here we don't delete it cause we don't want to end up // deleting the strings from the prototypes if (d->edit_mob) Mem->ClearCh(d->edit_mob); d->edit_mob = NULL; STATE(d) = CON_PLAYING; PLR_FLAGS(d->character).RemoveBit(PLR_EDITING); send_to_char("Done.\r\n", d->character); break; case 'n': case 'N': send_to_char("Mobile not saved, aborting.\r\n", d->character); STATE(d) = CON_PLAYING; // complete nuke if (d->edit_mob) Mem->DeleteCh(d->edit_mob); d->edit_mob = NULL; d->edit_number = 0; d->edit_zone = 0; PLR_FLAGS(d->character).RemoveBit(PLR_EDITING); break; default: send_to_char("Invalid choice!\r\n", d->character); send_to_char("Do you wish to save this mobile internally?\r\n", d->character); break; } break; case MEDIT_MAIN_MENU: switch (*arg) { case 'q': case 'Q': d->edit_mode = MEDIT_CONFIRM_SAVESTRING; medit_parse(d, "y"); break; case 'x': case 'X': d->edit_mode = MEDIT_CONFIRM_SAVESTRING; medit_parse(d, "n"); break; case '1': send_to_char("Enter keywords:", CH); d->edit_mode = MEDIT_EDIT_NAMELIST; break; case '2': send_to_char("Enter name:", CH); d->edit_mode = MEDIT_SHORT_DESCR; break; case '3': send_to_char("Enter room description:", CH); d->edit_mode = MEDIT_REG_DESCR; d->str = new (char *); if (!d->str) { mudlog("Malloc failed!", NULL, LOG_SYSLOG, TRUE); shutdown(); } *(d->str) = NULL; d->max_str = MAX_REG_DESC_LENGTH; d->mail_to = 0; break; case '4': // go to modify.cc send_to_char("Enter look description:\r\n", CH); d->edit_mode = MEDIT_LONG_DESCR; d->str = new (char *); if (!d->str) { mudlog("Malloc failed!", NULL, LOG_SYSLOG, TRUE); shutdown(); } *(d->str) = NULL; d->max_str = MAX_MESSAGE_LENGTH; d->mail_to = 0; break; case '5': medit_disp_mobflags_menu(d); d->edit_mode = MEDIT_MOB_FLAGS; break; case '6': medit_disp_affected_menu(d); d->edit_mode = MEDIT_AFF_FLAGS; break; case '8': send_to_char("Enter average nuyen: ", CH); d->edit_mode = MEDIT_NUYEN; break; case '9': send_to_char("Enter bonus karma points: ", CH); d->edit_mode = MEDIT_EXPERIENCE; break; case 'a': medit_disp_att_menu(d); d->edit_mode = MEDIT_ATTRIBUTES; break; case 'b': send_to_char("Enter level: ", CH); d->edit_mode = MEDIT_LEVEL; break; case 'c': send_to_char("Enter ballistic armor points: ", CH); d->edit_mode = MEDIT_BALLISTIC; break; case 'd': send_to_char("Enter impact armor points: ", CH); d->edit_mode = MEDIT_IMPACT; break; case 'e': send_to_char("Enter max physical points: ", CH); d->edit_mode = MEDIT_PHYSICAL; break; case 'f': send_to_char("Enter max mental points: ", CH); d->edit_mode = MEDIT_MENTAL; break; case 'g': medit_disp_pos_menu(d); send_to_char("Enter position: ", CH); d->edit_mode = MEDIT_POSITION; break; case 'h': medit_disp_pos_menu(d); send_to_char("Enter default position: ", CH); d->edit_mode = MEDIT_DEFAULT_POSITION; break; case 'i': medit_disp_gender_menu(d); d->edit_mode = MEDIT_GENDER; break; case 'j': send_to_char("Enter weight (in kilograms): ", CH); d->edit_mode = MEDIT_WEIGHT; break; case 'k': send_to_char("Enter height (in centimeters): ", CH); d->edit_mode = MEDIT_HEIGHT; break; case 'l': medit_disp_class_menu(d); d->edit_mode = MEDIT_CLASS; break; case 'm': medit_disp_attack_menu(d); d->edit_mode = MEDIT_ATTACK_TYPE; break; case 'n': medit_disp_skill_menu(d); d->edit_mode = MEDIT_SKILLS; break; case 'o': send_to_char("Enter arrive text: ", CH); d->edit_mode = MEDIT_ARRIVE_MSG; break; case 'p': send_to_char("Enter leave text: ", CH); d->edit_mode = MEDIT_LEAVE_MSG; break; default: medit_disp_menu(d); break; } break; case MEDIT_EDIT_NAMELIST: if (MOB->player.physical_text.keywords) delete [] MOB->player.physical_text.keywords; MOB->player.physical_text.keywords = str_dup(arg); medit_disp_menu(d); break; case MEDIT_SHORT_DESCR: if (MOB->player.physical_text.name) delete [] MOB->player.physical_text.name; MOB->player.physical_text.name = str_dup(arg); medit_disp_menu(d); break; case MEDIT_ARRIVE_MSG: if (MOB->mob_specials.arrive) delete [] MOB->mob_specials.arrive; MOB->mob_specials.arrive = str_dup(arg); medit_disp_menu(d); break; case MEDIT_LEAVE_MSG: if (MOB->mob_specials.leave) delete [] MOB->mob_specials.leave; MOB->mob_specials.leave = str_dup(arg); medit_disp_menu(d); break; case MEDIT_REG_DESCR: // you should not come here break; case MEDIT_LONG_DESCR: // you should not come here break; case MEDIT_MOB_FLAGS: number = atoi(arg); if ((number < 0) || (number > MOB_MAX)) medit_disp_mobflags_menu(d); else { if (number == 0) // 0 = quit medit_disp_menu(d); else { MOB_FLAGS(MOB).ToggleBit(number-1); medit_disp_mobflags_menu(d); } } break; case MEDIT_AFF_FLAGS: number = atoi(arg); if ((number < 0) || (number > AFF_MAX)) medit_disp_affected_menu(d); else { if (number == 0) // 0 = quit medit_disp_menu(d); else { AFF_FLAGS(MOB).ToggleBit(number - 1); medit_disp_affected_menu(d); } } break; case MEDIT_NUYEN: number = atoi(arg); if ((number < 0) || (number > 999999)) { send_to_char("Value must range between 0 and 999999.\r\n", CH); send_to_char("Enter average nuyen: ", CH); } else { GET_NUYEN(MOB) = number; send_to_char("Enter average credstick value: ", CH); d->edit_mode = MEDIT_CREDSTICK; } break; case MEDIT_CREDSTICK: number = atoi(arg); if ((number < 0) || (number > 999999)) { send_to_char("Value must range between 0 and 999999.\r\n", CH); send_to_char("Enter average credstick value: ", CH); } else { GET_BANK(MOB) = number; medit_disp_menu(d); } break; case MEDIT_EXPERIENCE: number = atoi(arg); if ((number < 0) || (number > 7500)) { send_to_char("Value must range between 0 and 7500.\r\n", CH); send_to_char("Enter bonus karma points: ", CH); } else { int karma; if (number > (karma=calc_karma(NULL, MOB))) { send_to_char("Bonus karma may not be higher than actual karma. Lowering.\r\n", CH); number = karma; } GET_KARMA(MOB) = number; medit_disp_menu(d); } break; case MEDIT_SKILLS: switch (*arg) { case '0': medit_disp_menu(d); break; case '1': medit_disp_skills(d); send_to_char("Enter a skill (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL1; break; case '2': medit_disp_skills(d); send_to_char("Enter a skill (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL2; break; case '3': medit_disp_skills(d); send_to_char("Enter a skill (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL3; break; case '4': medit_disp_skills(d); send_to_char("Enter a skill (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL4; break; case '5': medit_disp_skills(d); send_to_char("Enter a skill (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL5; break; default: medit_disp_skill_menu(d); break; } break; // end of MEDIT_SKILLS case MEDIT_SKILL1: number = atoi(arg); if ((number < 0) || (number > MAX_SKILLS)) { medit_disp_skills(d); send_to_char(CH, "Value must range between 1 and %d.\r\n", MAX_SKILLS); send_to_char("Enter a skill (0 to quit): ", CH); } else if (number == 0) { // 0 = quit medit_disp_skill_menu(d); d->edit_mode = MEDIT_SKILLS; } else { SET_SKILL(MOB, MOB->mob_specials.mob_skills[0], 0) MOB->mob_specials.mob_skills[0] = number; // to adjust it send_to_char("Enter skill level (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL1_VAL; } break; case MEDIT_SKILL2: number = atoi(arg); if ((number < 0) || (number > MAX_SKILLS)) { medit_disp_skills(d); send_to_char(CH, "Value must range between 1 and %d.\r\n", MAX_SKILLS); send_to_char("Enter a skill (0 to quit): ", CH); } else if (number == 0) { // 0 = quit medit_disp_skill_menu(d); d->edit_mode = MEDIT_SKILLS; } else { SET_SKILL(MOB, MOB->mob_specials.mob_skills[0], 0) MOB->mob_specials.mob_skills[0] = number; // to adjust it send_to_char("Enter skill level (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL2_VAL; } break; case MEDIT_SKILL3: number = atoi(arg); if ((number < 0) || (number > MAX_SKILLS)) { medit_disp_skills(d); send_to_char(CH, "Value must range between 1 and %d.\r\n", MAX_SKILLS); send_to_char("Enter a skill (0 to quit): ", CH); } else if (number == 0) { // 0 = quit medit_disp_skill_menu(d); d->edit_mode = MEDIT_SKILLS; } else { SET_SKILL(MOB, MOB->mob_specials.mob_skills[0], 0) MOB->mob_specials.mob_skills[0] = number; // to adjust it send_to_char("Enter skill level (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL3_VAL; } break; case MEDIT_SKILL4: number = atoi(arg); if ((number < 0) || (number > MAX_SKILLS)) { medit_disp_skills(d); send_to_char(CH, "Value must range between 1 and %d.\r\n", MAX_SKILLS); send_to_char("Enter a skill (0 to quit): ", CH); } else if (number == 0) { // 0 = quit medit_disp_skill_menu(d); d->edit_mode = MEDIT_SKILLS; } else { SET_SKILL(MOB, MOB->mob_specials.mob_skills[0], 0) MOB->mob_specials.mob_skills[0] = number; // to adjust it send_to_char("Enter skill level (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL4_VAL; } break; case MEDIT_SKILL5: number = atoi(arg); if ((number < 0) || (number > MAX_SKILLS)) { medit_disp_skills(d); send_to_char(CH, "Value must range between 1 and %d.\r\n", MAX_SKILLS); send_to_char("Enter a skill (0 to quit): ", CH); } else if (number == 0) { // 0 = quit medit_disp_skill_menu(d); d->edit_mode = MEDIT_SKILLS; } else { SET_SKILL(MOB, MOB->mob_specials.mob_skills[0], 0) MOB->mob_specials.mob_skills[0] = number; // to adjust it send_to_char("Enter skill level (0 to quit): ", CH); d->edit_mode = MEDIT_SKILL5_VAL; } break; case MEDIT_SKILL1_VAL: number = atoi(arg); if ((number < 0) || (number > 50)) { send_to_char("Skill level must be between 1 and 50.\r\n", CH); send_to_char("Enter skill level: ", CH); } else if (number == 0) { MOB->mob_specials.mob_skills[0] = 0; MOB->mob_specials.mob_skills[1] = 0; d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } else { MOB->mob_specials.mob_skills[1] = number; GET_SKILL(MOB, MOB->mob_specials.mob_skills[0]) = MOB->mob_specials.mob_skills[1]; SET_SKILL(MOB, MOB->mob_specials.mob_skills[0], MOB->mob_specials.mob_skills[1]); d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } break; case MEDIT_SKILL2_VAL: number = atoi(arg); if ((number < 0) || (number > 50)) { send_to_char("Skill level must be between 1 and 50.\r\n", CH); send_to_char("Enter skill level: ", CH); } else if (number == 0) { MOB->mob_specials.mob_skills[2] = 0; MOB->mob_specials.mob_skills[3] = 0; d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } else { MOB->mob_specials.mob_skills[3] = number; GET_SKILL(MOB, MOB->mob_specials.mob_skills[2]) = MOB->mob_specials.mob_skills[3]; SET_SKILL(MOB, MOB->mob_specials.mob_skills[2], MOB->mob_specials.mob_skills[3]); d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } break; case MEDIT_SKILL3_VAL: number = atoi(arg); if ((number < 0) || (number > 50)) { send_to_char("Skill level must be between 1 and 50.\r\n", CH); send_to_char("Enter skill level: ", CH); } else if (number == 0) { MOB->mob_specials.mob_skills[4] = 0; MOB->mob_specials.mob_skills[5] = 0; d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } else { MOB->mob_specials.mob_skills[5] = number; GET_SKILL(MOB, MOB->mob_specials.mob_skills[4]) = MOB->mob_specials.mob_skills[5]; SET_SKILL(MOB, MOB->mob_specials.mob_skills[4], MOB->mob_specials.mob_skills[5]); d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } break; case MEDIT_SKILL4_VAL: number = atoi(arg); if ((number < 0) || (number > 50)) { send_to_char("Skill level must be between 1 and 50.\r\n", CH); send_to_char("Enter skill level: ", CH); } else if (number == 0) { MOB->mob_specials.mob_skills[6] = 0; MOB->mob_specials.mob_skills[7] = 0; d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } else { MOB->mob_specials.mob_skills[7] = number; GET_SKILL(MOB, MOB->mob_specials.mob_skills[6]) = MOB->mob_specials.mob_skills[7]; SET_SKILL(MOB, MOB->mob_specials.mob_skills[6], MOB->mob_specials.mob_skills[7]); d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } break; case MEDIT_SKILL5_VAL: number = atoi(arg); if ((number < 0) || (number > 50)) { send_to_char("Skill level must be between 1 and 50.\r\n", CH); send_to_char("Enter skill level: ", CH); } else if (number == 0) { MOB->mob_specials.mob_skills[8] = 0; MOB->mob_specials.mob_skills[9] = 0; d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } else { MOB->mob_specials.mob_skills[9] = number; GET_SKILL(MOB, MOB->mob_specials.mob_skills[8]) = MOB->mob_specials.mob_skills[9]; SET_SKILL(MOB, MOB->mob_specials.mob_skills[8], MOB->mob_specials.mob_skills[9]); d->edit_mode = MEDIT_SKILLS; medit_disp_skill_menu(d); } break; case MEDIT_ATTRIBUTES: switch (*arg) { case '1': send_to_char("Enter body attribute: ", CH); d->edit_mode = MEDIT_BOD; break; case '2': send_to_char("Enter quickness attribute: ", CH); d->edit_mode = MEDIT_QUI; break; case '3': send_to_char("Enter strength attribute: ", CH); d->edit_mode = MEDIT_STR; break; case '4': send_to_char("Enter charisma attribute: ", CH); d->edit_mode = MEDIT_CHA; break; case '5': send_to_char("Enter intelligence attribute: ", CH); d->edit_mode = MEDIT_INT; break; case '6': send_to_char("Enter willpower attribute: ", CH); d->edit_mode = MEDIT_WIL; break; case '7': send_to_char("Enter magic attribute: ", CH); d->edit_mode = MEDIT_MAG; break; case 'q': case 'Q': // back to main menu medit_disp_menu(d); break; default: medit_disp_att_menu(d); break; } break; case MEDIT_BOD: number = atoi(arg); if ((number < 1) || (number > 50)) { send_to_char("Value must range between 1 and 50.\r\n", CH); send_to_char("Enter body attribute: ", CH); } else { GET_REAL_BOD(MOB) = number; MOB->real_abils.bod_index = number * 100; medit_disp_att_menu(d); } break; case MEDIT_QUI: number = atoi(arg); if ((number < 1) || (number > 50)) { send_to_char("Value must range between 1 and 50.\r\n", CH); send_to_char("Enter quickness attribute: ", CH); } else { GET_REAL_QUI(MOB) = number; GET_REAL_REA(MOB) = (number + GET_REAL_INT(MOB)) >> 1; medit_disp_att_menu(d); } break; case MEDIT_STR: number = atoi(arg); if ((number < 1) || (number > 50)) { send_to_char("Value must range between 1 and 50.\r\n", CH); send_to_char("Enter strength attribute: ", CH); } else { GET_REAL_STR(MOB) = number; medit_disp_att_menu(d); } break; case MEDIT_CHA: number = atoi(arg); if ((number < 1) || (number > 50)) { send_to_char("Value must range between 1 and 50.\r\n", CH); send_to_char("Enter charisma attribute: ", CH); } else { GET_REAL_CHA(MOB) = number; medit_disp_att_menu(d); } break; case MEDIT_INT: number = atoi(arg); if ((number < 1) || (number > 50)) { send_to_char("Value must range between 1 and 50.\r\n", CH); send_to_char("Enter intelligence attribute: ", CH); } else { GET_REAL_INT(MOB) = number; GET_REAL_REA(MOB) = (number + GET_REAL_QUI(MOB)) >> 1; medit_disp_att_menu(d); } break; case MEDIT_WIL: number = atoi(arg); if ((number < 1) || (number > 50)) { send_to_char("Value must range between 1 and 50.\r\n", CH); send_to_char("Enter willpower attribute: ", CH); } else { GET_REAL_WIL(MOB) = number; medit_disp_att_menu(d); } break; case MEDIT_MAG: number = atoi(arg); if ((number < 0) || (number > 50)) { send_to_char("Value must range between 0 and 50.\r\n", CH); send_to_char("Enter magic attribute: ", CH); } else { MOB->real_abils.mag = number * 100; medit_disp_att_menu(d); } break; case MEDIT_LEVEL: number = atoi(arg); if (number < 0) { send_to_char("Invalid choice.\r\n", CH); send_to_char("Enter level: ", CH); } else { GET_LEVEL(MOB) = number; medit_disp_menu(d); } break; case MEDIT_BALLISTIC: number = atoi(arg); if (number < 0) { send_to_char("Value must be greater than 0.\r\n", CH); send_to_char("Enter ballistic armor points: ", CH); } else { GET_BALLISTIC(MOB) = number; medit_disp_menu(d); } break; case MEDIT_IMPACT: number = atoi(arg); if (number < 0) { send_to_char("Value must be greater than 0.\r\n", CH); send_to_char("Enter impact armor points: ", CH); } else { GET_IMPACT(MOB) = number; medit_disp_menu(d); } break; case MEDIT_PHYSICAL: number = atoi(arg); if ((number < 0) || (number > 10)) { send_to_char("Value must range between 0 and 10.\r\n", CH); send_to_char("Enter max physical points: ", CH); } else { GET_MAX_PHYSICAL(MOB) = number * 100; GET_PHYSICAL(MOB) = number * 100; medit_disp_menu(d); } break; case MEDIT_MENTAL: number = atoi(arg); if ((number < 0) || (number > 10)) { send_to_char("Value must range between 0 and 10.\r\n", CH); send_to_char("Enter max mental points: ", CH); } else { GET_MAX_MENTAL(MOB) = number * 100; GET_MENTAL(MOB) = number * 100; medit_disp_menu(d); } break; case MEDIT_WEIGHT: number = atoi(arg); if (number < 0) { send_to_char("Value must be greater than 0.\r\n", CH); send_to_char("Enter weight (in kilograms): ", CH); } else { GET_WEIGHT(MOB) = number; medit_disp_menu(d); } break; case MEDIT_HEIGHT: number = atoi(arg); if (number < 0) { send_to_char("Value must be greater than 0.\r\n", CH); send_to_char("Enter height (in centimeters): ", CH); } else { GET_HEIGHT(MOB) = number; medit_disp_menu(d); } break; case MEDIT_CLASS: number = atoi(arg); if ((number < 1) || (number > NUM_MOB_CLASSES)) medit_disp_class_menu(d); else { GET_RACE(MOB) = (number - 1); medit_disp_menu(d); } break; case MEDIT_POSITION: number = atoi(arg); if ((number < POS_MORTALLYW) || (number > POS_STANDING)) { send_to_char("Invalid choice.\r\nEnter position: ", CH); medit_disp_pos_menu(d); } else { GET_POS(MOB) = number; medit_disp_menu(d); } break; case MEDIT_DEFAULT_POSITION: number = atoi(arg); if ((number < POS_MORTALLYW) || (number > POS_STANDING)) { send_to_char("Invalid choice.\r\nEnter default position: ", CH); medit_disp_pos_menu(d); } else { GET_DEFAULT_POS(MOB) = number; medit_disp_menu(d); } break; case MEDIT_GENDER: number = atoi(arg); if ((number < 0) || (number > 3)) { send_to_char("Invalid choice.\r\n", CH); medit_disp_gender_menu(d); } else if (number != 0) // 0 = quit GET_SEX(MOB) = (number - 1); medit_disp_menu(d); break; case MEDIT_ATTACK_TYPE: number = atoi(arg); if ((number < 0) || (number > NUM_ATTACK_TYPES)) { send_to_char("Invalid choice.\r\n", CH); medit_disp_attack_menu(d); } else if (number != 0) // 0 = quit MOB->mob_specials.attack_type = number-1 + TYPE_HIT; medit_disp_menu(d); break; } }
void mobile_activity(void) { struct char_data *ch, *next_ch, *vict; struct obj_data *obj, *best_obj; int door, found, max; memory_rec *names; for (ch = character_list; ch; ch = next_ch) { next_ch = ch->next; if (!IS_MOB(ch)) continue; /* Examine call for special procedure */ if (MOB_FLAGGED(ch, MOB_SPEC) && !no_specials) { if (mob_index[GET_MOB_RNUM(ch)].func == NULL) { log("SYSERR: %s (#%d): Attempting to call non-existing mob function.", GET_NAME(ch), GET_MOB_VNUM(ch)); REMOVE_BIT_AR(MOB_FLAGS(ch), MOB_SPEC); } else { char actbuf[MAX_INPUT_LENGTH] = ""; if ((mob_index[GET_MOB_RNUM(ch)].func) (ch, ch, 0, actbuf)) continue; /* go to next char */ } } /* If the mob has no specproc, do the default actions */ if (FIGHTING(ch) || !AWAKE(ch)) continue; /* hunt a victim, if applicable */ hunt_victim(ch); /* Scavenger (picking up objects) */ if (MOB_FLAGGED(ch, MOB_SCAVENGER)) if (world[IN_ROOM(ch)].contents && !rand_number(0, 10)) { max = 1; best_obj = NULL; for (obj = world[IN_ROOM(ch)].contents; obj; obj = obj->next_content) if (CAN_GET_OBJ(ch, obj) && GET_OBJ_COST(obj) > max) { best_obj = obj; max = GET_OBJ_COST(obj); } if (best_obj != NULL) { obj_from_room(best_obj); obj_to_char(best_obj, ch); act("$n gets $p.", FALSE, ch, best_obj, 0, TO_ROOM); } } /* Mob Movement */ if (!MOB_FLAGGED(ch, MOB_SENTINEL) && (GET_POS(ch) == POS_STANDING) && ((door = rand_number(0, 18)) < DIR_COUNT) && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_DEATH) && (!MOB_FLAGGED(ch, MOB_STAY_ZONE) || (world[EXIT(ch, door)->to_room].zone == world[IN_ROOM(ch)].zone))) { /* If the mob is charmed, do not move the mob. */ if (ch->master == NULL) perform_move(ch, door, 1); } /* Aggressive Mobs */ if (!MOB_FLAGGED(ch, MOB_HELPER) && (!AFF_FLAGGED(ch, AFF_BLIND) || !AFF_FLAGGED(ch, AFF_CHARM))) { found = FALSE; for (vict = world[IN_ROOM(ch)].people; vict && !found; vict = vict->next_in_room) { if (IS_NPC(vict) || !CAN_SEE(ch, vict) || PRF_FLAGGED(vict, PRF_NOHASSLE)) continue; if (MOB_FLAGGED(ch, MOB_WIMPY) && AWAKE(vict)) continue; if (MOB_FLAGGED(ch, MOB_AGGRESSIVE ) || (MOB_FLAGGED(ch, MOB_AGGR_EVIL ) && IS_EVIL(vict)) || (MOB_FLAGGED(ch, MOB_AGGR_NEUTRAL) && IS_NEUTRAL(vict)) || (MOB_FLAGGED(ch, MOB_AGGR_GOOD ) && IS_GOOD(vict))) { /* Can a master successfully control the charmed monster? */ if (aggressive_mob_on_a_leash(ch, ch->master, vict)) continue; hit(ch, vict, TYPE_UNDEFINED); found = TRUE; } } } /* Mob Memory */ if (MOB_FLAGGED(ch, MOB_MEMORY) && MEMORY(ch)) { found = FALSE; for (vict = world[IN_ROOM(ch)].people; vict && !found; vict = vict->next_in_room) { if (IS_NPC(vict) || !CAN_SEE(ch, vict) || PRF_FLAGGED(vict, PRF_NOHASSLE)) continue; for (names = MEMORY(ch); names && !found; names = names->next) { if (names->id != GET_IDNUM(vict)) continue; /* Can a master successfully control the charmed monster? */ if (aggressive_mob_on_a_leash(ch, ch->master, vict)) continue; found = TRUE; act("'Hey! You're the fiend that attacked me!!!', exclaims $n.", FALSE, ch, 0, 0, TO_ROOM); hit(ch, vict, TYPE_UNDEFINED); } } } /* Charmed Mob Rebellion: In order to rebel, there need to be more charmed * monsters than the person can feasibly control at a time. Then the * mobiles have a chance based on the charisma of their leader. * 1-4 = 0, 5-7 = 1, 8-10 = 2, 11-13 = 3, 14-16 = 4, 17-19 = 5, etc. */ if (AFF_FLAGGED(ch, AFF_CHARM) && ch->master && num_followers_charmed(ch->master) > (GET_CHA(ch->master) - 2) / 3) { if (!aggressive_mob_on_a_leash(ch, ch->master, ch->master)) { if (CAN_SEE(ch, ch->master) && !PRF_FLAGGED(ch->master, PRF_NOHASSLE)) hit(ch, ch->master, TYPE_UNDEFINED); stop_follower(ch); } } /* Helper Mobs */ if (MOB_FLAGGED(ch, MOB_HELPER) && (!AFF_FLAGGED(ch, AFF_BLIND) || !AFF_FLAGGED(ch, AFF_CHARM))) { found = FALSE; for (vict = world[IN_ROOM(ch)].people; vict && !found; vict = vict->next_in_room) { if (ch == vict || !IS_NPC(vict) || !FIGHTING(vict)) continue; if (IS_NPC(FIGHTING(vict)) || ch == FIGHTING(vict)) continue; act("$n jumps to the aid of $N!", FALSE, ch, 0, vict, TO_ROOM); hit(ch, FIGHTING(vict), TYPE_UNDEFINED); found = TRUE; } } /* Add new mobile actions here */ } /* end for() */ }
int add_mobile(struct char_data *mob, mob_vnum vnum) { int rnum, i, found = FALSE, shop, cmd_no; zone_rnum zone; struct char_data *live_mob; if ((rnum = real_mobile(vnum)) != NOBODY) { /* Copy over the mobile and free() the old strings. */ copy_mobile(&mob_proto[rnum], mob); /* Now re-point all existing mobile strings to here. */ for (live_mob = character_list; live_mob; live_mob = live_mob->next) if (rnum == live_mob->nr) update_mobile_strings(live_mob, &mob_proto[rnum]); add_to_save_list(zone_table[real_zone_by_thing(vnum)].number, SL_MOB); log("GenOLC: add_mobile: Updated existing mobile #%d.", vnum); return TRUE; } RECREATE(mob_proto, struct char_data, top_of_mobt + 2); RECREATE(mob_index, struct index_data, top_of_mobt + 2); top_of_mobt++; for (i = top_of_mobt; i > 0; i--) { if (vnum > mob_index[i - 1].vnum) { mob_proto[i] = *mob; mob_proto[i].nr = i; copy_mobile_strings(mob_proto + i, mob); mob_index[i].vnum = vnum; mob_index[i].number = 0; mob_index[i].func = 0; found = i; break; } mob_index[i] = mob_index[i - 1]; mob_proto[i] = mob_proto[i - 1]; mob_proto[i].nr++; } if (!found) { mob_proto[0] = *mob; mob_proto[0].nr = 0; copy_mobile_strings(&mob_proto[0], mob); mob_index[0].vnum = vnum; mob_index[0].number = 0; mob_index[0].func = 0; } log("GenOLC: add_mobile: Added mobile %d at index #%d.", vnum, found); #if CONFIG_GENOLC_MOBPROG GET_MPROG(OLC_MOB(d)) = OLC_MPROGL(d); GET_MPROG_TYPE(OLC_MOB(d)) = (OLC_MPROGL(d) ? OLC_MPROGL(d)->type : 0); while (OLC_MPROGL(d)) { GET_MPROG_TYPE(OLC_MOB(d)) |= OLC_MPROGL(d)->type; OLC_MPROGL(d) = OLC_MPROGL(d)->next; } #endif /* * Update live mobile rnums. */ for (live_mob = character_list; live_mob; live_mob = live_mob->next) GET_MOB_RNUM(live_mob) += (GET_MOB_RNUM(live_mob) >= found); /* * Update zone table. */ for (zone = 0; zone <= top_of_zone_table; zone++) for (cmd_no = 0; ZCMD(zone, cmd_no).command != 'S'; cmd_no++) if (ZCMD(zone, cmd_no).command == 'M') ZCMD(zone, cmd_no).arg1 += (ZCMD(zone, cmd_no).arg1 >= found); /* * Update shop keepers. */ if (shop_index) for (shop = 0; shop <= top_shop - top_shop_offset; shop++) SHOP_KEEPER(shop) += (SHOP_KEEPER(shop) >= found); add_to_save_list(zone_table[real_zone_by_thing(vnum)].number, SL_MOB); return found; }
void mobile_activity(void) { register struct char_data *ch, *next_ch, *vict; struct char_data *min_vict = NULL; struct obj_data *obj, *next_obj, *best_obj, *cont; int door, found, max, where; int casual, max_abil=0, curr_abil, gold; memory_rec *names; room_rnum target_room; extern int no_specials; ACMD(do_get); for (ch = character_list; ch; ch = next_ch) { next_ch = ch->next; if (!IS_MOB(ch)) continue; //lance ripristina il master! if (IS_NPC(ch) && MOB_FLAGGED(ch, MOB_SAVE)) chkmaster(ch); // Examine call for special procedure if (MOB_FLAGGED(ch, MOB_SPEC) && !no_specials) { if (mob_index[GET_MOB_RNUM(ch)].func == NULL) { sprintf(buf, "SYSERR: %s (#%d): Attempting to call non-existing mob func", GET_NAME(ch), GET_MOB_VNUM(ch)); log(buf); REMOVE_BIT(MOB_FLAGS(ch), MOB_SPEC); } else { //(mob_index[GET_MOB_RNUM(ch)].func) (ch, ch, 0, ""); if ((mob_index[GET_MOB_RNUM(ch)].func) (ch, ch, 0, "")) continue; /* go to next char*/ } } // If the mob has no specproc, do the default actions if (FIGHTING(ch) || !AWAKE(ch)) continue; // Nuovo Scavenger (picking up objects) by Rusty if (MOB_FLAGGED(ch, MOB_SCAVENGER)) if (world[ch->in_room].contents && (number(0, 10) > 5)) { max = -1000; best_obj = NULL; for (obj = world[ch->in_room].contents; obj; obj = obj->next_content) if (CAN_GET_OBJ(ch, obj) && objlevel(obj) > max) { best_obj = obj; max = objlevel(obj); } if (best_obj != NULL) { obj_from_room(best_obj); obj_to_char(best_obj, ch); act("$n prende $p.", FALSE, ch, best_obj, 0, TO_ROOM); // Orione, tolta la procedura che fa indossare l'eq raccolto ai mob scavenger // Scavenger Plus:Mob wear the best object /* where=find_eq_pos(ch, best_obj, 0); if (CAN_WEAR(best_obj, ITEM_WEAR_WIELD)) where=WEAR_WIELD; if ( (where>0) && GET_EQ(ch,where)) { // se ce l'ha gia! if ((objlevel((ch)->equipment[where]))< objlevel(best_obj)) { obj_to_char((obj=unequip_char(ch, where)), ch); act("$n smette di usare $p.", FALSE, ch, obj, 0, TO_ROOM); } else { where = NUM_WEARS; // cioe' oggetto non indossabile } if (GET_LEVEL(ch)>=objlevel(best_obj)) { if (where>=0 && where <NUM_WEARS) { obj_from_char(best_obj); equip_char(ch,best_obj,where); wear_message(ch,best_obj,where); } } } */ } } //End ifif // Mob BodyGuard !? if (MOB_FLAGGED(ch, MOB_BGUARD) && (ch->master)) { if ( (FIGHTING(ch->master) && (npc_rescue(ch, ch->master) == FALSE)) || (ch->master && WHOKILLED(ch->master)) ) { act("$N Si schiera Prontamente al tuo fianco!", FALSE,ch->master, 0, ch, TO_CHAR); act("$n Si schiera prontamente al fianco di $N", FALSE, ch, 0, ch->master, TO_ROOM); if (WHOKILLED(ch->master)) hit(ch, WHOKILLED(ch->master), TYPE_UNDEFINED);/*in ogni caso assiste*/ else hit(ch, FIGHTING(ch->master), TYPE_UNDEFINED);/*in ogni caso assiste*/ } if (FIGHTING(ch)) { npc_rescue(ch, ch->master); if (WHOKILLED(ch->master)) hit(ch, WHOKILLED(ch->master), TYPE_UNDEFINED); /*in ogni caso assiste*/ continue; } } //MOB_THIEF if ( MOB_FLAGGED(ch, MOB_CRIMINAL) && (GET_POS(ch) == POS_RESTING) && IS_AFFECTED(ch, AFF_HIDE) && GET_HIT(ch) >= 2*GET_MAX_HIT(ch)/3) { appear(ch); GET_POS(ch)=POS_STANDING; } if ( MOB_FLAGGED(ch, MOB_CRIMINAL) && ( GET_POS(ch) == POS_STANDING) && ( (casual = number(0, 11)) < 6 ) ) { // 50% Rubare // cerca le vittime 1) Devono aver almeno 1 coin // 2) Deve aver una buona prob di farcela for (found=FALSE, min_vict = NULL, vict = world[ch->in_room].people; vict; vict = vict->next_in_room) { if (CAN_SEE(ch, vict) && (vict != ch)) { if ((min_vict == NULL) || (max_abil < 100)) { //se ha il 100% tanto vale fermarsi //Calcolo dell abilita:presa esattamente da D n'D curr_abil = MIN(90, (10*(GET_LEVEL(ch)) - 5*GET_LEVEL(vict))); curr_abil -= dex_app[GET_DEX(vict)].reaction; if (GET_POS(vict) < POS_STANDING) curr_abil += 200; // Se la vittima e' addormentata-stunned - incap o morta ovviamente // deruberai questa sicuramente if ( (curr_abil >= 40) && (GET_GOLD(vict) != 0) && (curr_abil > max_abil) ) { min_vict = vict; max_abil = curr_abil; found=TRUE; } } } } // Se ha trovato la vittima if (found == TRUE) { if ((casual = number(1, 100)) > max_abil) { if (!IS_NPC(min_vict)) act(" $n cerca di prendere dei soldi dal tuo Borsello", FALSE, ch, 0, min_vict, TO_CHAR); else { act("Oops...", FALSE, ch, 0, min_vict, TO_ROOM); act("$n cerca di rubare soldi a $N..Ma viene Scoperto! ", FALSE, ch, 0, min_vict, TO_ROOM); } //Beccato ... fa 2 tentativi di fuga if (((door = number(1, 7)) < NUM_OF_DIRS) && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) ) perform_move(ch,door,1,CAN_SHOW_ROOM); if ((door -= 1) < NUM_OF_DIRS && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) ) perform_move(ch,door,1,CAN_SHOW_ROOM); if ((door += 2) < NUM_OF_DIRS && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) ) perform_move(ch,door,1,CAN_SHOW_ROOM); if (IS_NPC(min_vict)) { act("$n Urla: $N e' uno sporco LADRO!!!!", FALSE, min_vict, 0, ch, TO_ROOM); hit(min_vict, ch, TYPE_UNDEFINED); } } // Il Bastardo ce la fa! else { if (GET_POS(min_vict) < 5) { GET_GOLD(ch) += GET_GOLD(min_vict); GET_GOLD(min_vict) = 0; //la ripulisce completamente } else { gold = number((GET_GOLD(min_vict) / 10), (GET_GOLD(min_vict) / 2)); //gold = MIN(5000, gold); if (gold > 0) { GET_GOLD(ch) += gold; GET_GOLD(min_vict) -= gold; if (GET_GOLD(min_vict) < 0) GET_GOLD(min_vict) = 0; } } // Dopo il furto si allontana if (((door = number(1, 6)) < NUM_OF_DIRS) && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) ) perform_move(ch,door,1,CAN_SHOW_ROOM); if ((door -=1) < NUM_OF_DIRS && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) ) perform_move(ch,door,1,CAN_SHOW_ROOM); if ((door +=2) < NUM_OF_DIRS && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) ) perform_move(ch,door,1,CAN_SHOW_ROOM); } } else { // Nessuna vittima appetibile:se ne va! if (((door = number(0, 6)) < NUM_OF_DIRS) && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) ) perform_move(ch, door, 1, CAN_SHOW_ROOM); } } // Mob Sciacalli indossano EQ if (MOB_FLAGGED(ch, MOB_NECRO) && !FIGHTING(ch) && AWAKE(ch)) if (world[ch->in_room].contents) { max = -1000; best_obj=NULL; for (cont = world[ch->in_room].contents;cont;cont = cont->next_content) if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER) { for (obj = cont->contains; obj; obj = next_obj) { next_obj = obj->next_content; if (obj != NULL) { if (CAN_SEE_OBJ(ch, obj) && ( (max = objlevel(obj)) <= GET_LEVEL(ch)) ) { perform_get_from_container(ch, obj, cont, FIND_OBJ_INV); if (obj != NULL) { where = find_eq_pos(ch, obj, 0); if (CAN_WEAR(obj, ITEM_WEAR_HOLD)) where = WEAR_HOLD; if (GET_OBJ_TYPE(obj)==ITEM_LIGHT) where = WEAR_LIGHT; if (CAN_WEAR(obj, ITEM_WEAR_WIELD)) where = WEAR_WIELD; if (where < 0) { sprintf(buf,"SYSERR:pos < 0 ,in cont %s obj %d %s In room %d", cont->name, GET_OBJ_RNUM(obj), obj->name, IN_ROOM(ch)); log(buf); where = NUM_WEARS; } if (GET_EQ(ch, where) && where < NUM_WEARS) { if ((objlevel((ch)->equipment[where])) < objlevel(obj)) { obj_to_char((best_obj = unequip_char(ch, where)), ch); act("$n smette di usare $p.",FALSE, ch, best_obj, 0, TO_ROOM); } else where = NUM_WEARS; } if (where >= 0 && where < NUM_WEARS) { wear_message(ch, obj, where); obj_from_char(obj); equip_char(ch, obj, where); } } } } } } //End forif } //End ifif // Mob Movement if (HUNTING(ch)) hunt_victim(ch); else { if (MOB_FLAGGED(ch , MOB_SEARCHER)) {} else { if (ch->in_room != NOWHERE) { if (!IS_IN_WILD(ch)) { if ( !MOB_FLAGGED(ch, MOB_SENTINEL) && (GET_POS(ch) == POS_STANDING) && ( (door = number(0, 8)) < NUM_OF_DIRS) && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) && ( !MOB_FLAGGED(ch, MOB_STAY_ZONE) || (world[EXIT(ch, door)->to_room].zone == world[ch->in_room].zone))) { perform_move(ch, door, 1, CAN_SHOW_ROOM); } } else { // E' in wilderness if (MOB_FLAGGED(ch, MOB_WILDHUNT)) door = wild_mobhunter(ch); else door = number(0, 8); if (door >= 0 && door < NUM_OF_DIRS) target_room = wild_target_room(ch, door); else target_room = -1; if ( !MOB_FLAGGED(ch, MOB_SENTINEL) && (GET_POS(ch) == POS_STANDING) && (target_room != -1) && ( !MOB_FLAGGED(ch, MOB_STAY_ZONE) || (world[target_room].wild_rnum == world[ch->in_room].wild_rnum))) { perform_move(ch, door, 1, CAN_SHOW_ROOM); } } } } } // Aggressive Mobs if (MOB_FLAGGED(ch, MOB_AGGRESSIVE | MOB_AGGR_TO_ALIGN)) { found = FALSE; for (vict = world[ch->in_room].people; vict && !found; vict = vict->next_in_room) { if (IS_NPC(vict) || !CAN_SEE(ch, vict) || PRF_FLAGGED(vict, PRF_NOHASSLE)) continue; if (number(0, 3) < 2) continue; // Simple simulate Random a Joke from Phantom ;P if (GET_ABIL (vict, ABIL_TRATTATIVA) >= EXPERT_LIV) continue; // I pg con trattativa ad esperto fanno pace con gli aggressivi (by Spini) if (controllo_volo(ch, vict)) continue; if (affected_by_spell (vict, SPELLSKILL, DISEASE_PESTE)) continue; if (MOB_FLAGGED(ch, MOB_AGGR_NO_PROP) && (MASTER_ID(ch)==GET_IDNUM(vict))) continue; if (MOB_FLAGGED(ch, MOB_AGGR_NO_CLAN) && (CLAN_ID(ch)==GET_CLAN(vict))) continue; if (MOB_FLAGGED(ch, MOB_AGGR_NO_AL_CLAN) && (GET_CLAN_DIPLO(GET_CLAN(ch),GET_CLAN(vict)) == ALLIANCE)) continue; if (MOB_FLAGGED(ch, MOB_AGGR_NO_EN_CLAN) && (GET_CLAN_DIPLO(GET_CLAN(ch),GET_CLAN(vict)) == WAR)) continue; if (MOB_FLAGGED(ch, MOB_AGGR_NO_PC_CLAN) && (GET_CLAN_DIPLO(GET_CLAN(ch),GET_CLAN(vict)) == PEACE)) continue; if (MOB_FLAGGED(ch, MOB_AGGR_VAS_CLAN) && (GET_CLAN_DIPLO(GET_CLAN(ch),GET_CLAN(vict)) == VASSALLO)) continue; if ( !MOB_FLAGGED(ch, MOB_AGGR_TO_ALIGN) || (MOB_FLAGGED(ch, MOB_AGGR_EVIL) && IS_EVIL(vict)) || (MOB_FLAGGED(ch, MOB_AGGR_NEUTRAL) && IS_NEUTRAL(vict)) || (MOB_FLAGGED(ch, MOB_AGGR_GOOD) && IS_GOOD(vict)) ) { if (GET_MOB_SPEC(ch)== thief) npc_backstab(ch,vict); else hit(ch, vict, TYPE_UNDEFINED); found = TRUE; } } } // Mob Memory if (MOB_FLAGGED(ch, MOB_MEMORY) && MEMORY(ch)) { found = FALSE; for (vict = world[ch->in_room].people; vict && !found; vict = vict->next_in_room) { if (!CAN_SEE(ch, vict) || PRF_FLAGGED(vict, PRF_NOHASSLE)) continue; for (names = MEMORY(ch); names && !found; names = names->next) if (names->id == GET_IDNUM(vict)) { found = TRUE; act("$n esclama, 'Hey!! Tu sei il tipo che mi ha attaccato!!!'", FALSE, ch, 0, 0, TO_ROOM); hit(ch, vict, TYPE_UNDEFINED); } //End forif } } // Helper Mobs Paladino del bene if ( MOB_FLAGGED(ch, MOB_HELPER) && !MOB_FLAGGED(ch, MOB_CRIMINALHELPER) ) { found = FALSE; for (vict = world[ch->in_room].people; vict && !found; vict = vict->next_in_room) if ( ch != vict && IS_NPC(vict) && FIGHTING(vict) && !IS_NPC(FIGHTING(vict)) && ch != FIGHTING(vict) ) { if ( MOB_FLAGGED(vict, MOB_CRIMINAL) || ( (ch->master) && (FIGHTING(vict) == ch->master) ) ) { hit(ch, vict, TYPE_UNDEFINED); found = TRUE; } else { act("$n arriva in aiuto di $N!", FALSE, ch, 0, vict, TO_ROOM); hit(ch, FIGHTING(vict), TYPE_UNDEFINED); found = TRUE; } } //End forif } // Helper Mobs Servo del male if ( MOB_FLAGGED(ch, MOB_CRIMINALHELPER) && !MOB_FLAGGED(ch, MOB_HELPER) ) { found = FALSE; for (vict = world[ch->in_room].people; vict && !found; vict = vict->next_in_room) if ( ch != vict && IS_NPC(vict) && FIGHTING(vict) && !IS_NPC(FIGHTING(vict)) && ch != FIGHTING(vict) ) { if ( MOB_FLAGGED(vict, MOB_CRIMINAL) || ( (ch->master) && (vict == ch->master) ) ) { act("$n arriva in aiuto di $N!", FALSE, ch, 0, vict, TO_ROOM); hit(ch, FIGHTING(vict), TYPE_UNDEFINED); found = TRUE; } } //End forif } // Add new mobile actions here } // end for() }
/* Extract a ch completely from the world, and leave his stuff behind */ void extract_char_final(struct char_data *ch) { struct char_data *k, *temp; struct descriptor_data *d; struct obj_data *obj; int i; if (IN_ROOM(ch) == NOWHERE) { log("SYSERR: NOWHERE extracting char %s. (%s, extract_char_final)", GET_NAME(ch), __FILE__); exit(1); } /* We're booting the character of someone who has switched so first we need * to stuff them back into their own body. This will set ch->desc we're * checking below this loop to the proper value. */ if (!IS_NPC(ch) && !ch->desc) { for (d = descriptor_list; d; d = d->next) if (d->original == ch) { do_return(d->character, NULL, 0, 0); break; } } if (ch->desc) { /* This time we're extracting the body someone has switched into (not the * body of someone switching as above) so we need to put the switcher back * to their own body. If this body is not possessed, the owner won't have a * body after the removal so dump them to the main menu. */ if (ch->desc->original) do_return(ch, NULL, 0, 0); else { /* Now we boot anybody trying to log in with the same character, to help * guard against duping. CON_DISCONNECT is used to close a descriptor * without extracting the d->character associated with it, for being * link-dead, so we want CON_CLOSE to clean everything up. If we're * here, we know it's a player so no IS_NPC check required. */ for (d = descriptor_list; d; d = d->next) { if (d == ch->desc) continue; if (d->character && GET_IDNUM(ch) == GET_IDNUM(d->character)) STATE(d) = CON_CLOSE; } STATE(ch->desc) = CON_MENU; write_to_output(ch->desc, "%s", CONFIG_MENU); } } /* On with the character's assets... */ if (ch->followers || ch->master) die_follower(ch); /* Check to see if we are grouped! */ if (GROUP(ch)) leave_group(ch); /* transfer objects to room, if any */ while (ch->carrying) { obj = ch->carrying; obj_from_char(obj); obj_to_room(obj, IN_ROOM(ch)); } /* transfer equipment to room, if any */ for (i = 0; i < NUM_WEARS; i++) if (GET_EQ(ch, i)) obj_to_room(unequip_char(ch, i), IN_ROOM(ch)); if (FIGHTING(ch)) stop_fighting(ch); for (k = combat_list; k; k = temp) { temp = k->next_fighting; if (FIGHTING(k) == ch) stop_fighting(k); } /* Whipe character from the memory of hunters and other intelligent NPCs... */ for (temp = character_list; temp; temp = temp->next) { /* PCs can't use MEMORY, and don't use HUNTING() */ if (!IS_NPC(temp)) continue; /* If "temp" is hunting our extracted char, stop the hunt. */ if (HUNTING(temp) == ch) HUNTING(temp) = NULL; /* If "temp" has allocated memory data and our ch is a PC, forget the * extracted character (if he/she is remembered) */ if (!IS_NPC(ch) && GET_POS(ch) == POS_DEAD && MEMORY(temp)) forget(temp, ch); /* forget() is safe to use without a check. */ } char_from_room(ch); if (IS_NPC(ch)) { if (GET_MOB_RNUM(ch) != NOTHING) /* prototyped */ mob_index[GET_MOB_RNUM(ch)].number--; clearMemory(ch); if (SCRIPT(ch)) extract_script(ch, MOB_TRIGGER); if (SCRIPT_MEM(ch)) extract_script_mem(SCRIPT_MEM(ch)); } else { save_char(ch); Crash_delete_crashfile(ch); } /* If there's a descriptor, they're in the menu now. */ if (IS_NPC(ch) || !ch->desc) free_char(ch); }
/* Extract a ch completely from the world, and leave his stuff behind */ void extract_char(struct char_data * ch) { struct char_data *k, *temp; struct descriptor_data *t_desc; struct obj_data *obj; int i, freed = 0; //int j; extern struct char_data *combat_list; ACMD(do_return); void die_follower(struct char_data * ch); if (!IS_NPC(ch) && !ch->desc) { for (t_desc = descriptor_list; t_desc; t_desc = t_desc->next) { if (t_desc->original == ch) { do_return(t_desc->character, "", 0, 0); } } } if (ch->in_room == NOWHERE) { log("SYSERR: NOWHERE extracting char. (handler.c, extract_char)"); exit(1); } if (ch->followers || ch->master) { die_follower(ch); } if (RIDING(ch) || RIDDEN_BY(ch)) dismount_char(ch); REMOVE_BIT(PLR_FLAGS(ch), PLR_FISHING); REMOVE_BIT(PLR_FLAGS(ch), PLR_FISH_ON); REMOVE_BIT(PLR_FLAGS(ch), PLR_DIGGING); REMOVE_BIT(PLR_FLAGS(ch), PLR_DIG_ON); REMOVE_BIT(PLR_FLAGS(ch), PLR_FIRE_ON); REMOVE_BIT(PRF_FLAGS(ch), PRF_NOTSELF); //REMOVE_BIT(PRF_FLAGS(ch), PRF_DISGUISE); //REMOVE_BIT(PLR_FLAGS(ch), PLR_MAGE); //REMOVE_BIT(PLR_FLAGS(ch), PLR_MONK); //REMOVE_BIT(PLR_FLAGS(ch), PLR_KNIGHT); //REMOVE_BIT(PLR_FLAGS(ch), PLR_CLERIC); //REMOVE_BIT(PLR_FLAGS(ch), PLR_BARD); //REMOVE_BIT(PLR_FLAGS(ch), PLR_BEGGAR); REMOVE_BIT(PLR_FLAGS(ch), PLR_COURIER); REMOVE_BIT(PLR_FLAGS(ch), PLR_BEAR); REMOVE_BIT(PLR_FLAGS(ch), PLR_BIRD); REMOVE_BIT(PLR_FLAGS(ch), PLR_WOLF); REMOVE_BIT(PLR_FLAGS(ch), PLR_RABBIT); REMOVE_BIT(PLR_FLAGS(ch), PLR_CAT); /* Forget snooping, if applicable */ if (ch->desc) { if (ch->desc->snooping) { ch->desc->snooping->snoop_by = NULL; ch->desc->snooping = NULL; } if (ch->desc->snoop_by) { SEND_TO_Q("Your victim is no longer among us.\r\n", ch->desc->snoop_by); ch->desc->snoop_by->snooping = NULL; ch->desc->snoop_by = NULL; } } /* transfer objects to room, if any */ while (ch->carrying) { obj = ch->carrying; obj_from_char(obj); obj_to_room(obj, ch->in_room); } /* transfer equipment to room, if any */ for (i = 0; i < NUM_WEARS; i++) { if (GET_EQ(ch, i)) { obj_to_room(unequip_char(ch, i), ch->in_room); } } if (FIGHTING(ch)) { stop_fighting(ch); } for (k = combat_list; k; k = temp) { temp = k->next_fighting; if (FIGHTING(k) == ch) { stop_fighting(k); } } char_from_room(ch); /* pull the char from the list */ REMOVE_FROM_LIST(ch, character_list, next); if (ch->desc && ch->desc->original) { do_return(ch, NULL, 0, 0); } if (!IS_NPC(ch)) { save_char(ch, NOWHERE); Crash_delete_crashfile(ch); } else { if (GET_MOB_RNUM(ch) > -1) { /* if mobile */ mob_index[GET_MOB_RNUM(ch)].number--; } clearMemory(ch); /* Only NPC's can have memory */ if (SCRIPT(ch)) { extract_script(SCRIPT(ch)); } free_char(ch); freed = 1; } if (!freed && ch->desc != NULL) { STATE(ch->desc) = CON_MENU; SEND_TO_Q(MENU, ch->desc); } else { /* if a player gets purged from within the game */ if (ch->master || ch->followers) die_follower(ch); if (!freed) { free_char(ch); } } }