/** * This plays in an animation text file to create an animated component. * * @param world Pointer to the world structure (contains "world" info, entities / components) * @param entity The entity to cancel the animation for * @param animation_name The animation that gets played * * @designer Jordan Marling * @designer Mat Siwoski * * @author Jordan Marling * @author Mat Siwoski */ void play_animation(World *world, unsigned int entity, const char *animation_name) { int i; AnimationComponent *animationComponent = &(world->animation[entity]); RenderPlayerComponent *renderComponent = &(world->renderPlayer[entity]); if (!IN_THIS_COMPONENT(world->mask[entity], COMPONENT_ANIMATION)) { return; } //Check if the current animation is already playing. if (animationComponent->current_animation > -1 && strcmp(animationComponent->animations[animationComponent->current_animation].name, animation_name) == 0) { return; } for(i = 0; i < animationComponent->animation_count; i++) { if (strcmp(animationComponent->animations[i].name, animation_name) == 0) { animationComponent->current_animation = i; animationComponent->animations[i].ms_last = SDL_GetTicks(); animationComponent->animations[i].index = 0; renderComponent->playerSurface = animationComponent->animations[i].surfaces[0]; if (animationComponent->animations[i].sound_effect != MAX_EFFECTS && animationComponent->animations[i].sound_enabled == true) { play_effect(animationComponent->animations[i].sound_effect); } return; } } printf("I did not find the animation: %s\n", animation_name); }
/*! \brief Use item on selected target * * Do target selection for using an item and then use it. * * \param pp Item index */ static void camp_item_targetting(int pp) { int t1, tg, z; t1 = g_inv[pp][0]; if (items[t1].use == USE_NOT || items[t1].use > USE_CAMP_INF) { return; } if (items[t1].tgt == TGT_NONE || items[t1].tgt > TGT_ALLY_ALL) { return; } while (1) { update_equipstats(); tg = select_any_player(items[t1].tgt - 1, items[t1].icon, items[t1].name); if (tg > -1) { z = item_effects(0, tg, t1); if (z == 0) { play_effect(SND_BAD, 128); } else { revert_equipstats(); if (z == 1) { play_effect(SND_ITEM, 128); select_any_player(3, 0, ""); } if (items[t1].use != USE_ANY_INF && items[t1].use != USE_CAMP_INF) { remove_item(pp, 1); } return; } } else { return; } kq_yield(); } }
/*! \brief Activate the special skill * * This function activates the special skill for a hero, * including targetting etc. if required. * * \param attack_fighter_index Hero to process * \returns 1 if the skill was used, otherwise 0 */ int skill_use(size_t attack_fighter_index) { int tgt, found_item, a, b, c, p, cts, tx, ty, next_target = 0, nn[NUM_FIGHTERS]; size_t enemy_index; size_t fighter_index; std::unique_ptr<Raster> temp; tempa = Magic.status_adjust(attack_fighter_index); switch (pidx[attack_fighter_index]) { case SENSAR: tgt = select_enemy(attack_fighter_index, TGT_ENEMY_ONE); if (tgt == -1) { return 0; } enemy_index = (unsigned int)tgt; temp = std::unique_ptr<Raster>(new Raster(320, 240)); blit(Combat.backart, temp.get(), 0, 0, 0, 0, 320, 240); Draw.color_scale(temp.get(), Combat.backart, 16, 31); b = fighter[attack_fighter_index].mhp / 20; strcpy(attack_string, _("Rage")); display_attack_string = 1; tempa.stats[eStat::Attack] = fighter[attack_fighter_index].stats[eStat::Attack]; tempa.stats[eStat::Hit] = fighter[attack_fighter_index].stats[eStat::Hit]; if (fighter[enemy_index].crit == 1) { tempa.stats[eStat::Attack] += b; tempa.stats[eStat::Hit] += b; } Combat.fight(attack_fighter_index, enemy_index, 1); if (fighter[enemy_index].IsDead()) { for (fighter_index = PSIZE; fighter_index < PSIZE + Combat.GetNumEnemies(); fighter_index++) { if (fighter[fighter_index].IsAlive()) { nn[next_target] = fighter_index; next_target++; } } if (next_target > 0) { enemy_index = nn[kqrandom->random_range_exclusive(0, next_target)]; Combat.fight(attack_fighter_index, enemy_index, 1); } } fighter[attack_fighter_index].hp -= (b * 2); Combat.AdjustHealth(attack_fighter_index, b * 2); display_attack_string = 0; blit(temp.get(), Combat.backart, 0, 0, 0, 0, 320, 240); Effects.display_amount(attack_fighter_index, FONT_DECIDE, 0); if (fighter[attack_fighter_index].IsAlive() && fighter[attack_fighter_index].hp <= 0) { Combat.fkill(attack_fighter_index); Effects.death_animation(attack_fighter_index, 0); } break; case SARINA: fighter[attack_fighter_index].ctmem = 1000; strcpy(attack_string, _("Sweep")); display_attack_string = 1; tempa.stats[eStat::Attack] = tempa.stats[eStat::Attack] * 75 / 100; fighter[attack_fighter_index].aframe = 6; Combat.UnsetDatafileImageCoords(); Combat.battle_render(0, 0, 0); Draw.blit2screen(0, 0); kq_wait(150); Combat.multi_fight(attack_fighter_index); display_attack_string = 0; break; case CORIN: strcpy(attack_string, _("Elemental Infusion")); display_attack_string = 1; fighter[attack_fighter_index].aux = 2; if (combat_spell_menu(attack_fighter_index) == 1) { Effects.draw_castersprite( attack_fighter_index, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor); Combat.UnsetDatafileImageCoords(); play_effect(22, 128); Draw.convert_cframes( attack_fighter_index, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor - 3, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor + 3, 0); Combat.battle_render(0, 0, 0); fullblit(double_buffer, back); for (p = 0; p < 2; p++) { for (a = 0; a < 16; a++) { tx = fighter[attack_fighter_index].cx + (fighter[attack_fighter_index].cw / 2); ty = fighter[attack_fighter_index].cy + (fighter[attack_fighter_index].cl / 2); if (p == 0) { circlefill( double_buffer, tx, ty, a, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor); } else { circlefill( double_buffer, tx, ty, 15 - a, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor); Combat.draw_fighter(attack_fighter_index, 0); } Draw.blit2screen(0, 0); kq_wait(50); fullblit(back, double_buffer); } } Draw.revert_cframes(attack_fighter_index, 0); Combat.battle_render(0, 0, 0); Draw.blit2screen(0, 0); infusion(attack_fighter_index, fighter[attack_fighter_index].csmem); c = Magic.mp_needed(attack_fighter_index, fighter[attack_fighter_index].csmem); if (c < 1) { c = 1; } fighter[attack_fighter_index].mp -= c; Combat.SetEtherEffectActive(attack_fighter_index, false); fighter[attack_fighter_index].aux = 1; } else { fighter[attack_fighter_index].aux = 0; display_attack_string = 0; return 0; } display_attack_string = 0; fighter[attack_fighter_index].SetInfuse(magic[fighter[attack_fighter_index].csmem].elem); break; case AJATHAR: if (fighter[attack_fighter_index].unl > 0) { strcpy(attack_string, _("Dispel Undead")); display_attack_string = 1; fullblit(double_buffer, back); for (a = 0; a < 14/*MagicNumber*/; a++) { Draw.convert_cframes(PSIZE, 1 + a, 15, 1); for (fighter_index = PSIZE; fighter_index < PSIZE + Combat.GetNumEnemies(); fighter_index++) { if (Effects.is_active(fighter_index)) { Combat.draw_fighter(fighter_index, 0); } } Draw.blit2screen(0, 0); kq_wait(50); fullblit(back, double_buffer); } Draw.revert_cframes(PSIZE, 1); display_attack_string = 0; b = fighter[attack_fighter_index].lvl * 15; for (fighter_index = PSIZE; fighter_index < PSIZE + Combat.GetNumEnemies(); fighter_index++) { if (fighter[fighter_index].IsAlive() && fighter[fighter_index].mhp > 0) { if (fighter[fighter_index].unl == 99 || fighter[fighter_index].unl == 0) { cts = 0; } else { a = (fighter[attack_fighter_index].lvl + 5) - fighter[fighter_index].unl; if (a > 0) { cts = a * 8; } else { cts = 0; } } if (kqrandom->random_range_exclusive(0, 100) < cts) { if (b >= fighter[fighter_index].hp) { b -= fighter[fighter_index].hp; Combat.SetShowDeathEffectAnimation(fighter_index, true); Combat.fkill(fighter_index); } } } } Effects.death_animation(PSIZE, 1); Combat.UnsetDatafileImageCoords(); Combat.battle_render(attack_fighter_index, attack_fighter_index, 0); } else { a = kqrandom->random_range_exclusive(0, 100); c = fighter[attack_fighter_index].lvl / 10 + 1; if (a < 25) { b = kqrandom->random_range_exclusive(0, 5 * c) + 1; } else { if (a < 90) { b = kqrandom->random_range_exclusive(0, 10 * c) + (20 * c); } else { b = kqrandom->random_range_exclusive(0, 25 * c) + (50 * c); } } strcpy(attack_string, _("Divine Cure")); display_attack_string = 1; Effects.draw_spellsprite(0, 1, 15, 1); display_attack_string = 0; for (fighter_index = 0; fighter_index < numchrs; fighter_index++) { if (!fighter[fighter_index].IsStone() && fighter[fighter_index].IsAlive()) { int amount = Magic.do_shell_check(fighter_index, b); Combat.AdjustHealth(fighter_index, amount); } } Effects.display_amount(0, FONT_YELLOW, 1); for (fighter_index = 0; fighter_index < numchrs; fighter_index++) { if (!fighter[fighter_index].IsStone() && fighter[fighter_index].IsAlive()) { Magic.adjust_hp(fighter_index, Combat.GetHealthAdjust(fighter_index)); } } } break; case CASANDRA: fighter[attack_fighter_index].atrack[0] = fighter[attack_fighter_index].stats[eStat::Aura]; fighter[attack_fighter_index].atrack[1] = fighter[attack_fighter_index].stats[eStat::Spirit]; fighter[attack_fighter_index].stats[eStat::Aura] = fighter[attack_fighter_index].stats[eStat::Aura] * 15 / 10; fighter[attack_fighter_index].stats[eStat::Spirit] = fighter[attack_fighter_index].stats[eStat::Spirit] * 15 / 10; fighter[attack_fighter_index].atrack[2] = fighter[attack_fighter_index].mrp; fighter[attack_fighter_index].mrp = fighter[attack_fighter_index].mrp * 15 / 10; if (combat_spell_menu(attack_fighter_index) == 1) { Combat.SetEtherEffectActive(attack_fighter_index, false); fighter[attack_fighter_index].aux = 1; fighter[attack_fighter_index].stats[eStat::Aura] = fighter[attack_fighter_index].atrack[0]; fighter[attack_fighter_index].stats[eStat::Spirit] = fighter[attack_fighter_index].atrack[1]; fighter[attack_fighter_index].mrp = fighter[attack_fighter_index].atrack[2]; } else { fighter[attack_fighter_index].stats[eStat::Aura] = fighter[attack_fighter_index].atrack[0]; fighter[attack_fighter_index].stats[eStat::Spirit] = fighter[attack_fighter_index].atrack[1]; fighter[attack_fighter_index].mrp = fighter[attack_fighter_index].atrack[2]; return 0; } break; case TEMMIN: fighter[attack_fighter_index].aux = 1; fighter[attack_fighter_index].defend = 1; break; case AYLA: tgt = select_enemy(attack_fighter_index, TGT_ENEMY_ONE); if (tgt == -1) { return 0; } enemy_index = (uint32_t)tgt; tx = fighter[attack_fighter_index].cx; ty = fighter[attack_fighter_index].cy; fighter[attack_fighter_index].cx = fighter[enemy_index].cx - 16; fighter[attack_fighter_index].cy = fighter[enemy_index].cy + fighter[enemy_index].cl - 40; fighter[attack_fighter_index].facing = 1; strcpy(attack_string, _("Steal")); display_attack_string = 1; Combat.battle_render(0, attack_fighter_index + 1, 0); Draw.blit2screen(0, 0); kq_wait(100); play_effect(SND_MENU, 128); kq_wait(500); display_attack_string = 0; Combat.battle_render(attack_fighter_index, attack_fighter_index, 0); found_item = 0; #ifdef DEBUGMODE if (debugging > 2) { if (fighter[enemy_index].steal_item_rare > 0) { /* This steals a rare item from monster, if there is one */ found_item = fighter[enemy_index].steal_item_rare; fighter[enemy_index].steal_item_rare = 0; } else if (fighter[enemy_index].steal_item_common > 0) { /* This steals a common item from a monster, if there is one */ found_item = fighter[enemy_index].steal_item_common; fighter[enemy_index].steal_item_common = 0; } if (found_item > 0) { if (check_inventory(found_item, 1) != 0) { sprintf(strbuf, _("%s taken!"), items[found_item].name); Draw.message(strbuf, items[found_item].icon, 0, 0, 0); } } else { if (fighter[enemy_index].steal_item_common == 0 && fighter[enemy_index].steal_item_rare == 0) { Draw.message(_("Nothing to steal!"), 255, 0, 0, 0); } else { Draw.message(_("Couldn't steal!"), 255, 0, 0, 0); } } } #else cts = party[pidx[attack_fighter_index]].lvl * 2 + 35; if (cts > 95) { cts = 95; } if (kqrandom->random_range_exclusive(0, 100) < cts) { if (fighter[enemy_index].steal_item_rare > 0 && (kqrandom->random_range_exclusive(0, 100) < 5)) { /* This steals a rare item from monster, if there is one */ found_item = fighter[enemy_index].steal_item_rare; fighter[enemy_index].steal_item_rare = 0; } else if (fighter[enemy_index].steal_item_common > 0 && (kqrandom->random_range_exclusive(0, 100) < 95)) { /* This steals a common item from a monster, if there is one */ found_item = fighter[enemy_index].steal_item_common; fighter[enemy_index].steal_item_common = 0; } if (found_item > 0) { if (check_inventory(found_item, 1) != 0) { sprintf(strbuf, _("%s taken!"), items[found_item].name); Draw.message(strbuf, items[found_item].icon, 0, 0, 0); } } else { if (fighter[enemy_index].steal_item_common == 0 && fighter[enemy_index].steal_item_rare == 0) { Draw.message(_("Nothing to steal!"), 255, 0, 0, 0); } else { Draw.message(_("Couldn't steal!"), 255, 0, 0, 0); } } } else { Draw.message(_("Couldn't steal!"), 255, 0, 0, 0); } #endif fighter[attack_fighter_index].cx = tx; fighter[attack_fighter_index].cy = ty; display_attack_string = 0; fighter[attack_fighter_index].facing = 0; Combat.battle_render(attack_fighter_index, attack_fighter_index, 0); Draw.blit2screen(0, 0); break; case NOSLOM: tgt = select_enemy(attack_fighter_index, TGT_ENEMY_ONE); if (tgt == -1) { return 0; } enemy_index = (uint32_t)tgt; reveal(enemy_index); break; default: break; } return 1; }
/*! \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 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 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; }
/** * Updates animations * * Used to draw animations. This component determines which stage the animation * is at and updates the render player component accordingly so no special system * is needed for animations vs. static images. * * The animation can also be triggered at a random time, and can also trigger a sound effect. * * @param world Pointer to the world structure (contains "world" info, entities / components) * * @designer Jordan Marling * @designer Mat Siwoski * @designer Robin Hsieh * * @author Jordan Marling * @author Mat Siwoski * @author Robin Hsieh */ void animation_system(World *world) { unsigned int entity; AnimationComponent *animationComponent; RenderPlayerComponent *renderPlayer; Animation *animation; for(entity = 0; entity < MAX_ENTITIES; entity++){ if (IN_THIS_COMPONENT(world->mask[entity], SYSTEM_MASK)){ animationComponent = &(world->animation[entity]); renderPlayer = &(world->renderPlayer[entity]); if (animationComponent->current_animation > -1) { animation = &(animationComponent->animations[animationComponent->current_animation]); if (SDL_GetTicks() - animation->ms_last > animation->ms_to_skip) { animation->ms_last = SDL_GetTicks(); animation->index++; if (animation->index >= animation->surface_count) { animation->index = 1; if (animation->loop == -1) { animationComponent->current_animation = -1; renderPlayer->playerSurface = animation->surfaces[0]; //stop_effect(animation->sound_effect); animation_end(world, entity); continue; } } if (animation->index >= animation->surface_count) { animation->index = animation->surface_count - 1; } renderPlayer->playerSurface = animation->surfaces[animation->index]; } } else { //check if random trigger has triggered if (animationComponent->rand_animation < 0) { continue; } if (SDL_GetTicks() > animationComponent->next_random_occurance) { animationComponent->current_animation = animationComponent->rand_animation; animationComponent->last_random_occurance = SDL_GetTicks(); animationComponent->next_random_occurance = (rand() % (animationComponent->rand_occurance_max - animationComponent->rand_occurance_min)) + animationComponent->rand_occurance_min + SDL_GetTicks(); if (animationComponent->animations[animationComponent->rand_animation].sound_effect != MAX_EFFECTS && animationComponent->animations[animationComponent->rand_animation].sound_enabled == true) { play_effect(animationComponent->animations[animationComponent->rand_animation].sound_effect); } } } } } }
/*! \brief Actions for one entity * \date 20040310 PH added TARGET movemode, broke out chase into separate function * * Process an individual active entity. If the entity in question * is #0 (main character) and the party is not automated, then allow * for player input. * * \param target_entity Index of entity * \date 20040310 PH added TARGET movemode, broke out chase into separate function */ static void process_entity(t_entity target_entity) { s_entity *ent = &g_ent[target_entity]; s_player *player = 0; ent->scount = 0; if (!ent->active) { return; } if (!ent->moving) { if (target_entity == 0 && !autoparty) { player_move(); if (ent->moving && display_desc == 1) { display_desc = 0; } return; } switch (ent->movemode) { case MM_STAND: return; case MM_WANDER: wander(target_entity); break; case MM_SCRIPT: entscript(target_entity); break; case MM_CHASE: chase(target_entity); break; case MM_TARGET: target(target_entity); break; } } else /* if (.moving==0) */ { if (ent->tilex * TILE_W > ent->x) { ++ent->x; } if (ent->tilex * TILE_W < ent->x) { --ent->x; } if (ent->tiley * TILE_H > ent->y) { ++ent->y; } if (ent->tiley * TILE_H < ent->y) { --ent->y; } ent->movcnt--; if (ent->framectr < 20) { ent->framectr++; } else { ent->framectr = 0; } if (ent->movcnt == 0) { ent->moving = 0; if (target_entity < PSIZE) { player = &party[pidx[target_entity]]; if (steps < STEPS_NEEDED) { steps++; } if (player->sts[S_POISON] > 0) { if (player->hp > 1) { player->hp--; } play_effect(21, 128); } if (player->eqp[EQP_SPECIAL] == I_REGENERATOR) { if (player->hp < player->mhp) { player->hp++; } } } if (target_entity == 0) { zone_check(); } } if (target_entity == 0 && vfollow == 1) { calc_viewport(0); } } }
/*! \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 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 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 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 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 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 Perform item effects * * Perform item effects. This is kind of clunky, but it works. * * \param sa Index of attacker * \param t Index of item to use * \param ti Index of target(s) * \returns 0 if ineffective (cannot use item) * \returns 1 if success (1 target) * \returns 2 if success (multiple targets) */ int item_effects(int sa, int t, int ti) { int tmp = 0, i, a, b, z, san = 0, se = 0, sen = 0; if (sa == 0) { san = numchrs; se = PSIZE; sen = num_enemies; } else { san = num_enemies; se = 0; sen = numchrs; } switch (ti) { case I_MHERB: case I_SALVE: case I_PCURING: if (fighter[t].sts[S_DEAD] != 0) { return 0; } if (fighter[t].hp == fighter[t].mhp) { return 0; } tmp = rand() % (items[ti].stats[A_ATT] / 2) + items[ti].stats[A_ATT]; if (in_combat == 0) { adjust_hp(t, tmp); } else { ta[t] = tmp; draw_spellsprite(t, 0, items[ti].eff, 0); display_amount(t, FYELLOW, 0); adjust_hp(t, ta[t]); } break; case I_OSEED: case I_EDROPS: if (fighter[t].sts[S_DEAD] != 0) { return 0; } if (fighter[t].mp == fighter[t].mmp) { return 0; } tmp = rand() % (items[ti].stats[A_ATT] / 2) + items[ti].stats[A_ATT]; if (in_combat == 0) { adjust_mp(t, tmp); } else { ta[t] = tmp; draw_spellsprite(t, 0, items[ti].eff, 0); display_amount(t, FGREEN, 0); adjust_mp(t, ta[t]); } break; case I_NLEAF: case I_NPOULTICE: case I_KBREW: if (fighter[t].sts[S_DEAD] != 0 || fighter[t].sts[S_STONE] != 0) { return 0; } if (fighter[t].sts[items[ti].elem] != 0) { fighter[t].sts[items[ti].elem] = 0; } else { return 0; } if (in_combat == 1) { draw_spellsprite(t, 0, items[ti].eff, 0); } break; case I_WENSAI: if (fighter[t].sts[S_DEAD] != 0) { return 0; } if (fighter[t].sts[S_STONE] != 0) { fighter[t].sts[S_STONE] = 0; } else { return 0; } if (in_combat == 1) { draw_spellsprite(t, 0, items[ti].eff, 0); } break; case I_EDAENRA: tmp = 0; for (i = 0; i < 7; i++) if (fighter[t].sts[i] != 0) { tmp++; } if (tmp == 0 || fighter[t].sts[S_DEAD] != 0) { return 0; } if (fighter[t].sts[S_DEAD] != 0) { return 0; } for (i = 0; i < 12; i++) { fighter[t].sts[i] = 0; } if (in_combat == 1) { draw_spellsprite(t, 0, items[ti].eff, 0); } break; case I_LTONIC: if (fighter[t].sts[S_DEAD] == 0) { return 0; } for (a = 0; a < 24; a++) { fighter[t].sts[a] = 0; } fighter[t].hp = 1; fighter[t].aframe = 0; if (in_combat == 1) { draw_spellsprite(t, 0, items[ti].eff, 0); } break; case I_RRUNE: tmp = 0; for (i = sa; i < sa + san; i++) if (fighter[i].hp == fighter[i].mhp) { tmp++; } if (tmp == san) { return 0; } for (i = sa; i < sa + san; i++) { if (fighter[i].sts[S_DEAD] == 0 && fighter[i].sts[S_STONE] == 0) { b = fighter[i].lvl * items[ti].stats[A_ATT]; tmp = rand() % b + b + 1; if (in_combat == 0) { adjust_hp(i, tmp); } else { ta[i] = do_shell_check(i, tmp); } } } if (in_combat == 1) { draw_spellsprite(sa, 1, items[ti].eff, 1); display_amount(sa, FYELLOW, 1); for (i = sa; i < sa + san; i++) { adjust_hp(i, ta[i]); } } break; case I_ERUNE: case I_FRUNE: case I_WRUNE: case I_IRUNE: if (in_combat == 0) { return 0; } tmp = items[ti].elem; for (i = se; i < se + sen; i++) { if (fighter[i].sts[S_DEAD] == 0 && fighter[i].mhp > 0) { b = fighter[i].lvl * items[ti].stats[A_ATT]; a = rand() % b + b + 20; if (a > 250) { a = 250; } b = res_adjust(i, tmp, a); a = do_shell_check(i, b); ta[i] = 0 - a; } else { ta[i] = 0; } } draw_spellsprite(se, 1, items[ti].eff, 1); return 2; case I_TP100S: if (in_combat == 0) { return 0; } if (fighter[t].sts[S_DEAD] == 0 && fighter[t].sts[S_STONE] == 0) { ta[t] = items[ti].stats[A_ATT]; } draw_spellsprite(t, 0, items[ti].eff, 0); return 2; } if (sa == PSIZE || in_combat == 1) { return 1; } if (ti >= I_STRSEED && ti <= I_WISSEED) { if (fighter[t].sts[S_DEAD] != 0 || in_combat == 1 || t >= PSIZE) { return 0; } z = items[ti].bst; party[pidx[t]].stats[z] += (rand() % 3 + 1) * 100; play_effect(SND_TWINKLE, 128); switch (z) { case 0: message(_("Strength up!"), 255, 0, xofs, yofs); break; case 1: message(_("Agility up!"), 255, 0, xofs, yofs); break; case 2: message(_("Vitality up!"), 255, 0, xofs, yofs); break; case 3: message(_("Intellect up!"), 255, 0, xofs, yofs); break; case 4: message(_("Wisdom up!"), 255, 0, xofs, yofs); break; } return 2; } if ((items[ti].icon == W_SBOOK || items[ti].icon == W_ABOOK)) { tmp = 0; for (i = 0; i < 60; i++) if (party[pidx[t]].spells[i] > 0) { tmp++; } if (tmp == 60) { return 0; } tmp = 0; for (i = 0; i < 60; i++) if (party[pidx[t]].spells[i] == items[ti].hnds || party[pidx[t]].lvl < items[ti].ilvl) { tmp = 1; } if (tmp == 1) { return 0; } tmp = items[ti].hnds; for (i = 0; i < 60; i++) { if (party[pidx[t]].spells[i] == 0) { party[pidx[t]].spells[i] = tmp; i = 60; } } sprintf(strbuf, _("%s learned!"), magic[tmp].name); play_effect(SND_TWINKLE, 128); message(strbuf, magic[tmp].icon, 0, xofs, yofs); return 2; } if (ti == I_HPUP) { if (fighter[t].sts[S_DEAD] != 0) { return 0; } i = rand() % 11 + 10; party[pidx[t]].mhp += i; fighter[t].hp += i; } if (ti == I_MPUP) { if (fighter[t].sts[S_DEAD] != 0) { return 0; } i = rand() % 11 + 10; party[pidx[t]].mmp += i; fighter[t].mp += i; } if (ti == I_SSTONE) { if (use_sstone == 0) { return 0; } for (i = sa; i < sa + san; i++) { fighter[i].hp = fighter[i].mhp; fighter[i].mp = fighter[i].mmp; for (b = 0; b < 8; b++) { fighter[i].sts[b] = 0; } } } return 1; }