|
| 1 | +#include "ModWidget.h" |
| 2 | +#include <iostream> |
| 3 | +#include <fstream> |
| 4 | +#include <process.h> |
| 5 | + |
| 6 | +static std::string file_name = "mods-settings.cwb"; |
| 7 | +static const int MODS_PER_PAGE = 7; |
| 8 | +void* VTABLE[43]; |
| 9 | + |
| 10 | +mod::ModWidget* mod::ModWidget::ctor(cube::Game* game, plasma::Node* node, plasma::Node* background, std::vector<DLL*>* mods) |
| 11 | +{ |
| 12 | + // Construct basewidget |
| 13 | + std::wstring wstr_empty(L""); |
| 14 | + ((cube::BaseWidget*)this)->ctor(game->plasma_engine, node, &wstr_empty); |
| 15 | + |
| 16 | + // Set fields |
| 17 | + this->game = game; |
| 18 | + this->hover_state = 0; |
| 19 | + this->background = background; |
| 20 | + this->mods = mods; |
| 21 | + this->page = 0; |
| 22 | + this->changed = false; |
| 23 | + |
| 24 | + // Set scalable font |
| 25 | + std::wstring fontName(L"resource1.dat"); |
| 26 | + this->SetScalableFont(&fontName); |
| 27 | + this->Translate(100, 200, 1); |
| 28 | + |
| 29 | + for (int i = 0; i < 43; ++i) |
| 30 | + { |
| 31 | + this->artificial_vtable[i] = VTABLE[i]; |
| 32 | + } |
| 33 | + |
| 34 | + // Manually set vtable |
| 35 | + size_t* vptr = (size_t*)this; |
| 36 | + *vptr = (size_t)this->artificial_vtable; //(size_t)CWOffset(0x46CED8); |
| 37 | + |
| 38 | + return this; |
| 39 | +} |
| 40 | + |
| 41 | +void mod::ModWidget::MouseUp(cube::MouseButton mouse_button) |
| 42 | +{ |
| 43 | + if (mouse_button != cube::MouseButton::LeftMouseButton) |
| 44 | + { |
| 45 | + return; |
| 46 | + } |
| 47 | + |
| 48 | + switch (this->hover_state) |
| 49 | + { |
| 50 | + case HoverState::Exit: |
| 51 | + this->node->SetVisibility(false); |
| 52 | + if (this->changed) |
| 53 | + { |
| 54 | + // Restart the game |
| 55 | + char* argument_list[] = { (char *)"cubeworld.exe", NULL }; |
| 56 | + _execvp("cubeworld.exe", argument_list); |
| 57 | + } |
| 58 | + break; |
| 59 | + case HoverState::Toggle: |
| 60 | + if (this->selected < 0 || this->selected >= this->mods->size()) |
| 61 | + { |
| 62 | + return; |
| 63 | + } |
| 64 | + this->mods->at(this->selected)->enabled = !this->mods->at(this->selected)->enabled; |
| 65 | + ModWidget::StoreSave(this->mods); |
| 66 | + this->changed = true; |
| 67 | + break; |
| 68 | + case HoverState::Next: |
| 69 | + if (this->NextPageAvailable()) |
| 70 | + { |
| 71 | + this->page++; |
| 72 | + } |
| 73 | + break; |
| 74 | + case HoverState::Previous: |
| 75 | + if (this->PreviousPageAvailable()) |
| 76 | + { |
| 77 | + this->page--; |
| 78 | + } |
| 79 | + break; |
| 80 | + default: |
| 81 | + |
| 82 | + break; |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +bool mod::ModWidget::NextPageAvailable() |
| 87 | +{ |
| 88 | + return (this->page + 1) * MODS_PER_PAGE < this->mods->size(); |
| 89 | +} |
| 90 | + |
| 91 | +bool mod::ModWidget::PreviousPageAvailable() |
| 92 | +{ |
| 93 | + return this->page > 0; |
| 94 | +} |
| 95 | + |
| 96 | +void mod::ModWidget::Draw(ModWidget* widget) |
| 97 | +{ |
| 98 | + const static float text_size = 18.0f; // Original 18.0f |
| 99 | + const static float border_size = 4.0f; // Original 4.0f |
| 100 | + const static float title_size = 25.0f; |
| 101 | + |
| 102 | + cube::Game* game = widget->game; |
| 103 | + |
| 104 | + FloatRGBA text_color(1.0f, 1.0f, 1.0f, 1.0f); |
| 105 | + FloatRGBA hover_color(0.2f, 1.0f, 1.0f, 1.0f); |
| 106 | + FloatRGBA warn_color(1.0f, 0.65f, 0.0f, 1.0f); |
| 107 | + FloatRGBA disabled_color(1.0f, 1.0f, 1.0f, 0.2f); |
| 108 | + FloatRGBA border_color(0.0f, 0.0f, 0.0f, 1.0f); |
| 109 | + |
| 110 | + FloatVector2 mouse_pos; |
| 111 | + FloatVector2 pos(0, 0); |
| 112 | + FloatVector2 size(500, 500); |
| 113 | + |
| 114 | + std::wstring wstr_title(L"Mods"); |
| 115 | + std::wstring wstr_reminder(L"If you change something \n the game restarts to \n reload all the mods!"); |
| 116 | + std::wstring wstr_next(L">"); |
| 117 | + std::wstring wstr_prev(L"<"); |
| 118 | + std::wstring wstr_x(L"X"); |
| 119 | + |
| 120 | + // Translate background and node |
| 121 | + widget->node->Translate(game->width/2, game->height/2, -size.x/2, -size.y/2); |
| 122 | + widget->background->Translate(game->width / 2, game->height / 2, -size.x / 2, -size.y / 2); |
| 123 | + |
| 124 | + // Scale background and node |
| 125 | + widget->SetSize(&size); |
| 126 | + widget->background->widget1->SetSize(&size); |
| 127 | + |
| 128 | + // Get mouse position in the widget |
| 129 | + mouse_pos = *widget->GetRelativeMousePosition(&mouse_pos); |
| 130 | + |
| 131 | + // Set hover to 0 |
| 132 | + widget->hover_state = ModWidget::HoverState::None; |
| 133 | + |
| 134 | + // Text settings |
| 135 | + widget->SetTextSize(text_size); |
| 136 | + widget->SetTextColor(&text_color); |
| 137 | + widget->SetBorderSize(border_size); |
| 138 | + widget->SetBorderColor(&border_color); |
| 139 | + widget->SetTextPivot(plasma::TextPivot::Center); |
| 140 | + |
| 141 | + // Draw title |
| 142 | + widget->SetTextSize(title_size); |
| 143 | + widget->DrawString(&pos, &wstr_title, size.x/2, 20 + text_size); |
| 144 | + |
| 145 | + // Draw x to exit |
| 146 | + widget->SetTextPivot(plasma::TextPivot::Right); |
| 147 | + if (plasma::Widget::IsSquareHovered(&mouse_pos, size.x - 30, 20, 20, 30)) |
| 148 | + { |
| 149 | + widget->SetTextColor(&hover_color); |
| 150 | + widget->hover_state = ModWidget::HoverState::Exit; |
| 151 | + } |
| 152 | + widget->DrawString(&pos, &wstr_x, size.x - 10, 20 + text_size); |
| 153 | + |
| 154 | + // Draw reminder |
| 155 | + widget->SetTextColor(&warn_color); |
| 156 | + widget->SetTextSize(text_size - 5); |
| 157 | + widget->SetTextPivot(plasma::TextPivot::Center); |
| 158 | + widget->DrawString(&pos, &wstr_reminder, size.x / 2, 2 * (10 + text_size)); |
| 159 | + |
| 160 | + // Draw mods |
| 161 | + int y_count = 0; |
| 162 | + |
| 163 | + for (int i = widget->page * 7; i < (widget->page + 1)*7 && i < widget->mods->size(); i++) |
| 164 | + { |
| 165 | + DLL* dll = widget->mods->at(i); |
| 166 | + widget->SetTextPivot(plasma::TextPivot::Left); |
| 167 | + widget->SetTextColor(&text_color); |
| 168 | + if (!dll->enabled) |
| 169 | + { |
| 170 | + widget->SetTextColor(&disabled_color); |
| 171 | + } |
| 172 | + |
| 173 | + int y_pos = (4 + 2 * y_count) * (10 + text_size); |
| 174 | + if (plasma::Widget::IsSquareHovered(&mouse_pos, 0, y_pos - 20, size.x, 30)) |
| 175 | + { |
| 176 | + widget->SetTextColor(&hover_color); |
| 177 | + widget->hover_state = HoverState::Toggle; |
| 178 | + widget->selected = i; |
| 179 | + } |
| 180 | + std::wstring name = L"- " + std::wstring(dll->fileName.begin() + 5, dll->fileName.end()); |
| 181 | + if (name.size() > 45) |
| 182 | + { |
| 183 | + name = name.substr(0, 42) + L"..."; |
| 184 | + } |
| 185 | + widget->DrawString(&pos, &name, 20, y_pos); |
| 186 | + |
| 187 | + y_count++; |
| 188 | + if (y_pos > size.y - 2 * (10 + text_size)) |
| 189 | + { |
| 190 | + break; |
| 191 | + } |
| 192 | + } |
| 193 | + |
| 194 | + // Draw prev button |
| 195 | + widget->SetTextColor(&text_color); |
| 196 | + if (!widget->PreviousPageAvailable()) |
| 197 | + { |
| 198 | + widget->SetTextColor(&disabled_color); |
| 199 | + } |
| 200 | + else if (plasma::Widget::IsSquareHovered(&mouse_pos, 20, size.y - text_size - 20, 20, 30)) |
| 201 | + { |
| 202 | + widget->hover_state = HoverState::Previous; |
| 203 | + widget->SetTextColor(&hover_color); |
| 204 | + } |
| 205 | + widget->DrawString(&pos, &wstr_prev, 20, size.y - text_size); |
| 206 | + |
| 207 | + // Draw next button |
| 208 | + widget->SetTextPivot(plasma::TextPivot::Right); |
| 209 | + widget->SetTextColor(&text_color); |
| 210 | + |
| 211 | + if (!widget->NextPageAvailable()) |
| 212 | + { |
| 213 | + widget->SetTextColor(&disabled_color); |
| 214 | + } |
| 215 | + else if (plasma::Widget::IsSquareHovered(&mouse_pos, size.x - text_size - 20, size.y - text_size - 20, 20, 30)) |
| 216 | + { |
| 217 | + widget->hover_state = HoverState::Next; |
| 218 | + widget->SetTextColor(&hover_color); |
| 219 | + } |
| 220 | + widget->DrawString(&pos, &wstr_next, size.x - 20, size.y - text_size); |
| 221 | + |
| 222 | + // Draw current page |
| 223 | + widget->SetTextColor(&text_color); |
| 224 | + widget->SetTextPivot(plasma::TextPivot::Center); |
| 225 | + std::wstring page = std::to_wstring(widget->page + 1) + L"/" + std::to_wstring((int)(widget->mods->size() / MODS_PER_PAGE) + 1); |
| 226 | + widget->DrawString(&pos, &page, size.x / 2, size.y - text_size); |
| 227 | +} |
| 228 | + |
| 229 | +void mod::ModWidget::Init() |
| 230 | +{ |
| 231 | + void* NULLSUB = CWOffset(0xE8A20); |
| 232 | + void* RETZERO = CWOffset(0x368230); |
| 233 | + |
| 234 | + void* vtab[43] = { |
| 235 | + CWOffset(0x268B40), |
| 236 | + Draw, // void Draw(plasma::Widget*) |
| 237 | + CWOffset(0x26A720), |
| 238 | + CWOffset(0x26A720), |
| 239 | + RETZERO, |
| 240 | + RETZERO, |
| 241 | + NULLSUB, |
| 242 | + CWOffset(0x32B830), |
| 243 | + CWOffset(0x32BFD0), |
| 244 | + CWOffset(0x32BD70), |
| 245 | + NULLSUB, |
| 246 | + CWOffset(0x32B990), |
| 247 | + CWOffset(0x32BB40), |
| 248 | + NULLSUB, |
| 249 | + NULLSUB, |
| 250 | + NULLSUB, |
| 251 | + NULLSUB, |
| 252 | + NULLSUB, |
| 253 | + NULLSUB, |
| 254 | + NULLSUB, |
| 255 | + NULLSUB, |
| 256 | + CWOffset(0x32BB80), // void OnMouseOver(plasma::Widget*) |
| 257 | + NULLSUB, |
| 258 | + NULLSUB, |
| 259 | + NULLSUB, |
| 260 | + NULLSUB, |
| 261 | + NULLSUB, |
| 262 | + NULLSUB, |
| 263 | + NULLSUB, |
| 264 | + NULLSUB, |
| 265 | + NULLSUB, |
| 266 | + NULLSUB, |
| 267 | + NULLSUB, |
| 268 | + NULLSUB, |
| 269 | + NULLSUB, |
| 270 | + CWOffset(0x32B5A0), |
| 271 | + CWOffset(0x32B6B0), |
| 272 | + NULLSUB, |
| 273 | + NULLSUB, |
| 274 | + CWOffset(0x32B6E0), |
| 275 | + CWOffset(0x32A2C0), // plasma::Widget* CreateCopy(plasma::Widget*); |
| 276 | + CWOffset(0x32A8D0), |
| 277 | + NULLSUB |
| 278 | + }; |
| 279 | + |
| 280 | + for (int i = 0; i < 43; ++i) |
| 281 | + { |
| 282 | + VTABLE[i] = vtab[i]; |
| 283 | + } |
| 284 | +} |
| 285 | + |
| 286 | +void mod::ModWidget::LoadSave(std::vector<DLL*>* mods) |
| 287 | +{ |
| 288 | + std::ifstream in(file_name.c_str()); |
| 289 | + std::string line; |
| 290 | + |
| 291 | + while (getline(in, line)) { |
| 292 | + auto pos = line.find(":"); |
| 293 | + if (pos != std::string::npos) |
| 294 | + { |
| 295 | + std::string name(line.substr(0, pos)); |
| 296 | + bool enabled = stoi(line.substr(pos + 1, line.size() - 1)); |
| 297 | + for (DLL* dll : *mods) |
| 298 | + { |
| 299 | + if (!name.compare(dll->fileName)) |
| 300 | + { |
| 301 | + dll->enabled = enabled; |
| 302 | + } |
| 303 | + } |
| 304 | + } |
| 305 | + } |
| 306 | +} |
| 307 | + |
| 308 | +void mod::ModWidget::StoreSave(std::vector<DLL*>* mods) |
| 309 | +{ |
| 310 | + std::ofstream out(file_name.c_str()); |
| 311 | + for (DLL* dll : *mods) |
| 312 | + { |
| 313 | + out << dll->fileName << ":" << dll->enabled << "\n"; |
| 314 | + } |
| 315 | + out.close(); |
| 316 | +} |
0 commit comments