void FightsManager::fightHandler(Hotspot &h, uint16 moveOffset) { Resources &res = Resources::getReference(); FighterRecord &fighter = getDetails(h.hotspotId()); FighterRecord &opponent = getDetails(fighter.fwenemy_ad); uint16 v1, v2; bool breakFlag = false; while (!breakFlag) { if (moveOffset == 0) { // Player is doing nothing, so check the move number moveOffset = getWord(FIGHT_PLAYER_MOVE_TABLE + (fighter.fwmove_number << 1)); debugC(ERROR_DETAILED, kLureDebugFights, "Hotspot %xh fight move=%d, new offset=%xh", h.hotspotId(), fighter.fwmove_number, moveOffset); if (moveOffset == 0) return; fighter.fwseq_no = fighter.fwmove_number; fighter.fwseq_ad = moveOffset; } uint16 moveValue = getWord(moveOffset); debugC(ERROR_DETAILED, kLureDebugFights, "Hotspot %xh script offset=%xh value=%xh", h.hotspotId(), moveOffset, moveValue); moveOffset += sizeof(uint16); if ((moveValue & 0x8000) == 0) { // Set frame to specified number h.setFrameNumber(moveValue); // Set the new fighter position int16 newX, newY; newX = h.x() + (int16)getWord(moveOffset); if (newX < 32) newX = 32; if (newX > 240) newX = 240; newY = h.y() + (int16)getWord(moveOffset + 2); h.setPosition(newX, newY); if (fighter.fwweapon != 0) { Hotspot *weaponHotspot = res.getActiveHotspot(fighter.fwweapon); assert(weaponHotspot); uint16 newFrameNumber = getWord(moveOffset + 4); int16 xChange = (int16)getWord(moveOffset + 6); int16 yChange = (int16)getWord(moveOffset + 8); weaponHotspot->setFrameNumber(newFrameNumber); weaponHotspot->setPosition(h.x() + xChange, h.y() + yChange); } moveOffset += 5 * sizeof(uint16); fighter.fwseq_ad = moveOffset; return; } switch (moveValue) { case 0xFFFA: // Walk left if ((fighter.fwmove_number == 5) || (fighter.fwmove_number == 10)) { if (h.x() < 32) { breakFlag = true; } else { h.setPosition(h.x() - 4, h.y()); fighter.fwtrue_x = h.x(); if (fetchFighterDistance(fighter, opponent) < FIGHT_DISTANCE) { h.setPosition(h.x() + 4, h.y()); fighter.fwtrue_x += 4; breakFlag = true; } else { removeWeapon(fighter.fwweapon); fighter.fwtrue_x = h.x(); fighter.fwtrue_y = h.y(); uint16 frameNum = (fighter.fwwalk_roll == 7) ? 0 : fighter.fwwalk_roll + 1; fighter.fwwalk_roll = frameNum; fighter.fwseq_ad = moveOffset; h.setFrameNumber(frameNum); return; } } } else { // Signal to start a new action moveOffset = 0; } break; case 0xFFF9: // Walk right if ((fighter.fwmove_number == 9) || (fighter.fwmove_number == 14)) { if (h.x() >= 240) { breakFlag = true; } else { removeWeapon(fighter.fwweapon); h.setPosition(h.x() + 4, h.y()); fighter.fwtrue_x = h.x(); fighter.fwtrue_y = h.y(); fighter.fwwalk_roll = (fighter.fwwalk_roll == 0) ? 7 : fighter.fwwalk_roll - 1; fighter.fwseq_ad = moveOffset; h.setFrameNumber(fighter.fwwalk_roll); return; } } else { // Signal to start a new action moveOffset = 0; } break; case 0xFFEB: // Enemy right removeWeapon(fighter.fwweapon); h.setPosition(h.x() + 4, h.y()); fighter.fwtrue_x = h.x(); if (fetchFighterDistance(fighter, opponent) < FIGHT_DISTANCE) { h.setPosition(h.x() - 4, h.y()); fighter.fwtrue_x -= 4; fighter.fwseq_ad = 0; h.setFrameNumber(8); } else { h.setFrameNumber(getWord(moveOffset)); moveOffset += sizeof(uint16); fighter.fwseq_ad = moveOffset; } return; case 0xFFFB: // End of sequence breakFlag = true; break; case 0xFFF8: // Set fight address moveOffset = getWord(moveOffset); break; case 0xFFFF: case 0xFFFE: if (moveValue == 0xffff) // Set the animation record h.setAnimation(getWord(moveOffset)); else // New set animation record h.setAnimation(getWord(fighter.fwheader_list + (getWord(moveOffset) << 1))); h.setFrameNumber(0); moveOffset += sizeof(uint16); break; case 0xFFF7: // On hold if (getWord(moveOffset) == fighter.fwmove_number) moveOffset = getWord(moveOffset + 2); else moveOffset += 2 * sizeof(uint16); break; case 0xFFF6: // Not hold if (getWord(moveOffset) == fighter.fwmove_number) moveOffset += 2 * sizeof(uint16); else moveOffset = getWord(moveOffset + 2); break; case 0xFFF4: // End sequence fighter.fwseq_no = 0; break; case 0xFFF2: // Set defend fighter.fwblocking = getWord(moveOffset); moveOffset += sizeof(uint16); break; case 0xFFF1: // If blocking v1 = getWord(moveOffset); v2 = getWord(moveOffset + 2); moveOffset += 2 * sizeof(uint16); if (v1 == opponent.fwblocking) { Sound.addSound(42); moveOffset = v2; } break; case 0xFFF0: // Check hit v1 = getWord(moveOffset); moveOffset += sizeof(uint16); if (fighter.fwdist <= FIGHT_DISTANCE) { if (h.hotspotId() == PLAYER_ID) { // Player hits opponent Sound.addSound(52); if (opponent.fwhits != 5) { opponent.fwseq_ad = v1; if (++opponent.fwhit_value != opponent.fwhit_rate) { opponent.fwhit_value = 0; if (++opponent.fwhits == 5) opponent.fwseq_ad = opponent.fwdie_seq; } } } else { // Opponent hit player Sound.addSound(37); opponent.fwseq_ad = v1; if (++opponent.fwhits == 10) { // Player has been killed fighter.fwhits = 10; opponent.fwseq_ad = FIGHT_PLAYER_DIES; Sound.addSound(36); } } } break; case 0xFFEF: // Save co-ordinates fighter.fwtrue_x = h.x(); fighter.fwtrue_y = h.y(); break; case 0xFFEE: // Restore co-ordinates h.setPosition(fighter.fwtrue_x, fighter.fwtrue_y); break; case 0xFFED: // End of game getDetails(PLAYER_ID).fwhits = GENERAL_MAGIC_ID; Game::getReference().setState(GS_RESTORE_RESTART); return; case 0xFFEC: // Enemy has been killed enemyKilled(); break; case 0xFFEA: // Fight sound Sound.addSound(getWord(moveOffset) & 0xff); moveOffset += sizeof(uint16); break; default: error("Unknown fight command %xh", moveValue); } } fighter.fwseq_no = 0; fighter.fwseq_ad = 0; if (h.hotspotId() == PLAYER_ID) _mouseFlags = 0; }
bool Debugger::cmd_showAnim(int argc, const char **argv) { Resources &res = Resources::getReference(); if (argc < 2) { DebugPrintf("showAnim animId [[frame_width frame_height] | list]\n"); return true; } // Get the animation Id int animId = strToInt(argv[1]); HotspotAnimData *data = res.getAnimation(animId); if (data == NULL) { DebugPrintf("No such animation Id exists\n"); return true; } // Figure out the total size of the animation - this will be used for guestimating // frame sizes, or validating that a specified frame size is correct MemoryBlock *src = Disk::getReference().getEntry(data->animId); int numFrames = READ_LE_UINT16(src->data()); uint16 *headerEntry = (uint16 *) (src->data() + 2); assert((numFrames >= 1) && (numFrames < 100)); // Calculate total needed size for output and create memory block to hold it uint32 totalSize = 0; for (uint16 ctr = 0; ctr < numFrames; ++ctr, ++headerEntry) { totalSize += (READ_LE_UINT16(headerEntry) + 31) / 32; } totalSize = (totalSize + 0x81) << 4; MemoryBlock *dest = Memory::allocate(totalSize); uint32 srcStart = (numFrames + 1) * sizeof(uint16) + 6; uint32 destSize = AnimationDecoder::decode_data(src, dest, srcStart) - 0x40; // Figure out the frame size int frameSize; if ((data->flags & PIXELFLAG_HAS_TABLE) != 0) { // Table based animation, so get frame size from frame 1 offset frameSize = READ_LE_UINT16(src->data()); } else { // Get frame size from dividing uncompressed size by number of frames frameSize = destSize / numFrames; } // Free up the data delete src; delete dest; int width, height; if (argc == 4) { // Width and height specified width = strToInt(argv[2]); height = strToInt(argv[3]); if ((width * height) != (frameSize * 2)) { DebugPrintf("Warning: Total size = %d, Frame size (%d,%d) * %d frames = %d bytes\n", destSize, width, height, numFrames, width * height * numFrames / 2); } } else { // Guestimate a frame size frameSize = destSize / numFrames; // Figure out the approximate starting point of a width 3/4 the frame size width = frameSize * 3 / 4; bool descFlag = (argc == 3); if (descFlag) DebugPrintf("Target size = %d\n", frameSize * 2); while ((width > 0) && (descFlag || (((frameSize * 2) % width) != 0))) { if (((frameSize * 2) % width) == 0) DebugPrintf("Frame size (%d,%d) found\n", width, frameSize * 2 / width); --width; } if (argc == 3) { DebugPrintf("Done\n"); return true; } else if (width == 0) { DebugPrintf("Total size = %d, # frames = %d, frame Size = %d - No valid frame dimensions\n", destSize, numFrames, frameSize); return true; } height = (frameSize * 2) / width; DebugPrintf("# frames = %d, guestimated frame size = (%d,%d)\n", numFrames, width, height); } // Bottle object is used as a handy hotspot holder that doesn't have any // tick proc behavior that we need to worry about Hotspot *hotspot = res.activateHotspot(BOTTLE_HOTSPOT_ID); hotspot->setLayer(0xfe); hotspot->setSize(width, height); Hotspot *player = res.activateHotspot(PLAYER_ID); hotspot->setColorOffset(player->resource()->colorOffset); hotspot->setAnimation(animId); DebugPrintf("Done\n"); return true; }