/* 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 \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; }