/* Team skills, sorta like that of Chronotrigger, you make your choices, and hopefully, you make a good combonation
* as when you do, you get an amazing outcome, being in the form of a skill/spell against your target.
*
* Note: teamskills only work on enemies, but can have affects that cure your group, which makes it always very
* fun.
*
* note for installation, damage_new must return the damage delt, not a true/false
* this is done to affect our skillz.
*/
class teamskill {
public:
teamskill() { ch_name = NULL; buddy_name = NULL; victim_name = NULL; }
~teamskill() { extern void free_string(const char *); free_string(buddy_name); free_string(ch_name); free_string(victim_name); }
int ch_skill;
int bd_skill;
const char *ch_name;
const char *buddy_name;
const char *victim_name;
};
/* Create unique skills
* Basically, the intent of this is to take the teamskill information, and generate a 'new' skill where
* its effects can be anything from healing, to hurting, or both!
* skill 1 - primary skill
* skill 2 - modifier skill
* based on the first skill selected, the second skill will change the outcome of the overall system
* As seen :)
*/
void perform_teamskill(struct teamskill *tk) {
int skill_1 = tk->ch_skill;
int skill_2 = bd->skill;
bool failed = false;
int wait_adjustment = 8; // skill wait timer handled here.
// all 3 existed at the start!
CHAR_DATA *ch = get_char_world(NULL, tk->ch_name);
CHAR_DATA *buddy = get_char_world(NULL, tk->buddy_name);
CHAR_DATA *victim = get_char_world(NULL, tk->victim_name);
// we protect against a most horrible issue that may occur should someone die, quit, extract, or 'gulp' bug out ;)
if(!ch || !victim || !buddy) {
if(ch) {
ch->Sendf("Your teamskill failed! Someone is missing!!\n\r");
delete ch->teamskill;
turn_end(ch->turn, 10, ch);
}
if(victim) {
// hmm, we have a victim, but someone else is missing, crazy!
}
if(buddy) {
buddy->Sendf("Your teamskill failed! Someone is missing!!\n\r");
delete buddy->teamskill;
turn_end(buddy->turn, 10, buddy);
}
return;
}
/* We just want to leave alittle message here, showing that they are doing things in a little mystical way
* since the mud has little magic referance, we make team-skills based on them, removing 'restrictions'
* since there is no need to have restrictions on mystical powers.
* -- This is explained by our story why people can do this.
*/
switch(number_range(0,3)) {
default: case 0:
act("$n and $N make identical moves, as they swirl with mystic energies!", ch, NULL, buddy, TO_ROOM);
act("You and $N make identical moves.", ch, NULL, buddy, TO_CHAR);
act("You and $n make identical moves.", ch, NULL, buddy, TO_VICT);
break;
case 1:
act("$N, with the assistance of $n, surround themselves with swirling colours.", ch, NULL, buddy, TO_ROOM);
act("You and $N focus intently, as swirling colours surround you.", ch, NULL, buddy, TO_CHAR);
act("You and $n focus intently, as swirling colours surround you.", ch, NULL, buddy, TO_VICT);
break;
case 2:
act("$N begins to eminate a blinding light as $n channels $s power through $M!", ch, NULL, buddy, TO_ROOM);
act("You channel your power through $N, focusing through a blinding light!", ch, NULL, buddy, TO_CHAR);
act("You begin eminating a blinding light as $n channels $s power through you!", ch, NULL, buddy, TO_VICT);
break;
case 3:
act("$n and $N vanishes abruptly!", ch, NULL, buddy, TO_ROOM);
act("You vanish abruptly!", ch, NULL, buddy, TO_CHAR);
act("You vanish abruptly!", ch, NULL, buddy, TO_VICT);
break;
}
// lets parse through the overall skills, and create a new skill!
switch(skill_1) {
default: failed = true; break;
case gsn_backstab:
switch(skill_2) {
default: failed = true; break;
case gsn_backstab: // double backstab
act("$n and $N pair up, and double backstab $t with spirit daggers!", ch, victim->name, buddy, TO_ROOM);
damage_new(ch, victim, dam, gsn_backstab, NULL, TRUE, FALSE, DAM_PIERCE);
damage_new(buddy, victim, dam, gsn_backstab, NULL, TRUE, FALSE, DAM_PIERCE);
break;
case gsn_envenom: // damage + poison
break;
case gsn_steal: // damage and swipe stuff
break;
}
break;
case gsn_bash:
switch(skill_2) {
default: failed = true; break;
case gsn_backstab: // 'hammer' the dagger into the victim
break;
case gsn_triage: // damage enemy, heal group with % of damage delt.
{
int dam = 0;
int cnt = 0;
int chance;
/* size and weight */
chance += ch->carry_weight / 250;
chance -= victim->carry_weight / 200;
if (ch->size < victim->size)
chance += (ch->size - victim->size) * 15;
else
chance += (ch->size - victim->size) * 10;
/* stats */
chance += get_curr_stat(ch,STAT_STR);
chance -= (get_curr_stat(victim,STAT_DEX) * 4)/3;
chance -= GET_AC(victim,AC_BASH) /25;
/* Triage helps us out here for our overall bonus!*/
change += get_skill(buddy, gsn_triage)/3;
/* speed */
if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))
chance += 10;
if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
chance -= 30;
/* level */
chance += (ch->level - victim->level);
/* get the damage delt! */
dam = damage_new(ch, victim, number_range(2,2 + 2 * ch->size + chance/20), gsn_bash, NULL, TRUE, FALSE, DAM_BASH);
if(dam != 0) {
CHAR_DATA *list;
for (list = ch->in_battle->unit_list; list != NULL; list = list->next_in_battle)
if(is_same_group(ch, list)) cnt++;
// Okay, now we heal the party for a small percentage of the damage delt. + triage-skill-level bonus :)
for (list = ch->in_battle->unit_list; list != NULL; list = list->next_in_battle) {
if(is_same_group(ch,list)) {
// knocked out cold?
if(IS_AFFECTED(list, AFF_KNOCKOUT))
revive_unit(list);
list->hit += dam/cnt + get_skill(buddy, gsn_triage)/7;
if(list->hit > list->max_hit)
list->hit = list->max_hit;
}
}
}
ch->wait_adjustment+=9;
}
break;
case gsn_search: // finds secret weakness
break;
}
break;
case gsn_berserk:
switch(skill_2) {
default: failed = true; break;
case gsn_backstab: break; // mass backstabbing!
case gsn_bash: break; // overpowering bash
case gsn_trip: break; // thundering trip
case gsn_dirt: break; // boulders to the face
}
break;
case gsn_steal:
switch(skill_2) {
default: failed = true; break;
case gsn_hide: break; // steals armed weapon
case gsn_backstab: break; // causes victim to drop coin's
case gsn_parry: break; // causes 100% chance of coin stealing (divies to group)
case gsn_bow: break; // shoot victim, causing victims gold/20 damage.
}
break;
case gsn_disarm:
switch(skill_2) {
default: failed = true; break;
case gsn_bash: break; // causes massive damage to victims weapon
case gsn_disarm: break; // disarm chance *3 + damage on disarm
case gsn_parry: break; // causes rend-damage loss
}
break;
case gsn_triage:
switch(skill_2) {
default: failed = true; break;
case gsn_bash: break; // heals group 1 point for every bit of damage delt.
case gsn_revive: break; // drains live from victim, restores party
case gsn_polearm:
{
act("$n screams 'BLOOD SIPHON' in unison with $N as they hold onto a mystical polearm and impale $t!", ch, victim->name, buddy, TO_ROOM);
int max = victim->max_hit/2;
victim->hit -= max;
victim->killer = number_range(0,1) ? ch : buddy;
if(victim->hit < 0)
kill_unit(victim);
switch(number_range(0,1)) {
default: case 0:
ch->hit = ch->max_hit;
break;
case 1:
buddy->hit = buddy->max_hit;
break;
}
ch->wait_adjustment+=3;
}
break; // blood siphon ch || buddy is healed 100%, victim damaged for 50% of their health.
case gsn_shield_block: break; // causes victim's turn to be pushed back.
}
break;
case gsn_sword:
switch(skill_2) {
default: failed = true; break;
case gsn_second_attack: {
act("$n and $N pair up, and unleash a hidden fury!", ch, NULL, buddy, TO_ROOM);
for(int x = 0; x < 3; x++) {
one_hit(ch, victim, false);
one_hit(buddy, victim, false);
}
}
break; // 3 attacks per person against victim (one_hits)
case gsn_third_attack:
act("$n and $N pair up, and unleash a hidden fury!", ch, NULL, buddy, TO_ROOM);
for(int x = 0; x < 4; x++) {
one_hit(ch, victim, false);
one_hit(buddy, victim, false);
}
break; // 4 attacks per person against victim (one_hits)
case gsn_enhanced_damage:
act("$n wields 2 bright blue, and humming scimitars.", ch, NULL, NULL, TO_ROOM);
act("$n wields 2 bright green, and humming rapiers.", buddy, NULL, NULL, TO_ROOM);
for(int x = 0; x < 2; x++) {
one_hit(ch, victim, false);
one_hit(ch, victim, true);
one_hit(buddy, victim, false);
one_hit(buddy, victim, true);
}
wait_adjustment+=number_range(3,9);
break; // 2 hits per person against victim
}
break;
case gsn_polearm:
switch(skill_2) {
default: failed = true; break;
case gsn_polearm: break; // buddy dies, victim takes buddy's max_health as damage
case gsn_cpr: break; // ch dies, victim takes ch's max_health as damage
case gsn_grenade: break; // requires a grenade, if it finds one, it arms it, and bats it at the enemy. instantly exploding.
}
break;
case gsn_swimming:
switch(skill_2) {
default: failed = true; break;
case gsn_arm: break; // Completely random effect!
}
break;
}
// yeah, we went there!
delete ch->teamskill;
delete buddy->teamskill;
// failure is not an option!
if(failed) {
ch->Sendf("Your teamskill failed!\n\r");
buddy->Sendf("Your teamskill failed!\n\r");
turn_end(ch->turn, 300-GET_SPEED(ch), ch);
turn_end(buddy->turn, 300-GET_SPEED(ch), ch);
ch->skill_wait = 3;
buddy->skill_wait = 3;
return;
}
// combat still lingers!
if(is_fighting(ch)) {
turn_end(ch->turn, 600-GET_SPEED(ch), ch);
turn_end(buddy->turn, 600-GET_SPEED(ch), ch);
ch->skill_wait = wait_adjustment;
buddy->skill_wait = wait_adjustment;
}
return;
}
// Teamskills start at level 20!
COMMAND(do_teamskill) {
char arg[MIL], arg2[MIL], arg3[MIL];
CHAR_DATA *search, *buddy = NULL, *victim = NULL;
// okay, we want to decimate everything!
if(!NullString(argument) && !str_cmp(argument, "confirm")) {
if(ch->teamskill) {
if(!str_cmp(ch->name, ch->teamskill->buddy_name)) {
perform_teamskill(ch->teamskill);
return;
}
ch->Sendf("You started the teamskill! You cannot confirm its action!\n\r");
return;
}
ch->Sendf("There is no teamskill for you to confirm!\n\r");
return;
}
// not a confirmation?
argument = one_argument(argument, arg);
argument = one_argument(argument, arg2);
argument = one_argument(argument, arg3);
if(NullString(argument)) {
ch->Sendf("Syntax: teamskill <buddy> <their skill> <your skill> <victim>\n\r");
ch->Sendf("-------------------------------------------------------------\n\r");
ch->Sendf("Teamskill allows you to experiment with skills, and create a\n\r");
ch->Sendf("powerful combonation, though you have to be careful, as the\n\r");
ch->Sendf("skills you choose, may or may not work with eachother to create\n\r");
ch->Sendf("the joyful teamskill.\n\r");
return;
}
if(!is_fighting(ch)) {
ch->Sendf("But your not fighting!\n\r");
return;
}
if(!is_active(ch)) {
ch->Sendf("Its not your turn!\n\r");
return;
}
for (search = ch->in_battle->unit_list; search != NULL; search = search->next_in_battle) {
if(!str_cmp(arg, search->name) && is_same_group(ch, search)) {
buddy = search;
}
if(!str_cmp(argument, search->name) && !is_same_group(ch, search)) {
victim = search;
}
if(victim && buddy)
break;
}
if(!buddy || !victim) {
ch->Sendf("Make sure your buddy name, and victim name are correct!\n\r");
return;
}
// require level 20!
if(buddy->level < 20) {
ch->Sendf("%s does not know the team mystic arts yet!\n\r");
return;
}
if(buddy->teamskill) {
ch->Sendf("They are already working on a teamskill!\n\r");
return;
}
int sn = skill_lookup(arg2);
int sn2 = skill_lookup(arg3);
if(get_skill(ch, sn2) == 0) {
ch->Sendf("You do not know that skill!\n\r");
return;
}
if(get_skill(buddy, sn) == 0) {
ch->Sendf("Your buddy doesn't know that skill!\n\r");
return;
}
if(ch->teamskill)
delete ch->teamskill();
ch->teamskill = new teamskill();
ch->teamskill->ch_skill = sn2;
ch->teamskill->bd_skill = sn;
ch->teamskill->ch_name = str_dup(ch->name);
ch->teamskill->buddy_name = str_dup(buddy->name);
ch->teamskill->victim_name = str_dup(victim->name);
// duplicated here!
buddy->teamskill = new teamskill();
buddy->teamskill->ch_skill = sn2;
buddy->teamskill->bd_skill = sn;
buddy->teamskill->ch_name = str_dup(ch->name);
buddy->teamskill->buddy_name = str_dup(buddy->name);
buddy->teamskill->victim_name = str_dup(victim->name);
if(is_fighting(ch)) {
turn_end(ch->turn, 200-GET_SPEED(ch), ch);
ch->skill_wait = 8;
}
return;
}