using System; using System.Linq; using System.Text; namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { /// /// ZXHawk: Core Class /// * Handles all messaging (OSD) operations * /// public partial class ZXSpectrum { /// /// Writes a message to the OSD /// /// /// public void SendMessage(string message, MessageCategory category) { if (!CheckMessageSettings(category)) return; StringBuilder sb = new StringBuilder(); switch (category) { case MessageCategory.Tape: sb.Append("DATACORDER: "); sb.Append(message); break; case MessageCategory.Input: sb.Append("INPUT DETECTED: "); sb.Append(message); break; case MessageCategory.Disk: sb.Append("DISK DRIVE: "); sb.Append(message); break; case MessageCategory.Emulator: case MessageCategory.Misc: sb.Append("ZXHAWK: "); sb.Append(message); break; } CoreComm.Notify(sb.ToString()); } #region Input Message Methods /// /// Called when certain input presses are detected /// /// public void OSD_FireInputMessage(string input) { StringBuilder sb = new StringBuilder(); sb.Append(input); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Input); } #endregion #region DiskDevice Message Methods /// /// Disk message that is fired on core init /// public void OSD_DiskInit() { StringBuilder sb = new StringBuilder(); if (_machine.diskImages != null && _machine.UPDDiskDevice != null) { sb.Append("Disk Media Imported (count: " + _machine.diskImages.Count() + ")"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Emulator); } } /// /// Disk message that is fired when a new disk is inserted into the drive /// public void OSD_DiskInserted() { StringBuilder sb = new StringBuilder(); if (_machine.UPDDiskDevice == null) { sb.Append("No Drive Present"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); return; } sb.Append("DISK INSERTED (" + _machine.DiskMediaIndex + ": " + _diskInfo[_machine.DiskMediaIndex].Name + ")"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); } /// /// Tape message that prints the current status of the tape device /// public void OSD_ShowDiskStatus() { StringBuilder sb = new StringBuilder(); if (_machine.UPDDiskDevice == null) { sb.Append("No Drive Present"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); return; } if (_diskInfo.Count == 0) { sb.Append("No Disk Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); return; } if (_machine.UPDDiskDevice != null) { if (_machine.UPDDiskDevice.DiskPointer == null) { sb.Append("No Disk Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); return; } sb.Append("Disk: " + _machine.DiskMediaIndex + ": " + _diskInfo[_machine.DiskMediaIndex].Name); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); sb.Clear(); string protection = "None"; protection = Enum.GetName(typeof(ProtectionType), _machine.UPDDiskDevice.DiskPointer.Protection); if (protection == "None") protection += " (OR UNKNOWN)"; sb.Append("Detected Protection: " + protection); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); sb.Clear(); sb.Append("Status: "); if (_machine.UPDDiskDevice.DriveLight) sb.Append("READING/WRITING DATA"); else sb.Append("UNKNOWN"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Disk); sb.Clear(); } } #endregion #region TapeDevice Message Methods /// /// Tape message that is fired on core init /// public void OSD_TapeInit() { if (_tapeInfo.Count == 0) return; StringBuilder sb = new StringBuilder(); sb.Append("Tape Media Imported (count: " + _tapeInfo.Count() + ")"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Emulator); } /// /// Tape message that is fired when tape is playing /// public void OSD_TapePlaying() { if (_tapeInfo.Count == 0) return; StringBuilder sb = new StringBuilder(); sb.Append("PLAYING (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when tape is stopped /// public void OSD_TapeStopped() { if (_tapeInfo.Count == 0) return; StringBuilder sb = new StringBuilder(); sb.Append("STOPPED (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when tape is rewound /// public void OSD_TapeRTZ() { if (_tapeInfo.Count == 0) return; StringBuilder sb = new StringBuilder(); sb.Append("REWOUND (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when a new tape is inserted into the datacorder /// public void OSD_TapeInserted() { if (_tapeInfo.Count == 0) return; StringBuilder sb = new StringBuilder(); sb.Append("TAPE INSERTED (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when a tape is stopped automatically /// public void OSD_TapeStoppedAuto() { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("STOPPED (Auto Tape Trap Detected)"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when a tape is started automatically /// public void OSD_TapePlayingAuto() { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("PLAYING (Auto Tape Trap Detected)"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when a new block starts playing /// public void OSD_TapePlayingBlockInfo(string blockinfo) { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("...Starting Block " + blockinfo); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when a tape block is skipped (because it is empty) /// public void OSD_TapePlayingSkipBlockInfo(string blockinfo) { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("...Skipping Empty Block " + blockinfo); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when a tape is started automatically /// public void OSD_TapeEndDetected(string blockinfo) { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("...Skipping Empty Block " + blockinfo); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when user has manually skipped to the next block /// public void OSD_TapeNextBlock(string blockinfo) { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("Manual Skip Next " + blockinfo); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that is fired when user has manually skipped to the next block /// public void OSD_TapePrevBlock(string blockinfo) { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("Manual Skip Prev " + blockinfo); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } /// /// Tape message that prints the current status of the tape device /// public void OSD_ShowTapeStatus() { StringBuilder sb = new StringBuilder(); if (_tapeInfo.Count == 0) { sb.Append("No Tape Loaded"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); return; } sb.Append("Status: "); if (_machine.TapeDevice.TapeIsPlaying) sb.Append("PLAYING"); else sb.Append("STOPPED"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); sb.Clear(); sb.Append("Tape: " + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); sb.Clear(); sb.Append("Block: "); sb.Append("(" + (_machine.TapeDevice.CurrentDataBlockIndex + 1) + " of " + _machine.TapeDevice.DataBlocks.Count() + ") " + _machine.TapeDevice.DataBlocks[_machine.TapeDevice.CurrentDataBlockIndex].BlockDescription); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); sb.Clear(); sb.Append("Block Pos: "); int pos = _machine.TapeDevice.Position; int end = _machine.TapeDevice.DataBlocks[_machine.TapeDevice.CurrentDataBlockIndex].DataPeriods.Count; double p = 0; if (end != 0) p = ((double)pos / (double)end) * (double)100; sb.Append(p.ToString("N0") + "%"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); sb.Clear(); // get position within the tape itself sb.Append("Tape Pos: "); var ind = _machine.TapeDevice.CurrentDataBlockIndex; int cnt = 0; for (int i = 0; i < ind; i++) { cnt += _machine.TapeDevice.DataBlocks[i].DataPeriods.Count; } // now we are at our current block int ourPos = cnt + pos; cnt += end; // count periods in the remaining blocks for (int i = ind + 1; i < _machine.TapeDevice.DataBlocks.Count; i++) { cnt += _machine.TapeDevice.DataBlocks[i].DataPeriods.Count; } // work out overall position within the tape p = 0; p = ((double)ourPos / (double)cnt) * (double)100; sb.Append(p.ToString("N0") + "%"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } #endregion /// /// Checks whether message category is allowed to be sent /// /// /// public bool CheckMessageSettings(MessageCategory category) { switch (Settings.OSDMessageVerbosity) { case OSDVerbosity.Full: return true; case OSDVerbosity.None: return false; case OSDVerbosity.Medium: switch (category) { case MessageCategory.Disk: case MessageCategory.Emulator: case MessageCategory.Tape: case MessageCategory.Misc: return true; default: return false; } default: return true; } } /// /// Defines the different message categories /// public enum MessageCategory { /// /// No defined category as such /// Misc, /// /// User generated input messages (at the moment only tape/disk controls) /// Input, /// /// Tape device generated messages /// Tape, /// /// Disk device generated messages /// Disk, /// /// Emulator generated messages /// Emulator } } }