/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "common/events.h" #include "ultima/ultima8/audio/audio_process.h" #include "ultima/ultima8/gumps/keypad_gump.h" #include "ultima/ultima8/games/game_data.h" #include "ultima/ultima8/gfx/gump_shape_archive.h" #include "ultima/ultima8/kernel/kernel.h" #include "ultima/ultima8/kernel/mouse.h" #include "ultima/ultima8/gumps/widgets/button_widget.h" #include "ultima/ultima8/usecode/uc_process.h" namespace Ultima { namespace Ultima8 { DEFINE_RUNTIME_CLASSTYPE_CODE(KeypadGump) static const int TXT_CONTAINER_IDX = 0x100; // Actually the max val where we will allow another digit to be entered static const int MAX_CODE_VAL = 9999999; static const int CHEAT_CODE_VAL = 74697689; static const uint16 SFXNO_BUTTON = 0x3b; static const uint16 SFXNO_CORRECT = 0x32; static const uint16 SFXNO_WRONG = 0x31; static const uint16 SFXNO_DEL = 0x3a; KeypadGump::KeypadGump(int targetValue, uint16 ucnotifypid): ModalGump(0, 0, 5, 5), _value(0), _targetValue(targetValue), _ucNotifyPid(ucnotifypid) { Mouse *mouse = Mouse::get_instance(); mouse->pushMouseCursor(Mouse::MOUSE_HAND); for (int i = 0; i < 12; i++) { _buttons[i] = 0; } } KeypadGump::~KeypadGump() { Mouse::get_instance()->popMouseCursor(); } void KeypadGump::InitGump(Gump *newparent, bool take_focus) { ModalGump::InitGump(newparent, take_focus); _shape = GameData::get_instance()->getGumps()->getShape(10); UpdateDimsFromShape(); static const int buttonShapeNum = 11; static const uint16 xoffs[] = {0xc, 0x27, 0x42}; static const uint16 yoffs[] = {0x19, 0x32, 0x4a, 0x62}; for (int y = 0; y < 4; y++) { for (int x = 0; x < 3; x++) { int bnum = y * 3 + x; FrameID button_up(GameData::GUMPS, buttonShapeNum, bnum); FrameID button_down(GameData::GUMPS, buttonShapeNum, bnum + 12); Gump *widget = new ButtonWidget(xoffs[x], yoffs[y], button_up, button_down); widget->InitGump(this); widget->SetIndex(bnum); _buttons[bnum] = widget->getObjId(); } } // Default result is 0xff SetResult(0xff); } void KeypadGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool scaled) { Gump::PaintThis(surf, lerp_factor, scaled); } bool KeypadGump::OnKeyDown(int key, int mod) { uint16 sfxno = 0; bool shouldclose = false; switch (key) { case Common::KEYCODE_ESCAPE: _value = -1; shouldclose = true; break; case Common::KEYCODE_BACKSPACE: _value /= 10; sfxno = SFXNO_DEL; break; case Common::KEYCODE_RETURN: if (_value == _targetValue || _value == CHEAT_CODE_VAL) { sfxno = SFXNO_CORRECT; _value = _targetValue; SetResult(_targetValue); } else { // wrong. sfxno = SFXNO_WRONG; SetResult(0); } shouldclose = true; break; case Common::KEYCODE_0: case Common::KEYCODE_1: case Common::KEYCODE_2: case Common::KEYCODE_3: case Common::KEYCODE_4: case Common::KEYCODE_5: case Common::KEYCODE_6: case Common::KEYCODE_7: case Common::KEYCODE_8: case Common::KEYCODE_9: onDigit(key - (int)Common::KEYCODE_0); updateDigitDisplay(); sfxno = SFXNO_BUTTON; break; default: break; } AudioProcess *audio = AudioProcess::get_instance(); if (audio && sfxno) audio->playSFX(sfxno, 0x10, _objId, 1); if (shouldclose) Close(); return true; } void KeypadGump::onDigit(int digit) { assert(digit >= 0 && digit <= 9); if (_value < MAX_CODE_VAL) { _value *= 10; _value += digit; } } void KeypadGump::ChildNotify(Gump *child, uint32 message) { bool update = true; bool shouldclose = false; if (message == ButtonWidget::BUTTON_CLICK) { uint16 sfxno = SFXNO_BUTTON; int buttonNo = child->GetIndex(); if (buttonNo < 9) { onDigit(buttonNo + 1); } else if (buttonNo == 10) { onDigit(0); } else if (buttonNo == 9) { // Backspace key _value /= 10; sfxno = SFXNO_DEL; } else if (buttonNo == 11) { update = false; if (_value == _targetValue || _value == CHEAT_CODE_VAL) { sfxno = SFXNO_CORRECT; _value = _targetValue; SetResult(_targetValue); } else { // wrong. sfxno = SFXNO_WRONG; SetResult(0); } shouldclose = true; } AudioProcess *audio = AudioProcess::get_instance(); if (audio && sfxno) audio->playSFX(sfxno, 0x10, _objId, 1); } if (update) updateDigitDisplay(); if (shouldclose) Close(); } void KeypadGump::updateDigitDisplay() { Gump *txt = Gump::FindGump(&FindByIndex); if (txt) txt->Close(); txt = new Gump(25, 12, 200, 12); txt->InitGump(this); txt->SetIndex(TXT_CONTAINER_IDX); Std::vector digits; Shape *digitshape = GameData::get_instance()->getGumps()->getShape(12); int val = _value; while (val) { int digitval = val % 10; if (digitval == 0) digitval = 10; Gump *digit = new Gump(0, 0, 6, 12); digit->SetShape(digitshape, digitval - 1); digit->InitGump(txt); digits.push_back(digit); val /= 10; } int xoff = 0; while (digits.size()) { Gump *digit = digits.back(); digits.pop_back(); digit->setRelativePosition(TOP_LEFT, xoff); xoff += 6; } } void KeypadGump::Close(bool no_del) { _processResult = _value; if (_ucNotifyPid) { UCProcess *ucp = dynamic_cast(Kernel::get_instance()->getProcess(_ucNotifyPid)); assert(ucp); ucp->setReturnValue(_value); ucp->wakeUp(_value); } ModalGump::Close(no_del); } bool KeypadGump::OnTextInput(int unicode) { if (!(unicode & 0xFF80)) { //char c = unicode & 0x7F; // Could also accept numeric keyboard inputs here. // For now we do it in OnKeyDown. } return true; } uint32 KeypadGump::I_showKeypad(const uint8 *args, unsigned int /*argsize*/) { ARG_UINT16(target) UCProcess *current = dynamic_cast(Kernel::get_instance()->getRunningProcess()); assert(current); ModalGump *gump = new KeypadGump(target, current->getPid()); gump->InitGump(0); gump->setRelativePosition(CENTER); current->suspend(); return 0; } bool KeypadGump::loadData(Common::ReadStream *rs) { warning("Trying to load ModalGump"); return true; } void KeypadGump::saveData(Common::WriteStream *ws) { warning("Trying to save ModalGump"); } } // End of namespace Ultima8 } // End of namespace Ultima