// MAME-specific quest-driving code #include "driver.h" #include "ui.h" #include "uimenu.h" #include "deprecat.h" #include "quest.h" #include "timer.h" #include "attotime.h" // Global varaibles: emu_timer* QuestTimer; extern GlobalQuestInfo* GlobalQ; // Exit callback: Called when shutting down a machine(?) static void quest_exit(running_machine* machine) { //CleanupQuestInfo(); printf("quest_exit() - show cursor!\n"); } TIMER_CALLBACK(QuestTimerCallback) { QuestPeriodic(0); } void init_quests(running_machine* machine) { int CoinIndex; int SlicesPerFrame; attotime QuestTimerPeriod; ///////////////////////////////////////////////////////////////////////// // Add the quest callback: printf("init_quests()\n"); SlicesPerFrame = machine->config->cpu_slices_per_frame; if (SlicesPerFrame <= 0) { SlicesPerFrame = 1; } int numscreens = video_screen_count(machine->config); attoseconds_t refresh_attosecs = (numscreens == 0) ? HZ_TO_ATTOSECONDS(60) : video_screen_get_frame_period(machine->primary_screen).attoseconds; QuestTimerPeriod = attotime_make(0, refresh_attosecs); // Avoid registering the quest timer with the save/load system - we don't want // quest state to be affected by saves and loads, we want to manage it ourselves! QuestTimer = timer_alloc(QuestTimerCallback, NULL); timer_adjust_periodic(QuestTimer, QuestTimerPeriod, 0, QuestTimerPeriod); printf("Timer allocated...\n"); add_exit_callback(machine, quest_exit); GlobalQ->ElapsedTime = 0; if (GlobalQ->CurrentQuest) { printf("Call StartQuest() and lock out coins...\n"); StartQuest(GlobalQ->CurrentQuest); for (CoinIndex = 0; CoinIndex < COIN_COUNTERS; CoinIndex++) { coin_lockout_w(CoinIndex, 1); } } else { // Explicitly state that we're NOT questing right now: GlobalQ->State = QUEST_STATE_NONE; for (CoinIndex = 0; CoinIndex < COIN_COUNTERS; CoinIndex++) { coin_lockout_w(CoinIndex, 0); } } SetQuestTimeLimits(); printf("init_quests() end\n"); } // Just handle setting single-byte values. void QMemlocSetValue(QMemloc* Info, int Value) { cpunum_write_byte(Info->CPU, Info->MemoryLocation, Value); } // Look up the value of a game parameter. Usually it's just a matter // of asking the CPU for the byte stored at a memory location. // Sometimes we must read several bytes (mostly for SCORES) int QMemlocGetValue(QMemloc* Info) { int Value; int Byte; int BitIndex; int Scaling; int Multiplier = Info->Multiplier; // A multiplier of 0 is silly, so we'll assume that what's wanted is 1: if (Multiplier == 0) { Multiplier = 1; } switch (Info->StorageMethod) { case evStorageByte: Value = cpunum_read_byte(Info->CPU, Info->MemoryLocation); //printf("QIGV: Memory %s %x is %d\n", Info->Name, Info->MemoryLocation, Value); return Value * Multiplier; case evStorageFlag: Value = cpunum_read_byte(Info->CPU, Info->MemoryLocation); //printf("Check BitFlag: value %d vs 1 << %d\n", Value, Info->Width); if (Value & (1 << Info->Width)) { return 1; } return 0; case evStorage2Byte: Value = cpunum_read_byte(Info->CPU, Info->MemoryLocation) * 256; Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 1); //printf("QIGV: Memory %s %x is %d\n", Info->Name, Info->MemoryLocation, Value); return Value * Multiplier; case evStorage2ByteLE: Value = cpunum_read_byte(Info->CPU, Info->MemoryLocation); Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 1) * 256; //printf("QIGV: Memory %s %x is %d\n", Info->Name, Info->MemoryLocation, Value); return Value * Multiplier; case evStorage4Byte: Value = cpunum_read_byte(Info->CPU, Info->MemoryLocation) * 256 * 256 * 256; Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 1) * 256 * 256; Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 2) * 256; Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 3); //printf("QIGV: Memory %s %x is %d\n", Info->Name, Info->MemoryLocation, Value); return Value * Multiplier; case evStorage4ByteLE: Value = cpunum_read_byte(Info->CPU, Info->MemoryLocation); Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 1) * 256; Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 2) * 256 * 256; Value += cpunum_read_byte(Info->CPU, Info->MemoryLocation + 3) * 256 * 256 * 256; //printf("QIGV: Memory %s %x is %d\n", Info->Name, Info->MemoryLocation, Value); return Value * Multiplier; case evStorageScoreOnes: // Score is stored like this: // Score of 123, width 3: // 0x?1 0x?2 0x?3 Scaling = 1; for (BitIndex = 0; BitIndex < Info->Width - 1; BitIndex++) { Scaling *= 10; } Value = 0; for (BitIndex = 0; BitIndex < Info->Width; BitIndex++) { Byte = cpunum_read_byte(Info->CPU, Info->MemoryLocation + BitIndex); Value += (Byte % 16) * Scaling; Scaling /= 10; } return Value * Multiplier; break; case evStorageScoreOnesLE: // Score is stored like this: // Score of 123, width 3: // 0x?3 0x?2 0x?1 Scaling = 1; Value = 0; for (BitIndex = 0; BitIndex < Info->Width; BitIndex++) { Byte = cpunum_read_byte(Info->CPU, Info->MemoryLocation + BitIndex); Value += (Byte % 16) * Scaling; Scaling *= 10; } return Value * Multiplier; break; case evStorageScoreOnesOnlyLE: // Score is stored like this: // Score of 123, width 3: // 0x03 0x02 0x01 // If we encounter a value of 0x10 or larger, we STOP early. // (This is a weird storage format; it's used by galaga) Scaling = 1; Value = 0; for (BitIndex = 0; BitIndex < Info->Width; BitIndex++) { Byte = cpunum_read_byte(Info->CPU, Info->MemoryLocation + BitIndex); if (Byte >= 0x10) { break; } Value += (Byte % 16) * Scaling; Scaling *= 10; } return Value * Multiplier; break; case evStorageScoreLE: // Little-endian score Scaling = 1; Value = 0; for (BitIndex = 0; BitIndex < Info->Width; BitIndex++) { Byte = cpunum_read_byte(Info->CPU, Info->MemoryLocation + BitIndex); Value += (Byte / 16) * Scaling * 10; Value += (Byte % 16) * Scaling; Scaling *= 100; } return Value * Multiplier; case evStorageScore: // Scores are stored like this: // Score of 18625, width 3: // 0x01 0x86 0x25 Value = 0; // Read bits, from most to least significant: Scaling = 1; for (BitIndex = 0; BitIndex < Info->Width - 1; BitIndex++) { Scaling *= 100; } for (BitIndex = 0; BitIndex < Info->Width; BitIndex++) { Byte = cpunum_read_byte(Info->CPU, Info->MemoryLocation + BitIndex); Value += (Byte / 16) * Scaling * 10; Value += (Byte % 16) * Scaling; Scaling /= 100; } return Value * Multiplier; case evStorageScoreReverse: // Reversed scores are stored like this: // Score of 1625, width 2: // 0x61 0x52 Value = 0; // Read bits, from most to least significant: Scaling = 1; for (BitIndex = 0; BitIndex < Info->Width - 1; BitIndex++) { Scaling *= 100; } for (BitIndex = 0; BitIndex < Info->Width; BitIndex++) { Byte = cpunum_read_byte(Info->CPU, Info->MemoryLocation + BitIndex); Value += (Byte / 16) * Scaling; Value += (Byte % 16) * Scaling * 10; Scaling /= 100; } return Value * Multiplier; default: return 0; } } void QuestExitGame() { printf("QuestExitGame!\n"); mame_schedule_exit(Machine); } void QuestComplete(int CompletionType) { if (!GlobalQ->CurrentQuest) // wtf? { return; } switch (CompletionType) { case QUEST_STATE_GOLD: popmessage("GOLD! Quest completed."); break; case QUEST_STATE_SILVER: popmessage("Silver! Quest completed."); break; case QUEST_STATE_BRONZE: popmessage("(Bronze) Quest completed."); break; case QUEST_STATE_FAILURE: popmessage("Quest failed."); break; } }