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 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); }
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 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 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::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; } } } }
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 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)); }
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; } } }
void SDLSystem::run(RLMachine& machine) { // Give the event handler a chance to run. event_system_->executeEventSystem(machine); text_system_->executeTextSystem(); sound_system_->executeSoundSystem(); graphics_system_->executeGraphicsSystem(machine); if (platform()) platform()->run(machine); boost::shared_ptr<LongOperation> longop = machine.currentLongOperation(); int sleep_time = longop ? longop->sleepTime() : 0; // If forceWait is set, we've detected that the RealLive bytecode is trying // to call refresh() really fast in a loop and that we should inject some // sleep so the CPU doesn't burn. if (forceWait() && sleep_time < 10) sleep_time = 10; // If the longop wants us to sleep for a really long time, we also have a // problem because we cant't handle mouse input smoothly. So we have a // different maximum sleep time depending on whether the mouse is in the // window. int max_time = event_system_->mouseInsideWindow() ? 20 : 50; if (sleep_time > max_time) sleep_time = max_time; if (!forceFastForward() && sleep_time) { event_system_->wait(sleep_time); setForceWait(false); } }
bool SelectLongOperation::operator()(RLMachine& machine) { if (return_value_ != -1) { machine.setStoreRegister(return_value_); return true; } else { return false; } }
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 GraphicsSystem::replayGraphicsStack(RLMachine& machine) { if (graphics_object_impl_->use_old_graphics_stack) { // The actual act of replaying the graphics stack will recreate the graphics // stack, so clear it. vector<GraphicsStackFrame> stack_to_replay; stack_to_replay.swap(graphics_object_impl_->old_graphics_stack); replayDepricatedGraphicsStackVector(machine, stack_to_replay); graphics_object_impl_->use_old_graphics_stack = false; } else { std::deque<std::string> stack_to_replay; stack_to_replay.swap(graphics_object_impl_->graphics_stack); machine.set_replaying_graphics_stack(true); replayGraphicsStackCommand(machine, stack_to_replay); machine.set_replaying_graphics_stack(false); } }
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; } }
void EventSystem::broadcastEvent(RLMachine& machine, const std::function<void(EventListener&)>& event) { EventListeners::iterator listenerIt = listeners_begin(); for (; listenerIt != listeners_end(); ++listenerIt) { event(**listenerIt); } boost::shared_ptr<LongOperation> current_op = machine.currentLongOperation(); if (current_op) event(*current_op); }
// ----------------------------------------------------------------------- // 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); }
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()); } }
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(); }
// ----------------------------------------------------------------------- // 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) { }
void LittleBustersEF00DLL::performCalculations(RLMachine& machine, int index) { if (!lb_ef_param) { throw rlvm::Exception("Effect calculation was called before setting"); } int v5_1154 = machine.getIntValue(IntMemRef( libReallive::INTF_LOCATION, 1154 + index)); int j = ((v5_1154) & 0x1f) + index * 0x20; int k = ((v5_1154+1) & 0x1f) + index * 0x20; int l = ((v5_1154+2) & 0x1f) + index * 0x20; int m = ((v5_1154+3) & 0x1f) + index * 0x20; j *= 3; k *= 3; l *= 3; m *= 3; // 0 < x < 1 // va - vd は 0-1 の範囲で対称性を持つ3次関数 double x = double(machine.getIntValue(IntMemRef( libReallive::INTF_LOCATION, 1162 + index))) * 0.001; double va = (x * x * x)/6; double vb = (-x*x*x + 3*x*x - 3*x + 1) / 6; double vc = (3*x*x*x - 6*x*x + 4) / 6; double vd = (-3*x*x*x+3*x*x+3*x+1) / 6; double r1 = va * lb_ef_param[m+3] + vd * lb_ef_param[l+3] + vc * lb_ef_param[k+3] + vb * lb_ef_param[j+3]; double r2 = va * lb_ef_param[m+2] + vd * lb_ef_param[l+2] + vc * lb_ef_param[k+2] + vb * lb_ef_param[j+2]; double r3 = va * lb_ef_param[m+1] + vd * lb_ef_param[l+1] + vc * lb_ef_param[k+1] + vb * lb_ef_param[j+1]; if (r1 != 400) { r2 = r2 * 800 / (400-r1); r3 = r3 * 700 / (400-r1); } machine.setIntValue(IntMemRef(libReallive::INTF_LOCATION, 1151), r2); machine.setIntValue(IntMemRef(libReallive::INTF_LOCATION, 1152), r3); machine.setIntValue(IntMemRef(libReallive::INTF_LOCATION, 1153), r1); }
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 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(); }
// 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; }
/// @todo Port this up to the new expression handling code void MultiDispatch::operator()( RLMachine& machine, const libReallive::CommandElement& ff) { const ptr_vector<ExpressionPiece>& parameter_pieces = ff.getParameters(); for (unsigned int i = 0; i < parameter_pieces.size(); ++i) { const ptr_vector<ExpressionPiece>& element = dynamic_cast<const ComplexExpressionPiece&>(parameter_pieces[i]). getContainedPieces(); handler_->dispatch(machine, element); } machine.advanceInstructionPointer(); }
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; }
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); } }
// ----------------------------------------------------------------------- // SelectLongOperation // ----------------------------------------------------------------------- SelectLongOperation::SelectLongOperation(RLMachine& machine, const SelectElement& commandElement) : machine_(machine), return_value_(-1) { const vector<SelectElement::Param>& params = commandElement.getRawParams(); for (unsigned int i = 0; i < params.size(); ++i) { Option o; o.shown = true; std::string evaluated_native = libReallive::evaluatePRINT(machine, params[i].text); o.str = cp932toUTF8(evaluated_native, machine.getTextEncoding()); std::vector<SelectElement::Condition> conditions = params[i].cond_parsed; for (std::vector<SelectElement::Condition>::const_iterator it = conditions.begin(); it != conditions.end(); ++it) { switch (it->effect) { // TODO(erg): Someday, I might need to support the other options, but // for now, I've never seen anything other than hide. case SelectElement::OPTION_HIDE: { bool value = false; if (it->condition != "") { const char* location = it->condition.c_str(); scoped_ptr<ExpressionPiece> condition( libReallive::get_expression(location)); value = !condition->integerValue(machine); } o.shown = value; break; } default: cerr << "Unsupported option in select statement: " << it->effect << endl; break; } } options_.push_back(o); } }
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)); }