269 lines
6.8 KiB
C++
269 lines
6.8 KiB
C++
/* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#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<TXT_CONTAINER_IDX>);
|
|
if (txt)
|
|
txt->Close();
|
|
txt = new Gump(25, 12, 200, 12);
|
|
txt->InitGump(this);
|
|
txt->SetIndex(TXT_CONTAINER_IDX);
|
|
|
|
Std::vector<Gump *> 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<UCProcess *>(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<UCProcess *>(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
|