Initial commit
This commit is contained in:
65
engines/zvision/core/clock.cpp
Normal file
65
engines/zvision/core/clock.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "zvision/core/clock.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
Clock::Clock(OSystem *system)
|
||||
: _system(system),
|
||||
_lastTime(system->getMillis()),
|
||||
_deltaTime(0),
|
||||
_pausedTime(0),
|
||||
_paused(false) {
|
||||
}
|
||||
|
||||
void Clock::update() {
|
||||
uint32 currentTime = _system->getMillis();
|
||||
|
||||
_deltaTime = (currentTime - _lastTime);
|
||||
if (_paused) {
|
||||
_deltaTime -= (currentTime - _pausedTime);
|
||||
}
|
||||
|
||||
if (_deltaTime < 0) {
|
||||
_deltaTime = 0;
|
||||
}
|
||||
|
||||
_lastTime = currentTime;
|
||||
}
|
||||
|
||||
void Clock::start() {
|
||||
if (_paused) {
|
||||
_lastTime = _system->getMillis();
|
||||
_paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Clock::stop() {
|
||||
if (!_paused) {
|
||||
_pausedTime = _system->getMillis();
|
||||
_paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace ZVision
|
||||
83
engines/zvision/core/clock.h
Normal file
83
engines/zvision/core/clock.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ZVISION_CLOCK_H
|
||||
#define ZVISION_CLOCK_H
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
/* Class for handling frame to frame deltaTime while keeping track of time pauses/un-pauses */
|
||||
class Clock {
|
||||
public:
|
||||
Clock(OSystem *system);
|
||||
|
||||
private:
|
||||
OSystem *_system;
|
||||
uint32 _lastTime;
|
||||
int32 _deltaTime;
|
||||
uint32 _pausedTime;
|
||||
bool _paused;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Updates _deltaTime with the difference between the current time and
|
||||
* when the last update() was called.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Get the delta time since the last frame. (The time between update() calls)
|
||||
*
|
||||
* @return Delta time since the last frame (in milliseconds)
|
||||
*/
|
||||
uint32 getDeltaTime() const {
|
||||
return _deltaTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time from the program starting to the last update() call
|
||||
*
|
||||
* @return Time from program start to last update() call (in milliseconds)
|
||||
*/
|
||||
uint32 getLastMeasuredTime() {
|
||||
return _lastTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-pause the clock.
|
||||
* Has no effect if the clock is already un-paused.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Pause the clock. Any future delta times will take this pause into account.
|
||||
* Has no effect if the clock is already paused.
|
||||
*/
|
||||
void stop();
|
||||
};
|
||||
|
||||
} // End of namespace ZVision
|
||||
|
||||
#endif
|
||||
370
engines/zvision/core/console.cpp
Normal file
370
engines/zvision/core/console.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/* 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 "audio/mixer.h"
|
||||
#include "common/bufferedstream.h"
|
||||
#include "common/file.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "gui/debugger.h"
|
||||
#include "zvision/zvision.h"
|
||||
#include "zvision/core/console.h"
|
||||
#include "zvision/graphics/render_manager.h"
|
||||
#include "zvision/graphics/cursors/cursor.h"
|
||||
#include "zvision/scripting/script_manager.h"
|
||||
#include "zvision/sound/zork_raw.h"
|
||||
#include "zvision/text/string_manager.h"
|
||||
#include "zvision/video/zork_avi_decoder.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
Console::Console(ZVision *engine) : GUI::Debugger(), _engine(engine) {
|
||||
registerCmd("loadvideo", WRAP_METHOD(Console, cmdLoadVideo));
|
||||
registerCmd("loadsound", WRAP_METHOD(Console, cmdLoadSound));
|
||||
registerCmd("raw2wav", WRAP_METHOD(Console, cmdRawToWav));
|
||||
registerCmd("setrenderstate", WRAP_METHOD(Console, cmdSetRenderState));
|
||||
registerCmd("generaterendertable", WRAP_METHOD(Console, cmdGenerateRenderTable));
|
||||
registerCmd("setpanoramafov", WRAP_METHOD(Console, cmdSetPanoramaFoV));
|
||||
registerCmd("setpanoramascale", WRAP_METHOD(Console, cmdSetPanoramaScale));
|
||||
registerCmd("location", WRAP_METHOD(Console, cmdLocation));
|
||||
registerCmd("dumpfile", WRAP_METHOD(Console, cmdDumpFile));
|
||||
registerCmd("dumpfiles", WRAP_METHOD(Console, cmdDumpFiles));
|
||||
registerCmd("dumpimage", WRAP_METHOD(Console, cmdDumpImage));
|
||||
registerCmd("statevalue", WRAP_METHOD(Console, cmdStateValue));
|
||||
registerCmd("stateflag", WRAP_METHOD(Console, cmdStateFlag));
|
||||
}
|
||||
|
||||
bool Console::cmdLoadVideo(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Use %s <fileName> to load a video to the screen\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZorkAVIDecoder videoDecoder;
|
||||
if (videoDecoder.loadFile(argv[1])) {
|
||||
_engine->playVideo(videoDecoder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdLoadSound(int argc, const char **argv) {
|
||||
if (!Common::File::exists(argv[1])) {
|
||||
debugPrintf("File does not exist\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
Audio::AudioStream *soundStream = makeRawZorkStream(argv[1], _engine);
|
||||
Audio::SoundHandle handle;
|
||||
_engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, soundStream, -1, 100, 0, DisposeAfterUse::YES, false, false);
|
||||
} else if (argc == 4) {
|
||||
int isStereo = atoi(argv[3]);
|
||||
|
||||
Common::File *file = new Common::File();
|
||||
if (!file->open(argv[1])) {
|
||||
warning("File not found: %s", argv[1]);
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
Audio::AudioStream *soundStream = makeRawZorkStream(file, atoi(argv[2]), isStereo == 0 ? false : true);
|
||||
Audio::SoundHandle handle;
|
||||
_engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, soundStream, -1, 100, 0, DisposeAfterUse::YES, false, false);
|
||||
} else {
|
||||
debugPrintf("Use %s <fileName> [<rate> <isStereo: 1 or 0>] to load a sound\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdRawToWav(int argc, const char **argv) {
|
||||
if (argc != 3) {
|
||||
debugPrintf("Use %s <rawFilePath> <wavFileName> to dump a .RAW file to .WAV\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::File file;
|
||||
if (!file.open(argv[1])) {
|
||||
warning("File not found: %s", argv[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Audio::AudioStream *audioStream = makeRawZorkStream(argv[1], _engine);
|
||||
|
||||
Common::DumpFile output;
|
||||
output.open(argv[2]);
|
||||
|
||||
output.writeUint32BE(MKTAG('R', 'I', 'F', 'F'));
|
||||
output.writeUint32LE(file.size() * 2 + 36);
|
||||
output.writeUint32BE(MKTAG('W', 'A', 'V', 'E'));
|
||||
output.writeUint32BE(MKTAG('f', 'm', 't', ' '));
|
||||
output.writeUint32LE(16);
|
||||
output.writeUint16LE(1);
|
||||
uint16 numChannels;
|
||||
if (audioStream->isStereo()) {
|
||||
numChannels = 2;
|
||||
output.writeUint16LE(2);
|
||||
} else {
|
||||
numChannels = 1;
|
||||
output.writeUint16LE(1);
|
||||
}
|
||||
output.writeUint32LE(audioStream->getRate());
|
||||
output.writeUint32LE(audioStream->getRate() * numChannels * 2);
|
||||
output.writeUint16LE(numChannels * 2);
|
||||
output.writeUint16LE(16);
|
||||
output.writeUint32BE(MKTAG('d', 'a', 't', 'a'));
|
||||
output.writeUint32LE(file.size() * 2);
|
||||
int16 *buffer = new int16[file.size()];
|
||||
audioStream->readBuffer(buffer, file.size());
|
||||
#ifndef SCUMM_LITTLE_ENDIAN
|
||||
for (int i = 0; i < file.size(); ++i)
|
||||
buffer[i] = TO_LE_16(buffer[i]);
|
||||
#endif
|
||||
output.write(buffer, file.size() * 2);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdSetRenderState(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Use %s <RenderState: panorama, tilt, flat> to change the current render state\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::String renderState(argv[1]);
|
||||
|
||||
if (renderState.matchString("panorama", true))
|
||||
_engine->getRenderManager()->getRenderTable()->setRenderState(RenderTable::PANORAMA);
|
||||
else if (renderState.matchString("tilt", true))
|
||||
_engine->getRenderManager()->getRenderTable()->setRenderState(RenderTable::TILT);
|
||||
else if (renderState.matchString("flat", true))
|
||||
_engine->getRenderManager()->getRenderTable()->setRenderState(RenderTable::FLAT);
|
||||
else
|
||||
debugPrintf("Use %s <RenderState: panorama, tilt, flat> to change the current render state\n", argv[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdGenerateRenderTable(int argc, const char **argv) {
|
||||
_engine->getRenderManager()->getRenderTable()->generateRenderTable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdSetPanoramaFoV(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Use %s <fieldOfView> to change the current panorama field of view\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->getRenderManager()->getRenderTable()->setPanoramaFoV(atof(argv[1]));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdSetPanoramaScale(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Use %s <scale> to change the current panorama scale\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->getRenderManager()->getRenderTable()->setPanoramaScale(atof(argv[1]));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdLocation(int argc, const char **argv) {
|
||||
Location curLocation = _engine->getScriptManager()->getCurrentLocation();
|
||||
Common::String scrFile = Common::String::format("%c%c%c%c.scr", curLocation.world, curLocation.room, curLocation.node, curLocation.view);
|
||||
debugPrintf("Current location: world '%c', room '%c', node '%c', view '%c', offset %d, script %s\n",
|
||||
curLocation.world, curLocation.room, curLocation.node, curLocation.view, curLocation.offset, scrFile.c_str());
|
||||
|
||||
if (argc != 6) {
|
||||
debugPrintf("Use %s <char: world> <char: room> <char:node> <char:view> <int: x offset> to change your location\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->getScriptManager()->changeLocation(*(argv[1]), *(argv[2]), *(argv[3]), *(argv[4]), atoi(argv[5]));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dumpFile(Common::SeekableReadStream *s, const Common::Path &outName) {
|
||||
byte *buffer = new byte[s->size()];
|
||||
s->read(buffer, s->size());
|
||||
|
||||
Common::DumpFile dumpFile;
|
||||
dumpFile.open(outName);
|
||||
|
||||
dumpFile.write(buffer, s->size());
|
||||
dumpFile.flush();
|
||||
dumpFile.close();
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool Console::cmdDumpFile(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Use %s <fileName> to dump a file\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::File f;
|
||||
if (!f.open(argv[1])) {
|
||||
warning("File not found: %s", argv[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
dumpFile(&f, argv[1]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdDumpFiles(int argc, const char **argv) {
|
||||
Common::Path fileName;
|
||||
Common::SeekableReadStream *in;
|
||||
|
||||
if (argc != 2) {
|
||||
debugPrintf("Use %s <file extension> to dump all files with a specific extension\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::ArchiveMemberList fileList;
|
||||
Common::Path pattern;
|
||||
pattern = Common::Path(Common::String::format("*.%s", argv[1]));
|
||||
SearchMan.listMatchingMembers(fileList, pattern);
|
||||
|
||||
for (auto &file : fileList) {
|
||||
fileName = file.get()->getFileName();
|
||||
debugPrintf("Dumping %s\n", fileName.toString().c_str());
|
||||
|
||||
in = file.get()->createReadStream();
|
||||
if (in)
|
||||
dumpFile(in, fileName);
|
||||
else
|
||||
debugPrintf("Failed to dump!");
|
||||
delete in;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdDumpImage(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Use %s <TGA/TGZ name> to dump a Z-Vision TGA/TGZ image into a regular BMP image\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::Path fileName = Common::Path(argv[1], Common::Path::kNativeSeparator);
|
||||
Common::String baseName(fileName.baseName());
|
||||
if (!baseName.hasSuffix(".tga")) {
|
||||
debugPrintf("%s is not an image file", argv[1]);
|
||||
}
|
||||
|
||||
Common::File f;
|
||||
if (!f.open(fileName)) {
|
||||
warning("File not found: %s", argv[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Graphics::Surface surface;
|
||||
_engine->getRenderManager()->readImageToSurface(fileName, surface, false);
|
||||
|
||||
// Open file
|
||||
Common::DumpFile out;
|
||||
|
||||
baseName.setChar('b', baseName.size() - 3);
|
||||
baseName.setChar('m', baseName.size() - 2);
|
||||
baseName.setChar('p', baseName.size() - 1);
|
||||
|
||||
out.open(fileName.getParent().appendComponent(baseName));
|
||||
|
||||
// Write BMP header
|
||||
out.writeByte('B');
|
||||
out.writeByte('M');
|
||||
out.writeUint32LE(surface.h * surface.pitch + 54);
|
||||
out.writeUint32LE(0);
|
||||
out.writeUint32LE(54);
|
||||
out.writeUint32LE(40);
|
||||
out.writeUint32LE(surface.w);
|
||||
out.writeUint32LE(surface.h);
|
||||
out.writeUint16LE(1);
|
||||
out.writeUint16LE(16);
|
||||
out.writeUint32LE(0);
|
||||
out.writeUint32LE(0);
|
||||
out.writeUint32LE(0);
|
||||
out.writeUint32LE(0);
|
||||
out.writeUint32LE(0);
|
||||
out.writeUint32LE(0);
|
||||
|
||||
// Write pixel data to BMP
|
||||
out.write(surface.getPixels(), surface.pitch * surface.h);
|
||||
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
surface.free();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdStateValue(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Use %s <valuenum> to show the value of a state variable\n", argv[0]);
|
||||
debugPrintf("Use %s <valuenum> <newvalue> to set the value of a state variable\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int valueNum = atoi(argv[1]);
|
||||
int newValue = (argc > 2) ? atoi(argv[2]) : -1;
|
||||
|
||||
if (argc == 2)
|
||||
debugPrintf("[%d] = %d\n", valueNum, _engine->getScriptManager()->getStateValue(valueNum));
|
||||
else if (argc == 3)
|
||||
_engine->getScriptManager()->setStateValue(valueNum, newValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdStateFlag(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Use %s <flagnum> to show the value of a state flag\n", argv[0]);
|
||||
debugPrintf("Use %s <flagnum> <newvalue> to set the value of a state flag\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int valueNum = atoi(argv[1]);
|
||||
int newValue = (argc > 2) ? atoi(argv[2]) : -1;
|
||||
|
||||
if (argc == 2)
|
||||
debugPrintf("[%d] = %d\n", valueNum, _engine->getScriptManager()->getStateFlag(valueNum));
|
||||
else if (argc == 3)
|
||||
_engine->getScriptManager()->setStateFlag(valueNum, newValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace ZVision
|
||||
55
engines/zvision/core/console.h
Normal file
55
engines/zvision/core/console.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ZVISION_CONSOLE_H
|
||||
#define ZVISION_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
class ZVision;
|
||||
|
||||
class Console : public GUI::Debugger {
|
||||
public:
|
||||
Console(ZVision *engine);
|
||||
~Console() override {}
|
||||
|
||||
private:
|
||||
ZVision *_engine;
|
||||
|
||||
bool cmdLoadVideo(int argc, const char **argv);
|
||||
bool cmdLoadSound(int argc, const char **argv);
|
||||
bool cmdRawToWav(int argc, const char **argv);
|
||||
bool cmdSetRenderState(int argc, const char **argv);
|
||||
bool cmdGenerateRenderTable(int argc, const char **argv);
|
||||
bool cmdSetPanoramaFoV(int argc, const char **argv);
|
||||
bool cmdSetPanoramaScale(int argc, const char **argv);
|
||||
bool cmdLocation(int argc, const char **argv);
|
||||
bool cmdDumpFile(int argc, const char **argv);
|
||||
bool cmdDumpFiles(int argc, const char **argv);
|
||||
bool cmdDumpImage(int argc, const char **argv);
|
||||
bool cmdStateValue(int argc, const char **argv);
|
||||
bool cmdStateFlag(int argc, const char **argv);
|
||||
};
|
||||
|
||||
} // End of namespace ZVision
|
||||
#endif
|
||||
493
engines/zvision/core/events.cpp
Normal file
493
engines/zvision/core/events.cpp
Normal file
@@ -0,0 +1,493 @@
|
||||
/* 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 "audio/mixer.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/events.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/system.h"
|
||||
#include "common/rational.h"
|
||||
#include "engines/util.h"
|
||||
#include "zvision/detection.h"
|
||||
#include "zvision/zvision.h"
|
||||
#include "zvision/core/console.h"
|
||||
#include "zvision/graphics/cursors/cursor_manager.h"
|
||||
#include "zvision/graphics/render_manager.h"
|
||||
#include "zvision/scripting/script_manager.h"
|
||||
#include "zvision/scripting/menu.h"
|
||||
#include "zvision/sound/zork_raw.h"
|
||||
#include "zvision/text/string_manager.h"
|
||||
#include "zvision/text/subtitle_manager.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
void ZVision::pushKeyToCheatBuf(uint8 key) {
|
||||
for (int i = 0; i < KEYBUF_SIZE - 1; i++)
|
||||
_cheatBuffer[i] = _cheatBuffer[i + 1];
|
||||
_cheatBuffer[KEYBUF_SIZE - 1] = key;
|
||||
}
|
||||
|
||||
bool ZVision::checkCode(const char *code) {
|
||||
int codeLen = strlen(code);
|
||||
if (codeLen > KEYBUF_SIZE)
|
||||
return false;
|
||||
for (int i = 0; i < codeLen; i++)
|
||||
if (code[i] != _cheatBuffer[KEYBUF_SIZE - codeLen + i] && code[i] != '?')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 ZVision::getBufferedKey(uint8 pos) {
|
||||
if (pos >= KEYBUF_SIZE)
|
||||
return 0;
|
||||
else
|
||||
return _cheatBuffer[KEYBUF_SIZE - pos - 1];
|
||||
}
|
||||
|
||||
void ZVision::cheatCodes(uint8 key) {
|
||||
Location loc = _scriptManager->getCurrentLocation();
|
||||
// Do not process cheat codes while in the game menus
|
||||
if (loc.world == 'g' && loc.room == 'j')
|
||||
return;
|
||||
|
||||
pushKeyToCheatBuf(key);
|
||||
|
||||
if (getGameId() == GID_GRANDINQUISITOR) {
|
||||
if (checkCode("IMNOTDEAF")) {
|
||||
// Unknown cheat
|
||||
_subtitleManager->showDebugMsg(Common::String::format("IMNOTDEAF cheat or debug, not implemented"));
|
||||
}
|
||||
|
||||
if (checkCode("3100OPB")) {
|
||||
_subtitleManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c",
|
||||
_scriptManager->getStateValue(StateKey_World),
|
||||
_scriptManager->getStateValue(StateKey_Room),
|
||||
_scriptManager->getStateValue(StateKey_Node),
|
||||
_scriptManager->getStateValue(StateKey_View)));
|
||||
}
|
||||
|
||||
if (checkCode("KILLMENOW")) {
|
||||
_scriptManager->changeLocation('g', 'j', 'd', 'e', 0);
|
||||
_scriptManager->setStateValue(2201, 35);
|
||||
}
|
||||
|
||||
if (checkCode("MIKESPANTS")) {
|
||||
_scriptManager->changeLocation('g', 'j', 't', 'm', 0);
|
||||
}
|
||||
|
||||
// There are 3 more cheats in script files:
|
||||
// - "WHOAMI": gjcr.scr
|
||||
// - "HUISOK": hp1e.scr
|
||||
// - "EAT ME": uh1f.scr
|
||||
} else if (getGameId() == GID_NEMESIS) {
|
||||
if (checkCode("CHLOE")) {
|
||||
_scriptManager->changeLocation('t', 'm', '2', 'g', 0);
|
||||
_scriptManager->setStateValue(224, 1);
|
||||
}
|
||||
|
||||
if (checkCode("77MASSAVE")) {
|
||||
_subtitleManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c",
|
||||
_scriptManager->getStateValue(StateKey_World),
|
||||
_scriptManager->getStateValue(StateKey_Room),
|
||||
_scriptManager->getStateValue(StateKey_Node),
|
||||
_scriptManager->getStateValue(StateKey_View)));
|
||||
}
|
||||
|
||||
if (checkCode("IDKFA")) {
|
||||
_scriptManager->changeLocation('t', 'w', '3', 'f', 0);
|
||||
_scriptManager->setStateValue(249, 1);
|
||||
}
|
||||
|
||||
if (checkCode("309NEWDORMA")) {
|
||||
_scriptManager->changeLocation('g', 'j', 'g', 'j', 0);
|
||||
}
|
||||
|
||||
if (checkCode("HELLOSAILOR")) {
|
||||
Audio::AudioStream *soundStream;
|
||||
if (loc == "vb10") {
|
||||
soundStream = makeRawZorkStream("v000hpta.raw", this);
|
||||
} else {
|
||||
soundStream = makeRawZorkStream("v000hnta.raw", this);
|
||||
}
|
||||
Audio::SoundHandle handle;
|
||||
_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, soundStream);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkCode("FRAME")) {
|
||||
Common::String fpsStr = Common::String::format("FPS: %d", getFPS());
|
||||
_subtitleManager->showDebugMsg(fpsStr);
|
||||
}
|
||||
|
||||
if (checkCode("COMPUTERARCH"))
|
||||
_subtitleManager->showDebugMsg("COMPUTERARCH: var-viewer not implemented");
|
||||
|
||||
// This cheat essentially toggles the GOxxxx cheat below
|
||||
if (checkCode("XYZZY"))
|
||||
_scriptManager->setStateValue(StateKey_DebugCheats, 1 - _scriptManager->getStateValue(StateKey_DebugCheats));
|
||||
|
||||
if (_scriptManager->getStateValue(StateKey_DebugCheats) == 1)
|
||||
if (checkCode("GO????"))
|
||||
_scriptManager->changeLocation(getBufferedKey(3),
|
||||
getBufferedKey(2),
|
||||
getBufferedKey(1),
|
||||
getBufferedKey(0), 0);
|
||||
|
||||
// Show the Venus screen when "?" or "/" is pressed while inside the temple world
|
||||
if (_scriptManager->getStateValue(StateKey_VenusEnable) == 1)
|
||||
if (getBufferedKey(0) == 0xBF && _scriptManager->getStateValue(StateKey_World) == 't')
|
||||
_scriptManager->changeLocation('g', 'j', 'h', 'e', 0);
|
||||
}
|
||||
|
||||
void ZVision::processEvents() {
|
||||
while (_eventMan->pollEvent(_event)) {
|
||||
switch (_event.type) {
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
_cursorManager->cursorDown(true);
|
||||
_menu->onMouseDown(_event.mouse);
|
||||
if (!_menu->inMenu() || !_widescreen) {
|
||||
_scriptManager->setStateValue(StateKey_LMouse, 1);
|
||||
_scriptManager->addEvent(_event);
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
_cursorManager->cursorDown(false);
|
||||
_menu->onMouseUp(_event.mouse);
|
||||
if (!_menu->inMenu() || !_widescreen) {
|
||||
_scriptManager->setStateValue(StateKey_LMouse, 0);
|
||||
_scriptManager->addEvent(_event);
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
_cursorManager->cursorDown(true);
|
||||
if (!_menu->inMenu() || !_widescreen) {
|
||||
_scriptManager->setStateValue(StateKey_RMouse, 1);
|
||||
if (getGameId() == GID_NEMESIS)
|
||||
_scriptManager->inventoryCycle();
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_cursorManager->cursorDown(false);
|
||||
if (!_menu->inMenu() || !_widescreen)
|
||||
_scriptManager->setStateValue(StateKey_RMouse, 0);
|
||||
break;
|
||||
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
onMouseMove(_event.mouse);
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
switch ((ZVisionAction)_event.customType) {
|
||||
case kZVisionActionLeft:
|
||||
case kZVisionActionRight:
|
||||
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA)
|
||||
_keyboardVelocity = (_event.customType == kZVisionActionLeft ?
|
||||
-_scriptManager->getStateValue(StateKey_KbdRotateSpeed) :
|
||||
_scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2;
|
||||
break;
|
||||
|
||||
case kZVisionActionUp:
|
||||
case kZVisionActionDown:
|
||||
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT)
|
||||
_keyboardVelocity = (_event.customType == kZVisionActionUp ?
|
||||
-_scriptManager->getStateValue(StateKey_KbdRotateSpeed) :
|
||||
_scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2;
|
||||
break;
|
||||
|
||||
case kZVisionActionSave:
|
||||
if (_menu->getEnable(kMainMenuSave))
|
||||
_scriptManager->changeLocation('g', 'j', 's', 'e', 0);
|
||||
break;
|
||||
|
||||
case kZVisionActionRestore:
|
||||
if (_menu->getEnable(kMainMenuLoad))
|
||||
_scriptManager->changeLocation('g', 'j', 'r', 'e', 0);
|
||||
break;
|
||||
|
||||
case kZVisionActionPreferences:
|
||||
if (_menu->getEnable(kMainMenuPrefs))
|
||||
_scriptManager->changeLocation('g', 'j', 'p', 'e', 0);
|
||||
break;
|
||||
|
||||
case kZVisionActionQuit:
|
||||
if (_menu->getEnable(kMainMenuExit)) {
|
||||
if (ConfMan.hasKey("confirm_exit") && ConfMan.getBool("confirm_exit"))
|
||||
quit(true);
|
||||
else
|
||||
quit(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case kZVisionActionShowFPS: {
|
||||
Common::String fpsStr = Common::String::format("FPS: %d", getFPS());
|
||||
_subtitleManager->showDebugMsg(fpsStr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
|
||||
switch ((ZVisionAction)_event.customType) {
|
||||
case kZVisionActionLeft:
|
||||
case kZVisionActionRight:
|
||||
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA)
|
||||
_keyboardVelocity = 0;
|
||||
break;
|
||||
case kZVisionActionUp:
|
||||
case kZVisionActionDown:
|
||||
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT)
|
||||
_keyboardVelocity = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_KEYDOWN: {
|
||||
uint8 vkKey = getZvisionKey(_event.kbd.keycode);
|
||||
_scriptManager->setStateValue(StateKey_KeyPress, vkKey);
|
||||
_scriptManager->addEvent(_event);
|
||||
cheatCodes(vkKey);
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_KEYUP:
|
||||
_scriptManager->addEvent(_event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZVision::onMouseMove(const Common::Point &pos) {
|
||||
debugC(6, kDebugEvent, "ZVision::onMouseMove()");
|
||||
_menu->onMouseMove(pos);
|
||||
Common::Point imageCoord(_renderManager->screenSpaceToImageSpace(pos));
|
||||
Common::Rect workingArea = _renderManager->getWorkingArea();
|
||||
bool cursorWasChanged = false;
|
||||
|
||||
// Graph of the function governing rotation velocity:
|
||||
//
|
||||
// |---------------- working window ------------------|
|
||||
// ^ |---------|
|
||||
// | |
|
||||
// +Max velocity | rotation screen edge offset
|
||||
// | /|
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// Zero velocity |______________________________ ______________________________/_________|__________________________>
|
||||
// | Position -> | /
|
||||
// | | /
|
||||
// | | /
|
||||
// | | /
|
||||
// | | /
|
||||
// | | /
|
||||
// | | /
|
||||
// | | /
|
||||
// | | /
|
||||
// -Max velocity | |/
|
||||
// |
|
||||
// |
|
||||
// ^
|
||||
|
||||
// Clip the horizontal mouse position to the working window
|
||||
debugC(6, kDebugEvent, "Mouse pos.x, %d, clipping with %d+1, %d+1", pos.x, workingArea.left, workingArea.right);
|
||||
Common::Point clippedPos = pos;
|
||||
clippedPos.x = CLIP<int16>(pos.x, workingArea.left + 1, workingArea.right - 1);
|
||||
if (workingArea.contains(clippedPos) && !_menu->inMenu()) {
|
||||
cursorWasChanged = _scriptManager->onMouseMove(clippedPos, imageCoord);
|
||||
RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState();
|
||||
switch (renderState) {
|
||||
case RenderTable::PANORAMA:
|
||||
if (clippedPos.x >= workingArea.left && clippedPos.x < workingArea.left + ROTATION_SCREEN_EDGE_OFFSET) {
|
||||
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
|
||||
if (mspeed <= 0)
|
||||
mspeed = 25;
|
||||
_mouseVelocity = MIN(((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (clippedPos.x - workingArea.left)) - mspeed).toInt(), -1);
|
||||
_cursorManager->changeCursor(CursorIndex_Left);
|
||||
cursorWasChanged = true;
|
||||
} else if (clippedPos.x <= workingArea.right && clippedPos.x > workingArea.right - ROTATION_SCREEN_EDGE_OFFSET) {
|
||||
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
|
||||
if (mspeed <= 0)
|
||||
mspeed = 25;
|
||||
_mouseVelocity = MAX((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (clippedPos.x - workingArea.right + ROTATION_SCREEN_EDGE_OFFSET)).toInt(), 1);
|
||||
_cursorManager->changeCursor(CursorIndex_Right);
|
||||
cursorWasChanged = true;
|
||||
} else
|
||||
_mouseVelocity = 0;
|
||||
break;
|
||||
case RenderTable::TILT:
|
||||
if (clippedPos.y >= workingArea.top && clippedPos.y < workingArea.top + ROTATION_SCREEN_EDGE_OFFSET) {
|
||||
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
|
||||
if (mspeed <= 0)
|
||||
mspeed = 25;
|
||||
_mouseVelocity = MIN(((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - workingArea.top)) - mspeed).toInt(), -1);
|
||||
_cursorManager->changeCursor(CursorIndex_UpArr);
|
||||
cursorWasChanged = true;
|
||||
} else if (clippedPos.y <= workingArea.bottom && clippedPos.y > workingArea.bottom - ROTATION_SCREEN_EDGE_OFFSET) {
|
||||
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
|
||||
if (mspeed <= 0)
|
||||
mspeed = 25;
|
||||
_mouseVelocity = MAX((Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - workingArea.bottom + ROTATION_SCREEN_EDGE_OFFSET)).toInt(), 1);
|
||||
_cursorManager->changeCursor(CursorIndex_DownArr);
|
||||
cursorWasChanged = true;
|
||||
} else
|
||||
_mouseVelocity = 0;
|
||||
break;
|
||||
case RenderTable::FLAT:
|
||||
default:
|
||||
_mouseVelocity = 0;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
_mouseVelocity = 0;
|
||||
if (!cursorWasChanged)
|
||||
_cursorManager->changeCursor(CursorIndex_Idle);
|
||||
}
|
||||
|
||||
uint8 ZVision::getZvisionKey(Common::KeyCode scummKeyCode) {
|
||||
if (scummKeyCode >= Common::KEYCODE_a && scummKeyCode <= Common::KEYCODE_z)
|
||||
return 0x41 + scummKeyCode - Common::KEYCODE_a;
|
||||
if (scummKeyCode >= Common::KEYCODE_0 && scummKeyCode <= Common::KEYCODE_9)
|
||||
return 0x30 + scummKeyCode - Common::KEYCODE_0;
|
||||
if (scummKeyCode >= Common::KEYCODE_F1 && scummKeyCode <= Common::KEYCODE_F15)
|
||||
return 0x70 + scummKeyCode - Common::KEYCODE_F1;
|
||||
if (scummKeyCode >= Common::KEYCODE_KP0 && scummKeyCode <= Common::KEYCODE_KP9)
|
||||
return 0x60 + scummKeyCode - Common::KEYCODE_KP0;
|
||||
|
||||
switch (scummKeyCode) {
|
||||
case Common::KEYCODE_BACKSPACE:
|
||||
return 0x8;
|
||||
case Common::KEYCODE_TAB:
|
||||
return 0x9;
|
||||
case Common::KEYCODE_CLEAR:
|
||||
return 0xC;
|
||||
case Common::KEYCODE_RETURN:
|
||||
return 0xD;
|
||||
case Common::KEYCODE_CAPSLOCK:
|
||||
return 0x14;
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
return 0x1B;
|
||||
case Common::KEYCODE_SPACE:
|
||||
return 0x20;
|
||||
case Common::KEYCODE_PAGEUP:
|
||||
return 0x21;
|
||||
case Common::KEYCODE_PAGEDOWN:
|
||||
return 0x22;
|
||||
case Common::KEYCODE_END:
|
||||
return 0x23;
|
||||
case Common::KEYCODE_HOME:
|
||||
return 0x24;
|
||||
case Common::KEYCODE_LEFT:
|
||||
return 0x25;
|
||||
case Common::KEYCODE_UP:
|
||||
return 0x26;
|
||||
case Common::KEYCODE_RIGHT:
|
||||
return 0x27;
|
||||
case Common::KEYCODE_DOWN:
|
||||
return 0x28;
|
||||
case Common::KEYCODE_PRINT:
|
||||
return 0x2A;
|
||||
case Common::KEYCODE_INSERT:
|
||||
return 0x2D;
|
||||
case Common::KEYCODE_DELETE:
|
||||
return 0x2E;
|
||||
case Common::KEYCODE_HELP:
|
||||
return 0x2F;
|
||||
case Common::KEYCODE_KP_MULTIPLY:
|
||||
return 0x6A;
|
||||
case Common::KEYCODE_KP_PLUS:
|
||||
return 0x6B;
|
||||
case Common::KEYCODE_KP_MINUS:
|
||||
return 0x6D;
|
||||
case Common::KEYCODE_KP_PERIOD:
|
||||
return 0x6E;
|
||||
case Common::KEYCODE_KP_DIVIDE:
|
||||
return 0x6F;
|
||||
case Common::KEYCODE_NUMLOCK:
|
||||
return 0x90;
|
||||
case Common::KEYCODE_SCROLLOCK:
|
||||
return 0x91;
|
||||
case Common::KEYCODE_LSHIFT:
|
||||
return 0xA0;
|
||||
case Common::KEYCODE_RSHIFT:
|
||||
return 0xA1;
|
||||
case Common::KEYCODE_LCTRL:
|
||||
return 0xA2;
|
||||
case Common::KEYCODE_RCTRL:
|
||||
return 0xA3;
|
||||
case Common::KEYCODE_MENU:
|
||||
return 0xA5;
|
||||
case Common::KEYCODE_LEFTBRACKET:
|
||||
return 0xDB;
|
||||
case Common::KEYCODE_RIGHTBRACKET:
|
||||
return 0xDD;
|
||||
case Common::KEYCODE_SEMICOLON:
|
||||
return 0xBA;
|
||||
case Common::KEYCODE_BACKSLASH:
|
||||
return 0xDC;
|
||||
case Common::KEYCODE_QUOTE:
|
||||
return 0xDE;
|
||||
case Common::KEYCODE_SLASH:
|
||||
return 0xBF;
|
||||
case Common::KEYCODE_TILDE:
|
||||
return 0xC0;
|
||||
case Common::KEYCODE_COMMA:
|
||||
return 0xBC;
|
||||
case Common::KEYCODE_PERIOD:
|
||||
return 0xBE;
|
||||
case Common::KEYCODE_MINUS:
|
||||
return 0xBD;
|
||||
case Common::KEYCODE_PLUS:
|
||||
return 0xBB;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ZVision::quit(bool askFirst, bool streaming) {
|
||||
debugC(1, kDebugEvent, "ZVision::quit()");
|
||||
if (askFirst)
|
||||
if (!_subtitleManager->askQuestion(_stringManager->getTextLine(StringManager::ZVISION_STR_EXITPROMT), streaming, true)) {
|
||||
debugC(1, kDebugEvent, "~ZVision::quit()");
|
||||
return false;
|
||||
}
|
||||
//quitGame();
|
||||
_breakMainLoop = true;
|
||||
debugC(1, kDebugEvent, "~ZVision::quit()");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace ZVision
|
||||
Reference in New Issue
Block a user