////////////////////////////////////////////////////////////////////////////////////// // RAID system. // Overall goal: allow raids every few hours, if there are enough people online from // a sect, they will be teleported to an enemy city, with mobs (soldiers) to aid // in the raid, goal, kill as many people/mobs as possible // at the end of the raid, everyone is rewarded based on the kills they made. // and deaths lower points. // // killing certain mobs during a raid causes bonus points to be added for the raider group // those bonus points at the end of the raid, earn you bonus exp/money. // // killing enemy players during raid cause double xp. // // Things to add when home: // While raiding, no recalling, transfering, teleporting out of waiting room. // No leaving the zone your raiding! // On death you restart back in the Raid start-room apposed to your guild-hall/sect town // // Add level based stat controller for soldier vnum // Add act/plr flags to appropriate tables, non-settable. // Create holder-rooms, flagged to hell to prevent leaving/entering unless transfered in by // the system. // at the end of boot_db add in rebel_raid = new raid_data(); and ally_raid = new raid_data(); // on shutdown add delete rebel_raid; delete ally_raid; // on shutdown, transfer all RAIDERS to their hometowns to prevent glitchs, strip raider flag. // add random object rewards for competing in raids // add double-raid-bonus, to daily bonus's. // add aggress change that makes ALL mobs aggress against raiders that are not the same sect! // -- this will mean that any-mob in midgaard will aggress against rebel // -- if they have the RAIDER flag on. // raiders do not group-loot, mobs/players do not drop corpses when killed by raiders. // -- fair playing technique: forces safety of players, preventing them from being useless. // blocking of nukes of a area while raids are going on (you'd kill all your own guys aswell as the enemies, unfair advantage) // // checks to raw_kill about raiding, no dishonorable pvp points will be awarded unless you kill your own sect // removing the level checks for it. // // kill/death counters into raw_kill. // // #define MOB_VNUM_SOLDIER 298 #define ROOM_VNUM_REBEL_HOLDER 201 // room that holds rebels while waiting raid #define ROOM_VNUM_ALLY_HOLDER 202 // room that holds ally's while waiting raid #define RAID_SIZE 25 // how many people are required for a raid! #define ROOM_VNUM_REBEL_RAIDED 0000 // entrance 1 #define ROOM_VNUM_ALLY_RAIDED 3000 // entrance 1 #define PLR_RAIDER (ff) // are we a raider! #define ACT_RAIDING (ff) // for mobile raiders! ////////////////////////////////////////////////////////////////////////////////////// class raid_data; raid_data *rebel_raid; // global rebel raid data raid_data *ally_raid; // global ally raid data ////////////////////////////////////////////////////////////////////////////////////// class raid_data { public: raid_data() { kills = 0; deaths = 0; bonus = 0; start_time = 0; end_time = 0; next_raid = current_time+number_range(2600,4800); raid_list.clear(); } ~raid_data() { /* Oddly nothing happens :P */ raid_list.clear(); }; private: int kills; // how many people your team has killed in the raid int deaths; // how many deaths your team has had int bonus; // Bonus points earned time_t start_time; // start time of the raid time_t end_time; // end time of the raid. time_t next_raid; // how long before you can raid again! Lexi::Listraid_list; // who is raiding! public: void add_list(CHAR_DATA *ch) { if(!InList(raid_list, ch)) raid_list.push_back(ch); } void remove_list(CHAR_DATA*ch) { if(InList(raid_list, ch)) raid_list.remove_one(ch); } void in_raid(CHAR_DATA *ch) {if(InList(raid_list, ch)) return true; return false; } void send_to_raid(CHAR_DATA *ch, const char * argument) { FOREACH(Lexi::List, raid_list, raid_iter) { CHAR_DATA *r = (*raid_iter); if(r == ch) { r->Sendf("[RAID] %s\n\r", argument); } else { r->Sendf("[RAID] %s: %s\n\r", ch->name, argument); } } } CHAR_DATA *first_raider() { return (*raid_list.begin()); } size_t raid_size() { return raid_list.size; } time_t get_start() { return start_time; } time_t get_end() { return end_time; } time_t get_next() { return next_raid; } void add_bonus(int bonbon) { bonus +=bonbon; } // bonbon means candy ;) int get_bonus() { return bonus; } void add_kill() { kills++; } int get_kills() {return kills; } void add_death() { deaths++; } int get_deaths() { return deaths; } void set_next() { next_raid = current_time+(3600*3); start_time = 0; end_time = 0; kills = 0; deaths = 0; bonus = 0;} void set_start() { start_time = current_time; } void set_end() { end_time = start_time+400; } // 3600 = 1 hour, 400 should be approx 15 minutes (give or take, we hope) void reward() { // lets reward and cleanup! FOREACH(Lexi::List, raid_list, raid_iter) { CHAR_DATA *raider = (*raid_iter); int bon = (kills-deaths)*bonus; // this can work out to be a negative effect char_from_combat(ch); // stop fighting if engaged! if(!IS_NPC(raider)) { gain_exp(raider, bon); // LOTS of experience in raiding! raider->pcdata->questpoints +=bonus; // lots of quest-points in raiding. // add in RP-points for raids! raid_list.remove_one(raider); extract_char(raider, false); ch->Sendf("The raid is over!\n\r"); } else raid_list.remove_one(raider); extract_char(raider, true); } } // make-sure the raid-list is cleared out. raid_list.clear(); kills = 0; // reset our kill data deaths = 0; // reset our death data bonus = 0; // reset our bonus data. } void raid_start(long vnum) { ROOM_INDEX_DATA *rm = get_room_index(vnum); if(!rm) { log_string("[RAID]: failed to find raid start vnum!"); set_next(); FOREACH(Lexi::List, raid_list, raid_iter) { CHAR_DATA *raider = (*raid_iter); char_from_combat(ch); // stop fighting if engaged! if(!IS_NPC(raider)) { raid_list.remove_one(raider); extract_char(raider, false); ch->Sendf("The raid failed before it could begin!!\n\r"); } else raid_list.remove_one(raider); extract_char(raider, true); } } return; } // make-sure there are enemies to kill during the raid! log_string("[RAID]: %s has been reset by the raid system for %s's raid!", rm->area->name, first_raider()->name); reset_area( rm->area ); // log it for our records! (this is going to cause some SERIOUS fun! log_string("[RAID]: Raid started at %s, by %s, with %d player raiders!", grab_time_log(start_time), first_raider()->name, raid_list.size()); FOREACH(Lexi::List, raid_list, raid_iter) { CHAR_DATA *raider = (*raid_iter); char_from_room(raider); char_to_room(raider, rm); } // add our soldiers into the raid! MOB_INDEX_DATA *pM = get_mob_index(MOB_VNUM_SOLDIER); int bm = 0; if(pM) { int x = 0, y = number_range(25,100)-raid_list.size(); // larger the group, less soldiers added. if(y < 0) y = 10; // min of 10 get added! for(x = 0; x < y; x++) { pM->level = number_range(1, 45); // yeah, we adjust the index'level, because this // is a dummy mob, and on create_mobile, it sets // information based on the level (important) if(number_percent() > number_range(95,100)) { // chance we cause the mob to be a boss mob SET_BIT(pM->act, ACT_BOSS); // which increases our offensive greatly bm++; // this is a low chance, but if it happens } // the raid will be allot stronger for it. pM->iclass = number_range(0,7); // change our class, this will affect our // overall AI, aswell as what gear will get // loaded onto the mob CHAR_DATA *mob = create_mobile(pM); // add raid-gear loading onto the mobile // so we don't send naked mobs to the fight! char_to_room(mob, rm); mob->rebel = first_raider()->rebel; // make us the same team! raid_list.push_back(mob); if(!IS_SET(mob->act, ACT_AGGRESSIVE)) SET_BIT(mob->act, ACT_AGGRESSIVE); // just incase we aren't set to aggress. // mobs aggress against all *NON* sect // including npc's, thus making the soldiers // attack everything REMOVE_BIT(pM->act, ACT_BOSS); // we dont' want all our soldiers working // like a boss mob SET_BIT(mob->act, ACT_STAY_AREA); // force them to stay in the area, and // not leave into connected area's. // which would be annoying. SET_BIT(mob->act, ACT_RAIDING); // set the mob as a raider, so that when // victims are killed, it automatically // checks and updates the raid information. } // we want to keep track of this information for debugging purposes, aswell as being nosey // frankly this will help keep plenty of information incase something should happen and // we need to diagnose an issue pertaining to the raid core code. log_string("[RAID]: Raid added %d soldiers to %s's team, with %d boss mobs!!", y, first_raider()->name, bm); } else { log_string("[RAID]: Raid could not load any soldiers. This could be a tough one for %s's raid!", first_raider()->name); } // may need to make this formatted if it isn't :P but it is! we know this because we format { } sitrep(NULL, 0, "The %s are raiding %s: {%d}!", first_raider->rebel ? "Rebellion!" : "Alliance", first_raider->rebel ? "Midgaard" : "New Thalos", raid_list.size()); } }; ////////////////////////////////////////////////////////////////////////////////////// // Simple updater to control raid specifics. // Raid updates every 15 minutes, a raid shouldn't last longer then that, and should be // roughly 4 hours between raids Updater(raid_update) { if(ally_raid->get_start() != 0) { // raid ended! if(ally_raid->get_end() < current_time) { ally_raid->reward(); sitrep(NULL, 0, "The alliance raid is over, casualties a plenty."); ally_raid->set_next(); } } else { if(ally_raid->get_next() < current_time) { FOREACH(Lexi::List, player_list, player_iter) { CHAR_DATA *ch = (*player_iter); if(ch->rebel != SECT_ALLIANCE) continue; ch->Sendf("[RAID] It is possible to raid the rebellion hometown now! [RAID]\n\r"); } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////// // Check the rebellion now /////////////////////////////////////////////////////////////////////////////////////////////////////////// if(rebel_raid->get_start() != 0) { // raid ended! if(rebel_raid->get_end() < current_time) { rebel_raid->reward(); sitrep(NULL, 0, "The rebellion's raid is over, casualties a plenty."); rebel_raid->set_next(); } } else { if(rebel_raid->get_next() < current_time) { FOREACH(Lexi::List, player_list, player_iter) { CHAR_DATA *ch = (*player_iter); if(ch->rebel != SECT_REBELLION) continue; ch->Sendf("[RAID] It is possible to raid the alliance hometown now! [RAID]\n\r"); } } } return; } ////////////////////////////////////////////////////////////////////////////////////// // Here we go with the main data COMMAND(cmd_raid) { raid_data *rd; char arg[MIL]; if(NullString(argument)) { ch->Sendf("Syntax: raid join quit stats talk start\n\r"); return; } if(IS_NPC(ch)) { ch->Sendf("Mobiles have no control over raiding!\n\r"); return; } argument = one_argument(argument, arg); switch(ch->rebel) { default: return; case SECT_ALLIANCE: rd = ally_raid; break; case SECT_REBELLION: rd = rebel_raid; break; } if(!str_cmp(arg, "talk")) { if(rd->get_start() == 0){ ch->Sendf("There is no raid started yet!\n\r"); return; } if(!rd->in_raid(ch)) { ch->Sendf("Your not in a raid!\n\r"); return; } if(NullString(argument)) { ch->Sendf("Syntax: raid talk \n\r"); return; } send_to_raid(ch, argument); return; } if(!str_cmp(arg, "stats") || !str_cmp(arg, "info")) { if(!rd->in_raid(ch)) { ch->Sendf("Your not in a raid!\n\r"); return; } ch->Sendf("[----------------------------- RAID -----------------------------]\n\r"); ch->Sendf(" Kills: %3d Deaths: %3d\n\r", rd->get_kills(); rd->get_deaths()); ch->Sendf(" Bonus points earned: %d\n\r", rd->get_bonus()); ch->Sendf(" There are currently %d PCs and NPC's within the raid group!\n\r", rd->raid_size()); // what time the raid started at, and what time it will ultimatly end at! if(rd->get_start() != 0) { ch->Sendf(" Started at: %s\n\r", grab_time_log(rd->get_start()); ch->Sendf(" Will end At: %s\n\r", grab_time_log(rd->get_end()); } ch->Sendf("[----------------------------- RAID -----------------------------]\n\r"); return; } if(!str_cmp(arg, "start")) { time_t tt, tn; switch(ch->rebel) { default: break; case SECT_ALLIANCE: rd = ally_raid; tt = ally_raid->get_start(); tn = ally_raid->get_next(); break; case SECT_REBELLION: rd = rebel_raid; tt = rebel_raid->get_start(); tn = rebel_raid->get_next(); break; } if(rd->first_raider() != ch) { ch->Sendf("%s is in-charge of the raid! You cannot start it!\n\r", rd->first_raider()); return; } if(rd->raid_size() <=RAID_SIZE-1) { ch->Sendf("You need %d people to start a raid!", RAID_SIZE); return; } if(rd->get_next() > current_time) { ch->Sendf("You cannot start the raid yet!\n\r"); return; } if(rd->get_start() != 0) { ch->Sendf("The raid is already underway! KILL SOMETHING!\n\r"); return; } rd->set_start(); rd->set_end(); // send everyone in the raid-group to the area's start room! rd->start_raid(ch->rebel ? 3255 : 9511 ); return; } // add me to the group! if(!str_cmp(arg, "join")) { if(rd->get_start() != 0) { ch->Sendf("You cannot join a raid in progress!\n\r"); return; } if(rd->in_raid(ch)) { ch->Sendf("You are already in the raid!\n\r"); return; } ch->Sendf("You have been put into the raid list!\n\r"); rd->add_list(ch); if(!IS_SET(ch->act, PLR_RAIDER)) SET_BIT(ch->act, PLR_RAIDER); return; } // remove me from the group! if(!str_cmp(arg, "quit")) { if(!rd->in_raid(ch)) { ch->Sendf("You are not in a raid!\n\r"); return; } if(is_fighting(ch)) { ch->Sendf("You cannot quit a raid while fighting in one!\n\r"); return; } ch->Sendf("You have quit the raid group!\n\r"); rd->remove_list(ch); rd->send_to_raid(ch, "I have quit raiding like a coward!"); if(IS_SET(ch->act, PLR_RAIDER)) REMOVE_BIT(ch->act, PLR_RAIDER); // send to their hometown! extract_char(ch, false); return; } }