/*! \brief Give the bounded area a new background tile number * * \param box - Which box to assign the value to */ void rename_bound_tile (s_bound *box) { int response, done; int selected_tile = 0; make_rect (double_buffer, 2, 32); sprintf (strbuf, "Tile: %d", box->btile); print_sfont (6, 6, strbuf, double_buffer); print_sfont (6, 12, ">", double_buffer); done = 0; while (!done) { blit2screen (); response = get_line (12, 12, strbuf, 4); /* If the user hits ESC, break out of the function entirely */ if (response == 0) return; /* Make sure this line isn't blank */ if (strlen (strbuf) > 0) { selected_tile = atoi (strbuf); /* Make sure the value is valid */ if (selected_tile < 0 || selected_tile >= ICONSET_SIZE * max_sets) { sprintf (strbuf, "Invalid tile: %d", selected_tile); cmessage (strbuf); wait_enter (); } else { done = 1; } } } box->btile = selected_tile; } /* rename_bound_tile () */
/*! \brief Confirm save * * If the save slot selected already has a saved game in it, confirm that we * want to overwrite it. * * \returns 0 if cancelled, 1 if confirmed */ static int confirm_action (void) { int stop = 0; int pointer_offset = (save_ptr - top_pointer) * 48; if (snc[save_ptr] == 0) return 1; fullblit(double_buffer, back); menubox (double_buffer, 128, pointer_offset + 12, 14, 1, DARKBLUE); print_font (double_buffer, 136, pointer_offset + 20, _("Confirm/Cancel"), FNORMAL); blit2screen (0, 0); fullblit(back, double_buffer); while (!stop) { readcontrols (); if (balt) { unpress (); return 1; } if (bctrl) { unpress (); return 0; } kq_yield (); } return 0; }
/*! \brief Enemies defeated the player * \author Josh Bolduc * \date created ???????? * \date updated * * Play some sad music and set the dead flag so that the game * will return to the main menu. */ static void enemies_win (void) { play_music ("rain.s3m", 0); battle_render (0, 0, 0); /* RB FIXME: rest()? */ blit2screen (0, 0); kq_wait (1000); sprintf (strbuf, _("%s was defeated!"), party[pidx[0]].name); menubox (double_buffer, 152 - (strlen (strbuf) * 4), 48, strlen (strbuf), 1, BLUE); print_font (double_buffer, 160 - (strlen (strbuf) * 4), 56, strbuf, FNORMAL); blit2screen (0, 0); wait_enter (); do_transition (TRANS_FADE_OUT, 4); alldead = 1; }
/*! \brief Get value for option * * Display a bar and allow the user to adjust between fixed limits * * \param capt Caption * \param minu Minimum value of option * \param maxu Maximum vlaue of option * \param cv Current value (initial value) * \param sp Show percent. If sp==1, show as a percentage of maxu * \returns the new value for option, or -1 if cancelled. */ static int getavalue (const char *capt, int minu, int maxu, int cv, int sp) { int stop = 0, a, b; if (maxu == 0) return -1; while (!stop) { check_animation (); menubox (double_buffer, 148 - (maxu * 4) + xofs, 100 + yofs, maxu + 1, 3, DARKBLUE); print_font (double_buffer, 160 - (strlen (capt) * 4) + xofs, 108 + yofs, capt, FGOLD); print_font (double_buffer, 152 - (maxu * 4) + xofs, 116 + yofs, "<", FNORMAL); print_font (double_buffer, 160 + (maxu * 4) + xofs, 116 + yofs, ">", FNORMAL); b = 160 - (maxu * 4) + xofs; for (a = 0; a < cv; a++) { rectfill (double_buffer, a * 8 + b + 1, 117 + yofs, a * 8 + b + 7, 123 + yofs, 50); rectfill (double_buffer, a * 8 + b, 116 + yofs, a * 8 + b + 6, 122 + yofs, 21); } if (sp == 1) sprintf (strbuf, "%d%%", cv * 100 / maxu); else sprintf (strbuf, "%d", cv); print_font (double_buffer, 160 - (strlen (strbuf) * 4) + xofs, 124 + yofs, strbuf, FGOLD); blit2screen (xofs, yofs); readcontrols (); if (left) { unpress (); cv--; if (cv < minu) cv = minu; IF_VOLUME_ALERT (); } if (right) { unpress (); cv++; if (cv > maxu) cv = maxu; IF_VOLUME_ALERT (); } if (balt) { unpress (); stop = 1; } if (bctrl) { unpress (); return -1; } } return cv; }
/* \brief Enter console mode * * Run the console. Does not return until the console * is closed. */ void run_console(void) { int c; int sl; int running; g_console.inputline[0]='\0'; g_console.on = 1; /* Wait for all keys up */ while(keypressed()) { readkey(); } running = 1; while (running == 1) { sl = strlen(g_console.inputline); /* Get a key */ while (!keypressed()) { check_animation (); blit2screen (xofs, yofs); poll_music (); kq_yield(); } switch((c = readkey()) & 0xff) { case '\r': /* Return */ if (sl == 0) { /* Stop when blank line is entered */ running = 0; g_console.on = 0; } else { g_console.on = 0; scroll_console(g_console.inputline); do_console_command(g_console.inputline); g_console.inputline[0] = '\0'; g_console.on = 1; } break; case 127: /* backspace */ if (strlen(g_console.inputline) > 0) g_console.inputline[sl - 1] = '\0'; break; default: if (strlen(g_console.inputline) < sizeof(g_console.inputline) - 1) { g_console.inputline[sl] = c & 0xff; g_console.inputline[sl + 1] = '\0'; } break; } } /* Wait for enter key up */ do { readcontrols(); } while (benter); }
/*! \brief Process keypresses when mapping new keys * * This grabs whatever key is being pressed and returns it to the caller. * PH 20030527 Removed call to keypressed() and added poll_music() * * \returns the key being pressed, 0 if error (or cancel?) */ static int getakey (void) { int a; clear_keybuf (); menubox (double_buffer, 108 + xofs, 108 + yofs, 11, 1, DARKBLUE); print_font (double_buffer, 116 + xofs, 116 + yofs, _("Press a key"), FNORMAL); blit2screen (xofs, yofs); while (1) { poll_music (); for (a = 0; a < KEY_MAX; a++) if (key[a] != 0) return a; } return 0; }
/*! \brief Delete game * * You guessed it... delete the game. */ static void delete_game (void) { int a, stop = 0; int pointer_offset = (save_ptr - top_pointer) * 48; sprintf (strbuf, "sg%d.sav", save_ptr); a = remove (kqres (SAVE_DIR, strbuf)); if (a == 0) { menubox (double_buffer, 128, pointer_offset + 12, 12, 1, DARKBLUE); print_font (double_buffer, 136, pointer_offset + 20, _("File Deleted"), FNORMAL); snc[save_ptr] = 0; sgp[save_ptr] = 0; shr[save_ptr] = 0; smin[save_ptr] = 0; for (a = 0; a < PSIZE; a++) { sid[save_ptr][a] = 0; shp[save_ptr][a] = 0; smp[save_ptr][a] = 0; slv[save_ptr][a] = 0; } } else { menubox (double_buffer, 128, pointer_offset + 12, 16, 1, DARKBLUE); print_font (double_buffer, 136, pointer_offset + 20, _("File Not Deleted"), FNORMAL); } blit2screen (0, 0); blit (back, double_buffer, 0, 0, 0, 0, 352, 280); while (!stop) { readcontrols (); if (balt || bctrl) { unpress (); stop = 1; } kq_yield (); } }
/*! \brief Give the marker a new name if the name hasn't been taken already * * \param found - Which marker to rename */ void rename_marker (s_marker *found) { int response, done; s_marker *m; make_rect (double_buffer, 2, 32); print_sfont (6, 6, found->name, double_buffer); print_sfont (6, 12, ">", double_buffer); done = 0; while (!done) { blit2screen (); response = get_line (12, 12, strbuf, 31); /* If the user hits ESC, break out of the function entirely */ if (response == 0) return; /* Make sure this line isn't blank */ if (strlen (strbuf) == 0) { cmessage ("Do you want to clear the name of this marker? (y/n)"); if (yninput ()) done = 1; } else { done = 1; } /* Make sure no other markers have the same name */ for (m = gmap.markers; m < gmap.markers + num_markers; ++m) { if (!strcmp (strbuf, m->name) && m != found) { cmessage ("Another marker has that name. Use another name."); yninput (); done = 0; break; } } } strcpy (found->name, strbuf); } /* rename_marker () */
/*! \brief Show keys help * Show a screen with the keys listed, and other helpful info * \author PH * \date 20030527 */ void show_help (void) { menubox (double_buffer, 116 + xofs, yofs, 9, 1, BLUE); print_font (double_buffer, 132 + xofs, 8 + yofs, _("KQ Help"), FGOLD); menubox (double_buffer, 32 + xofs, 32 + yofs, 30, 20, BLUE); menubox (double_buffer, xofs, 216 + yofs, 38, 1, BLUE); print_font (double_buffer, 16 + xofs, 224 + yofs, _("Press CONFIRM to exit this screen"), FNORMAL); citem (72, _("Up Key:"), kq_keyname (kup), FNORMAL); citem (80, _("Down Key:"), kq_keyname (kdown), FNORMAL); citem (88, _("Left Key:"), kq_keyname (kleft), FNORMAL); citem (96, _("Right Key:"), kq_keyname (kright), FNORMAL); citem (104, _("Confirm Key:"), kq_keyname (kalt), FNORMAL); citem (112, _("Cancel Key:"), kq_keyname (kctrl), FNORMAL); citem (120, _("Menu Key:"), kq_keyname (kenter), FNORMAL); citem (128, _("System Menu Key:"), kq_keyname (kesc), FNORMAL); do { blit2screen (xofs, yofs); readcontrols (); } while (!balt && !bctrl); unpress (); }
/*! \brief Main fighting routine * * I don't really need to describe this :p * * \author Josh Bolduc * \date created ???????? * \date updated * \param ar Attacker ID * \param dr Defender ID * \param sk If non-zero, override the attacker's stats. * \returns 1 if damage done, 0 otherwise */ int fight (int ar, int dr, int sk) { int a; int tx = -1; int ty = -1; int f; int ares; for (a = 0; a < NUM_FIGHTERS; a++) { deffect[a] = 0; ta[a] = 0; } /* check the 'sk' variable to see if we are over-riding the */ /* attackers stats with temporary ones... used for skills */ /* and such */ if (sk == 0) tempa = status_adjust (ar); tempd = status_adjust (dr); ares = attack_result (ar, dr); for (a = 0; a < 24; a++) fighter[dr].sts[a] = tempd.sts[a]; /* RB TODO: rest(20) or vsync() before the blit? */ if (ares == 2) { for (f = 0; f < 3; f++) { battle_render (dr + 1, 0, 0); blit2screen (0, 0); kq_wait (20); rectfill (double_buffer, 0, 0, 320, 240, 15); blit2screen (0, 0); kq_wait (20); } } if ((pidx[dr] == TEMMIN) && (fighter[dr].aux == 2)) { fighter[dr].aux = 1; a = 1 - dr; tx = fighter[dr].cx; ty = fighter[dr].cy; fighter[dr].cx = fighter[a].cx; fighter[dr].cy = fighter[a].cy - 16; } if (ar < PSIZE) fighter[ar].aframe = 7; else fighter[ar].cy += 10; fight_animation (dr, ar, 0); if (ar < PSIZE) fighter[ar].aframe = 0; else fighter[ar].cy -= 10; if ((tx != -1) && (ty != -1)) { fighter[dr].cx = tx; fighter[dr].cy = ty; } if (ta[dr] != MISS) ta[dr] = do_shield_check (dr, ta[dr]); display_amount (dr, FDECIDE, 0); if (ta[dr] != MISS) { fighter[dr].hp += ta[dr]; if ((fighter[ar].imb_s > 0) && ((rand () % 5) == 0)) cast_imbued_spell (ar, fighter[ar].imb_s, fighter[ar].imb_a, dr); if ((fighter[dr].hp <= 0) && (fighter[dr].sts[S_DEAD] == 0)) { fkill (dr); death_animation (dr, 0); } if (fighter[dr].hp > fighter[dr].mhp) fighter[dr].hp = fighter[dr].mhp; if (fighter[dr].sts[S_SLEEP] > 0) fighter[dr].sts[S_SLEEP] = 0; if ((fighter[dr].sts[S_CHARM] > 0) && (ar == dr)) fighter[dr].sts[S_CHARM] = 0; return 1; } return 0; }
/*! \brief Process the item menu * * This screen displays the list of items that the character has, then * waits for the player to select one. */ void camp_item_menu(void) { int stop = 0, ptr = 0, pptr = 0, sel = 0; item_act = 0; play_effect(SND_MENU, 128); while (!stop) { check_animation(); drawmap(); draw_itemmenu(ptr, pptr, sel); blit2screen(xofs, yofs); readcontrols(); if (sel == 0) { if (down) { unpress(); ptr++; if (ptr > 15) { ptr = 0; } play_effect(SND_CLICK, 128); } if (up) { unpress(); ptr--; if (ptr < 0) { ptr = 15; } play_effect(SND_CLICK, 128); } } if (right) { unpress(); if (sel == 0) { /* One of the 16 items in the list */ pptr++; if (pptr > MAX_INV / 16 - 1) { pptr = 0; } } else { /* Use / Sort / Drop */ item_act++; if (item_act > 2) { item_act = 0; } } play_effect(SND_CLICK, 128); } if (left) { unpress(); if (sel == 0) { /* One of the 16 items in the list */ pptr--; if (pptr < 0) { pptr = MAX_INV / 16 - 1; } } else { /* Use / Sort / Drop */ item_act--; if (item_act < 0) { item_act = 2; } } play_effect(SND_CLICK, 128); } if (balt) { unpress(); if (sel == 1) { if (item_act == 1) { sort_items(); } else { sel = 0; } } else { if (g_inv[pptr * 16 + ptr][0] > 0) { // Player's cursor was over the USE menu if (item_act == 0) { camp_item_targetting(pptr * 16 + ptr); } // Player's curor was over the DROP menu else { if (item_act == 2) { int stop2 = 0; /* Make sure the player really wants to drop the item specified. */ while (!stop2) { check_animation(); drawmap(); draw_itemmenu(ptr, pptr, sel); menubox(double_buffer, 72 + xofs, 204 + yofs, 20, 1, DARKBLUE); print_font(double_buffer, 104 + xofs, 212 + yofs, _("Confirm/Cancel"), FNORMAL); blit2screen(xofs, yofs); readcontrols(); if (balt) { unpress(); stop2 = 2; } if (bctrl) { unpress(); stop2 = 1; } } if (stop2 == 2) { // Drop ALL of the selected items remove_item(pptr * 16 + ptr, g_inv[pptr * 16 + ptr][1]); } } } } } } if (bctrl) { unpress(); if (sel == 0) { sel = 1; } else { stop = 1; } } } }
/*! \brief Battle gauge, action controls * \author Josh Bolduc * \date Created ???????? * \date Updated 20020914 - 16:16 (RB) * * This function controls the battle gauges and calls for action * when necessary. This is also where things like poison, sleep, * and what-not are checked. */ static void do_round (void) { int a; int index; timer_count = 0; while (!combatend) { if (timer_count >= 10) { rcount += BATTLE_INC; if (rcount >= ROUND_MAX) rcount = 0; for (index = 0; index < PSIZE + numens; index++) { if ((index < numchrs) || (index >= PSIZE)) { if (((fighter[index].sts[S_POISON] - 1) == rcount) && (fighter[index].hp > 1)) { a = rand () % ((fighter[index].mhp / 20) + 1); if (a < 2) a = 2; if ((fighter[index].hp - a) < 1) a = fighter[index].hp - 1; ta[index] = a; display_amount (index, FNORMAL, 0); fighter[index].hp -= a; } /* RB: the character is regenerating? when needed, get a */ /* random value (never lower than 5), and increase */ /* the character's health by that amount. */ if ((fighter[index].sts[S_REGEN] - 1) == rcount) { a = rand () % 5 + (fighter[index].mhp / 10); if (a < 5) a = 5; ta[index] = a; display_amount (index, FYELLOW, 0); adjust_hp (index, a); } /* RB: the character has ether actived? */ cact[index] = 1; if ((fighter[index].sts[S_ETHER] > 0) && (rcount == 0)) fighter[index].sts[S_ETHER]--; /* RB: the character is stopped? */ if (fighter[index].sts[S_STOP] > 0) { if (pidx[index] == TEMMIN) fighter[index].aux = 0; if (rcount == 0) fighter[index].sts[S_STOP]--; cact[index] = 0; } /* RB: the character is sleeping? */ if (fighter[index].sts[S_SLEEP] > 0) { if (pidx[index] == TEMMIN) fighter[index].aux = 0; if (rcount == 0) fighter[index].sts[S_SLEEP]--; cact[index] = 0; } /* RB: the character is petrified? */ if (fighter[index].sts[S_STONE] > 0) { if (pidx[index] == TEMMIN) fighter[index].aux = 0; if (rcount == 0) fighter[index].sts[S_STONE]--; cact[index] = 0; } if ((fighter[index].sts[S_DEAD] != 0) || (fighter[index].mhp <= 0)) { if (pidx[index] == TEMMIN) fighter[index].aux = 0; bspeed[index] = 0; cact[index] = 0; } if (cact[index] > 0) { if (fighter[index].sts[S_TIME] == 0) bspeed[index] += nspeed[index]; else { if (fighter[index].sts[S_TIME] == 1) bspeed[index] += (nspeed[index] / 2 + 1); else bspeed[index] += (nspeed[index] * 2); } } } else cact[index] = 0; } readcontrols (); battle_render (0, 0, 0); blit2screen (0, 0); for (index = 0; index < (PSIZE + numens); index++) { if ((bspeed[index] >= ROUND_MAX) && (cact[index] > 0)) { do_action (index); fighter[index].ctmem = 0; fighter[index].csmem = 0; cact[index] = 1; bspeed[index] = 0; } if (combatend) return; } timer_count = 0; } kq_yield (); } }
/*! \brief Do the Quest Info menu * * Show the current list of quest information items * \sa ILIST * \author PH * \date 20050429 */ static void quest_info(void) { int ii = 0; int i, base; /* Call into the script */ ilist_clear(&quest_list); do_questinfo(); if (quest_list.count == 0) { /* There was nothing.. */ play_effect(SND_BAD, 128); return; } while (1) { timer_count = 0; drawmap(); base = ii - ii % 10; menubox(double_buffer, 88 + xofs, 92 + yofs, 18, 10, BLUE); menubox(double_buffer, 88 + xofs, 188 + yofs, 18, 3, BLUE); for (i = 0; i < 10; ++i) { if (i + base < quest_list.count) { print_font(double_buffer, 104 + xofs, 100 + 8 * i + yofs, quest_list.root[i + base].key, FNORMAL); } } draw_sprite(double_buffer, menuptr, 88 + xofs, 100 + 8 * (ii - base) + yofs); if (ii < quest_list.count) { print_font(double_buffer, 96 + xofs, 196 + yofs, quest_list.root[ii].text, FNORMAL); } blit2screen(xofs, yofs); readcontrols(); if (PlayerInput.up) { --ii; play_effect(SND_CLICK, 128); unpress(); } if (PlayerInput.down) { ++ii; play_effect(SND_CLICK, 128); unpress(); } if (PlayerInput.left) { ii -= 10; play_effect(SND_CLICK, 128); unpress(); } if (PlayerInput.right) { ii += 10; play_effect(SND_CLICK, 128); unpress(); } if (ii < 0) { ii = quest_list.count - 1; } if (ii >= quest_list.count) { ii = 0; } if (PlayerInput.balt || PlayerInput.bctrl) { unpress(); return; } } }
/*! \brief Player defeated the enemies * \author Josh Bolduc * \date Created ???????? * \date Updated * * Distribute the booty! */ static void heroes_win (void) { int tgp = 0; int index; int b; int c; int z; int nc = 0; int txp = 0; int found_item = 0; int nr = 0; int ent = 0; s_fighter t1; s_fighter t2; play_music ("rend5.s3m", 0); kq_wait (500); revert_equipstats (); for (index = 0; index < numchrs; index++) fighter[index].aframe = 4; battle_render (0, 0, 0); blit2screen (0, 0); kq_wait (250); for (index = 0; index < numchrs; index++) { if ((fighter[index].sts[S_STONE] == 0) && (fighter[index].sts[S_DEAD] == 0)) nc++; ta[index] = 0; } for (index = PSIZE; index < PSIZE + numens; index++) { txp += fighter[index].xp; tgp += fighter[index].gp; } /* JB: nc should never be zero if we won, but whatever */ if (nc > 0) txp /= nc; gp += tgp; if (tgp > 0) sprintf (strbuf, _("Gained %d xp and found %d gp."), txp, tgp); else sprintf (strbuf, _("Gained %d xp."), txp); menubox (double_buffer, 152 - (strlen (strbuf) * 4), 8, strlen (strbuf), 1, BLUE); print_font (double_buffer, 160 - (strlen (strbuf) * 4), 16, strbuf, FNORMAL); blit2screen (0, 0); blit (double_buffer, back, 0, 0, 0, 0, 352, 280); for (index = 0; index < numens; index++) { /* PH bug: (?) should found_item be reset to zero at the start of this loop? * If you defeat 2 enemies, you should (possibly) get 2 items, right? */ if ((rand () % 100) < fighter[index + PSIZE].dip) { if (fighter[index + PSIZE].defeat_item_common > 0) found_item = fighter[index + PSIZE].defeat_item_common; if (fighter[index + PSIZE].defeat_item_rare > 0) { if ((rand () % 100) < 5) found_item = fighter[index + PSIZE].defeat_item_rare; } if (found_item > 0) { if (check_inventory (found_item, 1) != 0) { sprintf (strbuf, _("%s found!"), items[found_item].name); menubox (double_buffer, 148 - (strlen (strbuf) * 4), nr * 24 + 48, strlen (strbuf) + 1, 1, BLUE); draw_icon (double_buffer, items[found_item].icon, 156 - (strlen (strbuf) * 4), nr * 24 + 56); print_font (double_buffer, 164 - (strlen (strbuf) * 4), nr * 24 + 56, strbuf, FNORMAL); nr++; } } } } if (nr > 0) { blit2screen (0, 0); wait_enter (); blit (back, double_buffer, 0, 0, 0, 0, 352, 280); } nr = 0; for (c = 0; c < numchrs; c++) { if ((party[pidx[c]].sts[S_STONE] == 0) && (party[pidx[c]].sts[S_DEAD] == 0)) { b = c * 160; player2fighter (pidx[c], &t1); if (give_xp (pidx[c], txp, 0) == 1) { menubox (double_buffer, b, 40, 18, 9, BLUE); player2fighter (pidx[c], &t2); print_font (double_buffer, b + 8, 48, _("Level up!"), FGOLD); print_font (double_buffer, b + 8, 56, _("Max HP"), FNORMAL); print_font (double_buffer, b + 8, 64, _("Max MP"), FNORMAL); print_font (double_buffer, b + 8, 72, _("Strength"), FNORMAL); print_font (double_buffer, b + 8, 80, _("Agility"), FNORMAL); print_font (double_buffer, b + 8, 88, _("Vitality"), FNORMAL); print_font (double_buffer, b + 8, 96, _("Intellect"), FNORMAL); print_font (double_buffer, b + 8, 104, _("Sagacity"), FNORMAL); sprintf (strbuf, "%3d>", t1.mhp); print_font (double_buffer, b + 96, 56, strbuf, FNORMAL); sprintf (strbuf, "%3d", t2.mhp); print_font (double_buffer, b + 128, 56, strbuf, FGREEN); sprintf (strbuf, "%3d>", t1.mmp); print_font (double_buffer, b + 96, 64, strbuf, FNORMAL); sprintf (strbuf, "%3d", t2.mmp); print_font (double_buffer, b + 128, 64, strbuf, FGREEN); for (z = 0; z < 5; z++) { sprintf (strbuf, "%3d>", t1.stats[z]); print_font (double_buffer, b + 96, z * 8 + 72, strbuf, FNORMAL); sprintf (strbuf, "%3d", t2.stats[z]); if (t2.stats[z] > t1.stats[z]) print_font (double_buffer, b + 128, z * 8 + 72, strbuf, FGREEN); else print_font (double_buffer, b + 128, z * 8 + 72, strbuf, FNORMAL); } nr++; } else menubox (double_buffer, b, 104, 18, 1, BLUE); sprintf (strbuf, _("Next level %7d"), party[pidx[c]].next - party[pidx[c]].xp); print_font (double_buffer, b + 8, 112, strbuf, FGOLD); } } blit2screen (0, 0); for (c = 0; c < numchrs; c++) if ((party[pidx[c]].sts[S_STONE] == 0) && (party[pidx[c]].sts[S_DEAD] == 0)) ent += learn_new_spells (pidx[c]); if (ent == 0) wait_enter (); }
/*! \brief Choose who attacks first, speeds, etc. * \author Josh Bolduc * \date Created ???????? * \date Updated * * Set up surprise vars, speeds, act vars, etc. */ static void roll_initiative (void) { int i, j; if (hs == 1 && ms == 1) { hs = 10; ms = 10; } for (i = 0; i < NUM_FIGHTERS; i++) { fighter[i].csmem = 0; fighter[i].ctmem = 0; cact[i] = 1; j = ROUND_MAX * 66 / 100; if (j < 1) j = 1; bspeed[i] = rand () % j; } for (i = 0; i < numchrs; i++) { if (ms == 1) bspeed[i] = ROUND_MAX; else if (hs == 1) bspeed[i] = 0; } for (i = PSIZE; i < PSIZE + numens; i++) { if (hs == 1) bspeed[i] = ROUND_MAX; else if (ms == 1) bspeed[i] = 0; } rcount = 0; /* PH: this isn't right because not all members of the fighter[] array * are valid - e.g. if you are attacked by 1 enemy, there are 4 enemy * slots that aren't used. Currently, no enemies use imbued stuff, but * this may change (?) */ #if 0 for (i = 0; i < NUM_FIGHTERS; i++) { /* TODO: Unroll this loop */ for (j = 0; j < 2; j++) if (fighter[i].imb[j] > 0) cast_imbued_spell (i, fighter[i].imb[j], 1, TGT_CASTER); } #endif /* PH: This should be ok */ for (i = 0; i < NUM_FIGHTERS; i++) { if (i < numchrs || (i >= PSIZE && i < (PSIZE + numens))) { for (j = 0; j < 2; j++) if (fighter[i].imb[j] > 0) cast_imbued_spell (i, fighter[i].imb[j], 1, TGT_CASTER); } } battle_render (-1, -1, 0); blit2screen (0, 0); if ((hs == 1) && (ms > 1)) message (_("You have been ambushed!"), 255, 1500, 0, 0); if ((hs > 1) && (ms == 1)) message (_("You've surprised the enemy!"), 255, 1500, 0, 0); }
/*! \brief Display system menu * * This is the system menu that is invoked from within the game. * From here you can save, load, configure a couple of options or * exit the game altogether. * \date 20040229 PH added 'Save anytime' facility when cheat mode is ON * * \returns 0 if cancelled or nothing happened, 1 otherwise */ int system_menu (void) { int stop = 0, ptr = 0; char save_str[10]; int text_color = FNORMAL; strcpy (save_str, _("Save ")); if (cansave == 0) { text_color = FDARK; #ifdef KQ_CHEATS if (cheat) { strcpy (save_str, _("[Save]")); text_color = FNORMAL; } #endif /* KQ_CHEATS */ } while (!stop) { check_animation (); drawmap (); menubox (double_buffer, xofs, yofs, 8, 4, BLUE); print_font (double_buffer, 16 + xofs, 8 + yofs, save_str, text_color); print_font (double_buffer, 16 + xofs, 16 + yofs, _("Load"), FNORMAL); print_font (double_buffer, 16 + xofs, 24 + yofs, _("Config"), FNORMAL); print_font (double_buffer, 16 + xofs, 32 + yofs, _("Exit"), FNORMAL); draw_sprite (double_buffer, menuptr, 0 + xofs, ptr * 8 + 8 + yofs); blit2screen (xofs, yofs); readcontrols (); // TT: // When pressed, 'up' or 'down' == 1. Otherwise, they equal 0. So: // ptr = ptr - up + down; // will correctly modify the pointer, but with less code. if (up || down) { ptr = ptr + up - down; if (ptr < 0) ptr = 3; else if (ptr > 3) ptr = 0; play_effect (SND_CLICK, 128); unpress (); } if (balt) { unpress (); if (ptr == 0) { // Pointer is over the SAVE option #ifdef KQ_CHEATS if (cansave == 1 || cheat) #else if (cansave == 1) #endif /* KQ_CHEATS */ { saveload (1); stop = 1; } else play_effect (SND_BAD, 128); } if (ptr == 1) { if (saveload (0) != 0) stop = 1; } if (ptr == 2) config_menu (); if (ptr == 3) return confirm_quit (); } if (bctrl) { stop = 1; unpress (); } } return 0; }
/*! \brief Show special items * * List any special items that the party has. * * WK: This function would be more appropriate in a script, such as global.lua. * This function is preventing me from completely removing progress.h */ void spec_items(void) { int a, num_items = 0, stop = 0, ptr = 0; short list_item_which[MAX_PLAYER_SPECIAL_ITEMS]; short list_item_quantity[MAX_PLAYER_SPECIAL_ITEMS]; /* Set number of items here */ for (a = 0; a < MAX_SPECIAL_ITEMS; a++) { if (player_special_items[a]) { list_item_which[num_items] = a; list_item_quantity[num_items] = player_special_items[a]; num_items++; } } if (num_items == 0) { play_effect(SND_BAD, 128); return; } play_effect(SND_MENU, 128); while (!stop) { check_animation(); drawmap(); menubox(double_buffer, 72 + xofs, 12 + yofs, 20, 1, BLUE); print_font(double_buffer, 108 + xofs, 20 + yofs, _("Special Items"), FGOLD); menubox(double_buffer, 72 + xofs, 36 + yofs, 20, 19, BLUE); for (a = 0; a < num_items; a++) { draw_icon(double_buffer, special_items[list_item_which[a]].icon, 88 + xofs, a * 8 + 44 + yofs); print_font(double_buffer, 96 + xofs, a * 8 + 44 + yofs, special_items[list_item_which[a]].name, FNORMAL); if (list_item_quantity[a] > 1) { sprintf(strbuf, "^%d", list_item_quantity[a]); print_font(double_buffer, 224 + xofs, a * 8 + 44 + yofs, strbuf, FNORMAL); } } menubox(double_buffer, 72 + xofs, 204 + yofs, 20, 1, BLUE); a = strlen(special_items[list_item_which[ptr]].description) * 4; print_font(double_buffer, 160 - a + xofs, 212 + yofs, special_items[list_item_which[ptr]].description, FNORMAL); draw_sprite(double_buffer, menuptr, 72 + xofs, ptr * 8 + 44 + yofs); blit2screen(xofs, yofs); readcontrols(); if (PlayerInput.down) { unpress(); ptr = (ptr + 1) % num_items; play_effect(SND_CLICK, 128); } if (PlayerInput.up) { unpress(); ptr = (ptr - 1 + num_items) % num_items; play_effect(SND_CLICK, 128); } if (PlayerInput.bctrl) { unpress(); stop = 1; } } }
/*! \brief Save/Load menu * * This is the actual save/load menu. The only parameter to * the function indicates whether we are saving or loading. * * \param am_saving 0 if loading, 1 if saving * \returns 0 if an error occurred or save/load cancelled */ static int saveload (int am_saving) { int stop = 0; // Have no more than 5 savestate boxes onscreen, but fewer if NUMSG < 5 max_onscreen = 5; if (max_onscreen > NUMSG) max_onscreen = NUMSG; play_effect (SND_MENU, 128); while (!stop) { check_animation (); clear_bitmap (double_buffer); show_sgstats (am_saving); blit2screen (0, 0); readcontrols (); if (up) { unpress (); save_ptr--; if (save_ptr < 0) save_ptr = NUMSG - 1; // Determine whether to update TOP if (save_ptr < top_pointer) top_pointer--; else if (save_ptr == NUMSG - 1) top_pointer = NUMSG - max_onscreen; play_effect (SND_CLICK, 128); } if (down) { unpress (); save_ptr++; if (save_ptr > NUMSG - 1) save_ptr = 0; // Determine whether to update TOP if (save_ptr >= top_pointer + max_onscreen) top_pointer++; else if (save_ptr == 0) top_pointer = 0; play_effect (SND_CLICK, 128); } if (right) { unpress (); if (am_saving < 2) am_saving = am_saving + 2; } if (left) { unpress (); if (am_saving >= 2) am_saving = am_saving - 2; } if (balt) { unpress (); switch (am_saving) { case 0: // Load if (snc[save_ptr] != 0) { if (load_game () == 1) stop = 2; else stop = 1; } break; case 1: // Save if (confirm_action () == 1) { if (save_game () == 1) stop = 2; else stop = 1; } break; case 2: // Delete (was LOAD) previously case 3: // Delete (was SAVE) previously if (snc[save_ptr] != 0) { if (confirm_action () == 1) delete_game (); } break; } } if (bctrl) { unpress (); stop = 1; } } return stop - 1; }
/*! \brief Main menu screen * * This is the main menu... just display the opening and then the menu and * then wait for input. Also handles loading a saved game, and the config menu. * * \param c zero if the splash (the bit with the staff and the eight heroes) * should be displayed. * \returns 1 if new game, 0 if continuing, 2 if exit */ int start_menu (int skip_splash) { int stop = 0, ptr = 0, redraw = 1, a, b; DATAFILE *bg; BITMAP *staff, *dudes, *tdudes; #ifdef DEBUGMODE if (debugging == 0) { #endif play_music ("oxford.s3m", 0); /* Play splash (with the staff and the heroes in circle */ if (skip_splash == 0) { bg = load_datafile_object (PCX_DATAFILE, "KQT_PCX"); staff = create_bitmap_ex (8, 72, 226); dudes = create_bitmap_ex (8, 112, 112); tdudes = create_bitmap_ex (8, 112, 112); blit ((BITMAP *) bg->dat, staff, 0, 7, 0, 0, 72, 226); blit ((BITMAP *) bg->dat, dudes, 80, 0, 0, 0, 112, 112); clear_bitmap (double_buffer); blit (staff, double_buffer, 0, 0, 124, 22, 72, 226); blit2screen (0, 0); kq_wait (1000); for (a = 0; a < 42; a++) { stretch_blit (staff, double_buffer, 0, 0, 72, 226, 124 - (a * 32), 22 - (a * 96), 72 + (a * 64), 226 + (a * 192)); blit2screen (0, 0); kq_wait (100); } for (a = 0; a < 5; a++) { color_scale (dudes, tdudes, 53 - a, 53 + a); draw_sprite (double_buffer, tdudes, 106, 64); blit2screen (0, 0); kq_wait (100); } draw_sprite (double_buffer, dudes, 106, 64); blit2screen (0, 0); kq_wait (1000); destroy_bitmap (staff); destroy_bitmap (dudes); destroy_bitmap (tdudes); unload_datafile_object(bg); /* TODO: this fade should actually be to white if (_color_depth == 8) fade_from (pal, whp, 1); else */ do_transition (TRANS_FADE_WHITE, 1); } clear_to_color (double_buffer, 15); blit2screen (0, 0); set_palette (pal); bg = load_datafile_object (PCX_DATAFILE, "TITLE_PCX"); for (a = 0; a < 16; a++) { clear_to_color (double_buffer, 15 - a); masked_blit ((BITMAP *) bg->dat, double_buffer, 0, 0, 0, 60 - (a * 4), 320, 124); blit2screen (0, 0); kq_wait (a == 0 ? 500 : 100); } if (skip_splash == 0) kq_wait (500); #ifdef DEBUGMODE } else { set_palette (pal); bg = load_datafile_object (PCX_DATAFILE, "TITLE_PCX"); } #endif reset_world (); /* Draw menu and handle menu selection */ while (!stop) { if (redraw) { clear_bitmap (double_buffer); masked_blit ((BITMAP *) bg->dat, double_buffer, 0, 0, 0, 0, 320, 124); menubox (double_buffer, 112, 116, 10, 4, BLUE); print_font (double_buffer, 128, 124, _("Continue"), FNORMAL); print_font (double_buffer, 128, 132, _("New Game"), FNORMAL); print_font (double_buffer, 136, 140, _("Config"), FNORMAL); print_font (double_buffer, 144, 148, _("Exit"), FNORMAL); draw_sprite (double_buffer, menuptr, 112, ptr * 8 + 124); redraw = 0; } display_credits (); blit2screen (0, 0); readcontrols (); if (bhelp) { unpress (); show_help (); redraw = 1; } if (up) { unpress (); if (ptr > 0) ptr--; else ptr = 3; play_effect (SND_CLICK, 128); redraw = 1; } if (down) { unpress (); if (ptr < 3) ptr++; else ptr = 0; play_effect (SND_CLICK, 128); redraw = 1; } if (balt) { unpress (); if (ptr == 0) { /* User selected "Continue" */ if (snc[0] == 0 && snc[1] == 0 && snc[2] == 0 && snc[3] == 0 && snc[4] == 0) stop = 2; else if (saveload (0) == 1) stop = 1; redraw = 1; } else if (ptr == 1) { /* User selected "New Game" */ stop = 2; } else if (ptr == 2) { /* Config */ clear (double_buffer); config_menu (); redraw = 1; /* TODO: Save Global Settings Here */ } else if (ptr == 3) { /* Exit */ unload_datafile_object (bg); klog (_("Then exit you shall!")); return 2; } } } unload_datafile_object (bg); if (stop == 2) { /* New game init */ for (a = 0; a < MAXCHRS; a++) memcpy (&party[a], &players[a].plr, sizeof (s_player)); init_players (); memset (progress, 0, SIZE_PROGRESS); memset (treasure, 0, SIZE_TREASURE); numchrs = 0; for (a = 0; a < NUMSHOPS; a++) { for (b = 0; b < SHOPITEMS; b++) shops[a].items_current[b] = shops[a].items_max[b]; } for (b = 0; b < 2; b++) { for (a = 0; a < MAX_INV; a++) g_inv[a][b] = 0; } } return stop - 1; }
/*! \brief Display configuration menu * * This is the config menu that is called from the system * menu. Here you can adjust the music or sound volume, or * the speed that the battle gauge moves at. */ void config_menu (void) { int stop = 0, ptr = 0, p; int temp_key = 0; #ifdef DEBUGMODE #define MENU_SIZE 18 #else #define MENU_SIZE 17 #endif static const char *dc[MENU_SIZE]; /* Define rows with appropriate spacings for breaks between groups */ int row[MENU_SIZE]; for (p = 0; p < 4; p++) row[p] = (p + 4) * 8; // (p * 8) + 32 for (p = 4; p < 12; p++) row[p] = (p + 5) * 8; // (p * 8) + 40 for (p = 12; p < 15; p++) row[p] = (p + 6) * 8; // (p * 8) + 48 for (p = 15; p < MENU_SIZE; p++) row[p] = (p + 7) * 8; // (p * 8) + 56 /* Helper strings */ dc[0]=_("Display KQ in a window."); dc[1]=_("Stretch to fit 640x480 resolution."); dc[2]=_("Display the frame rate during play."); dc[3]=_("Wait for vertical retrace."); dc[4]=_("Key used to move up."); dc[5]=_("Key used to move down."); dc[6]=_("Key used to move left."); dc[7]=_("Key used to move right."); dc[8]=_("Key used to confirm action."); dc[9]=_("Key used to cancel action."); dc[10]=_("Key used to call character menu."); dc[11]=_("Key used to call system menu."); dc[12]=_("Toggle sound and music on/off."); dc[13]=_("Overall sound volume (affects music)."); dc[14]=_("Music volume."); dc[15]=_("Animation speed-ups for slow machines."); dc[16]=_("Toggle how to allocate CPU usage."); #ifdef DEBUGMODE dc[17]=_("Things you can do only in DebugMode."); #endif unpress (); push_config_state (); set_config_file (kqres (SETTINGS_DIR, "kq.cfg")); while (!stop) { check_animation (); drawmap (); menubox (double_buffer, 88 + xofs, yofs, 16, 1, BLUE); print_font (double_buffer, 96 + xofs, 8 + yofs, _("KQ Configuration"), FGOLD); menubox (double_buffer, 32 + xofs, 24 + yofs, 30, MENU_SIZE + 3, BLUE); citem (row[0], _("Windowed mode:"), windowed == 1 ? _("YES") : _("NO"), FNORMAL); citem (row[1], _("Stretch Display:"), stretch_view == 1 ? _("YES") : _("NO"), FNORMAL); citem (row[2], _("Show Frame Rate:"), show_frate == 1 ? _("YES") : _("NO"), FNORMAL); citem (row[3], _("Wait for Retrace:"), wait_retrace == 1 ? _("YES") : _("NO"), FNORMAL); citem (row[4], _("Up Key:"), kq_keyname (kup), FNORMAL); citem (row[5], _("Down Key:"), kq_keyname (kdown), FNORMAL); citem (row[6], _("Left Key:"), kq_keyname (kleft), FNORMAL); citem (row[7], _("Right Key:"), kq_keyname (kright), FNORMAL); citem (row[8], _("Confirm Key:"), kq_keyname (kalt), FNORMAL); citem (row[9], _("Cancel Key:"), kq_keyname (kctrl), FNORMAL); citem (row[10], _("Menu Key:"), kq_keyname (kenter), FNORMAL); citem (row[11], _("System Menu Key:"), kq_keyname (kesc), FNORMAL); citem (row[12], _("Sound System:"), is_sound ? _("ON") : _("OFF"), FNORMAL); p = FNORMAL; /* TT: This needs to check for ==0 because 1 means sound init */ if (is_sound == 0) p = FDARK; sprintf (strbuf, "%3d%%", gsvol * 100 / 250); citem (row[13], _("Sound Volume:"), strbuf, p); sprintf (strbuf, "%3d%%", gmvol * 100 / 250); citem (row[14], _("Music Volume:"), strbuf, p); citem (row[15], _("Slow Computer:"), slow_computer ? _("YES") : _("NO"), FNORMAL); if (cpu_usage) sprintf (strbuf, _("rest(%d)"), cpu_usage - 1); else sprintf (strbuf, "yield_timeslice()"); citem (row[16], _("CPU Usage:"), strbuf, FNORMAL); #ifdef DEBUGMODE if (debugging) sprintf (strbuf, "%d", debugging); citem (row[17], _("DebugMode Stuff:"), debugging ? strbuf : _("OFF"), FNORMAL); #endif /* This affects the VISUAL placement of the arrow */ p = ptr; if (ptr > 3) p++; if (ptr > 11) p++; if (ptr > 14) p++; draw_sprite (double_buffer, menuptr, 32 + xofs, p * 8 + 32 + yofs); /* This is the bottom window, where the description goes */ menubox (double_buffer, xofs, 216 + yofs, 38, 1, BLUE); print_font (double_buffer, 8 + xofs, 224 + yofs, dc[ptr], FNORMAL); blit2screen (xofs, yofs); readcontrols (); if (up) { unpress (); // "jump" over unusable options if (ptr == 15 && is_sound == 0) ptr -= 2; ptr--; if (ptr < 0) ptr = MENU_SIZE - 1; play_effect (SND_CLICK, 128); } if (down) { unpress (); // "jump" over unusable options if (ptr == 12 && is_sound == 0) ptr += 2; ptr++; if (ptr > MENU_SIZE - 1) ptr = 0; play_effect (SND_CLICK, 128); } if (balt) { unpress (); switch (ptr) { case 0: #ifdef __DJGPP__ text_ex (B_TEXT, 255, _("This version of KQ was compiled for DOS and does not support windowed mode")); #else text_ex (B_TEXT, 255, _("Changing the display mode to or from windowed view could have serious ramifications. It is advised that you save first.")); if (windowed == 0) sprintf (strbuf, _("Switch to windowed mode?")); else sprintf (strbuf, _("Switch to full screen?")); p = prompt (255, 2, B_TEXT, strbuf, _(" no"), _(" yes"), ""); if (p == 1) { if (windowed == 0) windowed = 1; else windowed = 0; set_config_int (NULL, "windowed", windowed); set_graphics_mode (); } #endif break; case 1: #ifdef __DJGPP__ text_ex (B_TEXT, 255, _("This version of KQ was compiled for DOS and does not support stretching")); #else text_ex (B_TEXT, 255, _("Changing the stretched view option could have serious ramifications. It is advised that you save your game before trying this.")); if (stretch_view == 0) sprintf (strbuf, _("Try to stretch the display?")); else sprintf (strbuf, _("Switch to unstretched display?")); p = prompt (255, 2, B_TEXT, strbuf, _(" no"), _(" yes"), ""); if (p == 1) { if (stretch_view == 0) stretch_view = 1; else stretch_view = 0; set_config_int (NULL, "stretch_view", stretch_view); set_graphics_mode (); } #endif break; case 2: if (show_frate == 0) show_frate = 1; else show_frate = 0; set_config_int (NULL, "show_frate", show_frate); break; case 3: if (wait_retrace == 0) wait_retrace = 1; else wait_retrace = 0; set_config_int (NULL, "wait_retrace", wait_retrace); break; case 4: while ((temp_key = getakey ()) == 0); kup = temp_key; unpress (); set_config_int (NULL, "kup", kup); break; case 5: while ((temp_key = getakey ()) == 0); kdown = temp_key; unpress (); set_config_int (NULL, "kdown", kdown); break; case 6: while ((temp_key = getakey ()) == 0); kleft = temp_key; unpress (); set_config_int (NULL, "kleft", kleft); break; case 7: while ((temp_key = getakey ()) == 0); kright = temp_key; unpress (); set_config_int (NULL, "kright", kright); break; case 8: while ((temp_key = getakey ()) == 0); kalt = temp_key; unpress (); set_config_int (NULL, "kalt", kalt); break; case 9: while ((temp_key = getakey ()) == 0); kctrl = temp_key; unpress (); set_config_int (NULL, "kctrl", kctrl); break; case 10: while ((temp_key = getakey ()) == 0); kenter = temp_key; unpress (); set_config_int (NULL, "kenter", kenter); break; case 11: while ((temp_key = getakey ()) == 0); kesc = temp_key; unpress (); set_config_int (NULL, "kesc", kesc); break; case 12: if (is_sound == 2) sound_init (); else { if (is_sound == 0) { is_sound = 1; print_font (double_buffer, 92 + 2 + xofs, 204 + yofs, _("...please wait..."), FNORMAL); blit2screen (xofs, yofs); sound_init (); play_music (g_map.song_file, 0); } } set_config_int (NULL, "is_sound", is_sound != 0); break; case 13: if (is_sound == 2) { p = getavalue (_("Sound Volume"), 0, 25, gsvol / 10, 1); if (p != -1) gsvol = p * 10; /* make sure to set it no matter what */ set_volume (gsvol, 0); set_config_int (NULL, "gsvol", gsvol); } else /* Not as daft as it seems, SND_BAD also wobbles the screen */ play_effect (SND_BAD, 128); break; case 14: if (is_sound == 2) { p = getavalue (_("Music Volume"), 0, 25, gmvol / 10, 1); if (p != -1) gmvol = p * 10; /* make sure to set it no matter what */ set_music_volume (gmvol / 250.0); set_config_int (NULL, "gmvol", gmvol); } else play_effect (SND_BAD, 128); break; case 15: /* TT: toggle slow_computer */ slow_computer = !slow_computer; set_config_int (NULL, "slow_computer", slow_computer); break; case 16: /* TT: Adjust the CPU usage:yield_timeslice() or rest() */ cpu_usage++; if (cpu_usage > 2) cpu_usage = 0; break; #ifdef DEBUGMODE case 17: /* TT: Things we only have access to when we're in debug mode */ if (debugging < 4) debugging++; else debugging = 0; break; #endif } } if (bctrl) { unpress (); stop = 1; } } pop_config_state (); }
/*! \brief Main menu * * Main menu that calls all the other little menus :) */ void menu(void) { int stop = 0, ptr = 0, z = -1; play_effect(SND_MENU, 128); timer_count = 0; while (!stop) { check_animation(); drawmap(); draw_mainmenu(-1); draw_sprite(double_buffer, menuptr, 204 + xofs, ptr * 8 + 73 + yofs); blit2screen(xofs, yofs); readcontrols(); if (PlayerInput.up) { unpress(); ptr--; if (ptr < 0) { ptr = 5; } play_effect(SND_CLICK, 128); } if (PlayerInput.down) { unpress(); ptr++; if (ptr > 5) { ptr = 0; } play_effect(SND_CLICK, 128); } /* Allow player to rearrange the party at any time by pressing LEFT */ if (PlayerInput.left) { z = select_player(); if (z > 0) { party_newlead(); } } if (PlayerInput.balt) { unpress(); switch (ptr) { case 0: camp_item_menu(); break; case 3: spec_items(); break; case 5: quest_info(); break; default: z = select_player(); if (z >= 0) { switch (ptr) { case 1: camp_spell_menu(z); break; case 2: equip_menu(z); break; case 4: status_screen(z); break; } } break; } } if (PlayerInput.bctrl) { unpress(); stop = 1; } if (close_menu == 1) { close_menu = 0; stop = 1; } } }
/*! \brief Play sample effect * * Play an effect... if possible/necessary. If the effect to * be played is the 'bad-move' effect, than do something visually * so that even if sound is off you know you did something bad :) * PH added explode effect. * * \param efc Effect to play (index in sfx[]) * \param panning Left/right pan - see Allegro's play_sample() */ void play_effect (int efc, int panning) { int a, s, xo = 1, yo = 1; static const int bx[8] = { -1, 0, 1, 0, -1, 0, 1, 0 }; static const int by[8] = { -1, 0, 1, 0, 1, 0, -1, 0 }; static const int sc[] = { 1, 2, 3, 5, 3, 3, 3, 2, 1 }; SAMPLE *samp; PALETTE whiteout, old; /* Patch provided by mattrope: */ /* sfx array is empty if sound is not initialized */ if (is_sound != 0) samp = (SAMPLE *) sfx[efc]->dat; else samp = NULL; /* PH not strictly needed but I added it */ switch (efc) { default: if (samp) play_sample (samp, gsvol, panning, 1000, 0); break; case SND_BAD: blit (double_buffer, fx_buffer, 0, 0, 0, 0, 352, 280); if (samp) play_sample (samp, gsvol, panning, 1000, 0); clear_bitmap (double_buffer); blit (fx_buffer, double_buffer, xofs, yofs, xofs, yofs, 320, 240); if (in_combat == 0) { xo = xofs; yo = yofs; } /* blit (fx_buffer, double_buffer, xo, yo, xo, yo, 320, 240); */ for (a = 0; a < 8; a++) { blit2screen (xo + bx[a], yo + by[a]); kq_wait (10); } blit (fx_buffer, double_buffer, 0, 0, 0, 0, 352, 280); break; case SND_EXPLODE: blit (double_buffer, fx_buffer, 0, 0, 0, 0, 352, 280); clear_bitmap (double_buffer); get_palette (old); for (a = 0; a < 256; ++a) { s = (old[a].r + old[a].g + old[a].b) > 40 ? 0 : 63; whiteout[a].r = whiteout[a].g = whiteout[a].b = s; } blit (fx_buffer, double_buffer, xofs, yofs, xofs, yofs, 320, 240); if (samp) { play_sample (samp, gsvol, panning, 1000, 0); } for (s = 0; s < (int) (sizeof (sc) / sizeof (*sc)); ++s) { if (s == 1) set_palette (whiteout); if (s == 6) set_palette (old); for (a = 0; a < 8; a++) { blit2screen (xofs + bx[a] * sc[s], yofs + by[a] * sc[s]); kq_wait (10); } } blit (fx_buffer, double_buffer, 0, 0, 0, 0, 352, 280); break; } }
/*! \brief Draw a player's status screen * * Draw the verbose stats of a single player. * \param fighter_index - Character to draw (index in pidx array) */ static void status_screen(size_t fighter_index) { int stop = 0; int bc = 0; unsigned int rect_fill_amount = 0, curr_fill, res_index, stats_y, equipment_index; size_t pidx_index, stats_index; play_effect(SND_MENU, 128); pidx_index = pidx[fighter_index]; update_equipstats(); while (!stop) { check_animation(); // Redraw the map, clearing any menus under this new window drawmap(); // Box around top-left square menubox(double_buffer, xofs, 16 + yofs, 18, 5, BLUE); draw_playerstat(double_buffer, pidx_index, 8 + xofs, 24 + yofs); // Box around bottom-left square menubox(double_buffer, xofs, 72 + yofs, 18, 17, BLUE); print_font(double_buffer, 8 + xofs, 80 + yofs, _("Exp:"), FGOLD); sprintf(strbuf, "%d", party[pidx_index].xp); print_font(double_buffer, 152 - (strlen(strbuf) * 8) + xofs, 80 + yofs, strbuf, FNORMAL); print_font(double_buffer, 8 + xofs, 88 + yofs, _("Next:"), FGOLD); // TT: Does this mean we can only level up to 50? if (party[pidx_index].lvl < 50) { sprintf(strbuf, "%d", party[pidx_index].next - party[pidx_index].xp); } else { sprintf(strbuf, "%d", 0); } print_font(double_buffer, 152 - (strlen(strbuf) * 8) + xofs, 88 + yofs, strbuf, FNORMAL); print_font(double_buffer, 8 + xofs, 104 + yofs, _("Strength"), FGOLD); print_font(double_buffer, 8 + xofs, 112 + yofs, _("Agility"), FGOLD); print_font(double_buffer, 8 + xofs, 120 + yofs, _("Vitality"), FGOLD); print_font(double_buffer, 8 + xofs, 128 + yofs, _("Intellect"), FGOLD); print_font(double_buffer, 8 + xofs, 136 + yofs, _("Sagacity"), FGOLD); print_font(double_buffer, 8 + xofs, 144 + yofs, _("Speed"), FGOLD); print_font(double_buffer, 8 + xofs, 152 + yofs, _("Aura"), FGOLD); print_font(double_buffer, 8 + xofs, 160 + yofs, _("Spirit"), FGOLD); // Blank space on display of 16 pixels print_font(double_buffer, 8 + xofs, 176 + yofs, _("Attack"), FGOLD); print_font(double_buffer, 8 + xofs, 184 + yofs, _("Hit"), FGOLD); print_font(double_buffer, 8 + xofs, 192 + yofs, _("Defense"), FGOLD); print_font(double_buffer, 8 + xofs, 200 + yofs, _("Evade"), FGOLD); print_font(double_buffer, 8 + xofs, 208 + yofs, _("Mag.Def"), FGOLD); for (stats_index = 0; stats_index < NUM_STATS; stats_index++) { // Coordinates of stats on display stats_y = stats_index * 8 + 104; // Add an extra 8-pixel space to separate these from the others if (stats_index > A_SPI) { stats_y += 8; } print_font(double_buffer, 96 + xofs, stats_y + yofs, "$", FGOLD); sprintf(strbuf, "%d", fighter[fighter_index].stats[stats_index]); print_font(double_buffer, 152 - (strlen(strbuf) * 8) + xofs, stats_y + yofs, strbuf, FNORMAL); } menubox(double_buffer, 160 + xofs, 16 + yofs, 18, 16, BLUE); print_font(double_buffer, 168 + xofs, 24 + yofs, _("Earth"), FNORMAL); print_font(double_buffer, 168 + xofs, 32 + yofs, _("Black"), FNORMAL); print_font(double_buffer, 168 + xofs, 40 + yofs, _("Fire"), FNORMAL); print_font(double_buffer, 168 + xofs, 48 + yofs, _("Thunder"), FNORMAL); print_font(double_buffer, 168 + xofs, 56 + yofs, _("Air"), FNORMAL); print_font(double_buffer, 168 + xofs, 64 + yofs, _("White"), FNORMAL); print_font(double_buffer, 168 + xofs, 72 + yofs, _("Water"), FNORMAL); print_font(double_buffer, 168 + xofs, 80 + yofs, _("Ice"), FNORMAL); print_font(double_buffer, 168 + xofs, 88 + yofs, _("Poison"), FNORMAL); print_font(double_buffer, 168 + xofs, 96 + yofs, _("Blind"), FNORMAL); print_font(double_buffer, 168 + xofs, 104 + yofs, _("Charm"), FNORMAL); print_font(double_buffer, 168 + xofs, 112 + yofs, _("Paralyze"), FNORMAL); print_font(double_buffer, 168 + xofs, 120 + yofs, _("Petrify"), FNORMAL); print_font(double_buffer, 168 + xofs, 128 + yofs, _("Silence"), FNORMAL); print_font(double_buffer, 168 + xofs, 136 + yofs, _("Sleep"), FNORMAL); print_font(double_buffer, 168 + xofs, 144 + yofs, _("Time"), FNORMAL); for (res_index = 0; res_index < R_TOTAL_RES; res_index++) { rectfill(double_buffer, 240 + xofs, res_index * 8 + 25 + yofs, 310 + xofs, res_index * 8 + 31 + yofs, 3); if (fighter[fighter_index].res[res_index] < 0) { bc = 18; // bright red, meaning WEAK defense rect_fill_amount = abs(fighter[fighter_index].res[res_index]); } else if (fighter[fighter_index].res[res_index] >= 0 && fighter[fighter_index].res[res_index] <= 10) { bc = 34; // bright green, meaning so-so defense rect_fill_amount = fighter[fighter_index].res[res_index]; } else if (fighter[fighter_index].res[res_index] > 10) { bc = 50; // bright blue, meaning STRONG defense rect_fill_amount = fighter[fighter_index].res[res_index] - 10; } if (rect_fill_amount > 0) { for (curr_fill = 0; curr_fill < rect_fill_amount; curr_fill++) { rectfill(double_buffer, curr_fill * 7 + 241 + xofs, res_index * 8 + 26 + yofs, curr_fill * 7 + 246 + xofs, res_index * 8 + 30 + yofs, bc + curr_fill); } } } menubox(double_buffer, 160 + xofs, 160 + yofs, 18, 6, BLUE); for (equipment_index = 0; equipment_index < NUM_EQUIPMENT; equipment_index++) { draw_icon(double_buffer, items[party[pidx_index].eqp[equipment_index]].icon, 168 + xofs, equipment_index * 8 + 168 + yofs); print_font(double_buffer, 176 + xofs, equipment_index * 8 + 168 + yofs, items[party[pidx_index].eqp[equipment_index]].name, FNORMAL); } blit2screen(xofs, yofs); readcontrols(); if (PlayerInput.left && fighter_index > 0) { unpress(); fighter_index--; pidx_index = pidx[fighter_index]; play_effect(SND_MENU, 128); } if (PlayerInput.right && fighter_index < numchrs - 1) { unpress(); fighter_index++; pidx_index = pidx[fighter_index]; play_effect(SND_MENU, 128); } if (PlayerInput.bctrl) { unpress(); play_effect(SND_MENU, 128); stop = 1; } } }
/*! \brief Process each enemy skill * * Just a function to process each enemy skill by index number. * * \param who Index of attacker */ void combat_skill (int who) { int sk = fighter[who].ai[fighter[who].csmem] - 100; int tgt = fighter[who].ctmem; int a; int b; tempa = status_adjust (who); battle_render (0, 0, 0); blit2screen (0, 0); if (sk == 1) { strcpy (ctext, _("Venomous Bite")); dct = 1; tempa.welem = R_POISON + 1; fight (who, tgt, 1); dct = 0; fighter[who].atrack[fighter[who].csmem] = 2; } if (sk == 2) { strcpy (ctext, _("Double Slash")); dct = 1; tempa.stats[A_ATT] = tempa.stats[A_ATT] * 15 / 10; fight (who, tgt, 1); dct = 0; fighter[who].atrack[fighter[who].csmem] = 2; } if (sk == 3) { strcpy (ctext, _("Chill Touch")); dct = 1; draw_spellsprite (tgt, 0, 10, 1); special_damage_oneall_enemies (who, 60, R_ICE, tgt, 0); dct = 0; fighter[who].atrack[fighter[who].csmem] = 2; } if (sk == 4) { strcpy (ctext, _("Flash Flood")); dct = 1; draw_hugesprite (0, 80, 108, 21, 1); /* dudaskank suggest replacing 999 with SEL_ALL_ENEMIES */ special_damage_oneall_enemies (who, 40, R_ICE, SEL_ALL_ENEMIES, 1); dct = 0; fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 5) { b = 0; for (a = 0; a < numchrs; a++) if (fighter[a].sts[S_DEAD] == 0) b++; if (b > 1) fighter[who].ctmem = 1000; strcpy (ctext, _("Sweep")); dct = 1; tempa.stats[A_ATT] = tempa.stats[A_ATT] * 75 / 100; multi_fight (who); dct = 0; fighter[who].atrack[fighter[who].csmem] = 2; } if (sk == 6) { strcpy (ctext, _("ParaClaw")); dct = 1; tempa.welem = R_PARALYZE + 1; fight (who, tgt, 1); dct = 0; fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 7) { strcpy (ctext, _("Dragon Bite")); dct = 1; tempa.stats[A_ATT] = tempa.stats[A_ATT] * 15 / 10; tempa.stats[A_HIT] = tempa.stats[A_HIT] * 9 / 10; tempa.welem = 0; fight (who, tgt, 1); dct = 0; fighter[who].atrack[fighter[who].csmem] = 2; } if (sk == 8) { b = 0; strcpy (ctext, _("Stone Gas")); draw_spellsprite (0, 1, 46, 1); for (a = 0; a < numchrs; a++) { if (fighter[a].sts[S_DEAD] == 0) { if (res_throw (a, R_PETRIFY) == 0 && non_dmg_save (a, 75) == 0) { fighter[a].sts[S_STONE] = rand () % 3 + 2; ta[a] = NODISPLAY; } else { ta[a] = MISS; b++; } } } if (b > 0) display_amount (0, FNORMAL, 1); fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 9) { b = 0; strcpy (ctext, _("Zemmel Rod")); if (rand () % 4 < 2) { draw_spellsprite (0, 1, 11, 1); /* dudaskank suggest replacing 999 with SEL_ALL_ENEMIES */ special_damage_oneall_enemies (who, 25, R_THUNDER, SEL_ALL_ENEMIES, 1); fighter[who].atrack[fighter[who].csmem] = 2; return; } draw_spellsprite (0, 1, 40, 0); for (a = 0; a < numchrs; a++) { if (res_throw (a, R_TIME) == 0) { if (non_dmg_save (a, 75) == 0 && fighter[a].sts[S_STONE] == 0) { if (fighter[a].sts[S_TIME] == 2) fighter[a].sts[S_TIME] = 0; else { if (fighter[a].sts[S_TIME] == 0) { fighter[a].sts[S_TIME] = 1; ta[a] = NODISPLAY; } else { ta[a] = MISS; b++; } } } else { ta[a] = MISS; b++; } } else { ta[a] = MISS; b++; } } if (b > 0) display_amount (0, FNORMAL, 1); fighter[who].atrack[fighter[who].csmem] = 2; } if (sk == 10) { strcpy (ctext, _("Poison Gas")); draw_spellsprite (0, 1, 47, 1); /* dudaskank suggest replacing 999 with SEL_ALL_ENEMIES */ special_damage_oneall_enemies (who, 40, R_POISON, SEL_ALL_ENEMIES, 1); fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 11) { b = 0; strcpy (ctext, _("Tangle Root")); draw_spellsprite (0, 1, 24, 0); for (a = 0; a < numchrs; a++) { if (res_throw (a, S_STOP) == 0 && non_dmg_save (a, 65) == 0 && fighter[a].sts[S_STONE] == 0) { fighter[a].sts[S_STOP] = 2 + rand () % 2; ta[a] = NODISPLAY; } else { ta[a] = MISS; b++; } } if (b > 0) display_amount (0, FNORMAL, 1); fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 12) { strcpy (ctext, _("Petrifying Bite")); dct = 1; tempa.stats[A_ATT] = tempa.stats[A_ATT]; tempa.stats[A_HIT] = tempa.stats[A_HIT] * 8 / 10; tempa.welem = 13; fight (who, tgt, 1); dct = 0; fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 13) { strcpy (ctext, _("Maul of the Titans")); draw_hugesprite (0, 80, 110, 29, 1); /* dudaskank suggest replacing 999 with SEL_ALL_ENEMIES */ special_damage_oneall_enemies (who, 60, R_EARTH, SEL_ALL_ENEMIES, 1); fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 14) { strcpy (ctext, _("Stunning Strike")); dct = 1; tempa.stats[A_ATT] = tempa.stats[A_ATT] * 8 / 10; fight (who, tgt, 1); dct = 0; if (non_dmg_save (tgt, 80) == 0 && ta[tgt] != MISS) fighter[tgt].sts[S_STOP] = 2; fighter[who].atrack[fighter[who].csmem] = 4; } if (sk == 15) { strcpy (ctext, _("Howl")); draw_spellsprite (0, 1, 14, 0); b = 0; for (a = 0; a < numchrs; a++) { if (fighter[who].sts[S_MUTE] == 0) { if (res_throw (a, S_CHARM) == 0 && non_dmg_save (a, 65) == 0 && fighter[a].sts[S_STONE] == 0) { fighter[a].sts[S_CHARM] = 2 + rand () % 2; ta[a] = NODISPLAY; } else { ta[a] = MISS; b++; } } else { ta[a] = MISS; b++; } } if (b > 0) display_amount (0, FNORMAL, 1); fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 16) { strcpy (ctext, _("Rasp")); draw_spellsprite (0, 1, 48, 0); for (a = 0; a < numchrs; a++) { b = fighter[a].hp / 3; ta[a] = 0 - b; } display_amount (0, FNORMAL, 1); for (a = 0; a < numchrs; a++) adjust_hp (a, ta[a]); for (a = 0; a < numchrs; a++) { b = fighter[a].mp / 3; ta[a] = 0 - b; } display_amount (0, FRED, 1); for (a = 0; a < numchrs; a++) adjust_mp (a, ta[a]); fighter[who].atrack[fighter[who].csmem] = 3; } if (sk == 17) { strcpy (ctext, _("Shadow Blast")); draw_spellsprite (0, 1, 49, 1); special_damage_oneall_enemies (who, 75, R_BLACK, SEL_ALL_ENEMIES, 1); fighter[who].atrack[fighter[who].csmem] = 3; } }