/**************************************************************************** * Automated Warfare Code * * Markanth : dlmud@dlmud.com * * Devil's Lament : dlmud.com port 3778 * * Web Page : http://www.dlmud.com * * * * Provides 4 types of automated wars. * * * * All I ask in return is that you give me credit on your mud somewhere * * or email me if you use it. * ****************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "merc.h" #include "interp.h" #include "tables.h" #include "const.h" /* local variables*/ CHAR_DATA * find_warmaster ( CHAR_DATA *ch ) { CHAR_DATA * warmaster; for ( warmaster = ch->in_room->people; warmaster != NULL; warmaster = warmaster->next_in_room ) { if (!IS_NPC(warmaster)) continue; if (warmaster->spec_fun == spec_lookup( "spec_warmaster" ) ) return warmaster; } if ( warmaster == NULL || warmaster->spec_fun != spec_lookup( "warmaster" )) { send_to_char("What? You can't do that here.\n\r", ch); return NULL; } if ( warmaster->fighting != NULL ) { send_to_char("Wait until the fighting stops.\n\r",ch ); return NULL; } return NULL; } char *wartype_name(int type) { switch (type) { case 1: return "Race"; case 2: return "Class"; case 3: return "Genocide"; case 4: return "Clan"; default: return "Unknown"; } } bool start_war(CHAR_DATA * ch, char *argument) { char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; char arg3[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; CHAR_DATA *wch, *warmaster; int blevel, elevel, type; warmaster = find_warmaster( ch ); if (!warmaster) return FALSE; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); argument = one_argument(argument, arg3); if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0') { send_to_char("Syntax: war start <min_level> <max_level> <type>\n\r" "where <type> is either:\n\r" "1 - race war,\n\r2 - klass war,\n\r3 - genocide war,\n\r4 - clan war\n\r", ch); return FALSE; } blevel = atoi(arg1); elevel = atoi(arg2); type = atoi(arg3); if (blevel <= 0 || blevel > MAX_LEVEL) { sprintf(buf, "Level must be between 1 and %d.\n\r", MAX_LEVEL); send_to_char(buf, ch); return FALSE; } if (blevel <= 0 || elevel > MAX_LEVEL) { sprintf(buf, "Level must be between 1 and %d.\n\r", MAX_LEVEL); send_to_char(buf, ch); return FALSE; } if (elevel < blevel) { send_to_char("Max level must be greater than the min level.\n\r", ch); return FALSE; } if (elevel - blevel < 5) { send_to_char("Levels must have a difference of at least 5.\n\r", ch); return FALSE; } if (type < 1 || type > 4) { send_to_char ("The type either has to be 1 (race), 2 (class), 3 (genocide) or 4 (clan).\n\r", ch); return FALSE; } if (war_info.iswar != WAR_OFF) { send_to_char("There is already a war going!\n\r", ch); return FALSE; } if (!IS_IMMORTAL(ch)) { int cost = 500; if (ch->gold < cost) { sprintf(buf, "$N tells you 'It costs %d gold to start a %s war.'", cost, wartype_name(type)); act(buf, ch, NULL, warmaster, TO_CHAR); return FALSE; } else { sprintf(buf, "$N tells you 'Thank you $n, %s war started, you are %d gold lighter.'", wartype_name(type), cost); act(buf, ch, NULL, warmaster, TO_CHAR); ch->gold -= cost; } } war_info.iswar = WAR_WAITING; free_string(war_info.who); war_info.who = str_dup(ch->name); war_info.min_level = blevel; war_info.max_level = elevel; war_info.wartype = type; sprintf(buf, "$n announces a %s war for levels %d to %d. Type 'WAR' to kill or be killed.", wartype_name(war_info.wartype), war_info.min_level, war_info.max_level); war_channel(ch, buf); sprintf(buf, "You announce a %s war for levels %d to %d.\n\r", wartype_name(war_info.wartype), war_info.min_level, war_info.max_level); send_to_char(buf, ch); war_info.timer = 3; war_info.next = 0; for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && IS_SET(wch->act, PLR_WAR)) REMOVE_BIT(wch->act, PLR_WAR); } return TRUE; } void auto_war(void) { CHAR_DATA *wch, *wch_last, *warmaster; int maxlvl = 0, minlvl = MAX_LEVEL, middle = LEVEL_HERO / 2; int clan = 0, count = 0, lbonus = 0, half = 0; char buf[MAX_INPUT_LENGTH]; if (war_info.iswar != WAR_OFF) return; for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && !IS_IMMORTAL(wch)) { count++; maxlvl = UMAX(maxlvl, wch->level); minlvl = UMIN(minlvl, wch->level); if (is_clan(wch)) { for (wch_last = char_list; wch_last != NULL; wch_last = wch_last->next) { if (!IS_NPC(wch_last) && !IS_IMMORTAL(wch_last) && is_clan(wch_last) && !is_same_clan(wch, wch_last)) clan++; } } } } if (count < 2) { end_war(); return; } lbonus = number_range(5, 10); minlvl = UMAX(1, minlvl - lbonus); maxlvl = UMIN(LEVEL_HERO, maxlvl + lbonus); half = ((maxlvl - minlvl) / 2); middle = URANGE(minlvl, maxlvl - half, maxlvl); minlvl = number_range(minlvl, middle - lbonus); maxlvl = number_range(middle + lbonus, maxlvl); for(warmaster = char_list; warmaster != NULL; warmaster = warmaster->next) { if(!IS_NPC(warmaster)) continue; if(warmaster->pIndexData->vnum == MOB_VNUM_WARMASTER) break; } war_info.iswar = WAR_WAITING; free_string(war_info.who); war_info.who = !warmaster ? str_dup("AutoWar (tm)") : str_dup(warmaster->short_descr); war_info.min_level = minlvl; war_info.max_level = maxlvl; if (clan >= 2) war_info.wartype = number_range(1, 4); else war_info.wartype = number_range(1, 3); sprintf(buf, "{G%s {B%s{x war for levels {G%d to {B%d%s{x. Type 'WAR' to kill or be killed.", !warmaster ? "A" : "$n announces a", wartype_name(war_info.wartype), war_info.min_level, war_info.max_level, !warmaster ? " has started" : ""); war_channel(warmaster, buf); war_info.timer = 3; war_info.next = 0; for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && IS_SET(wch->act, PLR_WAR)) REMOVE_BIT(wch->act, PLR_WAR); } } void end_war(void) { CHAR_DATA *wch; free_string(war_info.who); war_info.who = str_dup(""); war_info.wartype = 0; war_info.min_level = 0; war_info.max_level = 0; war_info.iswar = WAR_OFF; war_info.inwar = 0; war_info.timer = 0; war_info.next = number_range(30, 60); for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && IS_SET(wch->act, PLR_WAR)) { stop_fighting(wch, TRUE); REMOVE_BIT(wch->act, PLR_WAR); if (IS_SET(wch->in_room->room_flags, ROOM_ARENA) || wch->in_room->vnum == ROOM_VNUM_WAITROOM) { char_from_room(wch); char_to_room(wch, get_room_index(ROOM_VNUM_TEMPLE)); } wch->hit = wch->max_hit; wch->mana = wch->max_mana; wch->move = wch->max_move; update_pos(wch); do_function( wch, &do_look, "auto" ); } } } void do_war(CHAR_DATA *ch, char *argument) { char arg[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; ROOM_INDEX_DATA *location; int i = 0; if (IS_NPC(ch)) { send_to_char("Mobiles not supported yet.\n\r", ch); return; } argument = one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Syntax: {Rwar {Bstart <minlev> <maxlev> <#type>{x\n\r", ch); send_to_char(" {Rwar {Btalk <message>{x\n\r", ch); send_to_char(" {Rwar {Bstatus{x\n\r", ch); send_to_char(" {Rwar {Binfo{x\n\r", ch); send_to_char(" {Rwar {Bjoin{x\n\r", ch); if (IS_IMMORTAL(ch)) { send_to_char(" war end\n\r" " war next\n\r", ch); } return; } else if (!str_cmp(arg, "start")) { start_war(ch, argument); return; } else if (!str_cmp(arg, "talk")) { war_talk(ch, argument); return; } else if (!str_cmp(arg, "next") && IS_IMMORTAL(ch)) { if (war_info.iswar == TRUE) { send_to_char("Not while a war is running.\n\r", ch); return; } i = is_number(argument) ? atoi(argument) : number_range(30, 100); war_info.next = i; sprintf(buf, "The next war will start in %d minutes.\n\r", war_info.next); send_to_char(buf, ch); return; } if (war_info.iswar != TRUE) { sprintf(buf, "Their is no war going! The next war will start in %d minutes.\n\r", war_info.next); send_to_char(buf, ch); return; } if (!str_cmp(arg, "end") && IS_IMMORTAL(ch)) { end_war(); sprintf(buf, "You end the war. Next war in %d minutes.\n\r", war_info.next); send_to_char(buf, ch); sprintf(buf, "$n has ended the war. The next autowar will start in %d minutes.", war_info.next); war_channel(ch, buf); sprintf(buf, "You have ended the war. The next autowar will start in %d minutes.\n\r", war_info.next); send_to_char(buf, ch); return; } else if (!str_cmp(arg, "info")) { sprintf(buf, "Started by : %s\n\r", war_info.who[0] == '\0' ? "Unknown" : war_info.who); send_to_char(buf, ch); sprintf(buf, "Fighting : %d player%s.\n\r", war_info.inwar, war_info.inwar == 1 ? "" : "s"); send_to_char(buf, ch); sprintf(buf, "Levels : %d - %d\n\r", war_info.min_level, war_info.max_level); send_to_char(buf, ch); sprintf(buf, "Status : %s for %d minutes.\n\r", war_info.iswar == WAR_WAITING ? "Waiting" : "Running", war_info.timer); send_to_char(buf, ch); sprintf(buf, "Type : %s war.\n\r", wartype_name(war_info.wartype)); send_to_char(buf, ch); return; } else if (!str_cmp(arg, "check")) { CHAR_DATA *wch; bool found = FALSE; for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && IS_SET(wch->act, PLR_WAR)) { sprintf(buf, "%-12s : [%ld%% hit] [%ld%% mana] [Pos: %s]\n\r", wch == ch ? "You" : wch->name, wch->hit * 100 / wch->max_hit, wch->mana * 100 / wch->max_mana, position_table[wch->position].short_name); send_to_char(buf, ch); found = TRUE; } } if (!found) send_to_char("No one in the war yet.\n\r", ch); return; } else if (!str_cmp(arg, "join")) { if (war_info.iswar == WAR_RUNNING) { send_to_char("The war has allready started, your too late.\n\r", ch); return; } if (ch->level < war_info.min_level || ch->level > war_info.max_level) { send_to_char("Sorry, you can't join this war.\n\r", ch); return; } if (IS_SET(ch->act, PLR_WAR)) { send_to_char("You are already in the war.\n\r", ch); return; } if (war_info.wartype == 4 && !is_clan(ch) ) { send_to_char("You aren't in a clan, you can't jon this war.\n\r", ch); return; } if ((location = get_room_index(ROOM_VNUM_WAITROOM)) == NULL) { send_to_char("The arena isn't completed yet, sorry.\n\r", ch); return; } else { act("$n has gone to join the war!", ch, NULL, NULL, TO_ROOM); char_from_room(ch); char_to_room(ch, location); SET_BIT(ch->act, PLR_WAR); sprintf(buf, "%s (Level %d) joins the war!", ch->name, ch->level); war_channel(NULL, buf); act("$n has arrived to join the war!", ch, NULL, NULL, TO_ROOM); war_info.inwar++; do_function( ch, &do_look, "auto" ); } return; } auto_war( ); return; } bool abort_race_war(void) { CHAR_DATA *ch; CHAR_DATA *vict; for (ch = char_list; ch != NULL; ch = ch->next) { if (!IS_NPC(ch) && IS_SET(ch->act, PLR_WAR)) { for (vict = char_list; vict != NULL; vict = vict->next) { if (!IS_NPC(vict) && IS_SET(vict->act, PLR_WAR)) { if (ch->race == vict->race) continue; else return FALSE; } } } } return TRUE; } bool abort_class_war(void) { CHAR_DATA *ch; CHAR_DATA *vict; for (ch = char_list; ch != NULL; ch = ch->next) { if (!IS_NPC(ch) && IS_SET(ch->act, PLR_WAR)) { for (vict = char_list; vict != NULL; vict = vict->next) { if (!IS_NPC(vict) && IS_SET(vict->act, PLR_WAR)) { if (ch->klass == vict->klass) continue; else return FALSE; } } } } return TRUE; } bool abort_clan_war(void) { CHAR_DATA *ch; CHAR_DATA *vict; for (ch = char_list; ch != NULL; ch = ch->next) { if (!IS_NPC(ch) && IS_SET(ch->act, PLR_WAR) && is_clan(ch)) { for (vict = char_list; vict != NULL; vict = vict->next) { if (!IS_NPC(vict) && IS_SET(vict->act, PLR_WAR) && is_clan(vict)) { if (is_same_clan(ch, vict)) continue; else return FALSE; } } } } return TRUE; } void war_update ( void ) { char buf[MAX_STRING_LENGTH]; if ( war_info.iswar == WAR_OFF && war_info.next > 0 ) { if ( --war_info.next <= 0 ) auto_war ( ); } else if ( war_info.iswar == WAR_WAITING ) { int randm = 0; war_info.timer--; if ( war_info.timer > 0 ) { sprintf ( buf, "%d minute%s left to join the war. (Levels %d - %d, %s War)", war_info.timer, war_info.timer == 1 ? "" : "s", war_info.min_level, war_info.max_level, wartype_name ( war_info.wartype ) ); war_channel(NULL, buf); } else { if ( war_info.inwar < 2 ) { end_war ( ); sprintf ( buf, "Not enough people for a war. Next autowar in %d minutes.", war_info.next ); war_channel(NULL, buf); } else if ( war_info.wartype == 1 && abort_race_war ( ) ) { end_war ( ); sprintf ( buf, "Not enough races for a war. Next autowar in %d minutes.", war_info.next ); war_channel(NULL, buf); } else if ( war_info.wartype == 2 && abort_class_war ( ) ) { end_war ( ); sprintf ( buf, "Not enough classes for a war. Next autowar in %d minutes.", war_info.next ); war_channel(NULL, buf); } else if ( war_info.wartype == 4 && abort_clan_war ( ) ) { end_war ( ); sprintf ( buf, "Not enough clans for a war. Next autowar in %d minutes.", war_info.next ); war_channel(NULL, buf); } else { CHAR_DATA *wch; sprintf(buf, "The battle begins! %d players are fighting!", war_info.inwar ); war_channel ( NULL, buf); war_info.timer = number_range ( 3 * war_info.inwar, 5 * war_info.inwar ); war_info.iswar = WAR_RUNNING; for ( wch = char_list; wch != NULL; wch = wch->next ) { if ( !IS_NPC(wch) && IS_SET ( wch->act, PLR_WAR ) ) { randm = number_range ( 12004, 12080 ); char_from_room ( wch ); char_to_room ( wch, get_room_index ( randm ) ); do_function ( wch, &do_look, "auto" ); } } } } } else if ( war_info.iswar == WAR_RUNNING ) { if ( war_info.inwar == 0 ) { end_war ( ); sprintf ( buf, "No one left in the War, next war will start in %d minutes.", war_info.next ); war_channel(NULL, buf); return; } switch ( war_info.timer ) { case 0: end_war ( ); sprintf ( buf, "Time has run out on the War, next war will start in %d minutes.", war_info.next ); war_channel(NULL, buf); return; case 1: case 2: case 3: case 4: case 5: case 10: case 15: sprintf ( buf, "%d minute%s remaining in the war.", war_info.timer, war_info.timer > 1 ? "s" : "" ); war_channel(NULL, buf); default: war_info.timer--; break; } return; } } void check_war(CHAR_DATA * ch, CHAR_DATA * victim) { CHAR_DATA *wch; char buf[MAX_STRING_LENGTH]; int reward = number_range(500, 1500); int qreward = number_range( 50, 150 ); if (IS_NPC(ch) || IS_NPC(victim)) return; REMOVE_BIT(victim->act, PLR_WAR); war_info.inwar--; stop_fighting(victim, TRUE); char_from_room(victim); char_to_room(victim, get_room_index(ROOM_VNUM_ALTAR)); victim->hit = UMAX(1, victim->hit); victim->mana = UMAX(1, victim->hit); victim->move = UMAX(1, victim->hit); update_pos(victim); do_look(victim, "auto"); send_to_char("\n\r", ch); send_to_char("\n\r", victim); sprintf(buf, "%s was killed in combat by %s!", victim->name, ch->name); war_channel(NULL, buf); switch (war_info.wartype) { case 1: if (abort_race_war()) { sprintf(buf, "The %s's have won the War!", pc_race_table[ch->race].name); war_channel(NULL, buf); for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && IS_SET(wch->act, PLR_WAR)) continue; if (wch->race == ch->race) { wch->gold += reward; wch->pcdata->questpoints += qreward; sprintf(buf, "You recieve %d gold and %d questpoints for winning the war!\n\r", reward, qreward ); send_to_char(buf, wch); } } end_war(); return; } // end abort break; case 2: if (abort_class_war()) { sprintf(buf, "The %s's have won the War!", class_long( ch ) ); war_channel(NULL, buf); for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && IS_SET(wch->act, PLR_WAR)) continue; if (wch->klass == ch->klass) { wch->gold += reward; wch->pcdata->questpoints += reward; sprintf(buf, "You recieve %d gold and %d questpoints for winning the war!\n\r", reward, qreward ); send_to_char(buf, wch); } } end_war(); return; } break; case 4: if (abort_clan_war()) { sprintf(buf, "%s has won the War!", clan_table[ch->clan].who_name); war_channel(NULL, buf); for (wch = char_list; wch != NULL; wch = wch->next) { if (!IS_NPC(wch) && IS_SET(wch->act, PLR_WAR)) continue; if (is_same_clan(ch, wch)) { wch->gold += reward; wch->pcdata->questpoints += qreward; sprintf(buf, "You recieve %d gold and %d questpoints for winning the war!\n\r", reward, qreward ); send_to_char(buf, wch); } } end_war(); return; } break; case 3: if (war_info.inwar == 1) { sprintf(buf, "%s has won the War!", ch->name); war_channel(NULL, buf); ch->gold += reward; ch->pcdata->questpoints += reward; sprintf(buf, "You recieve %d gold and %d questpoints for winning the war!\n\r", reward, qreward ); send_to_char(buf, ch); end_war(); return; } break; } return; } bool is_safe_war(CHAR_DATA * ch, CHAR_DATA * wch) { if (war_info.iswar == WAR_OFF) return FALSE; if (!IS_IN_WAR(ch) || !IS_IN_WAR(wch)) return FALSE; if (war_info.wartype == 3) return FALSE; if (war_info.wartype == 1 && ch->race == wch->race) return TRUE; if (war_info.wartype == 2 && ch->klass == wch->klass) return TRUE; if (war_info.wartype == 4 && is_same_clan(ch, wch)) return TRUE; return FALSE; } void war_talk(CHAR_DATA *ch, char *argument) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; if (argument[0] == '\0') { send_to_char ("Wartalk what?\n\r", ch); return; } sprintf(buf, "(WarTalk) You drum: %s\n\r", argument); send_to_char(buf, ch); for (d = descriptor_list; d != NULL; d = d->next) { CHAR_DATA *victim; if (d->connected == CON_PLAYING && (victim = d->character) != ch && !IS_SET(victim->comm, COMM_QUIET) && IS_IN_WAR(victim)) { sprintf(buf, "(WarTalk) %s drums: %s\n\r", PERS(ch, victim), argument); send_to_char(buf, victim); } } return; } void extract_war ( CHAR_DATA * ch ) { char buf[MAX_STRING_LENGTH]; if ( war_info.iswar != WAR_OFF && IS_SET ( ch->act, PLR_WAR ) ) { REMOVE_BIT ( ch->act, PLR_WAR ); war_info.inwar--; if ( war_info.iswar == WAR_RUNNING ) { if ( war_info.inwar == 0 || war_info.inwar == 1 ) { war_channel ( ch, "$n has left. War over." ); end_war ( ); } if ( abort_race_war ( ) ) { war_channel ( ch, "$n has left. War over." ); end_war ( ); } else if ( abort_class_war ( ) ) { war_channel ( ch, "$n has left. War over." ); end_war ( ); } else if ( abort_clan_war ( ) ) { war_channel ( ch, "$n has left. War over." ); end_war ( ); } else { sprintf ( buf, "$n has left. %d players in the war.", war_info.inwar ); war_channel(ch, buf); } } do_function( ch, &do_recall, "" ); } } void war_channel(CHAR_DATA *ch, char *message) { DESCRIPTOR_DATA *d; CHAR_DATA *dch; char buf[MAX_INPUT_LENGTH]; for(d = descriptor_list; d != NULL; d = d->next) { if(d->connected != CON_PLAYING) continue; if((dch = d->character) == NULL) continue; sprintf(buf, "WAR: %s", message); if(ch) /* don't use $N only $n in message */ act(buf, ch, NULL, dch, TO_VICT); else { strcat(buf, "\n\r"); send_to_char(buf, dch); } } }