178 lines
6.5 KiB
Python
178 lines
6.5 KiB
Python
import time
|
|
import sys
|
|
from OdenGraphQt import BaseNode
|
|
from Qt import QtWidgets, QtCore, QtGui
|
|
|
|
# Attempt to import winsound (Windows-only)
|
|
try:
|
|
import winsound
|
|
HAS_WINSOUND = True
|
|
except ImportError:
|
|
HAS_WINSOUND = False
|
|
|
|
|
|
class OverlayCanvas(QtWidgets.QWidget):
|
|
"""
|
|
UI overlay for displaying a red warning box, which can be repositioned by dragging.
|
|
"""
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
|
|
# **Full-screen overlay**
|
|
screen_geo = QtWidgets.QApplication.primaryScreen().geometry()
|
|
self.setGeometry(screen_geo) # Set to full screen
|
|
|
|
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
|
|
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
|
|
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
|
|
self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent, False)
|
|
self.setAttribute(QtCore.Qt.WA_AlwaysStackOnTop, True)
|
|
|
|
# **Draggable Low Health Alert**
|
|
self.helper_LowHealthAlert = QtCore.QRect(250, 300, 900, 35) # Default Position
|
|
self.dragging = False
|
|
self.drag_offset = QtCore.QPoint()
|
|
|
|
self.setVisible(False) # Initially hidden
|
|
|
|
def paintEvent(self, event):
|
|
"""Draw the helper overlay objects."""
|
|
if not self.isVisible():
|
|
return # Don't draw anything if invisible
|
|
|
|
painter = QtGui.QPainter(self)
|
|
painter.setPen(QtCore.Qt.NoPen)
|
|
painter.setBrush(QtGui.QColor(255, 0, 0)) # Solid red rectangle
|
|
painter.drawRect(self.helper_LowHealthAlert)
|
|
|
|
# Draw bold white text centered within the rectangle
|
|
font = QtGui.QFont("Arial", 14, QtGui.QFont.Bold)
|
|
painter.setFont(font)
|
|
painter.setPen(QtGui.QColor(255, 255, 255))
|
|
|
|
text = "LOW HEALTH"
|
|
metrics = QtGui.QFontMetrics(font)
|
|
text_width = metrics.horizontalAdvance(text)
|
|
text_height = metrics.height()
|
|
text_x = self.helper_LowHealthAlert.center().x() - text_width // 2
|
|
text_y = self.helper_LowHealthAlert.center().y() + text_height // 4
|
|
|
|
painter.drawText(text_x, text_y, text)
|
|
|
|
def toggle_alert(self, state):
|
|
"""
|
|
Show or hide the overlay based on the state (1 = show, 0 = hide).
|
|
"""
|
|
self.setVisible(state == 1)
|
|
self.update()
|
|
|
|
def mousePressEvent(self, event):
|
|
"""Detect clicks inside the red box and allow dragging."""
|
|
if event.button() == QtCore.Qt.LeftButton and self.helper_LowHealthAlert.contains(event.pos()):
|
|
self.dragging = True
|
|
self.drag_offset = event.pos() - self.helper_LowHealthAlert.topLeft()
|
|
|
|
def mouseMoveEvent(self, event):
|
|
"""Handle dragging movement."""
|
|
if self.dragging:
|
|
new_x = event.pos().x() - self.drag_offset.x()
|
|
new_y = event.pos().y() - self.drag_offset.y()
|
|
self.helper_LowHealthAlert.moveTopLeft(QtCore.QPoint(new_x, new_y))
|
|
self.update()
|
|
|
|
def mouseReleaseEvent(self, event):
|
|
"""Stop dragging when the mouse button is released."""
|
|
self.dragging = False
|
|
|
|
|
|
class FlyffLowHealthAlertNode(BaseNode):
|
|
"""
|
|
Custom OdenGraphQt node that toggles a visual alert overlay and plays a beep when health is low.
|
|
"""
|
|
|
|
__identifier__ = 'bunny-lab.io.flyff_low_health_alert_node'
|
|
NODE_NAME = 'Flyff - Low Health Alert'
|
|
|
|
overlay_instance = None # Shared overlay instance
|
|
last_beep_time = 0 # Time tracking for beep interval
|
|
BEEP_INTERVAL_SECONDS = 2 # Beep every 2 seconds
|
|
|
|
def __init__(self):
|
|
super(FlyffLowHealthAlertNode, self).__init__()
|
|
|
|
# Create checkboxes to decide which kind of alert(s) to utilize
|
|
self.add_checkbox('cb_1', '', 'Sound Alert', True)
|
|
self.add_checkbox('cb_2', '', 'Visual Alert', True)
|
|
|
|
# Create Input Port
|
|
self.add_input('Toggle (1 = On | 0 = Off)', color=(200, 100, 0))
|
|
|
|
# Add text input widget to display received value
|
|
self.add_text_input('value', 'Current Value', text='0')
|
|
|
|
# Ensure only one overlay instance exists
|
|
if not FlyffLowHealthAlertNode.overlay_instance:
|
|
FlyffLowHealthAlertNode.overlay_instance = OverlayCanvas()
|
|
FlyffLowHealthAlertNode.overlay_instance.show()
|
|
|
|
def process_input(self):
|
|
"""
|
|
This function runs every 500ms (via the global update loop).
|
|
It updates the displayed value and toggles the alert if needed.
|
|
"""
|
|
input_port = self.input(0)
|
|
|
|
# If there is a connected node, fetch its output value
|
|
if input_port.connected_ports():
|
|
connected_node = input_port.connected_ports()[0].node()
|
|
if hasattr(connected_node, 'get_property'):
|
|
value = connected_node.get_property('value')
|
|
else:
|
|
value = "0"
|
|
else:
|
|
value = "0" # Default to zero if nothing is connected
|
|
|
|
try:
|
|
input_value = int(value) # Ensure we interpret input as an integer (0 or 1)
|
|
except ValueError:
|
|
input_value = 0 # Default to off if the input is not valid
|
|
|
|
# Update the value display box
|
|
self.set_property('value', str(input_value))
|
|
|
|
# Check if the "Visual Alert" checkbox is enabled
|
|
visual_alert_enabled = self.get_property('cb_2')
|
|
|
|
# Ensure that if "Visual Alert" is unchecked, the overlay is always hidden
|
|
if not visual_alert_enabled:
|
|
FlyffLowHealthAlertNode.overlay_instance.toggle_alert(0)
|
|
else:
|
|
FlyffLowHealthAlertNode.overlay_instance.toggle_alert(input_value)
|
|
|
|
# Check if "Sound Alert" is enabled and beep if necessary
|
|
self.handle_beep(input_value)
|
|
|
|
def handle_beep(self, input_value):
|
|
"""
|
|
Plays a beep sound every 2 seconds when the value is `1` and "Sound Alert" is enabled.
|
|
"""
|
|
sound_alert_enabled = self.get_property('cb_1')
|
|
current_time = time.time()
|
|
|
|
if input_value == 1 and sound_alert_enabled:
|
|
if (current_time - FlyffLowHealthAlertNode.last_beep_time) >= FlyffLowHealthAlertNode.BEEP_INTERVAL_SECONDS:
|
|
FlyffLowHealthAlertNode.last_beep_time = current_time
|
|
self.play_beep()
|
|
else:
|
|
FlyffLowHealthAlertNode.last_beep_time = 0 # Reset when health is safe
|
|
|
|
def play_beep(self):
|
|
"""
|
|
Plays a beep using `winsound.Beep` (Windows) or prints a terminal bell (`\a`).
|
|
"""
|
|
if HAS_WINSOUND:
|
|
winsound.Beep(376, 100) # 376 Hz, 100ms duration
|
|
else:
|
|
print('\a', end='') # Terminal bell for non-Windows systems
|