BrowseTileWindow::BrowseTileWindow(wxWindow* parent, Tile* tile, wxPoint position /* = wxDefaultPosition */) : wxDialog(parent, wxID_ANY, "Browse Field", position, wxSize(600, 400), wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER) { wxSizer* sizer = newd wxBoxSizer(wxVERTICAL); item_list = newd BrowseTileListBox(this, wxID_ANY, tile); sizer->Add(item_list, wxSizerFlags(1).Expand()); wxString pos; pos << "x=" << tile->getX() << ", y=" << tile->getY() << ", z=" << tile->getZ(); wxSizer* infoSizer = newd wxBoxSizer(wxVERTICAL); wxBoxSizer* buttons = newd wxBoxSizer(wxHORIZONTAL); buttons->Add(newd wxButton(this, wxID_REMOVE, "Delete")); buttons->AddSpacer(5); buttons->Add(newd wxButton(this, wxID_FIND, "Select RAW")); infoSizer->Add(buttons); infoSizer->AddSpacer(5); infoSizer->Add(newd wxStaticText(this, wxID_ANY, "Position: " + pos), wxSizerFlags(0).Left()); infoSizer->Add(item_count_txt = newd wxStaticText(this, wxID_ANY, "Item count: " + i2ws(item_list->GetItemCount())), wxSizerFlags(0).Left()); infoSizer->Add(newd wxStaticText(this, wxID_ANY, "Protection zone: " + b2yn(tile->isPZ())), wxSizerFlags(0).Left()); infoSizer->Add(newd wxStaticText(this, wxID_ANY, "No PvP: " + b2yn(tile->getMapFlags() & TILESTATE_NOPVP)), wxSizerFlags(0).Left()); infoSizer->Add(newd wxStaticText(this, wxID_ANY, "No logout: " + b2yn(tile->getMapFlags() & TILESTATE_NOLOGOUT)), wxSizerFlags(0).Left()); infoSizer->Add(newd wxStaticText(this, wxID_ANY, "PvP zone: " + b2yn(tile->getMapFlags() & TILESTATE_PVPZONE)), wxSizerFlags(0).Left()); infoSizer->Add(newd wxStaticText(this, wxID_ANY, "House: " + b2yn(tile->isHouseTile())), wxSizerFlags(0).Left()); sizer->Add(infoSizer, wxSizerFlags(0).Left().DoubleBorder()); // OK/Cancel buttons wxSizer* btnSizer = newd wxBoxSizer(wxHORIZONTAL); btnSizer->Add(newd wxButton(this, wxID_OK, "OK"), wxSizerFlags(0).Center()); btnSizer->Add(newd wxButton(this, wxID_CANCEL, "Cancel"), wxSizerFlags(0).Center()); sizer->Add(btnSizer, wxSizerFlags(0).Center().DoubleBorder()); SetSizerAndFit(sizer); }
wxNotebookPage* PreferencesWindow::CreateGeneralPage() { wxNotebookPage* general_page = newd wxPanel(book, wxID_ANY); wxSizer* sizer = newd wxBoxSizer(wxVERTICAL); wxStaticText* tmptext; sizer->Add(always_make_backup_chkbox = newd wxCheckBox(general_page, wxID_ANY, wxT("Always make map backup"))); always_make_backup_chkbox->SetValue(settings.getInteger(Config::ALWAYS_MAKE_BACKUP) == 1); sizer->Add(create_on_startup_chkbox = newd wxCheckBox(general_page, wxID_ANY, wxT("Create map on startup"))); create_on_startup_chkbox->SetValue(settings.getInteger(Config::CREATE_MAP_ON_STARTUP) == 1); sizer->Add(update_check_on_startup_chkbox = newd wxCheckBox(general_page, wxID_ANY, wxT("Check for updates on startup"))); update_check_on_startup_chkbox->SetValue(settings.getInteger(Config::USE_UPDATER) == 1); sizer->Add(only_one_instance_chkbox = newd wxCheckBox(general_page, wxID_ANY, wxT("Open all maps in the same instance"))); only_one_instance_chkbox->SetValue(settings.getInteger(Config::ONLY_ONE_INSTANCE) == 1); only_one_instance_chkbox->SetToolTip(wxT("When checked, maps opened using the shell will all be opened in the same instance.")); wxFlexGridSizer* grid_sizer = newd wxFlexGridSizer(2, 10, 10); grid_sizer->AddGrowableCol(1); grid_sizer->Add(tmptext = newd wxStaticText(general_page, wxID_ANY, wxT("Undo queue size: ")), 0); undo_size_spin = newd wxSpinCtrl(general_page, wxID_ANY, i2ws(settings.getInteger(Config::UNDO_SIZE)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 0x10000000); grid_sizer->Add(undo_size_spin, 0); SetWindowToolTip(tmptext, undo_size_spin, wxT("How many action you can undo, be aware that a high value will increase memory usage.")); grid_sizer->Add(tmptext = newd wxStaticText(general_page, wxID_ANY, wxT("Undo maximum memory size (MB): ")), 0); undo_mem_size_spin = newd wxSpinCtrl(general_page, wxID_ANY, i2ws(settings.getInteger(Config::UNDO_MEM_SIZE)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 4096); grid_sizer->Add(undo_mem_size_spin, 0); SetWindowToolTip(tmptext, undo_mem_size_spin, wxT("The approximite limit for the memory usage of the undo queue.")); grid_sizer->Add(tmptext = newd wxStaticText(general_page, wxID_ANY, wxT("Worker Threads: ")), 0); worker_threads_spin = newd wxSpinCtrl(general_page, wxID_ANY, i2ws(settings.getInteger(Config::WORKER_THREADS)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 64); grid_sizer->Add(worker_threads_spin, 0); SetWindowToolTip(tmptext, worker_threads_spin, wxT("How many threads the editor will use for intensive operations. This should be equivalent to the amount of logical processors in your system.")); sizer->Add(20,10); sizer->Add(grid_sizer); general_page->SetSizerAndFit(sizer); return general_page; }
EditHouseDialog::EditHouseDialog(wxWindow* parent, Map* map, House* house) : wxDialog(parent, wxID_ANY, wxT("House"), wxDefaultPosition, wxSize(250,160)), map(map), what_house(house) { ASSERT(map); ASSERT(house); // Create topsizer wxSizer* sizer = newd wxBoxSizer(wxVERTICAL); wxSizer* tmpsizer; house_name = wxstr(house->name); house_id = i2ws(house->id); house_rent = i2ws(house->rent); // House options tmpsizer = newd wxStaticBoxSizer(wxHORIZONTAL, this, wxT("Name")); name_field = newd wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(230,20), 0, wxTextValidator(wxFILTER_ASCII, &house_name)); tmpsizer->Add(name_field); sizer->Add(tmpsizer, wxSizerFlags().Border(wxALL, 20)); tmpsizer = newd wxStaticBoxSizer(wxHORIZONTAL, this, wxT("Rent / ID")); rent_field = newd wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(160,20), 0, wxTextValidator(wxFILTER_NUMERIC, &house_rent)); tmpsizer->Add(rent_field); id_field = newd wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(70,20), 0, wxTextValidator(wxFILTER_NUMERIC, &house_id)); id_field->Enable(false); tmpsizer->Add(id_field); sizer->Add(tmpsizer, wxSizerFlags().Border(wxALL, 20)); // House options guildhall_field = newd wxCheckBox(this, wxID_ANY, wxT("Guildhall"), wxDefaultPosition); sizer->Add(guildhall_field, wxSizerFlags().Border(wxRIGHT | wxLEFT | wxBOTTOM, 20)); guildhall_field->SetValue(house->guildhall); // OK/Cancel buttons tmpsizer = newd wxBoxSizer(wxHORIZONTAL); tmpsizer->Add(newd wxButton(this, wxID_OK, wxT("OK")), wxSizerFlags(1).Center()); tmpsizer->Add(newd wxButton(this, wxID_CANCEL, wxT("Cancel")), wxSizerFlags(1).Center()); sizer->Add(tmpsizer, wxSizerFlags(1).Center().Border(wxRIGHT | wxLEFT | wxBOTTOM, 20)); SetSizerAndFit(sizer); }
void PropertiesWindow::SetGridValue(wxGrid* grid, int rowIndex, std::string label, const ItemAttribute& attr) { wxArrayString types; types.Add(wxT("Number")); types.Add(wxT("Float")); types.Add(wxT("Boolean")); types.Add(wxT("String")); grid->SetCellValue(label, rowIndex, 0); switch (attr.type) { case ItemAttribute::STRING: { grid->SetCellValue(wxT("String"), rowIndex, 1); grid->SetCellValue(wxstr(*attr.getString()), rowIndex, 2); break; } case ItemAttribute::INTEGER: { grid->SetCellValue(wxT("Number"), rowIndex, 1); grid->SetCellValue(i2ws(*attr.getInteger()), rowIndex, 2); grid->SetCellEditor(rowIndex, 2, new wxGridCellNumberEditor); break; } case ItemAttribute::DOUBLE: case ItemAttribute::FLOAT: { grid->SetCellValue(wxT("Float"), rowIndex, 1); wxString f; f << *attr.getFloat(); grid->SetCellValue(f, rowIndex, 2); grid->SetCellEditor(rowIndex, 2, new wxGridCellFloatEditor); break; } case ItemAttribute::BOOLEAN: { grid->SetCellValue(wxT("Boolean"), rowIndex, 1); grid->SetCellValue(*attr.getBoolean() ? wxT("1") : wxT(""), rowIndex, 2); grid->SetCellRenderer(rowIndex, 2, new wxGridCellBoolRenderer); grid->SetCellEditor(rowIndex, 2, new wxGridCellBoolEditor); break; } default: { grid->SetCellValue(wxT("Unknown"), rowIndex, 1); grid->SetCellBackgroundColour(*wxLIGHT_GREY, rowIndex, 1); grid->SetCellBackgroundColour(*wxLIGHT_GREY, rowIndex, 2); grid->SetReadOnly(rowIndex, 1, true); grid->SetReadOnly(rowIndex, 2, true); break; } } grid->SetCellEditor(rowIndex, 1, new wxGridCellChoiceEditor(types)); }
wxWindow* PropertiesWindow::createGeneralPanel(wxWindow* parent) { wxPanel* panel = newd wxPanel(parent, ITEM_PROPERTIES_GENERAL_TAB); wxFlexGridSizer* gridsizer = newd wxFlexGridSizer(2, 10, 10); gridsizer->AddGrowableCol(1); gridsizer->Add(newd wxStaticText(panel, wxID_ANY, "ID " + i2ws(edit_item->getID()))); gridsizer->Add(newd wxStaticText(panel, wxID_ANY, "\"" + wxstr(edit_item->getName()) + "\"")); gridsizer->Add(newd wxStaticText(panel, wxID_ANY, "Action ID")); wxSpinCtrl* action_id_field = newd wxSpinCtrl(panel, wxID_ANY, i2ws(edit_item->getActionID()), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 0xFFFF, edit_item->getActionID()); gridsizer->Add(action_id_field, wxSizerFlags(1).Expand()); gridsizer->Add(newd wxStaticText(panel, wxID_ANY, "Unique ID")); wxSpinCtrl* unique_id_field = newd wxSpinCtrl(panel, wxID_ANY, i2ws(edit_item->getUniqueID()), wxDefaultPosition, wxSize(-1, 20), wxSP_ARROW_KEYS, 0, 0xFFFF, edit_item->getUniqueID()); gridsizer->Add(unique_id_field, wxSizerFlags(1).Expand()); panel->SetSizerAndFit(gridsizer); return panel; }
bool GraphicManager::loadSpriteMetadataFlags(FileReadHandle& file, GameSprite* sType, wxString& error, wxArrayString& warnings) { uint8_t prev_flag = 0; uint8_t flag = DatFlagLast; for(int i = 0; i < DatFlagLast; ++i) { prev_flag = flag; file.getU8(flag); if(flag == DatFlagLast) { return true; } if(dat_format >= DAT_FORMAT_1010) { /* In 10.10+ all attributes from 16 and up were * incremented by 1 to make space for 16 as * "No Movement Animation" flag. */ if(flag == 16) flag = DatFlagNoMoveAnimation; else if(flag > 16) flag -= 1; } else if(dat_format >= DAT_FORMAT_86) { /* Default attribute values follow * the format of 8.6-9.86. * Therefore no changes here. */ } else if(dat_format >= DAT_FORMAT_78) { /* In 7.80-8.54 all attributes from 8 and higher were * incremented by 1 to make space for 8 as * "Item Charges" flag. */ if(flag == 8) { flag = DatFlagChargeable; } else if(flag > 8) flag -= 1; } else if(dat_format >= DAT_FORMAT_755) { /* In 7.55-7.72 attributes 23 is "Floor Change". */ if(flag == 23) flag = DatFlagFloorChange; } else if(dat_format >= DAT_FORMAT_74) { /* In 7.4-7.5 attribute "Ground Border" did not exist * attributes 1-15 have to be adjusted. * Several other changes in the format. */ if(flag > 0 && flag <= 15) flag += 1; else if(flag == 16) flag = DatFlagLight; else if(flag == 17) flag = DatFlagFloorChange; else if(flag == 18) flag = DatFlagFullGround; else if(flag == 19) flag = DatFlagElevation; else if(flag == 20) flag = DatFlagDisplacement; else if(flag == 22) flag = DatFlagMinimapColor; else if(flag == 23) flag = DatFlagRotateable; else if(flag == 24) flag = DatFlagLyingCorpse; else if(flag == 25) flag = DatFlagHangable; else if(flag == 26) flag = DatFlagHookSouth; else if(flag == 27) flag = DatFlagHookEast; else if(flag == 28) flag = DatFlagAnimateAlways; /* "Multi Use" and "Force Use" are swapped */ if(flag == DatFlagMultiUse) flag = DatFlagForceUse; else if(flag == DatFlagForceUse) flag = DatFlagMultiUse; } switch (flag) { case DatFlagGroundBorder: case DatFlagOnBottom: case DatFlagOnTop: case DatFlagContainer: case DatFlagStackable: case DatFlagForceUse: case DatFlagMultiUse: case DatFlagFluidContainer: case DatFlagSplash: case DatFlagNotWalkable: case DatFlagNotMoveable: case DatFlagBlockProjectile: case DatFlagNotPathable: case DatFlagPickupable: case DatFlagHangable: case DatFlagHookSouth: case DatFlagHookEast: case DatFlagRotateable: case DatFlagDontHide: case DatFlagTranslucent: case DatFlagLyingCorpse: case DatFlagAnimateAlways: case DatFlagFullGround: case DatFlagLook: case DatFlagWrappable: case DatFlagUnwrappable: case DatFlagTopEffect: case DatFlagFloorChange: case DatFlagNoMoveAnimation: case DatFlagChargeable: break; case DatFlagGround: case DatFlagWritable: case DatFlagWritableOnce: case DatFlagCloth: case DatFlagLensHelp: case DatFlagUsable: file.skip(2); break; case DatFlagLight: file.skip(4); break; case DatFlagDisplacement: { if(dat_format >= DAT_FORMAT_755) { uint16_t offset_x; uint16_t offset_y; file.getU16(offset_x); file.getU16(offset_y); sType->drawoffset_x = offset_x; sType->drawoffset_y = offset_y; } else { sType->drawoffset_x = 8; sType->drawoffset_y = 8; } break; } case DatFlagElevation: { uint16_t draw_height; file.getU16(draw_height); sType->draw_height = draw_height; break; } case DatFlagMinimapColor: { uint16_t minimap_color; file.getU16(minimap_color); sType->minimap_color = minimap_color; break; } case DatFlagMarket: { file.skip(6); std::string marketName; file.getString(marketName); file.skip(4); break; } default: { wxString err; err << "Metadata: Unknown flag: " << i2ws(flag) << ". Previous flag: " << i2ws(prev_flag) << "."; warnings.push_back(err); break; } } } return true; }
void TilesetCategory::loadBrush(xmlNodePtr node, wxArrayString& warnings) { std::string strVal; std::string brush_name; int intVal = 0; readXMLValue(node, "after", brush_name); if(readXMLValue(node, "afteritem", intVal)) { ItemType& it = item_db[intVal]; if(it.id != 0)// Verify that we have a valid item { brush_name = (it.raw_brush? it.raw_brush->getName() : ""); } } if(xmlStrcmp(node->name,(const xmlChar*)"brush") == 0) { if(readXMLString(node, "name", strVal)) { Brush* brush = tileset.brushes.getBrush(strVal); if(brush) { std::vector<Brush*>::iterator insert_here = brushlist.end(); if(brush_name.size()) { for(std::vector<Brush*>::iterator iter = brushlist.begin(); iter != brushlist.end(); ++iter) { if((*iter)->getName() == brush_name) { insert_here = ++iter; break; } } } brush->flagAsVisible(); brushlist.insert(insert_here, brush); } else { warnings.push_back(wxT("Brush \"") + wxstr(strVal) + wxT("\" doesn't exist.")); } } } else if(xmlStrcmp(node->name,(const xmlChar*)"item") == 0) { int fromid = 0, toid = 0; if(!readXMLInteger(node, "id", fromid)) { if(!readXMLInteger(node, "fromid", fromid)) { warnings.push_back(wxT("Couldn't read raw ids.")); } readXMLInteger(node, "toid", toid); } toid = std::max(toid, fromid); std::vector<Brush*>::iterator insert_here = brushlist.end(); if(brush_name.size()) { for(std::vector<Brush*>::iterator iter = brushlist.begin(); iter != brushlist.end(); ++iter) { if((*iter)->getName() == brush_name) { insert_here = ++iter; break; } } } std::vector<Brush*> temp_vec; for(int id = fromid; id <= toid; ++id) { ItemType& it = item_db[id]; if(it.id == 0) // Verify that we have a valid item { warnings.push_back(wxT("Unknown item id #") + i2ws(id) + wxT(".")); } else { RAWBrush* brush; if(it.raw_brush) { brush = it.raw_brush; } else { brush = it.raw_brush = newd RAWBrush(it.id); it.has_raw = true; tileset.brushes.addBrush(brush); // This will take care of cleaning up afterwards } if(it.doodad_brush == NULL && !isTrivial()) { it.doodad_brush = brush; } brush->flagAsVisible(); temp_vec.push_back(brush); } } brushlist.insert(insert_here, temp_vec.begin(), temp_vec.end()); } }
wxNotebookPage* PreferencesWindow::CreateGeneralPage() { wxNotebookPage* general_page = newd wxPanel(book, wxID_ANY); wxSizer* sizer = newd wxBoxSizer(wxVERTICAL); wxStaticText* tmptext; always_make_backup_chkbox = newd wxCheckBox(general_page, wxID_ANY, "Always make map backup"); always_make_backup_chkbox->SetValue(g_settings.getInteger(Config::ALWAYS_MAKE_BACKUP) == 1); sizer->Add(always_make_backup_chkbox, 0, wxLEFT | wxTOP, 5); create_on_startup_chkbox = newd wxCheckBox(general_page, wxID_ANY, "Create map on startup"); create_on_startup_chkbox->SetValue(g_settings.getInteger(Config::CREATE_MAP_ON_STARTUP) == 1); sizer->Add(create_on_startup_chkbox, 0, wxLEFT | wxTOP, 5); update_check_on_startup_chkbox = newd wxCheckBox(general_page, wxID_ANY, "Check for updates on startup"); update_check_on_startup_chkbox->SetValue(g_settings.getInteger(Config::USE_UPDATER) == 1); sizer->Add(update_check_on_startup_chkbox, 0, wxLEFT | wxTOP, 5); only_one_instance_chkbox = newd wxCheckBox(general_page, wxID_ANY, "Open all maps in the same instance"); only_one_instance_chkbox->SetValue(g_settings.getInteger(Config::ONLY_ONE_INSTANCE) == 1); only_one_instance_chkbox->SetToolTip("When checked, maps opened using the shell will all be opened in the same instance."); sizer->Add(only_one_instance_chkbox, 0, wxLEFT | wxTOP, 5); sizer->AddSpacer(10); wxFlexGridSizer* grid_sizer = newd wxFlexGridSizer(2, 10, 10); grid_sizer->AddGrowableCol(1); grid_sizer->Add(tmptext = newd wxStaticText(general_page, wxID_ANY, "Undo queue size: "), 0); undo_size_spin = newd wxSpinCtrl(general_page, wxID_ANY, i2ws(g_settings.getInteger(Config::UNDO_SIZE)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 0x10000000); grid_sizer->Add(undo_size_spin, 0); SetWindowToolTip(tmptext, undo_size_spin, "How many action you can undo, be aware that a high value will increase memory usage."); grid_sizer->Add(tmptext = newd wxStaticText(general_page, wxID_ANY, "Undo maximum memory size (MB): "), 0); undo_mem_size_spin = newd wxSpinCtrl(general_page, wxID_ANY, i2ws(g_settings.getInteger(Config::UNDO_MEM_SIZE)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 4096); grid_sizer->Add(undo_mem_size_spin, 0); SetWindowToolTip(tmptext, undo_mem_size_spin, "The approximite limit for the memory usage of the undo queue."); grid_sizer->Add(tmptext = newd wxStaticText(general_page, wxID_ANY, "Worker Threads: "), 0); worker_threads_spin = newd wxSpinCtrl(general_page, wxID_ANY, i2ws(g_settings.getInteger(Config::WORKER_THREADS)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 64); grid_sizer->Add(worker_threads_spin, 0); SetWindowToolTip(tmptext, worker_threads_spin, "How many threads the editor will use for intensive operations. This should be equivalent to the amount of logical processors in your system."); grid_sizer->Add(tmptext = newd wxStaticText(general_page, wxID_ANY, "Replace count: "), 0); replace_size_spin = newd wxSpinCtrl(general_page, wxID_ANY, i2ws(g_settings.getInteger(Config::REPLACE_SIZE)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 100000); grid_sizer->Add(replace_size_spin, 0); SetWindowToolTip(tmptext, replace_size_spin, "How many items you can replace on the map using the Replace Item tool."); sizer->Add(grid_sizer, 0, wxALL, 5); sizer->AddSpacer(10); wxString position_choices[] = { " {x = 0, y = 0, z = 0}", " {\"x\":0,\"y\":0,\"z\":0}", " x, y, z", " (x, y, z)", " Position(x, y, z)" }; int radio_choices = sizeof(position_choices) / sizeof(wxString); position_format = newd wxRadioBox(general_page, wxID_ANY, "Copy Position Format", wxDefaultPosition, wxDefaultSize, radio_choices, position_choices, 1, wxRA_SPECIFY_COLS); position_format->SetSelection(g_settings.getInteger(Config::COPY_POSITION_FORMAT)); sizer->Add(position_format, 0, wxALL | wxEXPAND, 5); SetWindowToolTip(tmptext, position_format, "The position format when copying from the map."); general_page->SetSizerAndFit(sizer); return general_page; }
bool ItemDatabase::loadFromOtb(const FileName& datafile, wxString& error, wxArrayString& warnings) { std::string filename = nstr((datafile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + datafile.GetFullName())); DiskNodeFileReadHandle f(filename, StringVector(1, "OTBI")); if(!f.isOk()) { error = wxT("Couldn't open file \"") + wxstr(filename) + wxT("\":") + wxstr(f.getErrorMessage()); return false; } BinaryNode* root = f.getRootNode(); #define safe_get(node, func, ...) do {\ if(!node->get##func(__VA_ARGS__)) {\ error = wxstr(f.getErrorMessage()); \ return false; \ } \ } while(false) // Read root flags root->skip(1); // Type info //uint32_t flags = root->skip(4); // Unused? uint8_t attr; safe_get(root, U8, attr); if(attr == ROOT_ATTR_VERSION) { uint16_t datalen; if(!root->getU16(datalen) || datalen != 4 + 4 + 4 + 1*128) { error = wxT("items.otb: Size of version header is invalid, updated .otb version?"); return false; } safe_get(root, U32, MajorVersion); // items otb format file version safe_get(root, U32, MinorVersion); // client version safe_get(root, U32, BuildNumber); // revision std::string csd; csd.resize(128); if(!root->getRAW((uint8_t*)csd.data(), 128)) { // CSDVersion ?? error = wxstr(f.getErrorMessage()); return false; } } else { error = wxT("Expected ROOT_ATTR_VERSION as first node of items.otb!"); } if(settings.getInteger(Config::CHECK_SIGNATURES)) { if(gui.GetCurrentVersion().getOTBVersion().format_version != MajorVersion) { error = wxT("Unsupported items.otb version (version ") + i2ws(MajorVersion) + wxT(")"); return false; } } BinaryNode* itemNode = root->getChild(); switch(MajorVersion) { case 1: return loadFromOtbVer1(itemNode, error, warnings); case 2: return loadFromOtbVer2(itemNode, error, warnings); case 3: return loadFromOtbVer3(itemNode, error, warnings); } return true; }
bool ItemDatabase::loadFromOtbVer3(BinaryNode* itemNode, wxString& error, wxArrayString& warnings) { uint8_t u8; for( ; itemNode != nullptr; itemNode = itemNode->advance()) { if(!itemNode->getU8(u8)) { // Invalid! warnings.push_back(wxT("Invalid item type encountered...")); continue; } if(ItemGroup_t(u8) == ITEM_GROUP_DEPRECATED) continue; ItemType* t = newd ItemType(); t->group = ItemGroup_t(u8); switch(t->group) { case ITEM_GROUP_NONE: case ITEM_GROUP_GROUND: case ITEM_GROUP_SPLASH: case ITEM_GROUP_FLUID: break; case ITEM_GROUP_CONTAINER: t->type = ITEM_TYPE_CONTAINER; break; break; default: warnings.push_back(wxT("Unknown item group declaration")); } uint32_t flags; if(itemNode->getU32(flags)) { t->blockSolid = ((flags & FLAG_BLOCK_SOLID) == FLAG_BLOCK_SOLID); t->blockProjectile = ((flags & FLAG_BLOCK_PROJECTILE) == FLAG_BLOCK_PROJECTILE); t->blockPathFind = ((flags & FLAG_BLOCK_PATHFIND) == FLAG_BLOCK_PATHFIND); t->pickupable = ((flags & FLAG_PICKUPABLE) == FLAG_PICKUPABLE); t->moveable = ((flags & FLAG_MOVEABLE) == FLAG_MOVEABLE); t->stackable = ((flags & FLAG_STACKABLE) == FLAG_STACKABLE); t->floorChangeDown = ((flags & FLAG_FLOORCHANGEDOWN) == FLAG_FLOORCHANGEDOWN); t->floorChangeNorth = ((flags & FLAG_FLOORCHANGENORTH) == FLAG_FLOORCHANGENORTH); t->floorChangeEast = ((flags & FLAG_FLOORCHANGEEAST) == FLAG_FLOORCHANGEEAST); t->floorChangeSouth = ((flags & FLAG_FLOORCHANGESOUTH) == FLAG_FLOORCHANGESOUTH); t->floorChangeWest = ((flags & FLAG_FLOORCHANGEWEST) == FLAG_FLOORCHANGEWEST); // Now this is confusing, just accept that the ALWAYSONTOP flag means it's always on bottom, got it?! t->alwaysOnBottom = ((flags & FLAG_ALWAYSONTOP) == FLAG_ALWAYSONTOP); t->isVertical = ((flags & FLAG_VERTICAL) == FLAG_VERTICAL); t->isHorizontal = ((flags & FLAG_HORIZONTAL) == FLAG_HORIZONTAL); t->isHangable = ((flags & FLAG_HANGABLE) == FLAG_HANGABLE); t->allowDistRead = ((flags & FLAG_ALLOWDISTREAD) == FLAG_ALLOWDISTREAD); t->rotable = ((flags & FLAG_ROTABLE) == FLAG_ROTABLE); t->canReadText = ((flags & FLAG_READABLE) == FLAG_READABLE); t->client_chargeable = ((flags & FLAG_CLIENTCHARGES) == FLAG_CLIENTCHARGES); } uint8_t attribute; while(itemNode->getU8(attribute)) { uint16_t datalen; if(!itemNode->getU16(datalen)) { warnings.push_back(wxT("Invalid item type property")); break; } switch(attribute) { case ITEM_ATTR_SERVERID: { if(datalen != sizeof(uint16_t)) { error = wxT("items.otb: Unexpected data length of server id block (Should be 2 bytes)"); return false; } if(!itemNode->getU16(t->id)) warnings.push_back(wxT("Invalid item type property (2)")); if(max_item_id < t->id) max_item_id = t->id; break; } case ITEM_ATTR_CLIENTID: { if(datalen != sizeof(uint16_t)) { error = wxT("items.otb: Unexpected data length of client id block (Should be 2 bytes)"); return false; } if(!itemNode->getU16(t->clientID)) warnings.push_back(wxT("Invalid item type property (2)")); t->sprite = static_cast<GameSprite*>(gui.gfx.getSprite(t->clientID)); break; } case ITEM_ATTR_SPEED: { if(datalen != sizeof(uint16_t)) { error = wxT("items.otb: Unexpected data length of speed block (Should be 2 bytes)"); return false; } //t->speed = itemNode->getU16(); if(!itemNode->skip(2)) // Just skip two bytes, we don't need speed warnings.push_back(wxT("Invalid item type property (3)")); break; } case ITEM_ATTR_LIGHT2: { if(datalen != sizeof(lightBlock2)) { warnings.push_back(wxT("items.otb: Unexpected data length of item light (2) block (Should be ") + i2ws(sizeof(lightBlock2)) + wxT(" bytes)")); break; } if(!itemNode->skip(4)) // Just skip two bytes, we don't need light warnings.push_back(wxT("Invalid item type property (4)")); //t->lightLevel = itemNode->getU16(); //t->lightColor = itemNode->getU16(); break; } case ITEM_ATTR_TOPORDER: { if(datalen != sizeof(uint8_t)) { warnings.push_back(wxT("items.otb: Unexpected data length of item toporder block (Should be 1 byte)")); break; } if(!itemNode->getU8(u8)) warnings.push_back(wxT("Invalid item type property (5)")); t->alwaysOnTopOrder = u8; break; } default: { //skip unknown attributes itemNode->skip(datalen); //warnings.push_back(wxT("items.otb: Skipped unknown attribute")); break; } } } if(t) { if(items[t->id]) { warnings.push_back(wxT("items.otb: Duplicate items")); delete items[t->id]; } items.set(t->id, t); } } return true; }
bool ItemDatabase::loadFromOtbVer1(BinaryNode* itemNode, wxString& error, wxArrayString& warnings) { uint8_t u8; for( ; itemNode != nullptr; itemNode = itemNode->advance()) { if(!itemNode->getU8(u8)) { // Invalid! warnings.push_back(wxT("Invalid item type encountered...")); continue; } if(u8 == ITEM_GROUP_DEPRECATED) continue; ItemType* t = newd ItemType(); t->group = ItemGroup_t(u8); switch(t->group) { case ITEM_GROUP_NONE: case ITEM_GROUP_GROUND: case ITEM_GROUP_SPLASH: case ITEM_GROUP_FLUID: case ITEM_GROUP_WEAPON: case ITEM_GROUP_AMMUNITION: case ITEM_GROUP_ARMOR: case ITEM_GROUP_WRITEABLE: case ITEM_GROUP_KEY: break; case ITEM_GROUP_DOOR: t->type = ITEM_TYPE_DOOR; break; case ITEM_GROUP_CONTAINER: t->type = ITEM_TYPE_CONTAINER; break; case ITEM_GROUP_RUNE: t->client_chargeable = true; break; case ITEM_GROUP_TELEPORT: t->type = ITEM_TYPE_TELEPORT; break; case ITEM_GROUP_MAGICFIELD: t->type = ITEM_TYPE_MAGICFIELD; break; default: warnings.push_back(wxT("Unknown item group declaration")); } uint32_t flags; if(itemNode->getU32(flags)) { t->blockSolid = ((flags & FLAG_BLOCK_SOLID) == FLAG_BLOCK_SOLID); t->blockProjectile = ((flags & FLAG_BLOCK_PROJECTILE) == FLAG_BLOCK_PROJECTILE); t->blockPathFind = ((flags & FLAG_BLOCK_PATHFIND) == FLAG_BLOCK_PATHFIND); // These are irrelevant //t->hasHeight = ((flags & FLAG_HAS_HEIGHT) == FLAG_HAS_HEIGHT); //t->useable = ((flags & FLAG_USEABLE) == FLAG_USEABLE); t->pickupable = ((flags & FLAG_PICKUPABLE) == FLAG_PICKUPABLE); t->moveable = ((flags & FLAG_MOVEABLE) == FLAG_MOVEABLE); t->stackable = ((flags & FLAG_STACKABLE) == FLAG_STACKABLE); t->floorChangeDown = ((flags & FLAG_FLOORCHANGEDOWN) == FLAG_FLOORCHANGEDOWN); t->floorChangeNorth = ((flags & FLAG_FLOORCHANGENORTH) == FLAG_FLOORCHANGENORTH); t->floorChangeEast = ((flags & FLAG_FLOORCHANGEEAST) == FLAG_FLOORCHANGEEAST); t->floorChangeSouth = ((flags & FLAG_FLOORCHANGESOUTH) == FLAG_FLOORCHANGESOUTH); t->floorChangeWest = ((flags & FLAG_FLOORCHANGEWEST) == FLAG_FLOORCHANGEWEST); // Now this is confusing, just accept that the ALWAYSONTOP flag means it's always on bottom, got it?! t->alwaysOnBottom = ((flags & FLAG_ALWAYSONTOP) == FLAG_ALWAYSONTOP); t->isVertical = ((flags & FLAG_VERTICAL) == FLAG_VERTICAL); t->isHorizontal = ((flags & FLAG_HORIZONTAL) == FLAG_HORIZONTAL); t->isHangable = ((flags & FLAG_HANGABLE) == FLAG_HANGABLE); t->allowDistRead = ((flags & FLAG_ALLOWDISTREAD) == FLAG_ALLOWDISTREAD); t->rotable = ((flags & FLAG_ROTABLE) == FLAG_ROTABLE); t->canReadText = ((flags & FLAG_READABLE) == FLAG_READABLE); } uint8_t attribute; while(itemNode->getU8(attribute)) { uint16_t datalen; if(!itemNode->getU16(datalen)) { warnings.push_back(wxT("Invalid item type property")); break; } switch(attribute) { case ITEM_ATTR_SERVERID: { if(datalen != sizeof(uint16_t)) { error = wxT("items.otb: Unexpected data length of server id block (Should be 2 bytes)"); return false; } if(!itemNode->getU16(t->id)) warnings.push_back(wxT("Invalid item type property (2)")); if(max_item_id < t->id) max_item_id = t->id; break; } case ITEM_ATTR_CLIENTID: { if(datalen != sizeof(uint16_t)) { error = wxT("items.otb: Unexpected data length of client id block (Should be 2 bytes)"); return false; } if(!itemNode->getU16(t->clientID)) warnings.push_back(wxT("Invalid item type property (2)")); t->sprite = static_cast<GameSprite*>(gui.gfx.getSprite(t->clientID)); break; } case ITEM_ATTR_SPEED: { if(datalen != sizeof(uint16_t)) { error = wxT("items.otb: Unexpected data length of speed block (Should be 2 bytes)"); return false; } //t->speed = itemNode->getU16(); if(!itemNode->skip(2)) // Just skip two bytes, we don't need speed warnings.push_back(wxT("Invalid item type property (3)")); break; } case ITEM_ATTR_LIGHT2: { if(datalen != sizeof(lightBlock2)) { warnings.push_back(wxT("items.otb: Unexpected data length of item light (2) block (Should be ") + i2ws(sizeof(lightBlock2)) + wxT(" bytes)")); break; } if(!itemNode->skip(4)) // Just skip two bytes, we don't need light warnings.push_back(wxT("Invalid item type property (4)")); //t->lightLevel = itemNode->getU16(); //t->lightColor = itemNode->getU16(); break; } case ITEM_ATTR_TOPORDER: { if(datalen != sizeof(uint8_t)) { warnings.push_back(wxT("items.otb: Unexpected data length of item toporder block (Should be 1 byte)")); break; } uint8_t u8 = 0; if(!itemNode->getU8(u8)) warnings.push_back(wxT("Invalid item type property (5)")); t->alwaysOnTopOrder = u8; break; } case ITEM_ATTR_NAME: { if(datalen >= 128) { warnings.push_back(wxT("items.otb: Unexpected data length of item name block (Should be 128 bytes)")); break; } uint8_t name[128]; memset(&name, 0, 128); if(!itemNode->getRAW(name, datalen)) { warnings.push_back(wxT("Invalid item type property (6)")); break; } t->name = (char*)name; break; } case ITEM_ATTR_DESCR: { if(datalen >= 128) { warnings.push_back(wxT("items.otb: Unexpected data length of item descr block (Should be 128 bytes)")); break; } uint8_t description[128]; memset(&description, 0, 128); if(!itemNode->getRAW(description, datalen)) { warnings.push_back(wxT("Invalid item type property (7)")); break; } t->description = (char*)description; break; } case ITEM_ATTR_MAXITEMS: { if(datalen != sizeof(unsigned short)) { warnings.push_back(wxT("items.otb: Unexpected data length of item volume block (Should be 2 bytes)")); break; } if(!itemNode->getU16(t->volume)) warnings.push_back(wxT("Invalid item type property (8)")); break; } case ITEM_ATTR_WEIGHT: { if(datalen != sizeof(double)) { warnings.push_back(wxT("items.otb: Unexpected data length of item weight block (Should be 8 bytes)")); break; } uint8_t w[sizeof(double)]; if(!itemNode->getRAW(w, sizeof(double))) { warnings.push_back(wxT("Invalid item type property (7)")); break; } double wi = *reinterpret_cast<double*>(&w); t->weight = wi; break; } case ITEM_ATTR_ROTATETO: { if(datalen != sizeof(unsigned short)) { warnings.push_back(wxT("items.otb: Unexpected data length of item rotateTo block (Should be 2 bytes)")); break; } uint16_t rotate; if(!itemNode->getU16(rotate)) { warnings.push_back(wxT("Invalid item type property (8)")); break; } t->rotateTo = rotate; break; } case ITEM_ATTR_WRITEABLE3: { if(datalen != sizeof(writeableBlock3)) { warnings.push_back(wxT("items.otb: Unexpected data length of item toporder block (Should be 1 byte)")); break; } uint16_t readOnlyID; uint16_t maxTextLen; if(!itemNode->getU16(readOnlyID)) { warnings.push_back(wxT("Invalid item type property (9)")); break; } if(!itemNode->getU16(maxTextLen)) { warnings.push_back(wxT("Invalid item type property (10)")); break; } //t->readOnlyId = wb3->readOnlyId; t->maxTextLen = maxTextLen; break; } default: { //skip unknown attributes itemNode->skip(datalen); //warnings.push_back(wxT("items.otb: Skipped unknown attribute")); break; } } } if(t) { if(items[t->id]) { warnings.push_back(wxT("items.otb: Duplicate items")); delete items[t->id]; } items.set(t->id, t); } } return true; }
void GUI::SetHotkey(int index, Hotkey& hotkey) { ASSERT(index >= 0 && index <= 9); hotkeys[index] = hotkey; SetStatusText(wxT("Set hotkey ") + i2ws(index) + wxT(".")); }
void BrowseTileWindow::OnClickDelete(wxCommandEvent& WXUNUSED(event)) { item_list->RemoveSelected(); item_count_txt->SetLabelText(wxT("Item count: ") + i2ws(item_list->GetItemCount())); }