void parse_partymsg(char *msg) { char *prefix = strtok_r(NULL, "|", &msg); prefix = strtok_r(NULL, "|", &msg); // it's a chat message to this party only if (strcmp(prefix, CHATMSG_PREFIX) == 0) { char *nick = strtok_r(NULL, "|", &msg); wattron(log_win, A_BOLD); char buf[20] = "(party) "; strncat(buf, nick, NAME_MAX_LENGTH); ncurs_log_chatmsg(msg, buf); wattroff(log_win, A_BOLD); } if (strcmp(prefix, CTRLMSG_PREFIX) == 0) { char *ctrlprefix = strtok_r(NULL, "|", &msg); // a party member has committed turn in combat if (strcmp(ctrlprefix, TURNREADY) == 0) { // who committed the turn char *nick = strtok_r(NULL, "|", &msg); // what skill used char *skill = strtok_r(NULL, "|", &msg); // what target chosen char *target = strtok_r(NULL, "|", &msg); // set player_party.characters[i].turnready to chosen skill AND combattarget to chosen target for (int i = 0; i <= 2; i++) if (strcmp(nick, player_party.characters[i]->name) == 0) { player_party.characters[i]->turnready = atoi(skill); player_party.characters[i]->combattarget = atoi(target); // display info about the committed turn ncurs_log_sysmsg("Player %s committed turn", nick); ncurs_fightinfo(player_party.characters[i], i); break; } // TODO: does this make sense? // if in combat, calculate combat stuff if (player.incombat) combat_seeifready(); } // when a player has ran from a fight if (strcmp(ctrlprefix, RUNMSG) == 0) { char *nick = strtok_r(NULL, "|", &msg); // only care about this if you are in combat if (player.incombat) combat_plr_ran(nick); } } }
void skill_effect(Character *source, Character *dest, Skills *skill) { ncurs_log_sysmsg("%s used %s on %s",source->name, skill->name, dest->name); int dmg = 0; /* calculate normal damage done based on skill + weapon */ dmg += skill->damage; dmg += source->weapon->damage; /* if the skill type matches the element in the wu xing day cycle, apply bonus damage */ if (check_wuxing_time(skill->dmg_type)) { ncurs_log_sysmsg(_("%s is in sync with the element cycle and deals bonus damage!"),source->name); dmg += skill->damage / 2; // TODO: balance the effect } /* calculate blocking by enemy*/ /* blocking elements are based on skill used to attack. TODO: should this be weapon instead? */ dmg -= dmg_calc_blocking(dest, skill->dmg_type); /* calculate damage */ if (dmg > 0) { dest->health -= dmg; ncurs_log_sysmsg(_("%s did %d damage to %s"), source->name, dmg, dest->name); /* ONLY ALIGN ELEMENTS IF DAMAGE WAS DONE */ /* elements align == player skill type and weapon type are the same */ /* also, if elements align, changes to enemy elemental balance occur */ if (skill->dmg_type == source->weapon->dmg_type) { ncurs_log_sysmsg(_("%s causes elemental damage to %s"), source->name, dest->name); dmg += source->elements[skill->dmg_type]; align_elements(dest, skill->dmg_type); // TODO is this correct? } } else { /* don't do negative damage */ ncurs_log_sysmsg(_("%s blocked attack from %s."), dest->name, source->name); } source->stamina -= skill->ap_cost; /* spend action points on the attack */ }
void parse_ctrlmsg(char *msg) { char *prefix = strtok_r(NULL, "|", &msg); prefix = strtok_r(NULL, "|", &msg); if (strcmp(prefix, FIGHTMSG) == 0) { // set random seed and fight char *seed = strtok_r(NULL, "|", &msg); randomseed = atoi(seed); srand(randomseed); ac_fightscreen(); } if (strcmp(prefix, JOINMSG) == 0) { char *joining_plr = strtok_r(NULL, "|", &msg); // don't show join msg when you're joining if (strcmp(joining_plr, player.name) != 0) { if (is_partymember(joining_plr)) ncurs_log_sysmsg(_("Partymember %s has entered the realm"), joining_plr); else ncurs_log_sysmsg(_("%s has entered the realm"), joining_plr); } } if (strcmp(prefix, QUITMSG) == 0) { char *leaving_plr = strtok_r(NULL, "|", &msg); // player quits after sending this msg, so it will never be echoed back to the quitting player if (is_partymember(leaving_plr)) ncurs_log_sysmsg(_("Partymember %s has left the realm"), leaving_plr); else ncurs_log_sysmsg(_("%s has left the realm"), leaving_plr); } }
void use_skill(int keypress) { /* this function is entered with a keypress from ac_fight0 and so on*/ /* the keypress is used to determine what attack is used */ /* 1. the player already chose the attack (int keypress), now it's time for the enemy */ // TODO enemy always uses skill 0 /* 2. calculate damage */ /* player does damage */ /* Wu Xing cycles: Wood causes +FIRE, -EARTH Fire causes +EARTH, -METAL Earth causes +METAL, -WATER Metal causes +WATER, -WOOD Water causes +WOOD, -FIRE */ if (keypress <= 4 && strcmp(player.skill[keypress]->name,"Unused") != 0) { // Player attacks skill_effect(&player, &enemy, player.skill[keypress]); // Enemy attack skill_effect(&enemy, &player, enemy.skill[0]); /* 3. check for dead player/enemy */ int enemy_dead = fight_check_dead(); /* 4. update stats and display them IF THE ENEMY DIDN'T DIE */ if (!enemy_dead) { ncurs_fightinfo(&player, 0); ncurs_fightinfo(&enemy, 3); } wrefresh(game_win); } else { ncurs_log_sysmsg(_("You dont have a skill in slot %d"), keypress+1); } }
void ncurs_chat() { /* TODO: figure out this toggle mess */ toggle_chat += 1; if (toggle_chat >= 3) /* never loop messageboard */ toggle_chat = 0; /* redraw the input line - chat toggle*/ ncurs_bold_input(toggle_chat); char *line = NULL; size_t len = 0; if (toggle_chat != 0) { if (todd_getline(&line, &len, input_win)) { Message msg = create_chat_msg(line, len); /* a chat message was succesfully input(ted) */ if (toggle_chat == 1) { // party message msg = wrap_as_partymsg(msg); } if (!send_msg(msg)) { ncurs_log_sysmsg(_("Message send failure")); } del_msg(msg); } // return to basic input prompt -> press any key for game commands // this is done here because if todd_getline returns 0 it means there's an empty line // TODO.. or todd_getline has an error... toggle_chat = 0; ncurs_bold_input(0); free(line); } }
void combat_plr_ran(char *nick) { // find out which screen to delete from fight window - naturally only affects multiplayer // do nothing if the running player is you if (strcmp(nick, player.name) == 0) return; ncurs_log_sysmsg(_("%s ran from a fight. What a coward!"),nick); int index; for (index = 0; index <=2; index++) if (strcmp(player_party.characters[index]->name, nick) == 0) break; wclear(fight_stat_win[index]); wrefresh(fight_stat_win[index]); // set the incombat to false for (int i = 0; i <= 2; i++) if (player_party.characters[i]->name != NULL) if (strcmp(player_party.characters[i]->name,nick) == 0) player_party.characters[i]->incombat = 0; }
void combat_seeifready() { // loop through all the players in combat int allready = 1; //if (is_online(partymember1.id) || is_online(partymember2.id)) // it's multiplayer combat if (combat_ismulti()) // it's multiplayer combat { // loop through all the effects of all party members taking part in the fight for (int i = 0; i <= 2; i++) if (player_party.characters[i]->incombat) { if (player_party.characters[i]->turnready < 0) { ncurs_log_sysmsg("still waiting for: %s",player_party.characters[i]->name); allready = 0; // still waiting for a keypress } } } else // it's single player combat { allready = 1; } // COMBAT EFFECTS START HERE if (allready) // if everyone is ready, do combat stuff { ncurs_log_sysmsg(_("all players have committed turns, calculating effects")); ncurs_log_sysmsg(_("Combat resolution============================")); // combat stuff begins here // players attack enemies for (int i = 0; i <= 2; i++) if (player_party.characters[i]->incombat) skill_effect(player_party.characters[i], enemy_party.characters[player_party.characters[i]->combattarget],player_party.characters[i]->skill[player_party.characters[i]->turnready]); // enemies attack players // choose which player to attack int dest = 0; int players = 0; for (int i = 0; i <= 2; i++) if (player_party.characters[i]->incombat) players++; // players now holds the number of players in combat, randomize one of them int i = 0; // enemies attack here for (int j = 0; j <= 2; j++) { if (enemy_party.characters[j]->incombat) // only enemies who are in combat attack { while (i == 0) // loop until you find an acceptable target, then attack { dest = rand() % players; // dest holds a number from 0..players in combat if (player_party.characters[dest]->incombat) // this player is in combat -> acceptable target i = 1; } // TODO: random enemy skill (enemies should have more than one skill.. skill_effect(enemy_party.characters[j], player_party.characters[dest], enemy_party.characters[j]->skill[0]); } } ncurs_log_sysmsg(_("=============================================")); // combat stuff ends here // reset turnready for (int i = 0; i <= 2; i++) if (player_party.characters[i]->incombat) player_party.characters[i]->turnready = -1; /* 3. check for dead player/enemy */ int all_enemies_dead = fight_check_dead(); /* 4. update stats and display them IF THE ENEMY DIDN'T DIE */ if (!all_enemies_dead) ac_update_fightscreen(); else { ncurs_clear_fightwindows(); ncurs_modal_msg(_("All enemies are slain! The battle is over")); // ac_dungeons makes the player go up a dungeon level // -> to stay at the same level, decrease the level here player.dungeon_lvl--; ac_dungeons(); } } }
void use_skill(int keypress) { player.turnready = -1; // when set to [0..3] it means a skill is used this turn /* this function is entered with a keypress from ac_fight0 and so on*/ /* the keypress is used to determine what attack is used */ /* 1. the player already chose the attack (int keypress), now it's time for the enemy */ // TODO enemy always uses skill 0 /* 2. calculate damage */ /* player does damage */ /* Wu Xing cycles: Wood causes +FIRE, -EARTH Fire causes +EARTH, -METAL Earth causes +METAL, -WATER Metal causes +WATER, -WOOD Water causes +WOOD, -FIRE */ // TODO: !succesful_target, return loop here? if (keypress <= 4 && strcmp(player.skill[keypress]->name,"Unused") != 0) { int enemynr = 0; for (int i = 0; i <=2; i++) if (enemy_party.characters[i]->incombat) enemynr++; // only target if there's more than 1 enemy - enemynr tells us how many we have int succesful_target = -1; player.combattarget = 0; // reset the target int, by default attack 0 if (enemynr > 1) { // Target the attack if it can be targeted if (is_targetable(player.skill[keypress])) succesful_target = target_attack(player.skill[keypress]); if (succesful_target == -1) return; // go back to select a different skill? TODO: How? //// end targeting // succesful_target now holds the enemy id - store it to your char array player.combattarget = succesful_target; } else // only one enemy, select that one (might be index 0,1 or 2 { for (int i = 0; i <=2; i++) if (enemy_party.characters[i]->incombat) { player.combattarget = i; break; } } // Players attack // wait for everyone in the game to commit the skill // go through all online players. Once a player commits a turn, // a TURNREADY is sent player.turnready = keypress; // if a multiplayer game, go through send_turnready, otherwise directly to combat // TODO: will hang if a party member joins game during combat - check for incombat instead of is_online // if (is_online(partymember1.id) || is_online(partymember2.id)) if (combat_ismulti()) send_turnready(); else combat_seeifready(); } else { ncurs_log_sysmsg(_("You dont have a skill in slot %d"), keypress+1); } }
int fight_check_dead() { /* TODO: figure out the order of checking deaths: attacks are simultaneous. Iniative? */ // TODO enemy and player codes are almost identical, refactor into a function // bool check_chr_dead(Character *chr); or something bool enemy_dead; bool enemy_dead_elements; // loop through all enemies in combat for (int i = 0; i <= 2; i++) { enemy_dead = false; enemy_dead_elements = false; if (enemy_party.characters[i]->incombat) { /* check if enemy dies */ for (size_t j = 0; j < ELEM_COUNT; j++) { if (enemy_party.characters[i]->elements[j] <= 0) { enemy_dead = true; enemy_dead_elements = true; } } if (enemy_party.characters[i]->health <= 0) enemy_dead = true; // the current enemy is dead (characters[i]) if (enemy_dead) { enemy_party.characters[i]->incombat = false; // TODO: would it look better to display "DEAD" instead of erasing the box? werase(fight_stat_win[3+i]); wrefresh(fight_stat_win[3+i]); int money = 7; player.money += money; if (enemy_dead_elements) ncurs_log_sysmsg(_("%s has caused an elemental imbalance in %s"), player.name, enemy_party.characters[i]->name); ncurs_log_sysmsg(_("%s has killed %s!"), player.name, enemy_party.characters[i]->name); // TODO: share money from a kill someway ncurs_log_sysmsg(_("%s found %d coins from the body"), player.name, money); // if there's no more enemies left, return to dungeons. int alldead = 1; for (int i = 0; i <= 2; i++) if (enemy_party.characters[i]->incombat) alldead = 0; // if all enemies are dead, the battle is over if (alldead) { player.incombat = false; // don't return to combat any more ncurs_log_sysmsg(_("All enemies are slain! The battle is over")); return 1; } // If there's enemies left, the battle continues (i.e. do nothing) } } } /* check if player dies as well */ // TODO: loop through all players, not just yourself bool player_dead = false; bool player_dead_elements = false; for (size_t i = 0; i < 5; i++) { if (player.elements[i] <= 0) { player_dead = true; player_dead_elements = true; } } if (player.health <= 0) player_dead = true; if (player_dead) { wclear (game_win); if (player_dead_elements) // elements below 0, don't die but faint only { db_player_location(LOC_FAINTED); // TODO: which enemy.. ncurs_log_sysmsg(_("%s has caused an elemental imbalance in %s"), enemy_party.characters[0]->name, player.name); mvwprintw(game_win, 6, 0, _("The world around you starts to spin.\nYou sense a great imbalance inside you.")); wattron(game_win, A_BOLD); wattron(game_win, A_UNDERLINE); mvwprintw(game_win, 8, 0, _("You faint. TODO: \"come back in 8 hours??\"")); wattroff(game_win, A_BOLD); wattroff(game_win, A_UNDERLINE); } else // PERMADEATH { /* first, set the player location to "DEAD" */ db_player_location(LOC_DEAD); // TODO: which enemy ncurs_log_sysmsg(_("%s has killed %s!"), enemy_party.characters[0]->name, player.name); mvwprintw(game_win, 6, 0, _("The world fades around you as you fall to the ground, \nbleeding.")); wattron(game_win, A_BOLD); wattron(game_win, A_UNDERLINE); mvwprintw(game_win, 8, 0, _("You are dead.")); wattroff(game_win, A_BOLD); wattroff(game_win, A_UNDERLINE); } // common stuff to death // elemental imbalance wrefresh(game_win); todd_getchar(NULL); playing = false; } if (enemy_dead || player_dead) return 1; /* if enemy / player is dead, don't redraw combat stuff anymore */ else return 0; // redraw combat stuff }
int fight_check_dead() { /* TODO: figure out the order of checking deaths: attacks are simultaneous. Iniative? */ // TODO enemy and player codes are almost identical, refactor into a function // bool check_chr_dead(Character *chr); or something /* check if enemy dies */ bool enemy_dead = false; bool enemy_dead_elements = false; for (size_t i = 0; i < ELEM_COUNT; i++) { if (enemy.elements[i] <= 0) { enemy_dead = true; enemy_dead_elements = true; } } if (enemy.health <= 0) enemy_dead = true; if (enemy_dead) { int money = 7; int exp = 10; player.money += money; player.experience += exp; werase(game_win); if (enemy_dead_elements) ncurs_log_sysmsg(_("%s has caused an elemental imbalance in %s"), player.name, enemy.name); ncurs_log_sysmsg(_("%s has killed %s!"), player.name, enemy.name); ncurs_log_sysmsg(_("%s received %d coins and %d XP"), player.name, money, exp); ncurs_modal_msg( _("%s is slain!\n\nYou find %d coins on the corpse, and gain %d experience\n"), enemy.name, money, exp); ac_dungeons(); } /* check if player dies as well */ bool player_dead = false; bool player_dead_elements = false; for (size_t i = 0; i < 5; i++) { if (player.elements[i] <= 0) { player_dead = true; player_dead_elements = true; } } if (player.health <= 0) player_dead = true; if (player_dead) { wclear (game_win); if (player_dead_elements) // elements below 0, don't die but faint only { db_player_location(LOC_FAINTED); ncurs_log_sysmsg(_("%s has caused an elemental imbalance in %s"), enemy.name, player.name); mvwprintw(game_win, 6, 0, _("The world around you starts to spin.\nYou sense a great imbalance inside you.")); wattron(game_win, A_BOLD); wattron(game_win, A_UNDERLINE); mvwprintw(game_win, 8, 0, _("You faint. TODO: \"come back in 8 hours??\"")); wattroff(game_win, A_BOLD); wattroff(game_win, A_UNDERLINE); } else // PERMADEATH { /* first, set the player location to "DEAD" */ db_player_location(LOC_DEAD); ncurs_log_sysmsg(_("%s has killed %s!"), enemy.name, player.name); mvwprintw(game_win, 6, 0, _("The world fades around you as you fall to the ground, \nbleeding.")); wattron(game_win, A_BOLD); wattron(game_win, A_UNDERLINE); mvwprintw(game_win, 8, 0, _("You are dead.")); wattroff(game_win, A_BOLD); wattroff(game_win, A_UNDERLINE); } // common stuff to death // elemental imbalance wrefresh(game_win); todd_getchar(NULL); playing = false; } if (enemy_dead || player_dead) return 1; /* if enemy / player is dead, don't redraw combat stuff anymore */ else return 0; // redraw combat stuff }