diff --git a/planet/Decoration.ocd/Room.ocd/Keypad.ocd/DefCore.txt b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/DefCore.txt new file mode 100644 index 000000000..dfc7304ba --- /dev/null +++ b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/DefCore.txt @@ -0,0 +1,8 @@ +[DefCore] +id=Keypad +Version=8,0 +Category=C4D_StaticBack +Picture=0,0,112,144 +Width=14 +Height=18 +Offset=-7,-9 diff --git a/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Graphics.8.png b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Graphics.8.png new file mode 100644 index 000000000..f5504728e Binary files /dev/null and b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Graphics.8.png differ diff --git a/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Normal.8.png b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Normal.8.png new file mode 100644 index 000000000..d8c417df5 Binary files /dev/null and b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Normal.8.png differ diff --git a/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Script.c b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Script.c new file mode 100644 index 000000000..c70840130 --- /dev/null +++ b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/Script.c @@ -0,0 +1,366 @@ +/** + Keypad + allows to enter digit codes to trigger an event. + + @author Maikel +*/ + +// Background colors for hovering and bars and description. +static const KEYPADMENU_BackgroundColor = 0x77000000; +static const KEYPADMENU_HoverColor = 0x99888888; +static const KEYPADMENU_BarColor = 0x99888888; + +local code, correct_code; +local target_door; +local correct_code_action, wrong_code_action; +local menu, menu_id, menu_target, menu_controller; + + +/*-- Script Interface --*/ + +public func SetKeypadCode(string to_code) +{ + // Check if code contains any non-digits. + var non_digits = RegexMatch(to_code, "[^0-9]+"); + if (!DeepEqual(non_digits, [])) + { + Log("$WarningKeypadCode$", to_code); + return; + } + // If code is valid, set it. + correct_code = to_code; + return; +} + +public func SetStoneDoor(object door) +{ + target_door = door; + return true; +} + +public func OpenDoor(object clonk) +{ + SetPlrView(clonk->GetController(), target_door); + var y_off = target_door->~GetFloorOffset(); + Global->CreateLight(target_door->GetX(), target_door->GetY() + y_off, 30, Fx_Light.LGT_Temp, clonk->GetController(), 30, 50); + target_door->OpenDoor(); + return; +} + +public func OnCorrectCodeEntered(object clonk) +{ + // Open door if specified. + if (target_door) + OpenDoor(clonk); + // Perform user action last; it may delete the door/clonk/etc. + UserAction->EvaluateAction(correct_code_action, this, clonk); + return; +} + +public func OnWrongCodeEntered(object clonk) +{ + // Perform user action last; it may delete the door/clonk/etc. + UserAction->EvaluateAction(wrong_code_action, this, clonk); + return; +} + +public func SetCodeActions(new_correct_action, new_wrong_action) +{ + correct_code_action = new_correct_action; + wrong_code_action = new_wrong_action; + return; +} + + +/*-- Saving --*/ + +public func SaveScenarioObject(proplist props) +{ + if (!_inherited(props, ...)) return false; + if (correct_code) props->AddCall("Code", this, "SetKeypadCode", Format("%v", correct_code)); + if (target_door) props->AddCall("Target", this, "SetStoneDoor", target_door); + if (correct_code_action || wrong_code_action) props->AddCall("Action", this, "SetCodeActions", correct_code_action, wrong_code_action); + return true; +} + + +/*-- Editor --*/ + +public func Definition(proplist def) +{ + if (!def.EditorProps) + def.EditorProps = {}; + def.EditorProps.correct_code = { Name = "$KeypadCode$", Type = "string", Set="SetKeypadCode", EditorHelp = "$HelpKeypadCode$" }; + def.EditorProps.target_door = { Name = "$KeypadTarget$", Type = "object", Filter = "IsSwitchTarget", EditorHelp = "$HelpKeypadTarget$" }; + def.EditorProps.correct_code_action = new UserAction.Prop { Name = "$OnCorrectCodeAction$", EditorHelp = "$HelpOnCorrectCodeAction$" }; + def.EditorProps.wrong_code_action = new UserAction.Prop { Name = "$OnWrongCodeAction$", EditorHelp = "$HelpOnWrongCodeAction$" }; + return; +} + + +/*-- Interaction --*/ + +public func IsInteractable(object clonk) +{ + return clonk->GetProcedure() == "WALK" && (!clonk->GetMenu() || clonk->GetMenu().ID != menu_id); +} + +public func Interact(object clonk) +{ + code = ""; + OpenKeypadMenu(clonk); + return true; +} + + +/*-- Menu --*/ + +public func OpenKeypadMenu(object clonk) +{ + // Only one clonk at a time can handle the keypad. + if (menu_controller) + return; + + // If the menu is already open, don't open another instance. + if (clonk->GetMenu() && clonk->GetMenu().ID == menu_id) + return; + + // This object functions as menu target and for visibility. + menu_target = CreateContents(Dummy); + menu_target.Visibility = VIS_Owner; + menu_target->SetOwner(clonk->GetOwner()); + menu_controller = clonk; + + // Make the room/credits menu. + menu = + { + Target = menu_target, + Left = "50%-6em", + Right = "50%+6em", + Top = "50%-10em", + Bottom = "50%+8em", + Decoration = GUI_MenuDeco, + BackgroundColor = {Std = KEYPADMENU_BackgroundColor}, + }; + menu.code = + { + Target = this, + ID = 2, + Bottom = "1.5em", + text = + { + Target = this, + ID = 21, + Right = "4em", + Style = GUI_TextVCenter, + Text = "$MsgEnterCode$" + }, + value = + { + Target = this, + ID = 22, + Left = "4em", + Right = "100%-0.05em", + Style = GUI_TextVCenter | GUI_TextRight, + Text = nil + } + }; + menu.bar = + { + Target = this, + ID = 3, + Top = "1.5em", + Bottom = "2em", + BackgroundColor = {Std = ROOMMENU_BarColor}, + }; + menu.keys = + { + Target = this, + ID = 4, + Top = "2em", + }; + menu.keys.key1 = MakePadButton(0, 0, Icon_Number, "1", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 1)); + menu.keys.key2 = MakePadButton(1, 0, Icon_Number, "2", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 2)); + menu.keys.key3 = MakePadButton(2, 0, Icon_Number, "3", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 3)); + menu.keys.key4 = MakePadButton(0, 1, Icon_Number, "4", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 4)); + menu.keys.key5 = MakePadButton(1, 1, Icon_Number, "5", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 5)); + menu.keys.key6 = MakePadButton(2, 1, Icon_Number, "6", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 6)); + menu.keys.key7 = MakePadButton(0, 2, Icon_Number, "7", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 7)); + menu.keys.key8 = MakePadButton(1, 2, Icon_Number, "8", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 8)); + menu.keys.key9 = MakePadButton(2, 2, Icon_Number, "9", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 9)); + menu.keys.key0 = MakePadButton(1, 3, Icon_Number, "0", "$TooltipDigit$", GuiAction_Call(this, "UpdateMenuCode", 0)); + menu.keys.enter = MakePadButton(2, 3, Icon_Ok, nil, "$TooltipCheck$", GuiAction_Call(this, "EnterKeypadCode", nil)); + + menu.keys.clearlast = MakePadButton(0, 0, Icon_Number, "Hash", "$TooltipClearLast$", GuiAction_Call(this, "UpdateMenuCode", nil)); + menu.keys.clearlast.Left = "0em"; menu.keys.clearlast.Right = "2em"; menu.keys.clearlast.Top = "12em"; menu.keys.clearlast.Bottom = "14em"; + menu.keys.clearlast.image = {Left = "50%", Top = "50%", Symbol = Icon_Arrow, GraphicsName = "Left"}; + + menu.keys.clearcode = MakePadButton(0, 0, Icon_Number, "Hash", "$TooltipClearCode$", GuiAction_Call(this, "ClearMenuCode", nil)); + menu.keys.clearcode.Left = "2em"; menu.keys.clearcode.Right = "4em"; menu.keys.clearcode.Top = "12em"; menu.keys.clearcode.Bottom = "14em"; + menu.keys.clearcode.image = {Left = "50%", Top = "50%", Symbol = Icon_Cancel}; + + menu.keys.resetcode = MakePadButton(0, 0, Icon_Number, "Hash", "$TooltipResetCode$", GuiAction_Call(this, "ResetKeypadCode", nil)); + menu.keys.resetcode.Left = "2em"; menu.keys.resetcode.Right = "4em"; menu.keys.resetcode.Top = "14em"; menu.keys.resetcode.Bottom = "16em"; + menu.keys.resetcode.image = {Left = "50%", Top = "50%", Symbol = Icon_Swap}; + + menu.keys.close = MakePadButton(0, 0, Icon_Cancel, nil, "$TooltipClose$", GuiAction_Call(this, "CloseKeypadMenu", nil)); + menu.keys.close.Left = "0em"; menu.keys.close.Right = "2em"; menu.keys.close.Top = "14em"; menu.keys.close.Bottom = "16em"; + + // Open the menu and store the menu ID. + menu_id = GuiOpen(menu); + // Notify the clonk and set the menu. + clonk->SetMenu(this); + return; +} + +public func MakePadButton(int x, int y, id symbol, string graphics_name, string tooltip, on_click) +{ + return { + Left = Format("%dem", 4 * x), + Right = Format("%dem", 4 * (x + 1)), + Top = Format("%dem", 4 * y), + Bottom = Format("%dem", 4 * (y + 1)), + Symbol = symbol, + GraphicsName = graphics_name, + BackgroundColor = {Std = 0, Hover = KEYPADMENU_HoverColor}, + OnMouseIn = GuiAction_SetTag("Hover"), + OnMouseOut = GuiAction_SetTag("Std"), + OnClick = on_click, + Tooltip = tooltip + }; +} + +public func UpdateMenuCode(int digit_pressed) +{ + if (digit_pressed == nil) + { + if (GetType(code) == C4V_String) + code = TakeString(code, 0, GetLength(code) - 1); + Sound("UI::Click?"); + } + else + { + if (code == nil) + code = Format("%d", digit_pressed); + else + code = Format("%s%d", code, digit_pressed); + Sound("UI::Tick"); + } + menu.code.value.Text = code; + GuiUpdate(menu.code.value, menu_id, menu.code.value.ID, this); + return; +} + +public func ClearMenuCode() +{ + code = nil; + Sound("UI::Click?"); + menu.code.value.Text = code; + GuiUpdate(menu.code.value, menu_id, menu.code.value.ID, this); + return; +} + +public func EnterKeypadCode() +{ + if (menu_controller.code_reset_state == "reset") + { + correct_code = code; + code = nil; + menu.code.value.Text = "$MsgCodeReset$"; + menu_controller.code_reset_state = nil; + Sound("UI::Confirmed"); + menu.code.text.Text = "$MsgEnterCode$"; + GuiUpdate(menu.code.text, menu_id, menu.code.text.ID, this); + } + else + { + if (correct_code == nil) + { + code = nil; + menu.code.value.Text = "$MsgNoCode$"; + Sound("UI::Error"); + } + else if (correct_code == code) + { + code = nil; + Sound("UI::Confirmed"); + if (menu_controller.code_reset_state == "confirm") + { + menu.code.value.Text = "$MsgCodeConfirmed$"; + menu_controller.code_reset_state = "reset"; + menu.code.text.Text = "$MsgEnterNewCode$"; + GuiUpdate(menu.code.text, menu_id, menu.code.text.ID, this); + } + else + { + menu.code.value.Text = "$MsgCorrectCode$"; + // Execute the correct code trigger. + OnCorrectCodeEntered(menu_controller); + } + } + else + { + code = nil; + menu.code.value.Text = "$MsgWrongCode$"; + Sound("UI::Error"); + // Execute the wrong code trigger. + OnWrongCodeEntered(menu_controller); + } + } + GuiUpdate(menu.code.value, menu_id, menu.code.value.ID, this); + return; +} + +public func ResetKeypadCode() +{ + // Only allow resetting the code if the clonk (menu_target) has entered the correct code before. + if (correct_code == nil) + { + menu_controller.code_reset_state = "reset"; + menu.code.text.Text = "$MsgEnterNewCode$"; + GuiUpdate(menu.code.text, menu_id, menu.code.text.ID, this); + } + else if (menu_controller.code_reset_state != "reset" && menu_controller.code_reset_state != "confirm") + { + menu_controller.code_reset_state = "confirm"; + menu.code.text.Text = "$MsgConfirmCode$"; + GuiUpdate(menu.code.text, menu_id, menu.code.text.ID, this); + } + else + { + menu_controller.code_reset_state = nil; + menu.code.text.Text = "$MsgEnterCode$"; + GuiUpdate(menu.code.text, menu_id, menu.code.text.ID, this); + } + Sound("UI::Tick"); + return; +} + +public func CloseKeypadMenu() +{ + // Close the menu and inform the controller. + Sound("UI::Close"); + GuiClose(menu_id, nil, this); + menu_target->RemoveObject(); + menu_target = nil; + menu_id = nil; + if (menu_controller) + { + menu_controller.code_reset_state = nil; + menu_controller->MenuClosed(); + } + menu_controller = nil; + return; +} + +public func Close() +{ + CloseKeypadMenu(); + return; +} + + +/*-- Properties --*/ + +local Name = "$Name$"; +local Description = "$Description$"; \ No newline at end of file diff --git a/planet/Decoration.ocd/Room.ocd/Keypad.ocd/StringTblDE.txt b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/StringTblDE.txt new file mode 100644 index 000000000..fce68adc9 --- /dev/null +++ b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/StringTblDE.txt @@ -0,0 +1,28 @@ +Name=Ziffernblock +Description=Richtiger Kennzahl eingeben um ein Ereignis aus zu lösen. + +MsgEnterCode=Kennzahl eingeben: +MsgEnterNewCode=Neue Kennzahl: +MsgConfirmCode=Kennzahl bestätigen: +MsgNoCode=Ziffernblock hat kein Kennzahl! +MsgCorrectCode=Richtiger Kennzahl! +MsgWrongCode=Falscher Kennzahl! +MsgCodeReset=Kennzahl wurde zurück gesetzt! +MsgCodeConfirmed=Kennzahl bestätigt, jetzt zurücksetzen. + +TooltipDigit=Gebe Nummer ein. +TooltipCheck=Kontrolliere die eingebene Kennzahl. +TooltipClose=Schließe das Ziffernblock. +TooltipClearLast=Entferne die letzte Nummer. +TooltipClearCode=Eingegebene Kennzahl löschen. +TooltipResetCode=Die Kennzahl des Ziffernblocks zurücksetzen. + +KeypadCode=Kennzahl +KeypadTarget=Ziel +OnCorrectCodeAction=Aktion 'richtige Kennzahl' +OnWrongCodeAction=Aktion 'falsche Kennzahl' +HelpKeypadCode=Gib den Kennzahl ein der vom Spieler eingetippt werden muss (darf nur Zahlen enthalten). +HelpKeypadTarget=Tür die geöffnet wird wenn den richtigen Kennzahl eingegeben wird. +HelpOnCorrectCodeAction=Aktion die ausgeführt wird wenn die richtige Kennzahl eingegeben wird. +HelpOnWrongCodeAction=Aktion die ausgeführt wird wenn eine falsche Kennzahl eingegeben wird. +WarningKeypadCode=WARNUNG: Kennzahl vom Ziffernblock (%s) enthält Charaktere die nicht Zahlen sind, Kennzahl wird nicht gesetzt. \ No newline at end of file diff --git a/planet/Decoration.ocd/Room.ocd/Keypad.ocd/StringTblUS.txt b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/StringTblUS.txt new file mode 100644 index 000000000..23a9d1eab --- /dev/null +++ b/planet/Decoration.ocd/Room.ocd/Keypad.ocd/StringTblUS.txt @@ -0,0 +1,28 @@ +Name=Keypad +Description=Enter the correct code to trigger an event. + +MsgEnterCode=Enter code: +MsgEnterNewCode=New code: +MsgConfirmCode=Confirm code: +MsgNoCode=Keypad has no code! +MsgCorrectCode=Correct code! +MsgWrongCode=Wrong code! +MsgCodeReset=Code has been reset! +MsgCodeConfirmed=Code confirmed, reset now. + +TooltipDigit=Enter digit. +TooltipCheck=Check the entered code. +TooltipClose=Close the keypad. +TooltipClearLast=Delete the last digit. +TooltipClearCode=Clear the entered code. +TooltipResetCode=Reset the keypad code. + +KeypadCode=Code +KeypadTarget=Target +OnCorrectCodeAction=Action 'correct code' +OnWrongCodeAction=Action 'wrong code' +HelpKeypadCode=Enter the keypad code the player must type in (must be digits only). +HelpKeypadTarget=Target door that will be opened when the correct has been entered. +HelpOnCorrectCodeAction=Action to be executed when the correct code has been entered. +HelpOnWrongCodeAction=Action to be executed when a wrong code has been entered. +WarningKeypadCode=WARNING: keypad code (%s) contains some non-digit characters, code will not be set. \ No newline at end of file