Page MenuHomePhabricator (Chris)

No OneTemporary

Size
168 KB
Referenced Files
None
Subscribers
None
diff --git a/util/gui/cutscene.cpp b/util/gui/cutscene.cpp
index 3d198c8a..a3647254 100644
--- a/util/gui/cutscene.cpp
+++ b/util/gui/cutscene.cpp
@@ -1,321 +1,321 @@
#include "cutscene.h"
#include "util/bitmap.h"
#include "util/init.h"
#include "util/input/input-map.h"
#include "util/input/input-manager.h"
#include "util/input/input-source.h"
#include "util/stretch-bitmap.h"
#include "util/token.h"
#include "util/tokenreader.h"
#include "util/file-system.h"
#include "configuration.h"
using namespace Gui;
Scene::Scene(const Token * token):
ticks(0),
endTicks(-1){
parseScene(token);
}
Scene::~Scene(){
}
void Scene::parseScene(const Token * token){
if (*token != "scene"){
throw LoadException(__FILE__, __LINE__, "Not a Scene");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if (*tok == "time"){
tok->view() >> endTicks;
} else if (*tok == "animation" || *tok == "anim"){
addAnimation(Util::ReferenceCount<Gui::Animation>(new Gui::Animation(tok)));
} else if (*tok == "fade"){
fader.parseDefaults(tok);
} else if (*tok == "file"){
std::string file;
tok->view() >> file;
TokenReader reader;
parseScene(reader.readTokenFromFile(Storage::instance().find(Filesystem::RelativePath(file)).path()));
} else {
Global::debug(3) << "Unhandled Scene attribute: " << std::endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Scene parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
void Scene::forward(int tickCount){
backgrounds.forward(tickCount);
fader.act();
// Increment ticks
ticks += tickCount;
// Fade out
if (endTicks >= 0){
const int check = endTicks - ticks;
if (check <= fader.getFadeOutTime() && fader.getState() != Gui::FadeTool::FadeOut){
fader.setState(Gui::FadeTool::FadeOut);
}
}
}
void Scene::reverse(int tickCount){
backgrounds.reverse(tickCount);
fader.act();
// Increment ticks
ticks -= tickCount;
// Fade out
if (ticks <= fader.getFadeInTime() && fader.getState() != Gui::FadeTool::FadeOut){
fader.setState(Gui::FadeTool::FadeOut);
}
}
void Scene::act(){
forward();
}
void Scene::render(const Graphics::Bitmap & work){
// Backgrounds
backgrounds.render(Gui::Animation::BackgroundBottom, work);
backgrounds.render(Gui::Animation::BackgroundMiddle, work);
backgrounds.render(Gui::Animation::BackgroundTop, work);
// Foregrounds
backgrounds.render(Gui::Animation::ForegroundBottom, work);
backgrounds.render(Gui::Animation::ForegroundMiddle, work);
backgrounds.render(Gui::Animation::ForegroundTop, work);
fader.draw(work);
}
void Scene::addAnimation(const Util::ReferenceCount<Gui::Animation> & animation){
backgrounds.add(animation);
}
void Scene::reset(){
ticks = 0;
backgrounds.reset();
fader.setState(Gui::FadeTool::FadeIn);
}
void Scene::setToEnd(){
if (endTicks >= 0){
ticks = endTicks;
} else {
if (backgrounds.totalTicks() != -1){
ticks = backgrounds.totalTicks();
}
}
backgrounds.setToEnd();
fader.setState(Gui::FadeTool::FadeIn);
}
bool Scene::done() const {
if (ticks <= 0){
return true;
}
if (endTicks >= 0){
if (ticks >= endTicks){
return true;
}
} else {
if (backgrounds.totalTicks() != -1){
if (ticks >= backgrounds.totalTicks()){
return true;
}
}
}
return false;
}
CutScene::CutScene():
width(640),
height(480),
current(0){
}
CutScene::CutScene(const Filesystem::AbsolutePath & path):
width(640),
height(480),
current(0){
TokenReader reader;
load(reader.readTokenFromFile(path.path().c_str()));
}
CutScene::CutScene(const Token * token):
width(640),
height(480),
current(0){
load(token);
}
CutScene::~CutScene(){
}
void CutScene::load(const Token * token){
if (*token != "cutscene"){
throw LoadException(__FILE__, __LINE__, "Not a CutScene");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if (*tok == "name"){
tok->view() >> name;
} else if (*tok == "scene"){
scenes.push_back(Util::ReferenceCount<Scene>(new Scene(tok)));
} else {
Global::debug(3) << "Unhandled Cutscene attribute: " << std::endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Cutscene parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
void CutScene::setName(const std::string & n){
name = n;
}
void CutScene::setResolution(int w, int h){
width = w;
height = h;
}
void CutScene::setScene(unsigned int scene){
if (scene >= scenes.size()){
current = scenes.size()-1;
} else {
current = scene;
}
}
enum Keys{
Esc
};
Util::ReferenceCount<Scene> CutScene::getCurrent(){
if (scenes.empty()){
return Util::ReferenceCount<Scene>(NULL);
}
return scenes[current];
}
void CutScene::playAll(){
for (unsigned int i = 0; i < scenes.size(); i++){
playScene(i);
}
}
void CutScene::playScene(unsigned int scene){
class Logic: public Util::Logic {
public:
Logic(InputMap<Keys> & input, Util::ReferenceCount<Scene> scene):
is_done(false),
input(input),
scene(scene){
}
bool is_done;
InputMap<Keys> & input;
Util::ReferenceCount<Scene> scene;
bool done(){
return is_done;
}
void run(){
std::vector<InputMap<Keys>::InputEvent> out = InputManager::getEvents(input, InputSource());
for (std::vector<InputMap<Keys>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<Keys>::InputEvent & event = *it;
if (event.enabled){
if (event.out == Esc){
is_done = true;
}
}
}
scene->act();
if (scene->done()){
is_done = true;
}
}
double ticks(double system){
return system * Global::ticksPerSecond(90);
}
};
class Draw: public Util::Draw {
public:
Draw(const Logic & logic, Util::ReferenceCount<Scene> scene, int width, int height):
logic(logic),
scene(scene),
width(width),
height(height){
}
const Logic & logic;
Util::ReferenceCount<Scene> scene;
int width, height;
void draw(const Graphics::Bitmap & buffer){
Graphics::StretchedBitmap work(width, height, buffer);
work.start();
scene->render(work);
work.finish();
buffer.BlitToScreen();
}
};
if (scene < scenes.size()){
InputMap<Keys> input;
input.set(Keyboard::Key_ESC, 0, true, Esc);
input.set(Joystick::Quit, 0, true, Esc);
input.set(Configuration::getAttack1(0), Esc);
- input.set(Configuration::getJoystickAttack1(0), Esc);
+ input.set(Joystick::Button1, Esc);
Logic logic(input, scenes[scene]);
Draw draw(logic, scenes[scene], width, height);
Util::standardLoop(logic, draw);
}
}
void CutScene::playScene(){
if (current < scenes.size()){
playScene(current);
}
}
void CutScene::next(){
if (current <= scenes.size()){
current += 1;
}
}
bool CutScene::hasMore(){
return (current < scenes.size());
}
diff --git a/util/input/sdl/joystick.cpp b/util/input/sdl/joystick.cpp
index b65c252d..3a30af83 100644
--- a/util/input/sdl/joystick.cpp
+++ b/util/input/sdl/joystick.cpp
@@ -1,743 +1,760 @@
#ifdef USE_SDL
#include <SDL.h>
#include "joystick.h"
#include "util/debug.h"
#include <string>
#include <vector>
#include <exception>
using std::string;
using std::vector;
class ButtonMapping{
public:
ButtonMapping(){
}
virtual ~ButtonMapping(){
}
virtual int toNative(int button) = 0;
virtual int fromNative(int button) = 0;
virtual Joystick::Key toKey(int button) = 0;
virtual void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events) = 0;
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events) = 0;
};
class DefaultButtonMapping: public ButtonMapping {
public:
int toNative(int button){
return button;
}
int fromNative(int button){
return button;
}
Joystick::Key toKey(int button){
switch (button){
case 0: return Joystick::Button1;
case 1: return Joystick::Button2;
case 2: return Joystick::Button3;
case 3: return Joystick::Button4;
case 4: return Joystick::Quit;
case 5: return Joystick::Button5;
case 6: return Joystick::Button6;
default: return Joystick::Invalid;
}
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: right = true; up = true; break;
case SDL_HAT_RIGHTDOWN: right = true; down = true; break;
case SDL_HAT_LEFTUP: left = true; up = true; break;
case SDL_HAT_LEFTDOWN: left = true; down = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
if (axis == 0){
if (motion < 0){
left = true;
} else if (motion > 0){
right = true;
}
} else if (axis == 1){
if (motion < 0){
up = true;
} else if (motion > 0){
down = true;
}
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
/* used when a ps3 controller is plugged into a usb port of a normal pc */
class Playstation3Controller: public ButtonMapping {
public:
enum Buttons{
Cross = 14,
Circle = 13,
Triangle = 12,
Square = 15,
Start = 3,
Select = 0,
Up = 4,
Left = 7,
Down = 6,
Right = 5,
Stick1 = 1,
Stick2 = 2,
L2 = 8,
L1 = 10,
R2 = 9,
R1 = 11,
/* the middle ps3 button */
Ps3 = 16
};
int toNative(int button){
switch (button){
case 0: return Square;
case 1: return Cross;
case 2: return Circle;
case 3: return Triangle;
case 4: return Start;
}
return button;
}
int fromNative(int button){
switch (button){
case Square: return 0;
case Cross: return 1;
case Circle: return 2;
case Triangle: return 3;
case Start: return Start;
default: return 5;
}
return button;
}
Joystick::Key toKey(int button){
switch (button){
case Square: return Joystick::Button1;
case Cross: return Joystick::Button2;
case Circle: return Joystick::Button3;
case Triangle: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
case Up: return Joystick::Up;
case Down: return Joystick::Down;
case Left: return Joystick::Left;
case Right: return Joystick::Right;
default: return Joystick::Invalid;
}
}
/* TODO */
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
}
};
class LogitechPrecision: public ButtonMapping {
public:
enum Buttons{
Button1 = 0,
Button2 = 1,
Button3 = 2,
Button4 = 3,
Start = 8,
Select = 9,
R2 = 7,
R1 = 5,
L2 = 6,
L1 = 4
};
int toNative(int button){
return -1;
}
int fromNative(int button){
return -1;
}
Joystick::Key toKey(int button){
switch (button){
case Button1: return Joystick::Button1;
case Button2: return Joystick::Button2;
case Button3: return Joystick::Button3;
case Button4: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
}
return Joystick::Invalid;
}
/* axis 1. negative up, positive down
* axis 0, negative left, positive right
*/
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
int tolerance = 10;
if (axis == 0){
+ if (motion == 0){
+ events.push_back(Joystick::Event(Joystick::Left, false));
+ events.push_back(Joystick::Event(Joystick::Right, false));
+ } else if (motion == -32768){
+ events.push_back(Joystick::Event(Joystick::Left, true));
+ } else if (motion == 32767){
+ events.push_back(Joystick::Event(Joystick::Right, true));
+ } else if (motion == 128){
+ events.push_back(Joystick::Event(Joystick::Up, false));
+ events.push_back(Joystick::Event(Joystick::Down, false));
+ } else if (motion == 1){
+ events.push_back(Joystick::Event(Joystick::Up, true));
+ } else if (motion == 255){
+ events.push_back(Joystick::Event(Joystick::Down, true));
+ }
+ /*
if (motion < -tolerance){
events.push_back(Joystick::Event(Joystick::Left, true));
} else if (motion > tolerance){
events.push_back(Joystick::Event(Joystick::Right, true));
} else {
- /* fake a release for left and right */
+ / * fake a release for left and right * /
events.push_back(Joystick::Event(Joystick::Left, false));
events.push_back(Joystick::Event(Joystick::Right, false));
}
+ */
} else if (axis == 1){
if (motion < -tolerance){
events.push_back(Joystick::Event(Joystick::Up, true));
} else if (motion > tolerance){
events.push_back(Joystick::Event(Joystick::Down, true));
} else {
events.push_back(Joystick::Event(Joystick::Up, false));
events.push_back(Joystick::Event(Joystick::Down, false));
}
}
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
}
};
/* used for the ps3 controller with psl1ght's SDL version */
class Ps3Controller: public ButtonMapping {
public:
enum Buttons{
Left = 0,
Down = 1,
Right = 2,
Up = 3,
Select = 7,
Start = 4,
Square = 8,
Cross = 9,
Circle = 10,
Triangle = 11,
L1 = 13,
R1 = 12,
L2 = 15,
R2 = 14,
L3 = 6,
R3 = 5
};
int toNative(int button){
switch (button){
case 0: return Square;
case 1: return Cross;
case 2: return Circle;
case 3: return Triangle;
case 4: return Start;
}
return button;
}
int fromNative(int button){
switch (button){
case Square: return 0;
case Cross: return 1;
case Circle: return 2;
case Triangle: return 3;
case Start: return Start;
default: return 5;
}
return button;
}
Joystick::Key toKey(int button){
switch (button){
case Square: return Joystick::Button1;
case Cross: return Joystick::Button2;
case Circle: return Joystick::Button3;
case Triangle: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
case Up: return Joystick::Up;
case Down: return Joystick::Down;
case Left: return Joystick::Left;
case Right: return Joystick::Right;
default: return Joystick::Invalid;
}
}
/* TODO */
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
}
};
class XBox360Controller: public ButtonMapping {
public:
enum Buttons{
A = 0,
B = 1,
X = 2,
Y = 3,
L1 = 4,
R1 = 5,
Start = 6,
Xbox = 7,
L3 = 8,
R3 = 9,
Select = 10
};
int toNative(int button){
return 0;
}
int fromNative(int button){
return 0;
}
Joystick::Key toKey(int button){
switch (button){
case A: return Joystick::Button1;
case B: return Joystick::Button2;
case X: return Joystick::Button3;
case Y: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
}
return Joystick::Invalid;
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
/* axis 6 and 7 are the hats. sdl passes them as hat events */
#if 0
if (axis == 6){
if (motion < 0){
events.push_back(Joystick::Event(Joystick::Left, true));
} else if (motion > 0){
events.push_back(Joystick::Event(Joystick::Right, true));
} else if (motion == 0){
/* fake a release for left and right */
events.push_back(Joystick::Event(Joystick::Left, false));
events.push_back(Joystick::Event(Joystick::Right, false));
}
} else if (axis == 7){
if (motion < 0){
events.push_back(Joystick::Event(Joystick::Up, true));
} else if (motion > 0){
events.push_back(Joystick::Event(Joystick::Down, true));
} else if (motion == 0){
events.push_back(Joystick::Event(Joystick::Up, false));
events.push_back(Joystick::Event(Joystick::Down, false));
}
}
#endif
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: right = true; up = true; break;
case SDL_HAT_RIGHTDOWN: right = true; down = true; break;
case SDL_HAT_LEFTUP: left = true; up = true; break;
case SDL_HAT_LEFTDOWN: left = true; down = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
class Wiimote: public ButtonMapping {
public:
enum Buttons{
A = 0,
B = 1,
Button1 = 2,
Button2 = 3,
Minus = 4,
Plus = 5,
Home = 6
};
int toNative(int button){
return 0;
}
int fromNative(int button){
return 0;
}
/* FIXME: need a start key */
Joystick::Key toKey(int button){
switch (button){
case A: return Joystick::Button1;
case B: return Joystick::Button2;
case Button1: return Joystick::Button3;
case Button2: return Joystick::Button4;
case Minus: return Joystick::Button5;
case Plus: return Joystick::Button6;
case Home: return Joystick::Quit;
}
return Joystick::Invalid;
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
/* rotate all the directions 90 degrees */
bool up = false; // right
bool down = false; // left
bool left = false; // up
bool right = false; // down
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: up = true; right = true; break;
case SDL_HAT_RIGHTDOWN: down = true; right = true; break;
case SDL_HAT_LEFTUP: up = true; left = true; break;
case SDL_HAT_LEFTDOWN: down = true; left = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
class GamecubePad: public ButtonMapping {
public:
enum Buttons{
A = 0,
B = 1,
X = 2,
Y = 3,
Z = 4,
Start = 7
};
int toNative(int button){
return 0;
}
int fromNative(int button){
return 0;
}
Joystick::Key toKey(int button){
switch (button){
case A: return Joystick::Button1;
case B: return Joystick::Button2;
case X: return Joystick::Button3;
case Y: return Joystick::Button4;
case Z: return Joystick::Button5;
case Start: return Joystick::Start;
}
return Joystick::Invalid;
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
// printf("axis %d motion %d\n", axis, motion);
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: right = true; up = true; break;
case SDL_HAT_RIGHTDOWN: right = true; down = true; break;
case SDL_HAT_LEFTUP: left = true; up = true; break;
case SDL_HAT_LEFTDOWN: left = true; down = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
ButtonMapping * makeButtonMapping(string name){
#ifdef PS3
return new Ps3Controller();
#endif
if (name == "Sony PLAYSTATION(R)3 Controller"){
return new Playstation3Controller();
}
if (name.find("Logitech(R) Precision(TM) Gamepad") != string::npos){
return new LogitechPrecision();
}
if (name == "Microsoft X-Box 360 pad"){
return new XBox360Controller();
}
if (name.find("Wiimote") != string::npos){
return new Wiimote();
}
if (name.find("Gamecube") != string::npos){
return new GamecubePad();
}
return new DefaultButtonMapping();
}
void SDLJoystick::poll(){
events.clear();
}
static bool read_button(SDL_Joystick * joystick, int button){
return SDL_JoystickGetButton(joystick, button);
}
/*
JoystickInput SDLJoystick::readAll(){
JoystickInput input;
return input;
if (joystick){
int buttons = SDL_JoystickNumButtons(joystick);
switch (buttons > 5 ? 5 : buttons){
case 5: input.quit = read_button(joystick, buttonMapping->toNative(4));
case 4: input.button4 = read_button(joystick, buttonMapping->toNative(3));
case 3: input.button3 = read_button(joystick, buttonMapping->toNative(2));
case 2: input.button2 = read_button(joystick, buttonMapping->toNative(1));
case 1: input.button1 = read_button(joystick, buttonMapping->toNative(0));
case 0: {
break;
}
}
}
int axis = SDL_JoystickNumAxes(joystick);
if (axis > 0){
int position = SDL_JoystickGetAxis(joystick, 0);
if (position < 0){
input.left = true;
} else if (position > 0){
input.right = true;
}
}
if (axis > 1){
int position = SDL_JoystickGetAxis(joystick, 1);
if (position < 0){
input.up = true;
} else if (position > 0){
input.down = true;
}
}
int hats = SDL_JoystickNumHats(joystick);
if (hats > 0){
int hat = SDL_JoystickGetHat(joystick, 0);
if ((hat & SDL_HAT_UP) == SDL_HAT_UP){
input.up = true;
}
if ((hat & SDL_HAT_DOWN) == SDL_HAT_DOWN){
input.down = true;
}
if ((hat & SDL_HAT_LEFT) == SDL_HAT_LEFT){
input.left = true;
}
if ((hat & SDL_HAT_RIGHT) == SDL_HAT_RIGHT){
input.right = true;
}
if ((hat & SDL_HAT_RIGHTUP) == SDL_HAT_RIGHTUP){
input.right = true;
input.up = true;
}
if ((hat & SDL_HAT_RIGHTDOWN) == SDL_HAT_RIGHTDOWN){
input.right = true;
input.down = true;
}
if ((hat & SDL_HAT_LEFTDOWN) == SDL_HAT_LEFTDOWN){
input.left = true;
input.down = true;
}
if ((hat & SDL_HAT_LEFTUP) == SDL_HAT_LEFTUP){
input.left = true;
input.up = true;
}
}
return input;
}
*/
SDLJoystick::~SDLJoystick(){
if (joystick){
SDL_JoystickClose(joystick);
}
}
#if 0
#include <io/pad.h>
#include <fstream>
void hack(){
padInfo padinfo;
int ok = ioPadGetInfo(&padinfo);
if (ok == 0){
std::ofstream out("/dev_hdd0/tmp/p.txt");
out << "PS3 Pad Info" << std::endl;
out << " max " << padinfo.max << std::endl;
out << " connected " << padinfo.connected << std::endl;
out << " status 0 " << (int) padinfo.status[0] << std::endl;
out << " status 1 " << (int) padinfo.status[1] << std::endl;
out << " status 2 " << (int) padinfo.status[2] << std::endl;
out << " status 3 " << (int) padinfo.status[3] << std::endl;
out << " status 4 " << (int) padinfo.status[4] << std::endl;
out.close();
} else {
Global::debug(0) << "Could not get pad info" << std::endl;
}
}
#endif
SDLJoystick::SDLJoystick(int id):
joystick(NULL){
if (SDL_NumJoysticks() > id){
joystick = SDL_JoystickOpen(id);
if (joystick == NULL){
Global::debug(0) << "Could not open joystick at index " << id << std::endl;
} else {
Global::debug(1) << "Opened joystick '" << SDL_JoystickName(id) << "'" << std::endl;
}
// printf("Opened joystick '%s'\n", SDL_JoystickName(4));
buttonMapping = makeButtonMapping(SDL_JoystickName(id));
}
}
void SDLJoystick::pressButton(int button){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->pressButton(this, button);
}
// Global::debug(0) << "Pressed button " << button << std::endl;
if (joystick){
Key event = buttonMapping->toKey(button);
if (event != Invalid){
events.push_back(Event(event, true));
}
}
}
void SDLJoystick::releaseButton(int button){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->releaseButton(this, button);
}
if (joystick){
Key event = buttonMapping->toKey(button);
if (event != Invalid){
events.push_back(Event(event, false));
}
}
}
void SDLJoystick::hatMotion(int motion){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->hatMotion(this, motion);
}
// Global::debug(0) << "Hat motion " << motion << std::endl;
if (joystick){
buttonMapping->hatMotionEvents(motion, events);
}
}
void SDLJoystick::axisMotion(int axis, int motion){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->axisMotion(this, axis, motion);
}
// Global::debug(0) << "Axis motion on " << axis << " motion " << motion << std::endl;
if (joystick){
buttonMapping->axisMotionEvents(axis, motion, events);
/*
Event move = buttonMapping->axisMotionToEvent(axis, motion);
if (move.key != Invalid){
events.push_back(move);
}
*/
}
}
int SDLJoystick::getDeviceId() const {
if (joystick){
return SDL_JoystickIndex(joystick);
}
return -1;
}
int Joystick::numberOfJoysticks(){
return SDL_NumJoysticks();
}
#endif
diff --git a/util/menu/menu.cpp b/util/menu/menu.cpp
index a2e117a4..fcb29d80 100644
--- a/util/menu/menu.cpp
+++ b/util/menu/menu.cpp
@@ -1,1811 +1,1811 @@
#include "util/bitmap.h"
#include "util/trans-bitmap.h"
#include "util/stretch-bitmap.h"
#include "menu.h"
#include "menu_option.h"
#include "util/funcs.h"
#include "util/sound.h"
#include "util/font.h"
#include "util/token.h"
#include "util/events.h"
#include "util/tokenreader.h"
#include "util/file-system.h"
#include "util/resource.h"
#include "globals.h"
#include "util/debug.h"
#include "util/init.h"
#include "configuration.h"
#include "util/music.h"
#include "util/gradient.h"
#include "util/exceptions/shutdown_exception.h"
#include "util/exceptions/exception.h"
#include "optionfactory.h"
#include "actionfactory.h"
#include "util/input/input-manager.h"
#include "util/input/input-map.h"
#include "util/input/input-source.h"
#include "util/parameter.h"
#include <queue>
#include <map>
#include <ostream>
#include <sstream>
#include "util/gui/context-box.h"
using namespace std;
using namespace Gui;
/* the current font is a property of the dynamic execution. so it will
* be modified by various functions that call Parameter::push
*/
static const Font & currentFont(){
return Menu::menuFontParameter.current()->get();
}
Util::Parameter<Util::ReferenceCount<Menu::FontInfo> > Menu::menuFontParameter;
static std::string sharedFont = "fonts/arial.ttf";
static int sharedFontWidth = 24;
static int sharedFontHeight = 24;
Effects::Gradient Menu::standardGradient(){
return Gui::standardGradient(50);
}
Menu::Point::Point():
x(0),
y(0){
}
Menu::Point::Point(int x, int y):
x(x),
y(y){
}
Menu::Point::~Point(){
}
Menu::InfoBox::InfoBox():
state(NotActive),
fadeAlpha(0){
popup.setFadeSpeed(20);
}
Menu::InfoBox::~InfoBox(){
}
void Menu::InfoBox::act(const Font & font){
popup.act(font);
int speed = 9;
switch (state){
case Opening: {
if (fadeAlpha < 255){
fadeAlpha += speed;
}
if (fadeAlpha >= 255){
fadeAlpha = 255;
if (popup.isActive()){
state = Active;
}
}
break;
}
case Closing: {
if (fadeAlpha > 0){
fadeAlpha -= speed;
}
if (fadeAlpha <= 0){
fadeAlpha = 0;
if (!popup.isActive()){
state = NotActive;
}
}
break;
}
case Active:
case NotActive:
default:
break;
}
}
void Menu::InfoBox::render(const Graphics::Bitmap &){
throw MenuException(__FILE__, __LINE__, "Don't call the render(Bitmap) function");
}
void Menu::InfoBox::render(const Graphics::Bitmap & bmp, const Font & vFont){
popup.render(bmp);
// const Font & vFont = Configuration::getMenuFont()->get(*font);
const int x1 = popup.getArea().getX()+(int)(popup.getTransforms().getRadius()/2);
const int y1 = popup.getArea().getY()+2;
const int x2 = popup.getArea().getX2()-(int)(popup.getTransforms().getRadius()/2);
const int y2 = popup.getArea().getY2()-2;
bmp.setClipRect(x1, y1, x2, y2);
// FIXME height is proportionally wrong in a majority of the cases, this is perhaps due to ftalleg.
int sy = location.getY() - vFont.getHeight()/6;// - location.getHeight()/2 - vFont.getHeight()/2;
static Graphics::Color white = Graphics::makeColor(255,255,255);
unsigned int padding_index = 0;
for (vector<string>::iterator it = text.begin(); it != text.end(); it++){
string & str = *it;
if (fadeAlpha < 255){
Graphics::Bitmap::transBlender(0, 0, 0, fadeAlpha);
vFont.printf(location.getX() + padding[padding_index]/2, sy, white, bmp.translucent(), str, 0 );
} else {
vFont.printf(location.getX() + padding[padding_index]/2, sy, white, bmp, str, 0 );
}
sy += vFont.getHeight();
padding_index++;
}
bmp.setClipRect(0, 0, bmp.getWidth(), bmp.getHeight());
}
void Menu::InfoBox::open(){
state = Opening;
popup.location = location;
popup.transforms = transforms;
popup.colors = colors;
popup.open();
fadeAlpha = 0;
}
void Menu::InfoBox::close(){
state = Closing;
popup.close();
}
/* dimensions are computed lazily when we get a font, but only compute once per font */
void Menu::InfoBox::initialize(const Font & font){
int maxWidth = 0;
int height = 0;
for (vector<string>::iterator it = text.begin(); it != text.end(); it++){
// Add the padding
ostringstream pad;
pad << (*it)[0] << (*it)[(*it).size()-1];
padding.push_back(font.textLength(pad.str().c_str()));
int w = font.textLength((*it).c_str()) + padding.back();
if (w > maxWidth){
maxWidth = w;
}
height += font.getHeight();
}
location.setDimensions(maxWidth, height);
}
void Menu::InfoBox::setText(const std::string & info){
if (info.empty()){
return;
}
text.clear();
// const Font & vFont = Configuration::getMenuFont()->get(*font);
size_t start = 0;
size_t last = 0;
start = info.find("\n");
while (start != string::npos){
text.push_back(info.substr(last, start - last));
last = start + 1;
start = info.find("\n", last);
}
text.push_back(info.substr(last));
}
static std::vector<Util::ReferenceCount<ContextItem> > toContextList(const ContextBox & context, const std::vector<Util::ReferenceCount<MenuOption> > & list){
std::vector<Util::ReferenceCount<ContextItem> > contextItems;
for (std::vector<Util::ReferenceCount<MenuOption> >::const_iterator i = list.begin(); i != list.end(); ++i){
const Util::ReferenceCount<MenuOption> & option = *i;
contextItems.push_back(option.convert<ContextItem>());
}
return contextItems;
}
static void tryPlaySound(const Filesystem::RelativePath & path){
Sound * ok = Resource::getSound(path);
if (ok != NULL){
ok->play();
}
}
/*
* FIXME Exception handling for ValueHolder*/
Menu::MenuException::MenuException(const std::string & file, int line, const std::string reason ):
Exception::Base(file, line),
reason(reason){
}
Menu::MenuException::MenuException(const MenuException & copy):
Exception::Base(copy),
reason(copy.reason){
}
Menu::MenuException::MenuException(const Exception::Base & copy):
Exception::Base(copy),
reason("unknown"){
}
Menu::MenuException::~MenuException() throw(){
}
Exception::Base * Menu::MenuException::copy() const {
return new MenuException(*this);
}
Menu::Reload::Reload(const std::string & file, int line, const std::string reason):
MenuException(file, line, reason){
}
Menu::Reload::~Reload() throw() {
}
Exception::Base * Menu::Reload::copy() const {
return new Reload(*this);
}
Menu::ValueHolder::ValueHolder(const std::string & name):
name(name),
location(0){
}
Menu::ValueHolder::~ValueHolder(){
}
Menu::ValueHolder::ValueHolder(const ValueHolder & copy){
// reset position
this->location = 0;
this->name = copy.name;
this->values = copy.values;
}
Menu::ValueHolder & Menu::ValueHolder::operator=(const ValueHolder & copy){
// reset position
this->location = 0;
this->name = copy.name;
this->values = copy.values;
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(const std::string & val){
values.push_back(val);
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(bool val){
std::ostringstream o;
o << val;
return *this << o.str();
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(int val){
std::ostringstream o;
o << val;
return *this << o.str();
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(double val){
std::ostringstream o;
o << val;
return *this << o.str();
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(TokenView & view){
std::string temp;
view >> temp;
return *this << temp;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(std::string & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
val = values[location];
next();
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(bool & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
std::istringstream i(values[location]);
i >> val;
next();
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(int & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
std::istringstream i(values[location]);
i >> val;
next();
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(double & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
std::istringstream i(values[location]);
i >> val;
next();
return *this;
}
void Menu::ValueHolder::next(){
location++;
if (location >= values.size()){
location = 0;
}
}
const std::string Menu::ValueHolder::getValues() {
std::string temp;
for (std::vector<std::string>::iterator i = values.begin(); i != values.end(); ++i){
temp += *i + "; ";
}
return temp;
}
static bool parseDisplayList(const Token * token, ContextBox & menu){
if (*token == "display-list"){
TokenView view = token->view();
while (view.hasMore()){
const Token * tok;
view >> tok;
std::string type;
bool wrap = true;
if (tok->match("type", type)){
if (type == "normal"){
menu.setListType(ContextBox::Normal);
} else if (type == "scroll"){
menu.setListType(ContextBox::Scroll);
}
} else if (tok->match("wrap", wrap)){
menu.setListWrap(wrap);
} else if ( *tok == "items"){
Gui::ListValues values;
values.getValues(tok);
menu.setListValues(values);
}
}
return true;
}
return false;
}
Menu::Renderer::Renderer(){
}
Menu::Renderer::~Renderer(){
// Kill info boxes
for (std::vector< ::Menu::InfoBox *>::iterator i = info.begin(); i != info.end();++i){
if (*i){
delete *i;
}
}
}
/*
void Menu::Renderer::setFont(const Util::ReferenceCount<FontInfo> & font){
}
*/
void Menu::Renderer::addInfo(const std::string & text, const Gui::Widget & defaults, Context & context, const Font & font){
if (!info.empty()){
info.back()->close();
}
if (text.empty()){
return;
}
::Menu::InfoBox * temp = new ::Menu::InfoBox();
// temp->setFont(context.getFont());
temp->setText(text);
temp->initialize(font);
const int width = temp->location.getWidth();
const int height = temp->location.getHeight();
temp->location.setPosition(Gui::AbsolutePoint(context.getInfoLocation().getX() - width/2, context.getInfoLocation().getY() - height/2));
// have to pass the dimensions back in to correct proper placement
temp->location.setPosition2(Gui::AbsolutePoint(temp->location.getX() + width,temp->location.getY() + height));
temp->transforms.setRadius(defaults.transforms.getRadius());
temp->colors = defaults.colors;
temp->open();
info.push_back(temp);
}
void Menu::Renderer::actInfo(const Font & font){
for (std::vector< ::Menu::InfoBox *>::iterator i = info.begin(); i != info.end();){
::Menu::InfoBox *box = *i;
box->act(font);
if (!box->isActive()){
delete box;
i = info.erase(i);
} else {
i++;
}
}
}
void Menu::Renderer::renderInfo(const Graphics::Bitmap & work, const Font & font){
for (std::vector< ::Menu::InfoBox *>::iterator i = info.begin(); i != info.end(); ++i){
::Menu::InfoBox *box = *i;
box->render(work, font);
}
}
Menu::DefaultRenderer::DefaultRenderer():
hasOverride(false),
overrideIndex(0){
// Default the menu to a certain size and details
menu.transforms.setRadius(15);
menu.location.set(-.6, -.3, .6, .8);
menu.colors.body = Graphics::makeColor(0,0,0);
menu.colors.bodyAlpha = 128;
menu.colors.border = Graphics::makeColor(200,200,200);
menu.colors.borderAlpha = 255;
}
vector<Util::ReferenceCount<MenuOption> > Menu::DefaultRenderer::getOptions() const {
return options;
}
void Menu::DefaultRenderer::invokeOverride(const Context & context){
if (hasOverride){
options[overrideIndex]->run(context);
throw Exception::Return(__FILE__, __LINE__);
}
}
Menu::DefaultRenderer::~DefaultRenderer(){
}
bool Menu::DefaultRenderer::readToken(const Token * token, const OptionFactory & factory){
if( *token == "option" ) {
try{
MenuOption * temp = factory.getOption(menu, token);
if (temp){
// Check for info/name
{
TokenView view = token->view();
while (view.hasMore()){
const Token * tok;
view >> tok;
try{
if (*tok == "info"){
temp->addInfo(tok);
} else if (*tok == "name"){
temp->addName(tok);
}
} catch (const TokenException & ex){
// Output something
}
}
}
options.push_back(Util::ReferenceCount<MenuOption>(temp));
if (!hasOverride){
const Token * tok;
token->view() >> tok;
if (tok->findToken("_/override") != NULL){
overrideIndex = options.size()-1;
hasOverride = true;
}
}
}
} catch (const LoadException & le){
Global::debug(0) << "Could not read option: " << le.getTrace() << endl;
token->print(" ");
}
} else if ( *token == "position" ) {
// This handles the placement of the menu list and surrounding box
menu.setCoordinates(token);
} else if ( *token == "relative-position"){
menu.setCoordinates(token);
} else if ( *token == "coordinate"){
menu.setCoordinates(token);
} else if ( *token == "position-body" ) {
// This handles the body color of the menu box
menu.setColors(token);
} else if ( *token == "position-border" ) {
// This handles the border color of the menu box
menu.setColors(token);
} else if ( *token == "transforms" ) {
// This handles the border color of the menu box
menu.setTransforms(token);
} else if ( *token == "fade-speed" ) {
// Menu fade in speed
int speed;
token->view() >> speed;
menu.setFadeSpeed(speed);
} else if ( parseDisplayList(token, menu) ){
} else {
return false;
}
return true;
}
void Menu::DefaultRenderer::initialize(Context & context){
menu.setList(toContextList(menu, options));
menu.open();
// const Font & font = Configuration::getMenuFont()->get(context.getFont()->get());
const Font & font = currentFont();
// Menu info
if (!context.getMenuInfoText().empty()){
menuInfo.setText(context.getMenuInfoText());
menuInfo.initialize(font);
const int width = menuInfo.location.getWidth();
const int height = menuInfo.location.getHeight();
menuInfo.location.setPosition(Gui::AbsolutePoint(context.getMenuInfoLocation().getX() - width/2, context.getMenuInfoLocation().getY() - height/2));
// have to pass the dimensions back in to correct proper placement
menuInfo.location.setPosition2(Gui::AbsolutePoint(menuInfo.location.getX() + width, menuInfo.location.getY() + height));
menuInfo.transforms.setRadius(menu.transforms.getRadius());
menuInfo.colors = menu.colors;
}
menuInfo.open();
// Add first info option
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
void Menu::DefaultRenderer::finish(){
menu.close();
menuInfo.close();
}
bool Menu::DefaultRenderer::active(){
return menu.isActive();
}
void Menu::DefaultRenderer::act(const Context & context){
// const Font & font = Configuration::getMenuFont()->get(context.getFont()->get());
const Font & font = currentFont();
// FIXME find a better way to get options to update this is a waste
for (std::vector<Util::ReferenceCount<MenuOption> >::iterator i = options.begin(); i != options.end(); ++i){
Util::ReferenceCount<MenuOption> & option = *i;
option->logic();
}
menu.act(font);
menuInfo.act(font);
actInfo(font);
}
void Menu::DefaultRenderer::render(const Graphics::Bitmap & bmp, const Font & font){
menu.render(bmp, font);
menuInfo.render(bmp, font);
renderInfo(bmp, font);
}
void Menu::DefaultRenderer::addOption(MenuOption * opt){
this->options.push_back(Util::ReferenceCount<MenuOption>(opt));
}
void Menu::DefaultRenderer::doAction(const Actions & action, Context & context){
const Font & font = currentFont();
switch(action){
case Up:
if (menu.previous(font)){
context.playSound(Up);
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
break;
case Down:
if (menu.next(font)){
context.playSound(Down);
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
break;
case Left:
if (options[menu.getCurrentIndex()]->leftKey()){
// setFont(context.getFont());
context.playSound(Left);
}
break;
case Right:
if (options[menu.getCurrentIndex()]->rightKey()){
// setFont(context.getFont());
context.playSound(Right);
}
break;
case Select: {
if (options[menu.getCurrentIndex()]->isRunnable()){
try{
context.playSound(Select);
options[menu.getCurrentIndex()]->run(context);
} catch (const Reload & reload){
menu.open();
menuInfo.open();
}
// setFont(context.getFont());
context.playMusic();
/* font might have been recreated */
const Font & font = currentFont();
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
menuInfo.initialize(font);
}
break;
}
case Cancel:
context.playSound(Cancel);
throw Exception::Return(__FILE__, __LINE__);
break;
default:
break;
}
}
Menu::TabInfo::TabInfo(){
}
Menu::TabInfo::~TabInfo(){
}
void Menu::TabInfo::act(){
// Miguel: FIXME find a better way to get options to update this is a waste
// Jon: Whats wrong with it?
for (std::vector<Util::ReferenceCount<MenuOption> >::iterator i = options.begin(); i != options.end(); ++i){
Util::ReferenceCount<MenuOption> & option = *i;
option->logic();
}
}
Menu::TabRenderer::TabRenderer():
hasOverride(false),
overrideIndex(0){
// Default the menu to a certain size and details
//menu.transforms.setRadius(15);
menu.location.set(-.6, -.3, .6, .8);
menu.colors.body = Graphics::makeColor(0,0,0);
menu.colors.bodyAlpha = 128;
menu.colors.border = Graphics::makeColor(200,200,200);
menu.colors.borderAlpha = 255;
}
vector<Util::ReferenceCount<MenuOption> > Menu::TabRenderer::getOptions() const {
vector<Util::ReferenceCount<MenuOption> > options;
for (vector<TabInfo *>::const_iterator it = tabs.begin(); it != tabs.end(); ++it){
options.insert(options.end(), (*it)->options.begin(), (*it)->options.end());
}
return options;
}
/* FIXME need to implement override for tabs */
void Menu::TabRenderer::invokeOverride(const Context & context){
if (hasOverride){
//options[overrideIndex]->run(context);
throw Exception::Return(__FILE__, __LINE__);
}
}
Menu::TabRenderer::~TabRenderer(){
// Kill tabs
for (std::vector<TabInfo *>::iterator i = tabs.begin(); i != tabs.end(); ++i){
if (*i){
delete *i;
}
}
}
bool Menu::TabRenderer::readToken(const Token * token, const OptionFactory & factory){
if (*token == "menu"){
TabInfo * tabInfo = new TabInfo();
Gui::Tab * tab = new Gui::Tab();
TokenView view = token->view();
while (view.hasMore()){
const Token * tok;
view >> tok;
try{
if (*tok == "name"){
tok->view() >> tabInfo->name;
tok->view() >> tab->name;
} else if (*tok == "info"){
tok->view() >> tabInfo->info;
} else if (*tok == "menuinfo"){
tok->view() >> tabInfo->menuInfo;
} else if (parseDisplayList(tok, tab->getContext())){
} else if (*tok == "option"){
try {
MenuOption *temp = factory.getOption(tab->getContext(), tok);
if (temp){
// Check for info/name
{
TokenView info = tok->view();
while (info.hasMore()){
const Token * check;
info >> check;
try{
if (*check == "info"){
temp->addInfo(check);
} else if (*check == "name"){
temp->addName(check);
}
} catch (const TokenException & ex){
// Output something
}
}
}
Util::ReferenceCount<MenuOption> ref(temp);
tabInfo->options.push_back(ref);
tab->addOption(ref.convert<Gui::ContextItem>());
// tab->addOption(ref->getAsScrollItem<ContextItem>(tab->getContext()));
}
} catch (const LoadException & le){
tok->print(" ");
}
}
} catch (const TokenException & ex){
// Output something
}
}
menu.addTab(tab);
tabs.push_back(tabInfo);
} else if ( *token == "position" ) {
// This handles the placement of the menu list and surrounding box
menu.setCoordinates(token);
} else if ( *token == "relative-position"){
menu.setCoordinates(token);
} else if ( *token == "coordinate"){
menu.setCoordinates(token);
} else if ( *token == "position-body" ) {
// This handles the body color of the menu box
menu.setColors(token);
} else if ( *token == "position-border" ) {
// This handles the border color of the menu box
menu.setColors(token);
} else if ( *token == "transforms" ) {
// This handles the border color of the menu box
menu.setTransforms(token);
} else if ( *token == "tab-body" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.tabColors.bodyAlpha;
menu.tabColors.body = Graphics::makeColor(r,g,b);
} else if ( *token == "tab-border" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.tabColors.borderAlpha;
menu.tabColors.border = Graphics::makeColor(r,g,b);
} else if ( *token == "selectedtab-body" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.selectedTabColors.bodyAlpha;
menu.selectedTabColors.body = Graphics::makeColor(r,g,b);
} else if ( *token == "selectedtab-border" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.selectedTabColors.borderAlpha;
menu.selectedTabColors.border = Graphics::makeColor(r,g,b);
} else if ( *token == "runningtab-body" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.runningTabColors.bodyAlpha;
menu.runningTabColors.body = Graphics::makeColor(r,g,b);
} else if ( *token == "runningtab-border" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.runningTabColors.borderAlpha;
menu.runningTabColors.border = Graphics::makeColor(r,g,b);
} else if ( *token == "font-color" ) {
int r,g,b;
token->view() >> r >> g >> b;
menu.setTabFontColor(Graphics::makeColor(r,g,b));
} else if ( *token == "selectedfont-color" ) {
int r,g,b;
token->view() >> r >> g >> b;
menu.setSelectedTabFontColor(Graphics::makeColor(r,g,b));
} else if ( *token == "runningfont-color" ) {
} else if ( *token == "fade-speed" ) {
// Menu fade in speed
int speed;
token->view() >> speed;
//menu.setFadeSpeed(speed);
} else {
return false;
}
return true;
}
void Menu::TabRenderer::initialize(Context & context){
const Font & font = currentFont();
// Menu info
if (!context.getMenuInfoText().empty()){
menuInfo.setText(context.getMenuInfoText());
menuInfo.initialize(font);
const int width = menuInfo.location.getWidth();
const int height = menuInfo.location.getHeight();
menuInfo.location.setPosition(Gui::AbsolutePoint(context.getMenuInfoLocation().getX() - width/2, context.getMenuInfoLocation().getY() - height/2));
// have to pass the dimensions back in to correct proper placement
menuInfo.location.setPosition2(Gui::AbsolutePoint(menuInfo.location.getX() + width,menuInfo.location.getY() + height));
menuInfo.transforms.setRadius(menu.transforms.getRadius());
menuInfo.colors = menu.colors;
}
menuInfo.open();
if (tabs.size() > 0 && tabs[menu.getCurrentTab()]->options.size() > menu.getCurrentIndex()){
// Add first info option
addInfo(tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
}
void Menu::TabRenderer::finish(){
//menu.close();
menuInfo.close();
}
bool Menu::TabRenderer::active(){
return true;//menu.isActive();
}
void Menu::TabRenderer::act(const Context & context){
const Font & font = currentFont();
// FIXME find a better way to get options to update this is a waste
for (std::vector<TabInfo *>::iterator i = tabs.begin(); i != tabs.end(); ++i){
TabInfo * tab = *i;
tab->act();
}
menu.act(font);
menuInfo.act(font);
actInfo(font);
}
void Menu::TabRenderer::render(const Graphics::Bitmap & bmp, const Font & font){
menu.render(bmp, font);
menuInfo.render(bmp, font);
renderInfo(bmp, font);
}
void Menu::TabRenderer::addOption(MenuOption * opt){
//this->options.push_back(opt);
}
void Menu::TabRenderer::doAction(const Actions & action, Context & context){
const Font & font = currentFont();
bool updateInfo = false;
switch (action){
case Up:
menu.up(font);
context.playSound(Up);
updateInfo = true;
break;
case Down:
menu.down(font);
context.playSound(Down);
updateInfo = true;
break;
case Left:
menu.left(font);
context.playSound(Up);
updateInfo = true;
break;
case Right:
menu.right(font);
context.playSound(Down);
updateInfo = true;
break;
case Select:
try{
if (!menu.isInTab()){
menu.toggleTabSelect();
} else {
if (menu.getCurrentTab() < tabs.size() &&
menu.getCurrentIndex() < tabs[menu.getCurrentTab()]->options.size() &&
tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->isRunnable()){
tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->run(context);
}
// tabs[menu.getCurrentTab()]->run(menu.getCurrentIndex(), context);
}
context.playSound(Select);
} catch (const Exception::Return & ex){
menuInfo.open();
}
context.playMusic();
updateInfo = true;
break;
case Cancel:
context.playSound(Cancel);
if (menu.isInTab()){
menu.toggleTabSelect();
} else {
throw Exception::Return(__FILE__, __LINE__);
}
break;
default:
break;
}
if (updateInfo){
if (tabs.size() > menu.getCurrentTab() &&
tabs[menu.getCurrentTab()]->options.size() > menu.getCurrentIndex()){
addInfo(tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
}
}
Menu::Context::Context():
cleanup(true),
state(NotStarted),
fades(0),
font(NULL),
infoLocation(0, -.5),
menuInfoLocation(0,.95){
}
Menu::Context::Context(const Context & parent, const Context & child):
cleanup(false),
state(NotStarted),
fades(NULL),
font(NULL),
infoLocation(0,-.5),
menuInfoLocation(0,.95),
/* include child's languages?? */
languages(parent.getLanguages()){
// Update with parents info
fades = parent.fades;
background = parent.background;
sounds = parent.sounds;
music = parent.music;
// font = parent.font;
infoLocation = parent.infoLocation;
menuInfoLocation = parent.menuInfoLocation;
// Then overwrite with childs
if (child.fades != NULL){
fades = child.fades;
}
if (!child.background.empty()){
background = child.background;
}
if (!child.sounds.empty()){
sounds = child.sounds;
}
if (Storage::instance().exists(child.music)){
music = child.music;
}
if (child.hasFont()){
font = child.getFontInfo();
} else if (parent.hasFont()){
font = parent.getFontInfo();
}
/* what are these magic numbers -.5 and .95? */
if (child.infoLocation.getRelativeX() != 0 || child.infoLocation.getRelativeY() != -.5){
infoLocation = child.infoLocation;
}
if (child.menuInfoLocation.getRelativeX() != 0 || child.menuInfoLocation.getRelativeY() != .95){
menuInfoLocation = child.menuInfoLocation;
}
if (!child.menuInfo.empty()){
menuInfo = child.menuInfo;
}
}
Menu::Context::~Context(){
// Only delete if required
if (cleanup){
if (fades != NULL){
delete fades;
}
}
}
std::vector<std::string> Menu::Context::getLanguages() const {
return languages;
}
void Menu::Context::setLanguages(const std::vector<std::string> & languages){
this->languages = languages;
}
bool Menu::Context::hasFont() const {
return font != NULL;
}
void Menu::Context::parseToken(const Token * token){
if ( *token != "context" ){
throw LoadException(__FILE__, __LINE__, "Not a menu context");
} else if (!token->hasTokens()){
return;
}
// Token
const Token * tok;
token->view() >> tok;
TokenView view = tok->view();
while (view.hasMore()){
const Token * context;
view >> context;
if (*context == "fade"){
// Fade info
if (!fades){
fades = new Gui::FadeTool();
}
// Set fader default to white
fades->setFadeInColor(Graphics::makeColor(255,255,255));
fades->setFadeOutColor(Graphics::makeColor(255,255,255));
fades->setFadeInTime(25);
fades->setFadeOutTime(12);
// Load defaults
fades->parseDefaults(context);
} else if (*context == "animation" || *context == "background"){
// Backgrounds
addBackground(context);
} else if (*context == ""){
}
}
}
void Menu::Context::addBackground(const Token * token){
// Backgrounds
/*if (background == NULL){
background = new Gui::AnimationManager();
}*/
background.add(Util::ReferenceCount<Gui::Animation>(new Gui::Animation(token)));
}
void Menu::Context::addBackground(const Graphics::Bitmap & image){
/*if (background == NULL){
background = new Gui::AnimationManager();
}*/
background.add(Util::ReferenceCount<Gui::Animation>(new Gui::Animation(Util::ReferenceCount<Graphics::Bitmap>(new Graphics::Bitmap(image)))));
}
void Menu::Context::addBackground(const std::string & image){
// Backgrounds
/*if (background == NULL){
background = new Gui::AnimationManager();
}*/
background.add(Util::ReferenceCount<Gui::Animation>(new Gui::Animation(image)));
}
void Menu::Context::initialize(){
if (fades){
// state
state = Initializing;
// set fader state
fades->setState(FadeTool::FadeIn);
} else {
// Running
state = Running;
}
}
void Menu::Context::finish(){
if (fades){
// state
state = Finishing;
// set fader state
fades->setState(FadeTool::FadeOut);
} else {
// Completed
state = Completed;
}
}
void Menu::Context::playSound(const Actions & sound) const {
map<Actions, Filesystem::RelativePath>::const_iterator find = sounds.find(sound);
if (find != sounds.end() && Storage::instance().exists(find->second)){
tryPlaySound(find->second);
}
}
void Menu::Context::addSound(const Actions & sound, const Filesystem::RelativePath & path){
sounds[sound] = path;
}
void Menu::Context::playMusic(){
if (Storage::instance().exists(music)){
if (Music::loadSong(Storage::instance().find(music).path())){
Music::pause();
Music::play();
}
}
}
void Menu::Context::act(){
// fader
if (fades){
fades->act();
if (state == Initializing){
if(fades->getState() == Gui::FadeTool::NoFade){
state = Running;
}
} else if (state == Finishing){
if(fades->getState() == Gui::FadeTool::EndFade){
state = Completed;
}
}
}
// Backgrounds
background.act();
}
void Menu::Context::render(Renderer * renderer, const Graphics::Bitmap & bmp){
if (!background.empty()){
// background
background.render(Gui::Animation::BackgroundBottom, bmp);
background.render(Gui::Animation::BackgroundMiddle, bmp);
background.render(Gui::Animation::BackgroundTop, bmp);
} else {
bmp.fill(Graphics::makeColor(0,0,0));
}
// Menu
if (renderer){
renderer->render(bmp, currentFont());
}
if (!background.empty()){
// foreground
background.render(Gui::Animation::ForegroundBottom, bmp);
background.render(Gui::Animation::ForegroundMiddle, bmp);
background.render(Gui::Animation::ForegroundTop, bmp);
}
// Fades
if (fades){
fades->draw(bmp);
}
}
void Menu::Context::setFadeTool(Gui::FadeTool *fade){
fades = fade;
}
/*
void Menu::Context::setBackground(Background *bg){
background = bg;
}
*/
/* New Menu */
// Utilizes default renderer
Menu::Menu::Menu(const Type & type):
renderer(0),
type(type){
setRenderer(type);
}
Menu::Menu::Menu(const Filesystem::AbsolutePath & filename, const Type & type):
renderer(0),
type(type){
// Load up tokenizer
try{
Global::debug(1,"menu") << "Loading menu " << filename.path() << endl;
TokenReader tr;
Token * token = tr.readTokenFromFile(*Storage::instance().open(filename));
OptionFactory defaultFactory;
load(token, defaultFactory);
} catch (const TokenException & e){
throw LoadException(__FILE__, __LINE__, e, "Error loading menu");
}
}
Menu::Menu::Menu(const Filesystem::AbsolutePath & filename, const OptionFactory & factory, const Type & type):
renderer(0),
type(type){
// Load up tokenizer
try{
Global::debug(1,"menu") << "Loading menu " << filename.path() << endl;
TokenReader tr;
Token * token = tr.readTokenFromFile(*Storage::instance().open(filename));
load(token, factory);
} catch (const TokenException & e){
throw LoadException(__FILE__, __LINE__, e, "Error loading menu");
}
}
Menu::Menu::Menu(const Token * token, const Type & type):
renderer(0),
type(type){
OptionFactory defaultFactory;
load(token, defaultFactory);
}
Menu::Menu::Menu(const Token * token, const OptionFactory & factory, const Type & type):
renderer(0),
type(type){
load(token, factory);
}
Menu::Menu::~Menu(){
// Kill values
for (std::map<string,ValueHolder *>::iterator i = data.begin(); i != data.end(); ++i){
if (i->second){
delete i->second;
}
}
// Kill renderer
if (renderer){
delete renderer;
}
}
void Menu::Menu::setFont(const Util::ReferenceCount<FontInfo> & font){
context.setFont(font);
/*
if (renderer){
renderer->setFont(font);
}
*/
}
void Menu::Menu::load(const Token * token, const OptionFactory & factory){
// version info;
int major=0, minor=0, micro=0;
if (!token->hasTokens()){
throw LoadException(__FILE__, __LINE__, "Empty Menu");
} else {
const Token *ourToken = token->findToken("_/type");
if (ourToken != NULL){
try {
std::string menuType;
ourToken->view() >> menuType;
if (menuType == "default"){
type = Default;
} else if (menuType == "tabbed"){
type = Tabbed;
}
} catch (const TokenException & ex){
}
}
ourToken = token->findToken("_/version");
if (ourToken != NULL){
try {
ourToken->view() >> major >> minor >> micro;
} catch (const TokenException & ex){
}
} else {
Global::debug(0, "menu") << "No version indicated, assuming 3.3.1 or below." << endl;
major = 3;
minor = 3;
micro = 1;
}
}
setRenderer(type);
if (Global::getVersion(major, minor, micro) != Global::getVersion()){
// Do compatible translations if necessary
handleCompatibility(token, Global::getVersion(major, minor, micro), factory);
} else {
handleCurrentVersion(token);
}
}
typedef Menu::Menu MenuClass;
class LanguageMenu: public Menu::Menu {
public:
class LanguageOption: public MenuOption {
public:
LanguageOption(const Gui::ContextBox & box, const string & language):
MenuOption(box, NULL){
setText(language);
setInfoText(language);
}
virtual void logic(){
}
virtual void run(const ::Menu::Context & context){
Configuration::setLanguage(getText());
Configuration::saveConfiguration();
throw ::Menu::MenuException(__FILE__, __LINE__);
}
};
static vector<string> findLanguages(const MenuClass & original){
return original.getLanguages();
}
static vector<string> putEnglishFirst(vector<string> languages){
vector<string> out;
bool haveEnglish = false;
for (vector<string>::iterator it = languages.begin(); it != languages.end(); it++){
const string & name = *it;
if (name == "English"){
out.insert(out.begin(), name);
haveEnglish = true;
} else {
out.push_back(name);
}
}
/* We should always have at least english available */
if (!haveEnglish){
out.insert(out.begin(), "English");
}
return out;
}
LanguageMenu(const MenuClass & original){
::Menu::DefaultRenderer * renderer = (::Menu::DefaultRenderer*) getRenderer();
vector<string> languages = putEnglishFirst(findLanguages(original));
for (vector<string>::iterator it = languages.begin(); it != languages.end(); it++){
addOption(new LanguageOption(renderer->getBox(), *it));
}
}
};
void Menu::Menu::setupDefaultLanguage(const Context & context, const MenuClass & parent){
LanguageMenu menu(parent);
menu.setFont(Util::ReferenceCount<FontInfo>(new RelativeFontInfo(Filesystem::RelativePath(sharedFont), sharedFontWidth, sharedFontHeight)));
Configuration::setLanguage("English");
try{
menu.run(context);
} catch (const ::Menu::MenuException & ignore){
}
}
void Menu::Menu::openOptions(){
vector<Util::ReferenceCount<MenuOption> > options = getRenderer()->getOptions();
for (vector<Util::ReferenceCount<MenuOption> >::iterator it = options.begin(); it != options.end(); it++){
Util::ReferenceCount<MenuOption> & option = *it;
option->open();
}
}
void Menu::Menu::closeOptions(){
vector<Util::ReferenceCount<MenuOption> > options = getRenderer()->getOptions();
for (vector<Util::ReferenceCount<MenuOption> >::iterator it = options.begin(); it != options.end(); it++){
Util::ReferenceCount<MenuOption> & option = *it;
option->close();
}
}
vector<string> Menu::Menu::getLanguages() const {
return languages;
}
void Menu::Menu::run(const Context & parentContext){
/* TODO: replace with Parameter */
Keyboard::pushRepeatState(true);
try{
// Setup context from parent and this menu and initialize
Context localContext(parentContext, context);
Util::Parameter<Util::ReferenceCount<FontInfo> > currentFont(menuFontParameter);
if (context.hasFont()){
currentFont.push(context.getFontInfo());
}
localContext.initialize();
/* Not sure if this is the right place to set the languages.
* For now the semantics is that if a sub-menu specifies a set
* of languages then we will use those, otherwise the
* languages will come from the parentContext.
*
* getLanguages() is supposed to hold at least one language
* which might be English, the default.
*
* This logic is sort of lame.. fix it.
*/
if (getLanguages().size() > 1 || (getLanguages().size() == 1 && getLanguages()[0] != "English")){
localContext.setLanguages(getLanguages());
}
// Setup menu fonts etc
if (renderer){
renderer->initialize(localContext);
// Invoke Override if available
renderer->invokeOverride(localContext);
}
//Play music
localContext.playMusic();
if (Configuration::getLanguage() == ""){
setupDefaultLanguage(localContext, *this);
}
/* do any lazy loading options want to do */
openOptions();
/* vi keys -- make these optional? */
input.set(Keyboard::Key_J, 0, true, Down);
input.set(Keyboard::Key_K, 0, true, Up);
input.set(Keyboard::Key_H, 0, true, Left);
input.set(Keyboard::Key_L, 0, true, Right);
/* regular keys */
input.set(Configuration::getUp(0), 0, true, Up);
input.set(Configuration::getDown(0), 0, true, Down);
input.set(Configuration::getLeft(0), 0, true, Left);
input.set(Configuration::getRight(0), 0, true, Right);
input.set(Configuration::getAttack1(0), 0, true, Select);
/* FIXME: use configuration keys */
input.set(Keyboard::Key_ENTER, 0, true, Select);
input.set(Keyboard::Key_ESC, 0, true, Cancel);
/* joystick */
- input.set(Configuration::getJoystickUp(0), 0, true, Up);
- input.set(Configuration::getJoystickDown(0), 0, true, Down);
- input.set(Configuration::getJoystickLeft(0), 0, true, Left);
- input.set(Configuration::getJoystickRight(0), 0, true, Right);
+ input.set(Joystick::Up, 0, true, Up);
+ input.set(Joystick::Down, 0, true, Down);
+ input.set(Joystick::Left, 0, true, Left);
+ input.set(Joystick::Right, 0, true, Right);
/*! FIXME this should be changed to Select/Cancel buttons, all other buttons should be Select */
- input.set(Configuration::getJoystickAttack1(0), 0, true, Select);
- input.set(Configuration::getJoystickAttack2(0), 0, true, Select);
- input.set(Configuration::getJoystickAttack3(0), 0, true, Select);
- input.set(Configuration::getJoystickJump(0), 0, true, Select);
- input.set(Configuration::getJoystickStart(0), 0, true, Select);
- input.set(Configuration::getJoystickQuit(0), 0, true, Cancel);
+ input.set(Joystick::Button1, 0, true, Select);
+ input.set(Joystick::Button2, 0, true, Select);
+ input.set(Joystick::Button3, 0, true, Select);
+ input.set(Joystick::Button4, 0, true, Select);
+ input.set(Joystick::Start, 0, true, Select);
+ input.set(Joystick::Quit, 0, true, Cancel);
class Logic: public Util::Logic {
public:
Logic(Menu & menu, Context & localContext, Renderer * renderer):
menu(menu),
localContext(localContext),
renderer(renderer){
}
Menu & menu;
Context & localContext;
Renderer * renderer;
void run(){
try {
menu.act(localContext);
} catch (const Exception::Return & ex){
// signaled to quit current menu, closing this one out
localContext.finish();
if (renderer){
renderer->finish();
}
}
}
double ticks(double system){
return system * Global::ticksPerSecond(90);
}
bool done(){
return localContext.getState() == Context::Completed ||
!(renderer && renderer->active());
}
};
class Draw: public Util::Draw {
public:
Draw(Menu & menu, Context & localContext):
menu(menu),
localContext(localContext){
}
Menu & menu;
Context & localContext;
void draw(const Graphics::Bitmap & buffer){
Graphics::StretchedBitmap work(640, 480, buffer, Graphics::qualityFilterName(Configuration::getQualityFilter()));
Util::Parameter<Util::ReferenceCount<FontInfo> > currentFont(menuFontParameter);
if (Configuration::hasMenuFont()){
currentFont.push(Configuration::getMenuFont());
}
work.start();
menu.render(localContext, work);
work.finish();
buffer.BlitToScreen();
}
};
Logic logic(*this, localContext, renderer);
Draw draw(*this, localContext);
Util::standardLoop(logic, draw);
closeOptions();
// FIXME Menu is finished, lets return. Is this even required anymore?
throw Exception::Return(__FILE__, __LINE__);
} catch (...){
Keyboard::popRepeatState();
throw;
}
}
void Menu::Menu::act(Context & ourContext){
// Keys
vector<InputMap<Actions>::InputEvent> events = InputManager::getEvents(input, InputSource());
for (vector<InputMap<Actions>::InputEvent>::iterator it = events.begin(); it != events.end(); it++){
InputMap<Actions>::InputEvent event = *it;
if (!event.enabled){
continue;
}
if (event.out == Cancel){
if (renderer){
InputManager::waitForRelease(input, InputSource(), Cancel);
renderer->doAction(Cancel, ourContext);
} else {
ourContext.playSound(Cancel);
InputManager::waitForRelease(input, InputSource(), Cancel);
throw Exception::Return(__FILE__, __LINE__);
}
}
if (renderer){
switch (event.out){
case Up: renderer->doAction(Up, ourContext); break;
case Down: renderer->doAction(Down, ourContext); break;
case Left: renderer->doAction(Left, ourContext); break;
case Right: renderer->doAction(Right, ourContext); break;
case Select: renderer->doAction(Select, ourContext); break;
default: break;
}
}
}
if (renderer){
Util::Parameter<Util::ReferenceCount<FontInfo> > currentFont(menuFontParameter);
if (Configuration::hasMenuFont()){
currentFont.push(Configuration::getMenuFont());
}
renderer->act(ourContext);
}
// Act context
ourContext.act();
}
void Menu::Menu::render(Context & ourContext, const Graphics::Bitmap & bmp){
// Render context
ourContext.render(renderer, bmp);
}
std::string Menu::Menu::getName(){
std::string name;
try {
if (data["name"]){
*data["name"] >> name;
}
} catch (const MenuException & ex){
}
return name;
}
std::string Menu::Menu::getInfo(){
std::string name;
try {
if (data["info"]){
*data["info"] >> name;
}
} catch (const MenuException & ex){
}
return name;
}
void Menu::Menu::addData(ValueHolder * item){
std::pair<std::map<std::string,ValueHolder *>::iterator,bool> check;
check = data.insert( std::pair<std::string,ValueHolder *>(item->getName(),item) );
if (check.second == false){
Global::debug(0,"menu") << "Value \"" << check.first->second->getName() << "\" already exists - (" << check.first->second->getValues() << ")." << endl;
Global::debug(0,"menu") << "Replacing with value \"" << item->getName() << "\" - (" << item->getValues() << ")." << endl;
data[item->getName()] = item;
}
}
void Menu::Menu::handleCurrentVersion(const Token * token){
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
// Newer items
if (*tok == "val" || *tok == "value"){
const Token * val;
tok->view() >> val;
ValueHolder * value = new ValueHolder(val->getName());
TokenView valueView = val->view();
try {
while (true){
*value << valueView;
}
} catch (const TokenException & ex){
}
addData(value);
} else if (*tok == "context"){
context.parseToken(tok);
} else {
Global::debug(3,"menu") <<"Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch (const LoadException & ex){
throw ex;
} catch (const Filesystem::NotFound & ex){
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
}
}
}
void Menu::Menu::handleCompatibility(const Token * token, int version, const OptionFactory & factory){
Global::debug(1,"menu") << "Trying version: " << version << endl;
if (version <= Global::getVersion(3, 3, 1)){
const Token * languages = token->findToken("_/languages");
if (languages != NULL){
try{
TokenView view = languages->view();
while (true){
string language;
view >> language;
this->languages.push_back(language);
}
} catch (const TokenException & fail){
}
}
if (this->languages.size() == 0){
this->languages.push_back("English");
}
TokenView view = token->view();
while (view.hasMore()){
try {
const Token * tok;
view >> tok;
if ( *tok == "name" ){
ValueHolder * value = new ValueHolder("name");
TokenView nameView = tok->view();
*value << nameView;
addData(value);
} else if ( *tok == "music" ) {
ValueHolder * value = new ValueHolder("music");
TokenView musicView = tok->view();
*value << musicView;
addData(value);
try {
std::string music;
*value >> music;
context.setMusic(Filesystem::RelativePath(music));
} catch (const MenuException & ex){
}
} else if( *tok == "select-sound" ) {
ValueHolder * value = new ValueHolder("select-sound");
TokenView soundView = tok->view();
*value << soundView;
addData(value);
try{
std::string sound;
*value >> sound;
context.addSound(Up, Filesystem::RelativePath(sound));
context.addSound(Down, Filesystem::RelativePath(sound));
} catch (const MenuException & ex){
}
} else if (*tok == "back-sound"){
ValueHolder * value = new ValueHolder("back-sound");
TokenView soundView = tok->view();
*value << soundView;
addData(value);
try{
std::string sound;
*value >> sound;
context.addSound(Back,Filesystem::RelativePath(sound));
context.addSound(Cancel,Filesystem::RelativePath(sound));
} catch (const MenuException & ex){
}
} else if (*tok == "ok-sound"){
ValueHolder * value = new ValueHolder("ok-sound");
TokenView okView = tok->view();
*value << okView;
addData(value);
try{
std::string sound;
*value >> sound;
context.addSound(Select,Filesystem::RelativePath(sound));
} catch (const MenuException & ex){
}
} else if ( *tok == "background" ) {
std::string temp;
tok->view() >> temp;
context.addBackground(temp);
} else if (*tok == "anim"){
context.addBackground(tok);
} else if ( *tok == "clear-color" ) {
// Not necessary ignore
} else if (renderer && renderer->readToken(tok, factory)){
// Nothing checks compatible version of renderer
} else if ( *tok == "font" ) {
ValueHolder * value = new ValueHolder("font");
TokenView fontView = tok->view();
*value << fontView << fontView << fontView;
addData(value);
try {
std::string font;
int w = 24, h = 24;
*value >> font >> w >> h;
/*context.setFont(Filesystem::RelativePath(font));
context.setFontWidth(w);
context.setFontHeight(h);*/
context.setFont(Util::ReferenceCount<FontInfo>(new RelativeFontInfo(Filesystem::RelativePath(font), w, h)));
} catch (const MenuException & ex){
}
} else if ( *tok == "action"){
// Set speed
//ActionAct(tok);
} else if ( *tok == "info-position"){
ValueHolder * value = new ValueHolder("info-position");
TokenView infoView = tok->view();
*value << infoView << infoView;
addData(value);
try {
double x=0, y=-.5;
*value >> x >> y;
context.setInfoLocation(x,y);
} catch (const MenuException & ex){
}
} else if (*tok == "menuinfo"){
ValueHolder * value = new ValueHolder("menuinfo");
TokenView infoView = tok->view();
*value << infoView;
addData(value);
try {
std::string info;
*value >> info;
context.setMenuInfoText(info);
} catch (const MenuException & ex){
}
} else if (*tok == "menuinfo-position"){
ValueHolder * value = new ValueHolder("menuinfo-position");
TokenView infoView = tok->view();
*value << infoView << infoView;
addData(value);
try {
double x=0, y=.95;
*value >> x >> y;
context.setMenuInfoLocation(x,y);
} catch (const MenuException & ex){
}
} else {
Global::debug(3,"menu") <<"Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch (const LoadException & ex){
throw ex;
} catch (const Filesystem::NotFound & ex){
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
}
}
}
}
void Menu::Menu::setRenderer(const Type & type){
if (renderer){
delete renderer;
}
renderer = rendererType(type);
}
Menu::Renderer * Menu::Menu::rendererType(const Type & type){
switch (type){
case Tabbed: {
return new TabRenderer();
break;
}
case Default:
default: {
return new DefaultRenderer();
break;
}
}
}
diff --git a/util/menu/options.cpp b/util/menu/options.cpp
index d6b9f8b0..c4e57f92 100644
--- a/util/menu/options.cpp
+++ b/util/menu/options.cpp
@@ -1,2546 +1,2548 @@
#include "util/bitmap.h"
#include "util/stretch-bitmap.h"
#include "util/trans-bitmap.h"
#include "options.h"
#include "util/token.h"
#include "util/input/input-source.h"
#include "util/parameter.h"
#include "util/tokenreader.h"
#include "menu.h"
#include "configuration.h"
#include "menu-exception.h"
#include "util/init.h"
#include "util/events.h"
#include "optionfactory.h"
#include "util/music.h"
#include "util/input/keyboard.h"
#include "util/funcs.h"
#include "util/file-system.h"
#include "factory/font_factory.h"
#include "globals.h"
#include "util/exceptions/shutdown_exception.h"
#include "util/exceptions/exception.h"
#include "util/font.h"
#include "util/gui/box.h"
#include "util/thread.h"
#include "util/loading.h"
#include "util/fire.h"
#include "util/input/input-map.h"
#include "util/input/input-manager.h"
#include <sstream>
#include <algorithm>
#include <time.h>
#include <math.h>
using namespace std;
using namespace Gui;
/* true if the arguments passed in match todays date.
* pass 0 for any argument that you don't care about (it will match any date)
*/
static bool todaysDate(int month, int day, int year){
int currentMonth;
int currentDay;
int currentYear;
time_t result = time(NULL);
struct tm * local = localtime(&result);
return (month == 0 || month == (local->tm_mon + 1)) &&
(day == 0 || day == local->tm_mday) &&
(year == 0 || year == local->tm_year + 1900);
}
static bool jonBirthday(){
return todaysDate(3, 25, 0);
}
static bool miguelBirthday(){
return todaysDate(8, 11, 0);
}
OptionCredits::Block::Block(const std::string & title):
title(title),
titleColorOverride(false),
titleColor(Graphics::makeColor(0,255,255)),
colorOverride(false),
color(Graphics::makeColor(255,255,255)),
spacing(0){
}
OptionCredits::Block::Block(const Token * token):
titleColorOverride(false),
titleColor(Graphics::makeColor(0,255,255)),
colorOverride(false),
color(Graphics::makeColor(255,255,255)),
topWidth(0),
topHeight(0),
bottomWidth(0),
bottomHeight(0),
spacing(0){
if ( *token != "block" ){
throw LoadException(__FILE__, __LINE__, "Not a credit block");
}
TokenView view = token->view();
while (view.hasMore()){
std::string match;
try{
const Token * tok;
view >> tok;
if ( *tok == "title" ) {
tok->view() >> title;
} else if (*tok == "credit"){
std::string credit;
tok->view() >> credit;
credits.push_back(credit);
} else if ( *tok == "titlecolor" ) {
try{
int r,b,g;
tok->view() >> r >> g >> b;
titleColor = Graphics::makeColor( r, g, b );
titleColorOverride = true;
} catch (const TokenException & ex){
}
} else if ( *tok == "color" ) {
try{
int r,b,g;
tok->view() >> r >> g >> b;
color = Graphics::makeColor( r, g, b );
colorOverride = true;
} catch (const TokenException & ex){
}
} else if ( *tok == "animation" ) {
TokenView animView = tok->view();
while (animView.hasMore()){
const Token * animTok;
animView >> animTok;
if (*animTok == "top"){
tok->match("_/width", topWidth);
tok->match("_/height", topHeight);
topAnimation = Util::ReferenceCount<Gui::Animation>(new Animation(tok));
} else if (*animTok == "bottom"){
tok->match("_/width", bottomWidth);
tok->match("_/height", bottomHeight);
bottomAnimation = Util::ReferenceCount<Gui::Animation>(new Animation(tok));
}
}
} else if (*tok == "spacing"){
tok->view() >> spacing;
} else {
Global::debug( 3 ) <<"Unhandled Credit Block attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Credit Block parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
OptionCredits::Block::Block(const OptionCredits::Block & copy):
title(copy.title),
credits(copy.credits),
titleColorOverride(copy.titleColorOverride),
titleColor(copy.titleColor),
colorOverride(copy.colorOverride),
color(copy.color),
topAnimation(copy.topAnimation),
topWidth(copy.topWidth),
topHeight(copy.topHeight),
bottomAnimation(copy.bottomAnimation),
bottomWidth(copy.bottomWidth),
bottomHeight(copy.bottomHeight),
spacing(copy.spacing){
}
OptionCredits::Block::~Block(){
}
const OptionCredits::Block & OptionCredits::Block::operator=(const OptionCredits::Block & copy){
title = copy.title;
credits = copy.credits;
titleColor = copy.titleColor;
titleColorOverride = copy.titleColorOverride;
color = copy.color;
colorOverride = copy.colorOverride;
topAnimation = copy.topAnimation;
topWidth =copy.topWidth;
topHeight = copy.topHeight;
bottomAnimation = copy.bottomAnimation;
bottomWidth = copy.bottomWidth;
bottomHeight = copy.bottomHeight;
spacing = copy.spacing;
return *this;
}
void OptionCredits::Block::addCredit(const std::string & credit){
credits.push_back(credit);
}
void OptionCredits::Block::act(){
// Top animation
if (topAnimation != NULL){
topAnimation->act();
}
// Bottom animation
if (bottomAnimation != NULL){
bottomAnimation->act();
}
}
int OptionCredits::Block::print(int x, int y, Graphics::Color defaultTitleColor, Graphics::Color defaultColor, const Font & font, const Graphics::Bitmap & work, const Justification & justification) const {
int currentY = y;
// Top animation
if (topAnimation != NULL){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = topWidth/2;
break;
case Right:
xmod = topWidth;
break;
}
// FIXME temporary solution
const Graphics::Bitmap & temp = Graphics::Bitmap::temporaryBitmap(topWidth, topHeight);
//topAnimation->draw(x - xmod, y, topWidth, topHeight, work);
topAnimation->draw(0, 0, topWidth, topHeight, temp);
temp.translucent().draw(x-xmod, y, work);
currentY+=topHeight;
}
if (!title.empty()){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = font.textLength(title.c_str())/2;
break;
case Right:
xmod = font.textLength(title.c_str());
break;
}
font.printf(x - xmod, currentY, (titleColorOverride ? titleColor : defaultTitleColor), work, title, 0);
currentY += font.getHeight();
}
for (std::vector<std::string>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const std::string & credit = *i;
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = font.textLength(credit.c_str())/2;
break;
case Right:
xmod = font.textLength(credit.c_str());
break;
}
font.printf(x - xmod, currentY, (colorOverride ? color : defaultColor), work, credit, 0);
currentY += font.getHeight();
}
// Bottom animation
if (bottomAnimation != NULL){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = bottomWidth/2;
break;
case Right:
xmod = bottomWidth;
break;
}
// FIXME temporary solution
const Graphics::Bitmap & temp = Graphics::Bitmap::temporaryBitmap(topWidth, topHeight);
//bottomAnimation->draw(x - xmod, y, bottomWidth, bottomHeight, work);
bottomAnimation->draw(0, 0, bottomWidth, bottomHeight, temp);
temp.translucent().draw(x-xmod, y, work);
currentY+=bottomHeight;
}
currentY += font.getHeight() + spacing;
return currentY;
}
const int OptionCredits::Block::size(const Font & font) const{
// Counts title and space in between
int total = 0;
if (topAnimation != NULL){
total += topHeight;
}
if (!title.empty()){
total+= font.getHeight();
}
total += credits.size() * font.getHeight();
if (bottomAnimation != NULL){
total += bottomHeight;
}
total += font.getHeight();
total += spacing;
return total;
}
OptionCredits::Sequence::Sequence(const Token * token):
type(Primary),
x(0),
y(0),
startx(0),
endx(0),
starty(0),
endy(0),
ticks(0),
duration(250),
speed(0),
alpha(0),
alphaMultiplier(0),
justification(Block::Center),
current(0),
done(false),
creditLength(0){
if ( *token != "sequence" ){
throw LoadException(__FILE__, __LINE__, "Not a credit sequence");
}
TokenView view = token->view();
while (view.hasMore()){
std::string match;
try{
const Token * tok;
view >> tok;
if (*tok == "type"){
std::string sequenceType;
tok->view() >> sequenceType;
if (sequenceType == "roll"){
type = Roll;
} else if (sequenceType == "primary"){
type = Primary;
}
} else if (*tok == "start-x"){
tok->view() >> startx;
} else if (*tok == "end-x"){
tok->view() >> endx;
} else if (*tok == "start-y"){
tok->view() >> starty;
} else if (*tok == "end-y"){
tok->view() >> endy;
} else if (*tok == "duration"){
tok->view() >> duration;
} else if (*tok == "speed"){
tok->view() >> speed;
} else if (*tok == "alpha-multiplier"){
tok->view() >> alphaMultiplier;
} else if ( *tok == "justification" ) {
std::string justify;
tok->view() >> justify;
if (justify == "left"){
justification = Block::Left;
} else if (justify == "center"){
justification = Block::Center;
} else if (justify == "right"){
justification = Block::Right;
}
} else if (*tok == "block"){
credits.push_back(Block(tok));
} else {
Global::debug( 3 ) <<"Unhandled Credit Sequence attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Credit Sequence parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
// Initial
reset();
for (std::vector<OptionCredits::Block>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const OptionCredits::Block & block = *i;
creditLength += block.size(Menu::menuFontParameter.current()->get());
}
}
OptionCredits::Sequence::Sequence(const Sequence & copy):
type(copy.type),
x(copy.x),
y(copy.y),
startx(copy.startx),
endx(copy.endx),
starty(copy.starty),
endy(copy.endy),
ticks(copy.ticks),
duration(copy.duration),
speed(copy.speed),
alpha(copy.alpha),
alphaMultiplier(copy.alphaMultiplier),
justification(copy.justification),
credits(copy.credits),
current(copy.current),
done(false),
creditLength(copy.creditLength){
}
OptionCredits::Sequence::~Sequence(){
}
const OptionCredits::Sequence & OptionCredits::Sequence::operator=(const OptionCredits::Sequence & copy){
type = copy.type;
x = copy.x;
y = copy.y;
startx = copy.startx;
endx = copy.endx;
starty = copy.starty;
endy = copy.endy;
ticks = copy.ticks;
duration = copy.duration;
speed = copy.speed;
alpha = copy.alpha;
alphaMultiplier = copy.alphaMultiplier;
justification = copy.justification;
credits = copy.credits;
current = copy.current;
done = false;
creditLength = copy.creditLength;
return *this;
}
static int alphaClamp(int x, double multiplier){
int clamp = x * multiplier;
if (clamp < 0){
clamp = 0;
} else if (clamp > 255){
clamp = 255;
}
return clamp;
}
void OptionCredits::Sequence::act(){
if (!done && !credits.empty()){
if (type == Roll){
y += speed;
if (starty > endy){
if ((y + (creditLength * 1.1)) < endy){
done = true;
}
} else if (starty < endy){
if ((y * 1.1) > endy){
done = true;
}
}
} else if (type == Primary){
credits[current].act();
if (startx != endx){
x += speed;
if (startx > endx){
const double midpoint = (startx+endx)/2;
const int mid = x > midpoint ? startx -x : x - endx;
alpha = alphaClamp(mid, alphaMultiplier);
if (x < endx){
next();
}
} else if (startx < endx){
const double midpoint = (startx+endx)/2;
const int mid = x < midpoint ? x - startx : endx - x;
alpha = alphaClamp(mid, alphaMultiplier);
//Global::debug(0) << "alpha: " << alpha << " midpoint: " << midpoint << " mid: " << mid << std::endl;
if (x > endx){
next();
}
}
} else {
const double midpoint = duration/2;
const int mid = ticks < midpoint ? ticks : duration - ticks;
alpha = alphaClamp(mid, alphaMultiplier);
ticks++;
if (ticks >= duration){
ticks = 0;
next();
}
}
}
}
}
void OptionCredits::Sequence::draw(Graphics::Color title, Graphics::Color color, const Graphics::Bitmap & work){
if (!done && !credits.empty()){
if (type == Roll){
int rollY = (int) y;
for (std::vector<OptionCredits::Block>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const OptionCredits::Block & block = *i;
rollY = block.print(x, rollY, title, color, Menu::menuFontParameter.current()->get(), work, justification);
}
} else if (type == Primary){
Graphics::Bitmap::transBlender(0, 0, 0, alpha);
credits[current].print(x, y, title, color, Menu::menuFontParameter.current()->get(), work.translucent(), justification);
}
}
}
void OptionCredits::Sequence::reset(){
done = false;
current = 0;
ticks = 0;
if (!credits.empty()){
if (type == Roll){
x = startx;
y = starty;
} else if (type == Primary){
x = startx;
y = starty - (credits[current].size(Menu::menuFontParameter.current()->get())/2);
}
}
}
void OptionCredits::Sequence::next(){
if (type == Primary){
if (current < credits.size()){
current++;
if (current == credits.size()){
done = true;
} else {
x = startx;
y = starty - (credits[current].size(Menu::menuFontParameter.current()->get())/2);
}
}
}
}
static std::string defaultPositions(){
const int width = Configuration::getScreenWidth();
const int height = Configuration::getScreenHeight();
std::ostringstream out;
out << "(start-x " << width/2.3 << ") (end-x " << width/1.8 << ") (start-y " << height/2 << ") ";
//out << "(start-x " << width/2 << ") (end-x " << width/2 << ") (start-y " << height/2 << ") (duration 250) ";
return out.str();
}
OptionCredits::OptionCredits(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token),
creditsContext(new Menu::Context()),
music(""),
color(Graphics::makeColor(255,255,255)),
title(Graphics::makeColor(0,255,255)),
clearColor(Graphics::makeColor(0,0,0)){
std::string defaultSequence = "(sequence (type primary) (speed 0.3) (alpha-multiplier 20) (justification center) " + defaultPositions();
/* Always */
if (jonBirthday()){
defaultSequence += "(block (title \"Happy birthday, Jon!\"))";
}
if (miguelBirthday()){
defaultSequence += "(block (title \"Happy birthday, Jon!\"))";
}
defaultSequence += "(block (animation (top) (width 350) (height 65) (image 0 \"sprites/paintown.png\") (frame (image 0) (time -1))) (credit \"Version " + Global::getVersionString() + "\"))";
defaultSequence += "(block (title \"Programming\") (credit \"Jon Rafkind\") (credit \"Miguel Gavidia\"))";
defaultSequence += "(block (title \"Level design\") (credit \"Jon Rafkind\") (credit \"Miguel Gavidia\"))";
defaultSequence += "(block (title \"Contact\") (credit \"Website: http://paintown.org\") (credit \"Email: jon@rafkind.com\")))";
TokenReader reader;
Sequence sequence(reader.readTokenFromString(defaultSequence));
sequences.push_back(sequence);
//Global::debug(0) << defaultSequence << std::endl;
if ( *token != "credits" ){
throw LoadException(__FILE__, __LINE__, "Not a credit menu");
}
readName(token);
TokenView view = token->view();
// NOTE Use this to handle legacy additional blocks for the time being
Block legacyAdditional("");
bool additionalTitle = true;
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "music" ) {
/* Set music for credits */
tok->view() >> music;
} else if ( *tok == "background" ) {
/* Create an image and push it back on to vector */
std::string temp;
tok->view() >> temp;
creditsContext->addBackground(temp);
} else if ( *tok == "anim" || *tok == "animation" ){
creditsContext->addBackground(tok);
} else if ( *tok == "additional" ) {
std::string str;
TokenView additionalView = tok->view();
while (additionalView.hasMore()){
additionalView >> str;
if (additionalTitle){
legacyAdditional = Block(str);
additionalTitle = false;
} else {
legacyAdditional.addCredit(str);
}
}
} else if (*tok == "sequence"){
sequences.push_back(OptionCredits::Sequence(tok));
} else if ( *tok == "titlecolor" ) {
int r,b,g;
tok->view() >> r >> g >> b;
title = Graphics::makeColor( r, g, b );
} else if ( *tok == "color" ) {
int r,b,g;
tok->view() >> r >> g >> b;
color = Graphics::makeColor( r, g, b );
} else if ( *tok == "clear-color" ) {
int r,b,g;
tok->view() >> r >> g >> b;
clearColor = Graphics::makeColor( r, g, b );
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
if (!legacyAdditional.empty()){
//creditsRoll.push_back(legacyAdditional);
}
input.set(Keyboard::Key_ESC, 0, true, Exit);
input.set(Joystick::Button2, 0, true, Exit);
}
OptionCredits::~OptionCredits(){
}
void OptionCredits::logic(){
}
class LogicDraw : public Util::Logic, public Util::Draw{
public:
LogicDraw(std::vector<OptionCredits::Sequence> & sequences, Graphics::Color clearColor, Graphics::Color title, Graphics::Color color, const Font & font, InputMap<OptionCredits::CreditKey> & input, Menu::Context & context):
sequences(sequences),
clearColor(clearColor),
title(title),
color(color),
font(font),
input(input),
quit(false),
context(context),
current(0){
}
std::vector<OptionCredits::Sequence> & sequences;
Graphics::Color clearColor, title, color;
const Font & font;
InputMap<OptionCredits::CreditKey> & input;
bool quit;
Menu::Context & context;
unsigned int current;
void run(){
vector<InputMap<OptionCredits::CreditKey>::InputEvent> out = InputManager::getEvents(input, InputSource());
for (vector<InputMap<OptionCredits::CreditKey>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<OptionCredits::CreditKey>::InputEvent & event = *it;
if (event.enabled){
if (event.out == OptionCredits::Exit){
quit = true;
context.finish();
}
}
}
sequences[current].act();
if (sequences[current].isDone()){
sequences[current].reset();
current++;
if (current >= sequences.size()){
current = 0;
}
}
context.act();
}
bool done(){
return quit;
}
double ticks(double system){
return system * Global::ticksPerSecond(90);
}
void draw(const Graphics::Bitmap & buffer){
/* FIXME: hard coded resolution */
Graphics::StretchedBitmap work(640, 480, buffer, Graphics::qualityFilterName(Configuration::getQualityFilter()));
work.fill(clearColor);
work.start();
//background.Blit(work);
context.render(NULL, work);
sequences[current].draw(title, color, work);
work.finish();
buffer.BlitToScreen();
}
};
void OptionCredits::run(const Menu::Context & context){
Menu::Context localContext(context, *creditsContext);
localContext.initialize();
if (!music.empty()){
if (Music::loadSong(Storage::instance().find(Filesystem::RelativePath(music)).path())){
Music::pause();
Music::play();
}
}
const Font & vFont = Menu::menuFontParameter.current()->get();
LogicDraw loop(sequences, clearColor, title, color, vFont, input, localContext);
Util::standardLoop(loop, loop);
InputManager::waitForRelease(input, InputSource(), Exit);
throw Menu::Reload(__FILE__, __LINE__);
}
OptionDummy::OptionDummy(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
if ( *token != "dummy" ){
throw LoadException(__FILE__, __LINE__, "Not dummy option");
}
readName(token);
if (getText().empty()){
this->setText("Dummy");
}
setRunnable(false);
}
OptionDummy::OptionDummy(const Gui::ContextBox & parent, const std::string &name):
MenuOption(parent, 0){
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name given to dummy");
}
this->setText(name);
setRunnable(false);
}
OptionDummy::~OptionDummy(){
}
void OptionDummy::logic(){
}
void OptionDummy::run(const Menu::Context & context){
}
OptionFullscreen::OptionFullscreen(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "fullscreen" )
throw LoadException(__FILE__, __LINE__, "Not fullscreen option");
readName(token);
}
OptionFullscreen::~OptionFullscreen()
{
// Nothing
}
std::string OptionFullscreen::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << (Configuration::getFullscreen() ? "Yes" : "No");
return out.str();
}
void OptionFullscreen::logic(){;
}
static void changeScreenMode(){
Configuration::setFullscreen(!Configuration::getFullscreen());
int gfx = (Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED);
Graphics::setGraphicsMode(gfx, Global::getScreenWidth(), Global::getScreenHeight());
}
void OptionFullscreen::run(const Menu::Context & context){
changeScreenMode();
}
bool OptionFullscreen::leftKey(){
changeScreenMode();
return true;
}
bool OptionFullscreen::rightKey(){
changeScreenMode();
return true;
}
OptionFps::OptionFps(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
setRunnable(false);
}
void OptionFps::logic(){
}
void OptionFps::run(const Menu::Context & context){
}
std::string OptionFps::getText() const {
ostringstream out;
out << "Frames per second: " << Global::TICS_PER_SECOND;
return out.str();
}
bool OptionFps::leftKey(){
Global::setTicksPerSecond(Global::TICS_PER_SECOND - 1);
Configuration::setFps(Global::TICS_PER_SECOND);
return true;
}
bool OptionFps::rightKey(){
Global::setTicksPerSecond(Global::TICS_PER_SECOND + 1);
Configuration::setFps(Global::TICS_PER_SECOND);
return true;
}
OptionFps::~OptionFps(){
}
OptionQualityFilter::OptionQualityFilter(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
setRunnable(false);
}
std::string OptionQualityFilter::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getQualityFilter();
return out.str();
}
void OptionQualityFilter::logic(){
}
bool OptionQualityFilter::leftKey(){
string quality = Configuration::getQualityFilter();
if (quality == "none"){
quality = "hqx";
} else if (quality == "hqx"){
quality = "xbr";
} else if (quality == "xbr"){
quality = "none";
}
Configuration::setQualityFilter(quality);
return true;
}
bool OptionQualityFilter::rightKey(){
string quality = Configuration::getQualityFilter();
if (quality == "none"){
quality = "xbr";
} else if (quality == "hqx"){
quality = "none";
} else if (quality == "xbr"){
quality = "hqx";
}
Configuration::setQualityFilter(quality);
return true;
}
void OptionQualityFilter::run(const Menu::Context & context){
}
OptionQualityFilter::~OptionQualityFilter(){
}
OptionInvincible::OptionInvincible(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "invincible" )
throw LoadException(__FILE__, __LINE__, "Not invincible option");
readName(token);
}
OptionInvincible::~OptionInvincible()
{
// Nothing
}
std::string OptionInvincible::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << (Configuration::getInvincible() ? "Yes" : "No");
return out.str();
}
void OptionInvincible::logic(){
}
void OptionInvincible::run(const Menu::Context & context){
}
bool OptionInvincible::leftKey(){
Configuration::setInvincible(!Configuration::getInvincible());
return true;
}
bool OptionInvincible::rightKey(){
Configuration::setInvincible(!Configuration::getInvincible());
return true;
}
static OptionJoystick::JoystickType convertToKey(const std::string &k){
std::string temp = k;
for(unsigned int i=0;i<temp.length();i++){
temp[i] = tolower(temp[i]);
}
if (temp == "up") return OptionJoystick::Up;
if (temp == "down") return OptionJoystick::Down;
if (temp == "left") return OptionJoystick::Left;
if (temp == "right") return OptionJoystick::Right;
if (temp == "jump") return OptionJoystick::Jump;
if (temp == "attack1") return OptionJoystick::Attack1;
if (temp == "attack2") return OptionJoystick::Attack2;
if (temp == "attack3") return OptionJoystick::Attack3;
if (temp == "attack4") return OptionJoystick::Attack4;
if (temp == "attack5") return OptionJoystick::Attack5;
if (temp == "attack6") return OptionJoystick::Attack6;
return OptionJoystick::Invalidkey;
}
static Configuration::JoystickInput getKey(int player, OptionJoystick::JoystickType k){
switch(k){
case OptionJoystick::Up:
- return Configuration::getJoystickUp(player);
+ return Joystick::Up;
case OptionJoystick::Down:
- return Configuration::getJoystickDown(player);
+ return Joystick::Down;
case OptionJoystick::Left:
- return Configuration::getJoystickLeft(player);
+ return Joystick::Left;
case OptionJoystick::Right:
- return Configuration::getJoystickRight(player);
+ return Joystick::Right;
case OptionJoystick::Jump:
- return Configuration::getJoystickJump(player);
+ return Joystick::Button4;
case OptionJoystick::Attack1:
- return Configuration::getJoystickAttack1(player);
+ return Joystick::Button1;
case OptionJoystick::Attack2:
- return Configuration::getJoystickAttack2(player);
+ return Joystick::Button2;
case OptionJoystick::Attack3:
- return Configuration::getJoystickAttack3(player);
+ return Joystick::Button3;
case OptionJoystick::Attack4:
- return Configuration::getJoystickAttack4(player);
+ return Joystick::Button4;
case OptionJoystick::Attack5:
- return Configuration::getJoystickAttack5(player);
+ return Joystick::Button5;
case OptionJoystick::Attack6:
- return Configuration::getJoystickAttack6(player);
+ return Joystick::Button6;
default:
break;
}
- return Configuration::getJoystickUp(player);
+ return Joystick::Up;
}
static void setKey(int player, OptionJoystick::JoystickType k, Configuration::JoystickInput key){
+ /*
switch(k){
case OptionJoystick::Up:
Configuration::setJoystickUp(player, key);
break;
case OptionJoystick::Down:
Configuration::setJoystickDown(player, key);
break;
case OptionJoystick::Left:
Configuration::setJoystickLeft(player, key);
break;
case OptionJoystick::Right:
Configuration::setJoystickRight(player, key);
break;
case OptionJoystick::Jump:
Configuration::setJoystickJump(player, key);
break;
case OptionJoystick::Attack1:
Configuration::setJoystickAttack1(player, key);
break;
case OptionJoystick::Attack2:
Configuration::setJoystickAttack2(player, key);
break;
case OptionJoystick::Attack3:
Configuration::setJoystickAttack3(player, key);
break;
case OptionJoystick::Attack4:
Configuration::setJoystickAttack4(player, key);
break;
case OptionJoystick::Attack5:
Configuration::setJoystickAttack5(player, key);
break;
case OptionJoystick::Attack6:
Configuration::setJoystickAttack6(player, key);
break;
default:
break;
}
+ */
}
static Configuration::JoystickInput readJoystick(){
vector<Joystick::Key> keys;
keys.push_back(Joystick::Up);
keys.push_back(Joystick::Down);
keys.push_back(Joystick::Left);
keys.push_back(Joystick::Right);
keys.push_back(Joystick::Button1);
keys.push_back(Joystick::Button2);
keys.push_back(Joystick::Button3);
keys.push_back(Joystick::Button4);
keys.push_back(Joystick::Button5);
keys.push_back(Joystick::Button6);
InputMap<Joystick::Key> input;
for (vector<Joystick::Key>::iterator it = keys.begin(); it != keys.end(); it++){
input.set(*it, 0, true, *it);
}
input.set(Keyboard::Key_ESC, 0, true, Joystick::Invalid);
while (true){
InputManager::poll();
vector<InputMap<Joystick::Key>::InputEvent> out = InputManager::getEvents(input, InputSource());
for (vector<InputMap<Joystick::Key>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<Joystick::Key>::InputEvent & event = *it;
if (event.enabled){
Global::debug(1) << "Press: " << event.out << std::endl;
if (event.out == Joystick::Invalid){
InputManager::waitForRelease(input, InputSource(), Joystick::Invalid);
throw Exception::Return(__FILE__, __LINE__);
}
return event.out;
}
}
Util::rest(1);
}
/* control probably shouldn't get here.. */
return Joystick::Up;
}
OptionJoystick::OptionJoystick(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
player(-1),
type(Invalidkey),
keyCode(0){
if (*token != "joystick"){
throw LoadException(__FILE__, __LINE__, "Not joystick option");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "name" ){
tok->view() >> name;
} else if ( *tok == "player" ) {
tok->view() >> player;
} else if ( *tok == "type" ) {
std::string temp;
tok->view() >> temp;
type = convertToKey(temp);
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name set, this option should have a name!");
}
if (type == Invalidkey){
throw LoadException(__FILE__, __LINE__, "Invalid joystick button, should be up, down, left, right, up, down, jump, attack1-6!");
}
if (player == -1){
throw LoadException(__FILE__, __LINE__, "Player not specified in joystick configuration");
}
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
}
OptionJoystick::~OptionJoystick(){
// Nothing
}
void OptionJoystick::logic(){
/*
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Joystick::keyToName(getKey(player,type)));
setText(std::string(temp));
*/
}
void OptionJoystick::run(const Menu::Context & context){
/*
//int x, y, width, height;
const Font & vFont = Menu::menuFontParameter.current()->get();
const char * message = "Press a joystick button!";
const int width = vFont.textLength(message) + 10;
const int height = vFont.getHeight() + 10;
// const int x = (getParent()->getWork()->getWidth()/2) - (width/2);
// const int y = (getParent()->getWork()->getHeight()/2) - (height/2);
const int x = Menu::Menu::Width / 2 - width/2;
const int y = Menu::Menu::Height / 2 - height/2;
Box dialog;
dialog.location.setPosition(Gui::AbsolutePoint(0,0));
dialog.location.setDimensions(vFont.textLength(message) + 10, vFont.getHeight() + 10);
dialog.transforms.setRadius(0);
dialog.colors.body = Graphics::makeColor(0,0,0);
dialog.colors.bodyAlpha = 200;
dialog.colors.border = Graphics::makeColor(255,255,255);
dialog.colors.borderAlpha = 255;
Graphics::Bitmap temp = Graphics::Bitmap::temporaryBitmap(width,height);
dialog.render(temp, vFont);
vFont.printf( 5, 5, Graphics::makeColor(255,255,255), temp, message, -1);
temp.BlitToScreen(x,y);
setKey(player, type, readJoystick());
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
*/
Graphics::Bitmap temp(Menu::Menu::Width, Menu::Menu::Height);
// Menu::Context tempContext = context;
Menu::Context tempContext(context);
tempContext.initialize();
Menu::InfoBox keyDialog;
// keyDialog.setFont(tempContext.getFont());
//keyDialog.location.set(-1,-1,1,1);
const int width = temp.getWidth();
const int height = temp.getHeight();
const Font & font = Menu::menuFontParameter.current()->get();
const int radius = 15;
keyDialog.setText("Press a joystick button!");
keyDialog.initialize(font);
keyDialog.location.setDimensions(font.textLength("Press a joystick button!") + radius, font.getHeight() + radius);
keyDialog.location.setCenterPosition(Gui::RelativePoint(0, 0));
// keyDialog.location.setPosition(Gui::AbsolutePoint((width/2)-(keyDialog.location.getWidth()/2), (height/2)-(keyDialog.location.getHeight()/2)));
// keyDialog.location.setPosition2(Gui::AbsolutePoint((
keyDialog.transforms.setRadius(radius);
keyDialog.colors.body = Graphics::makeColor(0,0,0);
keyDialog.colors.bodyAlpha = 180;
keyDialog.colors.border = Graphics::makeColor(255,255,255);
keyDialog.colors.borderAlpha = 255;
keyDialog.open();
InputManager::waitForClear();
while (!InputManager::anyInput() && keyDialog.isActive()){
InputManager::poll();
keyDialog.act(font);
/*
if (keyDialog.isActive()){
InputManager::poll();
}
*/
tempContext.act();
tempContext.render(0, temp);
keyDialog.render(temp, font);
temp.BlitToScreen();
}
tempContext.finish();
setKey(player, type, readJoystick());
InputManager::waitForClear();
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
/*
Keyboard key;
keyCode = readKey(key);
setKey(player,type, keyCode);
*/
}
static OptionKey::keyType convertToKeyboardKey(const std::string &k){
std::string temp = k;
for(unsigned int i=0;i<temp.length();i++){
temp[i] = tolower(temp[i]);
}
if (temp == "up") return OptionKey::up;
if (temp == "down") return OptionKey::down;
if (temp == "left") return OptionKey::left;
if (temp == "right") return OptionKey::right;
if (temp == "jump") return OptionKey::jump;
if (temp == "attack1") return OptionKey::attack1;
if (temp == "attack2") return OptionKey::attack2;
if (temp == "attack3") return OptionKey::attack3;
if (temp == "attack4") return OptionKey::attack4;
if (temp == "attack5") return OptionKey::attack5;
if (temp == "attack6") return OptionKey::attack6;
return OptionKey::invalidkey;
}
static int getKey(int player, OptionKey::keyType k){
switch(k){
case OptionKey::up:
return Configuration::getUp(player);
break;
case OptionKey::down:
return Configuration::getDown(player);
break;
case OptionKey::left:
return Configuration::getLeft(player);
break;
case OptionKey::right:
return Configuration::getRight(player);
break;
case OptionKey::jump:
return Configuration::getJump(player);
break;
case OptionKey::attack1:
return Configuration::getAttack1(player);
break;
case OptionKey::attack2:
return Configuration::getAttack2(player);
break;
case OptionKey::attack3:
return Configuration::getAttack3(player);
break;
case OptionKey::attack4:
return Configuration::getAttack4(player);
case OptionKey::attack5:
return Configuration::getAttack5(player);
case OptionKey::attack6:
return Configuration::getAttack6(player);
default:
break;
}
return 0;
}
static void setKey(int player, OptionKey::keyType k, int key){
switch(k){
case OptionKey::up:
Configuration::setUp(player, key);
break;
case OptionKey::down:
Configuration::setDown(player, key);
break;
case OptionKey::left:
Configuration::setLeft(player, key);
break;
case OptionKey::right:
Configuration::setRight(player, key);
break;
case OptionKey::jump:
Configuration::setJump(player, key);
break;
case OptionKey::attack1:
Configuration::setAttack1(player, key);
break;
case OptionKey::attack2:
Configuration::setAttack2(player, key);
break;
case OptionKey::attack3:
Configuration::setAttack3(player, key);
break;
case OptionKey::attack4:
Configuration::setAttack4(player, key);
break;
case OptionKey::attack5:
Configuration::setAttack5(player, key);
break;
case OptionKey::attack6:
Configuration::setAttack6(player, key);
break;
default:
break;
}
}
/*
static int readKey( Keyboard & key ){
int k = key.readKey();
key.wait();
return k;
}
*/
OptionKey::OptionKey(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
player(-1),
type(invalidkey),
keyCode(0){
if ( *token != "key" )
throw LoadException(__FILE__, __LINE__, "Not key option");
TokenView view = token->view();
while (view.hasMore()) {
try {
const Token * tok;
view >> tok;
if ( *tok == "name" ) {
tok->view() >> name;
} else if ( *tok == "player" ) {
tok->view() >> player;
} else if ( *tok == "type" ) {
std::string temp;
tok->view() >> temp;
type = convertToKeyboardKey(temp);
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
} catch ( const TokenException & ex ){
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
if(name.empty())throw LoadException(__FILE__, __LINE__, "No name set, this option should have a name!");
if(type == invalidkey)throw LoadException(__FILE__, __LINE__, "Invalid key, should be up, down, left, right, up, down, jump, attack1-6!");
if(player == -1)throw LoadException(__FILE__, __LINE__, "Player not specified in key configuration");
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
setText(std::string(temp));
}
OptionKey::~OptionKey(){
// Nothing
}
void OptionKey::logic(){
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
setText(std::string(temp));
}
void OptionKey::run(const Menu::Context & context){
// Do dialog
//Box::messageDialog(Menu::Menu::Width, Menu::Menu::Height, "Press a Key!",2);
/*
Keyboard key;
key.wait();
*/
Graphics::Bitmap temp(Menu::Menu::Width, Menu::Menu::Height);
// Menu::Context tempContext = context;
Menu::Context tempContext(context);
tempContext.initialize();
Menu::InfoBox keyDialog;
// keyDialog.setFont(tempContext.getFont());
//keyDialog.location.set(-1,-1,1,1);
const int width = temp.getWidth();
const int height = temp.getHeight();
const Font & font = Menu::menuFontParameter.current()->get();
const int radius = 15;
keyDialog.setText("Press a Key!");
keyDialog.initialize(font);
keyDialog.location.setDimensions(font.textLength("Press a Key!") + radius, font.getHeight() + radius);
keyDialog.location.setCenterPosition(Gui::RelativePoint(0, 0));
// keyDialog.location.setPosition(Gui::AbsolutePoint((width/2)-(keyDialog.location.getWidth()/2), (height/2)-(keyDialog.location.getHeight()/2)));
// keyDialog.location.setPosition2(Gui::AbsolutePoint((
keyDialog.transforms.setRadius(radius);
keyDialog.colors.body = Graphics::makeColor(0,0,0);
keyDialog.colors.bodyAlpha = 180;
keyDialog.colors.border = Graphics::makeColor(255,255,255);
keyDialog.colors.borderAlpha = 255;
keyDialog.open();
InputManager::waitForClear();
while (!InputManager::anyInput() && keyDialog.isActive()){
InputManager::poll();
keyDialog.act(font);
/*
if (keyDialog.isActive()){
InputManager::poll();
}
*/
tempContext.act();
tempContext.render(0, temp);
keyDialog.render(temp, font);
temp.BlitToScreen();
}
tempContext.finish();
keyCode = InputManager::readKey();
setKey(player,type, keyCode);
InputManager::waitForClear();
}
OptionLevel::OptionLevel(const Gui::ContextBox & parent, const Token *token, int * set, int value):
MenuOption(parent, token),
set(set),
value(value){
// Nothing
}
OptionLevel::~OptionLevel(){
}
void OptionLevel::logic(){
}
void OptionLevel::run(const Menu::Context & context){
*set = value;
throw Menu::MenuException(__FILE__, __LINE__);
}
OptionLives::OptionLives(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "lives" ){
throw LoadException(__FILE__, __LINE__, "Not lives option" );
}
readName(token);
}
OptionLives::~OptionLives(){
}
std::string OptionLives::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getLives();
return out.str();
}
void OptionLives::logic(){
}
void OptionLives::run(const Menu::Context & context){
}
bool OptionLives::leftKey(){
Configuration::setLives(Configuration::getLives() - 1);
if ( Configuration::getLives() < 1 ){
Configuration::setLives(1);
}
return false;
}
bool OptionLives::rightKey(){
Configuration::setLives( Configuration::getLives() + 1 );
return false;
}
OptionMenu::OptionMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory):
MenuOption(parent, token),
menu(0){
if (*token != "menu"){
throw LoadException(__FILE__, __LINE__, "Not a menu");
}
if (token->numTokens() == 1){
std::string temp;
token->view() >> temp;
menu = new Menu::Menu(Storage::instance().find(Filesystem::RelativePath(temp)), factory);
} else {
menu = new Menu::Menu(token, factory);
}
this->setText(menu->getName());
this->setInfoText(menu->getInfo());
// Lets check if this menu is going bye bye
//if ( menu->checkRemoval() ) setForRemoval(true);
}
OptionMenu::~OptionMenu(){
// Delete our menu
if (menu){
delete menu;
}
}
void OptionMenu::logic(){
// Nothing
}
void OptionMenu::run(const Menu::Context & context){
// Do our new menu
try{
menu->run(context);
} catch (const Exception::Return ignore){
throw Menu::Reload(__FILE__, __LINE__);
}
}
OptionNpcBuddies::OptionNpcBuddies(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "npc" ){
throw LoadException(__FILE__, __LINE__, "Not npc option" );
}
readName(token);
}
OptionNpcBuddies::~OptionNpcBuddies(){
// Nothing
}
std::string OptionNpcBuddies::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getNpcBuddies();
return out.str();
}
void OptionNpcBuddies::logic(){
}
void OptionNpcBuddies::run(const Menu::Context & context){
}
bool OptionNpcBuddies::leftKey(){
Configuration::setNpcBuddies(Configuration::getNpcBuddies() - 1);
if ( Configuration::getNpcBuddies() < 1 ){
Configuration::setNpcBuddies(1);
}
return false;
}
bool OptionNpcBuddies::rightKey(){
Configuration::setNpcBuddies( Configuration::getNpcBuddies() + 1 );
rblue = rgreen = 0;
return false;
}
OptionPlayMode::OptionPlayMode(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "play-mode" ){
throw LoadException(__FILE__, __LINE__, "Not a play-mode");
}
readName(token);
}
OptionPlayMode::~OptionPlayMode(){
// Nothing
}
std::string OptionPlayMode::getText() const {
ostringstream out;
out << MenuOption::getText() << ": ";
/* TODO: language translations of these */
if (Configuration::getPlayMode() == Configuration::FreeForAll){
out << "Free for all";
} else if (Configuration::getPlayMode() == Configuration::Cooperative){
out << "Cooperative";
}
return out.str();
}
void OptionPlayMode::logic(){
}
void OptionPlayMode::run(const Menu::Context & context){
}
void OptionPlayMode::changeMode(){
if (Configuration::getPlayMode() == Configuration::FreeForAll){
Configuration::setPlayMode(Configuration::Cooperative);
} else if (Configuration::getPlayMode() == Configuration::Cooperative){
Configuration::setPlayMode(Configuration::FreeForAll);
}
}
bool OptionPlayMode::leftKey(){
changeMode();
lblue = lgreen = 0;
return true;
}
bool OptionPlayMode::rightKey(){
changeMode();
rblue = rgreen = 0;
return true;
}
OptionReturn::OptionReturn(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
if (*token != "return"){
throw LoadException(__FILE__, __LINE__, "Not a return option");
}
readName(token);
}
void OptionReturn::logic(){
}
/* maybe this option is misnamed, but its supposed to quit the current game
* and go back to the main menu
*/
void OptionReturn::run(const Menu::Context & context){
throw Exception::Quit(__FILE__, __LINE__);
}
OptionReturn::~OptionReturn(){
}
OptionContinue::OptionContinue(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
if (*token != "continue"){
throw LoadException(__FILE__, __LINE__, "Not a continue option");
}
readName(token);
}
void OptionContinue::logic(){
}
void OptionContinue::run(const Menu::Context & context){
throw Exception::Return(__FILE__, __LINE__);
}
OptionContinue::~OptionContinue(){
}
OptionQuit::OptionQuit(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
if ( *token != "quit" ){
throw LoadException(__FILE__, __LINE__, "Not quit option");
}
readName(token);
}
OptionQuit::OptionQuit(const Gui::ContextBox & parent, const std::string &name):
MenuOption(parent, 0){
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name given to quit");
}
this->setText(name);
}
OptionQuit::~OptionQuit(){
}
void OptionQuit::logic(){
}
void OptionQuit::run(const Menu::Context & context){
throw ShutdownException();
}
#if defined(WINDOWS) && defined(doesnt_work_yet)
#include <windows.h>
#include <stdio.h>
/* contributed by Roy Underthump from allegro.cc */
static vector<ScreenSize> getScreenResolutions(){
HWND hwnd;
HDC hdc;
// int iPixelFormat;
int descerr;
int retval;
DEVMODE d;
PIXELFORMATDESCRIPTOR pfd;
hwnd = GetDesktopWindow();
hdc = GetDC(hwnd);
vector<ScreenSize> modes;
for (int i = 0;; i++){
retval = EnumDisplaySettings(0,i,&d);
if (!retval){
break;
}
descerr = DescribePixelFormat(hdc, i+1, sizeof(pfd), &pfd);
if(!descerr){
continue;
}
/*
printf("\n#%d bpp %d width %d height %d colorbits %d fps %d",i,d.dmBitsPerPel,
d.dmPelsWidth, d.dmPelsHeight,pfd.cColorBits,d.dmDisplayFrequency);
if(pfd.dwFlags & PFD_SUPPORT_OPENGL)printf(" OGL OK");
*/
modes.push_back(ScreenSize(d.dmPelsWidth, d.dmPelsHeight));
}
if (modes.empty()){
modes.push_back(ScreenSize(640,480));
}
return modes;
}
#else
static vector<ScreenSize> getScreenResolutions(){
vector<ScreenSize> modes;
modes.push_back(ScreenSize(320, 240));
modes.push_back(ScreenSize(640, 480));
modes.push_back(ScreenSize(800, 600));
modes.push_back(ScreenSize(960, 720));
modes.push_back(ScreenSize(1024, 768));
modes.push_back(ScreenSize(1280, 960));
modes.push_back(ScreenSize(1600, 1200));
return modes;
}
#endif
static bool doSort(const ScreenSize & a, const ScreenSize & b){
return (a.w * a.h) < (b.w * b.h);
}
static vector<ScreenSize> sortResolutions(const vector<ScreenSize> & modes){
vector<ScreenSize> copy(modes);
std::sort(copy.begin(), copy.end(), doSort);
return copy;
}
OptionScreenSize::OptionScreenSize(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
Global::debug(1) << "Get screen resolution" << endl;
modes = sortResolutions(getScreenResolutions());
if (Global::getDebug() >= 1){
for (vector<ScreenSize>::iterator it = modes.begin(); it != modes.end(); it++){
Global::debug(1) << "Screen size: " << it->w << " x " << it->h << endl;
}
}
if ( *token != "screen-size" ){
throw LoadException(__FILE__, __LINE__, "Not a screen-size");
}
readName(token);
}
OptionScreenSize::~OptionScreenSize(){
// Nothing
}
void OptionScreenSize::logic(){
ostringstream temp;
temp << "Screen size: " << Configuration::getScreenWidth() << " x " << Configuration::getScreenHeight();
setText(temp.str());
}
void OptionScreenSize::run(const Menu::Context & context){
}
void OptionScreenSize::setMode(int width, int height){
if (width != Configuration::getScreenWidth() ||
height != Configuration::getScreenHeight()){
Global::debug(1) << "Changing mode to " << width << " x " << height << endl;
int gfx = Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED;
int ok = Graphics::setGraphicsMode(gfx, width, height);
if (ok == 0){
Global::debug(1) << "Success" << endl;
Configuration::setScreenWidth(width);
Configuration::setScreenHeight(height);
} else {
Global::debug(1) << "Fail" << endl;
int ok = Graphics::setGraphicsMode(gfx, Configuration::getScreenWidth(), Configuration::getScreenHeight());
Global::debug(1) << "Set mode back " << ok << endl;
}
}
}
/*
static int modes[][2] = {{640,480}, {800,600}, {1024,768}, {1280,1024}, {1600,1200}};
// static int max_modes = sizeof(modes) / sizeof(int[]);
static int max_modes = 5;
*/
int OptionScreenSize::findMode(int width, int height){
for (int mode = 0; mode < (int) modes.size(); mode++){
if (modes[mode].w == width && modes[mode].h == height){
return mode;
}
}
return -1;
}
bool OptionScreenSize::leftKey(){
int mode = findMode(Configuration::getScreenWidth(), Configuration::getScreenHeight());
if (mode >= 1 && mode < (int)modes.size()){
mode -= 1;
} else {
mode = 0;
}
setMode(modes[mode].w, modes[mode].h);
lblue = lgreen = 0;
return true;
}
bool OptionScreenSize::rightKey(){
int mode = findMode(Configuration::getScreenWidth(), Configuration::getScreenHeight());
if (mode >= 0 && mode < (int)modes.size() - 1){
mode += 1;
} else {
mode = 0;
}
setMode(modes[mode].w, modes[mode].h);
rblue = rgreen = 0;
return true;
}
static string joinPaths(const vector<Filesystem::AbsolutePath> & strings, const string & middle){
ostringstream out;
for (vector<Filesystem::AbsolutePath>::const_iterator it = strings.begin(); it != strings.end(); it++){
out << (*it).path() << middle;
}
return out.str();
}
static bool sortInfo(const Util::ReferenceCount<Menu::FontInfo> & info1,
const Util::ReferenceCount<Menu::FontInfo> & info2){
string name1 = Util::lowerCaseAll(info1->getName());
string name2 = Util::lowerCaseAll(info2->getName());
return name1 < name2;
}
static bool isWindows(){
#ifdef WINDOWS
return true;
#else
return false;
#endif
}
static bool isOSX(){
#ifdef MACOSX
return true;
#else
return false;
#endif
}
template <class X>
static vector<X> operator+(const vector<X> & v1, const vector<X> & v2){
vector<X> out;
for (typename vector<X>::const_iterator it = v1.begin(); it != v1.end(); it++){
out.push_back(*it);
}
for (typename vector<X>::const_iterator it = v2.begin(); it != v2.end(); it++){
out.push_back(*it);
}
return out;
}
static vector<Filesystem::AbsolutePath> findSystemFonts(){
if (isWindows()){
const char * windows = getenv("windir");
if (windows != NULL){
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath(string(windows) + "/fonts"), "*.ttf");
}
return vector<Filesystem::AbsolutePath>();
} else if (isOSX()){
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/Library/Fonts"), "*.ttf");
} else {
/* assume unix/linux conventions */
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/usr/share/fonts/truetype"), "*.ttf") +
Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/usr/local/share/fonts/truetype"), "*.ttf");
}
}
static vector<Util::ReferenceCount<Menu::FontInfo> > findFonts(){
vector<Util::ReferenceCount<Menu::FontInfo> > fonts;
try{
Filesystem::AbsolutePath fontsDirectory = Storage::instance().find(Filesystem::RelativePath("fonts"));
Global::debug(1, "fonts") << "Font directory " << fontsDirectory.path() << endl;
vector<Filesystem::AbsolutePath> ttfFonts = Storage::instance().getFiles(fontsDirectory, "*.ttf");
Global::debug(1, "fonts") << "Found ttf fonts " << joinPaths(ttfFonts, ", ") << endl;
vector<Filesystem::AbsolutePath> otfFonts = Storage::instance().getFiles(fontsDirectory, "*.otf");
Global::debug(1, "fonts") << "Found otf fonts " << joinPaths(otfFonts, ", ") << endl;
for (vector<Filesystem::AbsolutePath>::iterator it = ttfFonts.begin(); it != ttfFonts.end(); it++){
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::RelativeFontInfo(Storage::instance().cleanse(*it), Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
for (vector<Filesystem::AbsolutePath>::iterator it = otfFonts.begin(); it != otfFonts.end(); it++){
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::RelativeFontInfo(Storage::instance().cleanse(*it), Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
/* linux specific fonts */
vector<Filesystem::AbsolutePath> systemFonts = findSystemFonts();
for (vector<Filesystem::AbsolutePath>::iterator it = systemFonts.begin(); it != systemFonts.end(); it++){
Global::debug(1) << "Adding system font `" << (*it).path() << "'" << endl;
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::AbsoluteFontInfo(*it, Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
sort(fonts.begin(), fonts.end(), sortInfo);
// DEFAULT (blank)
// fonts.insert(fonts.begin(), new Menu::DefaultFontInfo());
fonts.insert(fonts.begin(), Util::ReferenceCount<Menu::FontInfo>(NULL));
} catch (const Filesystem::NotFound & e){
throw LoadException(__FILE__, __LINE__, e, "Could not load font");
}
return fonts;
}
OptionSelectFont::OptionSelectFont(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
typeAdjust(fontName),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "font-select" ){
throw LoadException(__FILE__, __LINE__, "Not a font selector");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "adjust" ){
std::string temp;
tok->view() >> temp;
if ( temp == "name" ) typeAdjust = fontName;
else if ( temp == "width" ) typeAdjust = fontWidth;
else if ( temp == "height" ) typeAdjust = fontHeight;
else throw LoadException(__FILE__, __LINE__, "Incorrect value \"" + temp + "\" in font-select");
} else {
Global::debug(3) << "Unhandled menu attribute: " << endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
}
void OptionSelectFont::open(){
// Find and set fonts now
if (typeAdjust == fontName){
fonts = findFonts();
}
}
void OptionSelectFont::close(){
if (typeAdjust == fontName){
/* the user probably loaded a bunch of different fonts that will
* never be used again, so clear the font cache
* TODO: dont clear the currently selected font
*/
FontFactory::clear();
}
}
OptionSelectFont::~OptionSelectFont(){
// Nothing
}
void OptionSelectFont::logic(){
/* FIXME Get current font and display info */
switch (typeAdjust){
case fontName:{
std::string name;
if (Configuration::hasMenuFont()){
name = Configuration::getMenuFont()->getName();
} else {
name = "Default";
}
setText("Current Font: " + name);
break;
}
case fontWidth:{
ostringstream temp;
temp << "Font Width: " << Configuration::getMenuFontWidth();
setText(temp.str());
break;
}
case fontHeight:{
ostringstream temp;
temp << "Font Height: " << Configuration::getMenuFontHeight();
setText(temp.str());
break;
}
default: break;
}
if (lblue < 255){
lblue += 5;
}
if (rblue < 255){
rblue += 5;
}
if (lgreen < 255){
lgreen += 5;
}
if (rgreen < 255){
rgreen += 5;
}
}
void OptionSelectFont::run(const Menu::Context & context){
// throw Menu::MenuException(__FILE__, __LINE__);
/* throw something to quit back to the previous menu */
}
bool OptionSelectFont::leftKey(){
switch (typeAdjust){
case fontName:
nextIndex(false);
break;
case fontWidth:
Configuration::setMenuFontWidth(Configuration::getMenuFontWidth() - 1);
break;
case fontHeight:
Configuration::setMenuFontHeight(Configuration::getMenuFontHeight() - 1);
break;
default:
break;
}
lblue = lgreen = 0;
return true;
}
bool OptionSelectFont::rightKey(){
switch (typeAdjust){
case fontName:
nextIndex(true);
break;
case fontWidth:
Configuration::setMenuFontWidth(Configuration::getMenuFontWidth() + 1);
break;
case fontHeight:
Configuration::setMenuFontHeight(Configuration::getMenuFontHeight() + 1);
break;
default:
break;
}
rblue = rgreen = 0;
return true;
}
static bool saneFont(const Util::ReferenceCount<Menu::FontInfo> & info){
class Context: public Loader::LoadingContext {
public:
Context(const Util::ReferenceCount<Menu::FontInfo> & info):
info(info),
isok(false){
}
bool ok(){
try{
const Font & font = info->get();
return font.textLength("A") != 0 &&
font.getHeight() != 0;
} catch (const Exception::Base & ignore){
return true;
}
}
virtual void load(){
isok = ok();
}
const Util::ReferenceCount<Menu::FontInfo> & info;
bool isok;
};
if (info == NULL){
return true;
}
Context context(info);
/* an empty Info object, we don't really care about it */
Loader::Info level;
Loader::loadScreen(context, level, Loader::SimpleCircle);
return context.isok;
}
void OptionSelectFont::nextIndex(bool forward){
if (fonts.size() == 0){
return;
}
int index = 0;
for (unsigned int i = 0 ; i < fonts.size() ; ++i){
if ((Configuration::getMenuFont() == NULL && fonts[i] == NULL) ||
((Configuration::getMenuFont() != NULL && fonts[i] != NULL) &&
(*Configuration::getMenuFont() == *fonts[i]))){
index = i;
}
}
if (forward){
index++;
if (index >= (int) fonts.size()){
index = 0;
}
} else {
index--;
if (index < 0){
index = (int)fonts.size()-1;
}
}
while (!saneFont(fonts[index])){
Global::debug(0) << "Warning: erasing font `" << fonts[index]->getName() << "'" << endl;
int where = 0;
vector<Util::ReferenceCount<Menu::FontInfo> >::iterator it;
for (it = fonts.begin(); it != fonts.end() && where != index; it++, where++){
}
fonts.erase(it);
if (index >= (int) fonts.size()){
index = fonts.size() - 1;
}
}
Configuration::setMenuFont(fonts[index]);
/* FIXME */
/*
if (fonts[index] == "Default"){
Configuration::setMenuFont("");
} else {
Configuration::setMenuFont(fonts[index]);
}
*/
}
OptionSpeed::OptionSpeed(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "speed" )
throw LoadException(__FILE__, __LINE__, "Not speed option");
readName(token);
}
OptionSpeed::~OptionSpeed(){
// Nothing
}
std::string OptionSpeed::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getGameSpeed();
return out.str();
}
void OptionSpeed::logic(){
/*
//ostringstream temp;
char temp[255];
sprintf( temp, "%s: %0.2f", name.c_str(), MenuGlobals::getGameSpeed() );
setText(std::string(temp));
*/
}
void OptionSpeed::run(const Menu::Context & context){
}
bool OptionSpeed::leftKey(){
Configuration::setGameSpeed(Configuration::getGameSpeed() - 0.05);
if (Configuration::getGameSpeed() < 0.1){
Configuration::setGameSpeed(0.1);
}
return false;
}
bool OptionSpeed::rightKey(){
Configuration::setGameSpeed(Configuration::getGameSpeed() + 0.05);
rblue = rgreen = 0;
return false;
}
OptionTabMenu::OptionTabMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory):
MenuOption(parent, token),
menu(0){
if (token->numTokens() == 1){
std::string temp;
token->view() >> temp;
menu = new Menu::Menu(Storage::instance().find(Filesystem::RelativePath(temp)), factory, Menu::Menu::Tabbed);
} else {
menu = new Menu::Menu(token, factory, Menu::Menu::Tabbed);
}
// this->setText(menu->getName());
// token->print("Menu: ");
const Token * tok = token->findToken("_/name");
if (tok != NULL){
std::string name;
tok->view() >> name;
// Global::debug(0, "menu") << "Menu name: " << name << endl;
this->setText(name);
} else {
// No name?
throw LoadException(__FILE__, __LINE__, "Menu has no name");
}
}
OptionTabMenu::~OptionTabMenu(){
// Delete our menu
if (menu){
delete menu;
}
}
void OptionTabMenu::logic(){
// Nothing
}
void OptionTabMenu::run(const Menu::Context & context){
// Do our new menu
// menu->run(context);
try{
menu->run(context);
} catch (const Exception::Return ignore){
throw Menu::Reload(__FILE__, __LINE__);
}
}
OptionSound::OptionSound(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if (*token != "sound" ){
throw LoadException(__FILE__, __LINE__, "Not a sound option");
}
readName(token);
originalName = getName();
}
OptionSound::~OptionSound(){
}
void OptionSound::logic(){
ostringstream temp;
temp << originalName << ": " << Configuration::getSoundVolume();
setText(temp.str());
}
void OptionSound::run(const Menu::Context & context){
}
void OptionSound::changeSound(int much){
int volume = Configuration::getSoundVolume();
volume += much;
if (volume < 0){
volume = 0;
}
if (volume > 100){
volume = 100;
}
Configuration::setSoundVolume(volume);
}
bool OptionSound::leftKey(){
changeSound(-1);
lblue = lgreen = 0;
return true;
}
bool OptionSound::rightKey(){
changeSound(+1);
rblue = rgreen = 0;
return true;
}
OptionMusic::OptionMusic(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if (*token != "music" ){
throw LoadException(__FILE__, __LINE__, "Not a music option");
}
readName(token);
originalName = getName();
}
void OptionMusic::logic(){
ostringstream temp;
temp << originalName << ": " << Configuration::getMusicVolume();
setText(temp.str());
}
void OptionMusic::run(const Menu::Context & context){
}
void OptionMusic::changeMusic(int much){
int volume = Configuration::getMusicVolume();
volume += much;
if (volume < 0){
volume = 0;
}
if (volume > 100){
volume = 100;
}
Configuration::setMusicVolume(volume);
Music::setVolume((double) volume / 100.0);
}
bool OptionMusic::leftKey(){
changeMusic(-1);
lblue = lgreen = 0;
return true;
}
bool OptionMusic::rightKey(){
changeMusic(+1);
lblue = lgreen = 0;
return true;
}
OptionMusic::~OptionMusic(){
}
OptionLanguage::OptionLanguage(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
#if 0
const Token * start = token->getRootParent();
vector<const Token*> tokens = start->findTokens("*/language");
vector<string> all;
for (vector<const Token*>::iterator it = tokens.begin(); it != tokens.end(); it++){
string language;
const Token * token = *it;
if (token->match("language", language)){
all.push_back(language);
}
}
sort(all.begin(), all.end());
unique_copy(all.begin(), all.end(), back_insert_iterator<vector<string> >(languages));
// Global::debug(0) << "Found " << languages.size() << " languages" << endl;
#endif
}
void OptionLanguage::run(const Menu::Context & context){
class LanguageOption: public MenuOption {
public:
LanguageOption(const Gui::ContextBox & parent, const string & language):
MenuOption(parent, NULL){
setText(language);
setInfoText(language);
}
virtual void logic(){
}
virtual void run(const ::Menu::Context & context){
Configuration::setLanguage(getText());
Configuration::saveConfiguration();
throw ::Menu::MenuException(__FILE__, __LINE__);
}
};
Menu::Menu temp;
/* FIXME don't hardcode arial.ttf */
Util::ReferenceCount<Menu::FontInfo> info(new Menu::RelativeFontInfo(Filesystem::RelativePath("fonts/arial.ttf"), 24, 24));
temp.setFont(info);
const Gui::ContextBox & box = ((Menu::DefaultRenderer*) temp.getRenderer())->getBox();
vector<string> languages = context.getLanguages();
for (vector<string>::iterator it = languages.begin(); it != languages.end(); it++){
temp.addOption(new LanguageOption(box, *it));
}
try {
temp.run(context);
} catch (const Exception::Return & ignore){
} catch (const Menu::MenuException & ex){
}
throw Menu::Reload(__FILE__, __LINE__);
// throw Exception::Return(__FILE__, __LINE__);
}
void OptionLanguage::logic(){
}
OptionGibs::OptionGibs(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
setRunnable(false);
if (*token != "gibs" ){
throw LoadException(__FILE__, __LINE__, "Not a gibs option");
}
readName(token);
originalName = getName();
}
void OptionGibs::logic(){
ostringstream temp;
/* FIXME: we want to use Gib::GibProperty here but that would necessitate a
* dependancy on the Paintown engine.
*/
temp << originalName << ": " << Configuration::getProperty("paintown/gibs", 5);
setText(temp.str());
}
void OptionGibs::run(const Menu::Context & context){
}
void OptionGibs::changeGibs(int much){
int gibs = Configuration::getProperty("paintown/gibs", 5);
gibs += much;
if (gibs < 0){
gibs = 0;
}
if (gibs > 10){
gibs = 10;
}
Configuration::setProperty("paintown/gibs", gibs);
}
bool OptionGibs::leftKey(){
changeGibs(-1);
return true;
}
bool OptionGibs::rightKey(){
changeGibs(+1);
return true;
}
OptionGibs::~OptionGibs(){
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jan 30, 5:39 PM (5 d, 5 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55512
Default Alt Text
(168 KB)

Event Timeline