bool WaitLongOperation::operator()(RLMachine& machine) { bool done = ctrl_pressed_ || machine.system().fastForward(); if (!done && wait_until_target_time_) { done = machine.system().event().getTicks() > target_time_; } if (!done && break_on_event_) { done = event_function_(); } GraphicsSystem& graphics = machine.system().graphics(); if (mouse_moved_) { graphics.markScreenAsDirty(GUT_MOUSE_MOTION); mouse_moved_ = false; } else if (graphics.objectStateDirty()) { graphics.markScreenAsDirty(GUT_DISPLAY_OBJ); } if (break_on_clicks_) { if (button_pressed_) { done = true; machine.setStoreRegister(button_pressed_); } else if (done) { // TODO(erg): this is fishy. shouldn't we record when clicked? if (save_click_location_) recordMouseCursorPosition(); machine.setStoreRegister(0); } } return done; }
void SDLEventSystem::handleKeyUp(RLMachine& machine, SDL_Event& event) { switch (event.key.keysym.sym) { case SDLK_LSHIFT: case SDLK_RSHIFT: { shift_pressed_ = false; break; } case SDLK_LCTRL: case SDLK_RCTRL: { ctrl_pressed_ = false; break; } case SDLK_F1: { machine.system().showSystemInfo(machine); break; } case SDLK_F12: { machine.system().dumpRenderTree(machine); break; } default: break; } KeyCode code = KeyCode(event.key.keysym.sym); dispatchEvent(machine, bind(&EventListener::keyStateChanged, _1, code, false)); }
void GCNPlatform::pushBlocker(RLMachine& machine) { if (blocker_ == NULL) { // Block the world! SDLEventSystem& event = dynamic_cast<SDLEventSystem&>( machine.system().event()); GraphicsSystem& graphics = machine.system().graphics(); machine.pushLongOperation(new GCNPlatformBlocker(event, graphics, shared_from_this())); } }
void SDLEventSystem::handleActiveEvent(RLMachine& machine, SDL_Event& event) { if (event.active.state & SDL_APPINPUTFOCUS) { // Assume the mouse is inside the window. Actually checking the mouse // state doesn't work in the case where we mouse click on another window // that's partially covered by rlvm's window and then alt-tab back. mouse_inside_window_ = true; machine.system().graphics().markScreenAsDirty(GUT_MOUSE_MOTION); } else if (event.active.state & SDL_APPMOUSEFOCUS) { mouse_inside_window_ = event.active.gain == 1; // Force a mouse refresh: machine.system().graphics().markScreenAsDirty(GUT_MOUSE_MOTION); } }
void SDLGraphicsSystem::executeGraphicsSystem(RLMachine& machine) { // For now, nothing, but later, we need to put all code each cycle // here. if (isResponsibleForUpdate() && screenNeedsRefresh()) { refresh(NULL); screenRefreshed(); redraw_last_frame_ = false; } else if (isResponsibleForUpdate() && redraw_last_frame_) { redrawLastFrame(); redraw_last_frame_ = false; } // Update the seen. int current_time = machine.system().event().getTicks(); if ((current_time - time_of_last_titlebar_update_) > 60) { time_of_last_titlebar_update_ = current_time; if (machine.sceneNumber() != last_seen_number_ || machine.lineNumber() != last_line_number_) { last_seen_number_ = machine.sceneNumber(); last_line_number_ = machine.lineNumber(); setWindowTitle(); } } GraphicsSystem::executeGraphicsSystem(machine); }
void SDLEventSystem::handleKeyDown(RLMachine& machine, SDL_Event& event) { switch (event.key.keysym.sym) { case SDLK_LSHIFT: case SDLK_RSHIFT: { shift_pressed_ = true; break; } case SDLK_LCTRL: case SDLK_RCTRL: { ctrl_pressed_ = true; break; } case SDLK_RETURN: case SDLK_f: { if ((event.key.keysym.mod & KMOD_ALT) || (event.key.keysym.mod & KMOD_META)) { machine.system().graphics().toggleFullscreen(); // Stop processing because we don't want to dispatch this event, which // might advance the text. return; } break; } default: break; } KeyCode code = KeyCode(event.key.keysym.sym); dispatchEvent(machine, bind(&EventListener::keyStateChanged, _1, code, true)); }
void SDLGraphicsSystem::executeGraphicsSystem(RLMachine& machine) { // For now, nothing, but later, we need to put all code each cycle // here. if (isResponsibleForUpdate() && screenNeedsRefresh()) { refresh(NULL); screenRefreshed(); redraw_last_frame_ = false; } else if (isResponsibleForUpdate() && redraw_last_frame_) { redrawLastFrame(); redraw_last_frame_ = false; } // Check to see if any of the graphics objects are reporting that // they want to force a redraw for_each(foregroundObjects().allocated_begin(), foregroundObjects().allocated_end(), bind(&GraphicsObject::execute, _1)); // Update the seen. int current_time = machine.system().event().getTicks(); if ((current_time - time_of_last_titlebar_update_) > 60) { time_of_last_titlebar_update_ = current_time; if (machine.sceneNumber() != last_seen_number_ || machine.lineNumber() != last_line_number_) { last_seen_number_ = machine.sceneNumber(); last_line_number_ = machine.lineNumber(); setWindowTitle(); } } GraphicsSystem::executeGraphicsSystem(machine); }
bool TextWindow::handleMouseClick(RLMachine& machine, const Point& pos, bool pressed) { using namespace boost; if (inSelectionMode()) { bool found = find_if(selections_.begin(), selections_.end(), bind(&SelectionElement::handleMouseClick, _1, pos, pressed)) != selections_.end(); if (found) return true; } for (std::vector<std::pair<Point, int> >::const_iterator it = koe_replay_button_.begin(); it != koe_replay_button_.end(); ++it) { Rect r = Rect(textSurfaceRect().origin() + it->first, koe_replay_info_->icon->size()); if (r.contains(pos)) { // We only want to actually replay the voice clip once, but we want to // catch both clicks. if (pressed) system_.sound().koePlay(it->second); return true; } } if (isVisible() && !machine.system().graphics().interfaceHidden()) { return textbox_waku_->handleMouseClick(machine, pos, pressed); } return false; }
std::vector<int> getSELEffect(RLMachine& machine, int selNum) { Gameexe& gexe = machine.system().gameexe(); vector<int> selEffect; if (gexe("SEL", selNum).exists()) { selEffect = gexe("SEL", selNum).to_intVector(); grpToRecCoordinates(selEffect[0], selEffect[1], selEffect[2], selEffect[3]); } else if (gexe("SELR", selNum).exists()) { selEffect = gexe("SELR", selNum).to_intVector(); } else { // Can't find the specified #SEL effect. See if there's a #SEL.000 effect: if (gexe("SEL", 0).exists()) { selEffect = gexe("SEL", 0).to_intVector(); grpToRecCoordinates(selEffect[0], selEffect[1], selEffect[2], selEffect[3]); } else if (gexe("SELR", 0).exists()) { selEffect = gexe("SELR", 0).to_intVector(); } else { // Crap! Couldn't fall back on the default one either, so instead return // a SEL vector that is a screenwide, short fade because we absolutely // can't fail here. Size screen = getScreenSize(gexe); selEffect = { 0, 0, screen.width(), screen.height(), 0, 0, 1000, 000, 0, 0, 0, 0, 0, 0, 255, 0 }; } } return selEffect; }
void loadGlobalMemory(RLMachine& machine) { fs::path home = buildGlobalMemoryFilename(machine); fs::ifstream file(home, ios::binary); // If we were able to open the file for reading, load it. Don't // complain if we're unable to, since this may be the first run on // this certain game and it may not exist yet. if (file) { try { loadGlobalMemoryFrom(file, machine); } catch(...) { // Swallow ALL exceptions during file reading. If loading the global // memory file fails in any way, something is EXTREMELY wrong. Either // we're trying to read an incompatible old version's files or the global // data is corrupted. Either way, we can't safely do ANYTHING with this // game's entire save data so move it out of the way. fs::path save_dir = machine.system().gameSaveDirectory(); fs::path dest_save_dir = save_dir.parent_path() / (save_dir.filename() / ".old_corrupted_data"); if (fs::exists(dest_save_dir)) fs::remove_all(dest_save_dir); fs::rename(save_dir, dest_save_dir); cerr << "WARNING: Unable to read saved global memory file. Moving " << save_dir << " to " << dest_save_dir << endl; } } }
int RlBabelDLL::callDLL(RLMachine& machine, int func, int arg1, int arg2, int arg3, int arg4) { switch (func) { case dllInitialise: return initialize(arg1, arg2); case dllTextoutStart: if (arg1 == -1) { textoutClear(); return 1; } else { textoutClear(); return textoutAdd(*getSvar(arg1)); } case dllTextoutAppend: return textoutAdd(*getSvar(arg1)); case dllTextoutGetChar: return textoutGetChar(getSvar(arg1), getIvar(arg2)); case dllTextoutNewScreen: return startNewScreen(*getSvar(arg1)); case dllSetNameMod: { boost::shared_ptr<TextWindow> textWindow = getWindow(arg1); int original_mod = textWindow->nameMod(); textWindow->setNameMod(arg2); return original_mod; } case dllGetNameMod: return getWindow(arg1)->nameMod(); case dllGetTextWindow: return getWindow(-1)->windowNumber(); case dllSetWindowName: return setCurrentWindowName(getSvar(arg1)); case endSetWindowName: case endGetCharWinNam: { // Should never happen since we don't do the insane trick of overwriting // instruction memory to set the name of set the window name. return getcError; } case dllClearGlosses: return clearGlosses(); case dllNewGloss: return newGloss(); case dllAddGloss: return addGloss(*getSvar(arg1)); case dllTestGlosses: return testGlosses(arg1, arg2, getSvar(arg3), arg4); case dllGetRCommandMod: { int window = getWindow(arg1)->windowNumber(); return machine.system().gameexe()("WINDOW")(window)("R_COMMAND_MOD"); } case dllMessageBox: // return rlMsgBox(arg1, arg2); default: return -1; } }
// ----------------------------------------------------------------------- // NormalSelectLongOperation // ----------------------------------------------------------------------- NormalSelectLongOperation::NormalSelectLongOperation( RLMachine& machine, const libReallive::SelectElement& commandElement) : SelectLongOperation(machine, commandElement), text_window_(machine.system().text().currentWindow()) { machine.system().text().setInSelectionMode(true); text_window_->setVisible(true); text_window_->startSelectionMode(); text_window_->setSelectionCallback( bind(&NormalSelectLongOperation::selected, this, _1)); for (size_t i = 0; i < options_.size(); ++i) { // TODO(erg): Also deal with colour. if (options_[i].shown) { text_window_->addSelectionItem(options_[i].str, i); } } machine.system().graphics().markScreenAsDirty(GUT_TEXTSYS); }
// ----------------------------------------------------------------------- // WaitLongOperation // ----------------------------------------------------------------------- WaitLongOperation::WaitLongOperation(RLMachine& machine) : machine_(machine), wait_until_target_time_(false), target_time_(0), break_on_clicks_(false), button_pressed_(0), break_on_event_(false), has_sleep_time_provider_(false), break_on_ctrl_pressed_(machine.system().text().ctrlKeySkip()), ctrl_pressed_(false), mouse_moved_(false), save_click_location_(false) { }
LoadGameLongOperation::LoadGameLongOperation(RLMachine& machine) { // Render the current state of the screen GraphicsSystem& graphics = machine.system().graphics(); boost::shared_ptr<Surface> currentWindow = graphics.renderToSurface(); Size s = currentWindow->size(); // Blank dc0 (because we won't be using it anyway) for the image // we're going to render to boost::shared_ptr<Surface> dc0 = graphics.getDC(0); dc0->fill(RGBAColour::Black()); machine.pushLongOperation(this); machine.pushLongOperation( new FadeEffect(machine, dc0, currentWindow, s, 250)); // We have our before and after images to use as a transition now. Reset the // system to prevent a brief flash of the previous contents of the screen for // whatever number of user preceivable milliseconds. machine.system().reset(); }
int ReturnGameexeInt::operator()(RLMachine& machine) { Gameexe& gexe = machine.system().gameexe(); vector<int> values = gexe(full_key_name_); if (static_cast<size_t>(entry_) < values.size()) { return values[entry_]; } else { ostringstream oss; oss << "Could not access piece " << entry_ << " in Gameexe key \"" << full_key_name_ << "\""; throw std::runtime_error(oss.str()); } }
int ObjectMutator::GetValueForTime(RLMachine& machine, int start, int end) { unsigned int ticks = machine.system().event().getTicks(); if (ticks < (creation_time_ + delay_)) { return start; } else if (ticks < (creation_time_ + delay_ + duration_time_)) { // TODO(erg): This is the implementation for type_ == 0. Add nonlinear ones // for 1 and 2. unsigned int ticks_into_duration_ = ticks - creation_time_ - delay_; float percentage = float(ticks_into_duration_) / float(duration_time_); return start + ((end - start) * percentage); } else { return end; } }
void SDLEventSystem::executeEventSystem(RLMachine& machine) { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: { if (raw_handler_) raw_handler_->pushInput(event); else handleKeyDown(machine, event); break; } case SDL_KEYUP: { if (raw_handler_) raw_handler_->pushInput(event); else handleKeyUp(machine, event); break; } case SDL_MOUSEMOTION: { if (raw_handler_) raw_handler_->pushInput(event); handleMouseMotion(machine, event); break; } case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { if (raw_handler_) raw_handler_->pushInput(event); else { LOGD("got mouse event\n"); handleMouseButtonEvent(machine, event); } break; } case SDL_QUIT: machine.halt(); break; case SDL_ACTIVEEVENT: if (raw_handler_) raw_handler_->pushInput(event); handleActiveEvent(machine, event); break; case SDL_VIDEOEXPOSE: { machine.system().graphics().forceRefresh(); break; } } } }
// Overridden from LongOperation: virtual bool operator()(RLMachine& machine) { while (delayed_tasks_.size()) { delayed_tasks_.front()(); delayed_tasks_.pop(); } while (delayed_rlmachine_tasks_.size()) { delayed_rlmachine_tasks_.front()(machine); delayed_rlmachine_tasks_.pop(); } machine.system().graphics().forceRefresh(); return platform_->window_stack_.size() == 0; }
void saveGlobalMemoryTo(std::ostream& oss, RLMachine& machine) { using namespace boost::iostreams; filtering_stream<output> filtered_output; filtered_output.push(zlib_compressor()); filtered_output.push(oss); text_oarchive oa(filtered_output); System& sys = machine.system(); oa << CURRENT_GLOBAL_VERSION << const_cast<const GlobalMemory&>(machine.memory().global()) << const_cast<const SystemGlobals&>(sys.globals()) << const_cast<const GraphicsSystemGlobals&>(sys.graphics().globals()) << const_cast<const EventSystemGlobals&>(sys.event().globals()) << const_cast<const TextSystemGlobals&>(sys.text().globals()) << const_cast<const SoundSystemGlobals&>(sys.sound().globals()); }
void setGraphicsObject(RLMachine& machine, RLOperation* op, int obj, GraphicsObject& gobj) { GraphicsSystem& graphics = machine.system().graphics(); int fgbg; if (!op->getProperty(P_FGBG, fgbg)) fgbg = OBJ_FG; int parentobj; if (op->getProperty(P_PARENTOBJ, parentobj)) { GraphicsObject& parent = graphics.getObject(fgbg, parentobj); ensureIsParentObject(parent, graphics.objectLayerSize()); static_cast<ParentGraphicsObjectData&>(parent.objectData()). setObject(obj, gobj); } else { graphics.setObject(fgbg, obj, gobj); } }
void GCNPlatform::buildSyscomMenuFor( const std::string& label, const MenuSpec menu_items[], RLMachine& machine) { System& sys = machine.system(); std::vector<GCNMenuButton> buttons; for (int i = 0; menu_items[i].syscom_id != MENU_END; ++i) { GCNMenuButton button_definition; if (menu_items[i].syscom_id == MENU_SEPARATOR) { button_definition.separator = true; buttons.push_back(button_definition); } else if (menu_items[i].syscom_id == MENU) { button_definition.label = syscomString(menu_items[i].label); button_definition.action = menu_items[i].event_name; button_definition.enabled = true; buttons.push_back(button_definition); } else { int id = menu_items[i].syscom_id; int enabled = sys.isSyscomEnabled(id); if (enabled != SYSCOM_INVISIBLE) { ostringstream labelss; labelss << setw(3) << setfill('0') << id; if (menu_items[i].label == NULL) button_definition.label = syscomString(labelss.str()); else button_definition.label = syscomString(menu_items[i].label); if (menu_items[i].event_name == NULL) button_definition.action = SYSCOM_EVENTS[id]; else button_definition.action = menu_items[i].event_name; button_definition.enabled = enabled != SYSCOM_GREYED_OUT; buttons.push_back(button_definition); } } } pushWindowOntoStack(new GCNMenu(label, buttons, this)); }
void loadGlobalMemoryFrom(std::istream& iss, RLMachine& machine) { using namespace boost::iostreams; filtering_stream<input> filtered_input; filtered_input.push(zlib_decompressor()); filtered_input.push(iss); text_iarchive ia(filtered_input); System& sys = machine.system(); int version; ia >> version; // Load global memory. ia >> machine.memory().global(); // When Karmic Koala came out, support for all boost earlier than 1.36 was // dropped. For years, I had used boost 1.35 on Ubuntu. It turns out that // boost 1.35 had a serious bug in it, where it wouldn't save vectors of // primitive data types correctly. These global data files no longer load // correctly. // // After flirting with moving to Google protobuf (can't; doesn't handle // complex object graphs like GraphicsObject and its copy-on-write stuff), // and then trying to fix the problem in a forked copy of the serialization // headers which was unsuccessful, I'm just saying to hell with the user's // settings. Most people don't change these values and save games and global // memory still work (per above.) if (version == CURRENT_GLOBAL_VERSION) { ia >> sys.globals() >> sys.graphics().globals() >> sys.event().globals() >> sys.text().globals() >> sys.sound().globals(); // Restore options which may have System specific implementations. (This // will probably expand as more of RealLive is implemented). sys.sound().restoreFromGlobals(); }
bool LoadGameLongOperation::operator()(RLMachine& machine) { load(machine); // Warning: the stack has now been nuked and |this| is an invalid. // Render the current state of the screen GraphicsSystem& graphics = machine.system().graphics(); boost::shared_ptr<Surface> currentWindow = graphics.renderToSurface(); Size s = currentWindow->size(); // Blank dc0 (because we won't be using it anyway) for the image // we're going to render to boost::shared_ptr<Surface> blankScreen = graphics.buildSurface(s); blankScreen->fill(RGBAColour::Black()); machine.pushLongOperation( new FadeEffect(machine, currentWindow, blankScreen, s, 250)); // At this point, the stack has been nuked, and this current // object has already been deleted, leaving an invalid // *this. Returning false is the correct thing to do since // *returning true will pop an unrelated stack frame. return false; }
// ----------------------------------------------------------------------- // ButtonSelectLongOperation // ----------------------------------------------------------------------- ButtonSelectLongOperation::ButtonSelectLongOperation( RLMachine& machine, const libReallive::SelectElement& commandElement, int selbtn_set) : SelectLongOperation(machine, commandElement), highlighted_item_(-1), normal_frame_(0), select_frame_(0) { machine.system().graphics().addRenderable(this); // Load all the data about this #SELBTN from the Gameexe.ini file. Gameexe& gexe = machine.system().gameexe(); GameexeInterpretObject selbtn(gexe("SELBTN", selbtn_set)); vector<int> vec = selbtn("BASEPOS"); basepos_x_ = vec.at(0); basepos_y_ = vec.at(1); vec = selbtn("REPPOS"); reppos_x_ = vec.at(0); reppos_y_ = vec.at(1); vec = selbtn("CENTERING"); int center_x = vec.at(0); int center_y = vec.at(1); moji_size_ = selbtn("MOJISIZE"); // Retrieve the parameters needed to render as a color mask. shared_ptr<TextWindow> window = machine.system().text().currentWindow(); window_bg_colour_ = window->colour(); window_filter_ = window->filter(); int default_colour_num_ = selbtn("MOJIDEFAULTCOL"); int select_colour_num_ = selbtn("MOJISELECTCOL"); if (default_colour_num_ == select_colour_num_) select_colour_num_ = 1; // For CLANNAD if (select_colour_num_ == -1) // For little busters select_colour_num_ = 1; GraphicsSystem& gs = machine.system().graphics(); if (selbtn("NAME").exists() && selbtn("NAME").to_string() != "") name_surface_ = gs.loadNonCGSurfaceFromFile(selbtn("NAME")); if (selbtn("BACK").exists() && selbtn("BACK").to_string() != "") back_surface_ = gs.loadNonCGSurfaceFromFile(selbtn("BACK")); std::vector<int> tmp; if (selbtn("NORMAL").exists()) { tmp = selbtn("NORMAL"); normal_frame_ = tmp.at(0); } if (selbtn("SELECT").exists()) { tmp = selbtn("SELECT"); select_frame_ = tmp.at(0); } // Pick the correct font colour vec = gexe("COLOR_TABLE", default_colour_num_); RGBColour default_colour(vec.at(0), vec.at(1), vec.at(2)); vec = gexe("COLOR_TABLE", select_colour_num_); RGBColour select_colour(vec.at(0), vec.at(1), vec.at(2)); vec = gexe("COLOR_TABLE", 255); RGBColour shadow_colour(vec.at(0), vec.at(1), vec.at(2)); // Build graphic representations of the choices to display to the user. TextSystem& ts = machine.system().text(); int shown_option_count = std::count_if(options_.begin(), options_.end(), bind(&Option::shown, _1)); // Calculate out the bounding rectangles for all the options. Size screen_size = machine.system().graphics().screenSize(); int baseposx = 0; if (center_x) { int totalwidth = ((shown_option_count - 1) * reppos_x_); if (back_surface_) totalwidth += back_surface_->size().width(); else totalwidth += name_surface_->getPattern(normal_frame_).rect.width(); baseposx = (screen_size.width() / 2) - (totalwidth / 2); } else { baseposx = basepos_x_; } int baseposy = 0; if (center_y) { int totalheight = ((shown_option_count - 1) * reppos_y_); if (back_surface_) totalheight += back_surface_->size().height(); baseposy = (screen_size.height() / 2) - (totalheight / 2); } else { baseposy = basepos_y_; } for (size_t i = 0; i < options_.size(); i++) { if (options_[i].shown) { const std::string& text = options_[i].str; ButtonOption o; o.id = i; o.default_surface = ts.renderText( text, moji_size_, 0, 0, default_colour, &shadow_colour); o.select_surface = ts.renderText( text, moji_size_, 0, 0, select_colour, &shadow_colour); if (back_surface_) { o.bounding_rect = Rect(baseposx, baseposy, back_surface_->size()); } else { o.bounding_rect = Rect(baseposx, baseposy, name_surface_->getPattern(0).rect.size()); } buttons_.push_back(o); baseposx += reppos_x_; baseposy += reppos_y_; } } machine.system().graphics().markScreenAsDirty(GUT_TEXTSYS); }
void InvokeSyscomAsOp::operator()(RLMachine& machine) { machine.system().invokeSyscom(machine, syscom_); }
void GCNPlatform::InvokeSyscom(RLMachine& machine, int syscom) { machine.system().invokeSyscom(machine, syscom); }
bool ObjectMutator::operator()(RLMachine& machine, GraphicsObject& object) { unsigned int ticks = machine.system().event().getTicks(); PerformSetting(machine, object); return ticks > (creation_time_ + delay_ + duration_time_); }