~ubuntu-branches/ubuntu/trusty/rlvm/trusty

« back to all changes in this revision

Viewing changes to .pc/002_675426ad62bccf1de10b0ae31dd46331ec47aacb.patch/src/Systems/Base/System.cpp

  • Committer: Package Import Robot
  • Author(s): Ying-Chun Liu (PaulLiu)
  • Date: 2013-11-02 02:57:13 UTC
  • mfrom: (10.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20131102025713-yzg31grxr8i7xerh
Tags: 0.13-1
* New upstream release
  - rlvm will now warn on startup when it detects Japanese save data, but
    English patched game files, and offer to reset the save data.
  - Much better support for Little Busters. Most graphical glitches during
    the Little Busters Refrain have been fixed.
  - TCC tone curve effects have been reverse-engineered and implemented
    (thanks to lurkmoar)
  - Sepia scenes (and other graphical filters) should look much better.
  - Simple shake commands implemented (fancy per-layer shaking still
    unimplemented).
  - Make animations smooth: data should be uploaded to the graphics card
    before an animation loop starts, not while the animation loop is
    running.
  - Fixes finding system fonts on Linux
  - Thanks to Elliot Glaysher <glaysher@umich.edu>
* Remove upstreamed patches:
  - debian/patches/002_675426ad62bccf1de10b0ae31dd46331ec47aacb.patch
  - debian/patches/003_5dafabf5448635c4d4526d6e35ea7ec664a27261.patch
  - debian/patches/004_boost-drop-mt.patch
  - debian/patches/005_missing-include.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 
// vi:tw=80:et:ts=2:sts=2
3
 
//
4
 
// -----------------------------------------------------------------------
5
 
//
6
 
// This file is part of RLVM, a RealLive virtual machine clone.
7
 
//
8
 
// -----------------------------------------------------------------------
9
 
//
10
 
// Copyright (C) 2006, 2007 Elliot Glaysher
11
 
//
12
 
// This program is free software; you can redistribute it and/or modify
13
 
// it under the terms of the GNU General Public License as published by
14
 
// the Free Software Foundation; either version 3 of the License, or
15
 
// (at your option) any later version.
16
 
//
17
 
// This program is distributed in the hope that it will be useful,
18
 
// but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 
// GNU General Public License for more details.
21
 
//
22
 
// You should have received a copy of the GNU General Public License
23
 
// along with this program; if not, write to the Free Software
24
 
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25
 
//
26
 
// -----------------------------------------------------------------------
27
 
 
28
 
#include "Systems/Base/System.hpp"
29
 
 
30
 
#include <algorithm>
31
 
#include <boost/algorithm/string.hpp>
32
 
#include <boost/assign/list_of.hpp>  // for 'list_of()'
33
 
#include <boost/bind.hpp>
34
 
#include <boost/filesystem/convenience.hpp>
35
 
#include <boost/filesystem/operations.hpp>
36
 
#include <boost/filesystem/path.hpp>
37
 
#include <fstream>
38
 
#include <iomanip>
39
 
#include <iostream>
40
 
#include <string>
41
 
#include <vector>
42
 
 
43
 
#include "LongOperations/LoadGameLongOperation.hpp"
44
 
#include "MachineBase/LongOperation.hpp"
45
 
#include "MachineBase/RLMachine.hpp"
46
 
#include "MachineBase/Serialization.hpp"
47
 
#include "Modules/Module_Sys.hpp"
48
 
#include "Systems/Base/EventSystem.hpp"
49
 
#include "Systems/Base/GraphicsSystem.hpp"
50
 
#include "Systems/Base/Platform.hpp"
51
 
#include "Systems/Base/RlvmInfo.hpp"
52
 
#include "Systems/Base/SoundSystem.hpp"
53
 
#include "Systems/Base/SystemError.hpp"
54
 
#include "Systems/Base/TextSystem.hpp"
55
 
#include "Utilities/Exception.hpp"
56
 
#include "Utilities/StringUtilities.hpp"
57
 
#include "libReallive/gameexe.h"
58
 
 
59
 
using namespace std;
60
 
using boost::assign::list_of;
61
 
using boost::bind;
62
 
using boost::replace_all;
63
 
using boost::to_lower;
64
 
 
65
 
namespace fs = boost::filesystem;
66
 
 
67
 
namespace {
68
 
 
69
 
const std::vector<std::string> ALL_FILETYPES =
70
 
    list_of("g00")("pdt")("anm")("gan")("hik")("wav")("ogg")("nwa")("mp3")
71
 
    ("ovk")("koe")("nwk");
72
 
 
73
 
struct LoadingGameFromStream : public LoadGameLongOperation {
74
 
  LoadingGameFromStream(RLMachine& machine,
75
 
                        const boost::shared_ptr<std::stringstream>& selection)
76
 
      : LoadGameLongOperation(machine),
77
 
        selection_(selection) {}
78
 
 
79
 
  virtual void load(RLMachine& machine) {
80
 
    // We need to copy data here onto the stack because the action of loading
81
 
    // will deallocate this object.
82
 
    boost::shared_ptr<std::stringstream> s = selection_;
83
 
    Serialization::loadGameFrom(*s, machine);
84
 
    // Warning: |this| is an invalid pointer now.
85
 
  }
86
 
 
87
 
  boost::shared_ptr<std::stringstream> selection_;
88
 
};
89
 
 
90
 
}  // namespace
91
 
 
92
 
// I assume GAN files can't go through the OBJ_FILETYPES path.
93
 
const std::vector<std::string> OBJ_FILETYPES =
94
 
    list_of("anm")("g00")("pdt");
95
 
const std::vector<std::string> IMAGE_FILETYPES =
96
 
    list_of("g00")("pdt");
97
 
const std::vector<std::string> PDT_IMAGE_FILETYPES =
98
 
    list_of("pdt");
99
 
const std::vector<std::string> GAN_FILETYPES =
100
 
    list_of("gan");
101
 
const std::vector<std::string> ANM_FILETYPES =
102
 
    list_of("anm");
103
 
const std::vector<std::string> HIK_FILETYPES =
104
 
    list_of("hik")("g00")("pdt");
105
 
const std::vector<std::string> SOUND_FILETYPES =
106
 
    list_of("wav")("ogg")("nwa")("mp3");
107
 
const std::vector<std::string> KOE_ARCHIVE_FILETYPES =
108
 
    list_of("ovk")("koe")("nwk");
109
 
const std::vector<std::string> KOE_LOOSE_FILETYPES =
110
 
    list_of("ogg");
111
 
 
112
 
class MenuReseter : public LongOperation {
113
 
 public:
114
 
  explicit MenuReseter(System& sys) : sys_(sys) {}
115
 
 
116
 
  bool operator()(RLMachine& machine) {
117
 
    sys_.in_menu_ = false;
118
 
    return true;
119
 
  }
120
 
 
121
 
 private:
122
 
  System& sys_;
123
 
};
124
 
 
125
 
// -----------------------------------------------------------------------
126
 
// SystemGlobals
127
 
// -----------------------------------------------------------------------
128
 
 
129
 
SystemGlobals::SystemGlobals()
130
 
  : confirm_save_load_(true), low_priority_(false) {}
131
 
 
132
 
 
133
 
// -----------------------------------------------------------------------
134
 
// System
135
 
// -----------------------------------------------------------------------
136
 
 
137
 
System::System()
138
 
    : in_menu_(false),
139
 
      force_fast_forward_(false),
140
 
      force_wait_(false),
141
 
      use_western_font_(false) {
142
 
  fill(syscom_status_, syscom_status_ + NUM_SYSCOM_ENTRIES, SYSCOM_VISIBLE);
143
 
}
144
 
 
145
 
System::~System() {
146
 
}
147
 
 
148
 
void System::takeSelectionSnapshot(RLMachine& machine) {
149
 
  previous_selection_.reset(new std::stringstream);
150
 
  Serialization::saveGameTo(*previous_selection_, machine);
151
 
}
152
 
 
153
 
void System::restoreSelectionSnapshot(RLMachine& machine) {
154
 
  // We need to reference this on the stack because it will call
155
 
  // System::reset() to get the black screen. (We'll reset again inside
156
 
  // LoadingGameFromStream.)
157
 
  boost::shared_ptr<std::stringstream> s = previous_selection_;
158
 
  if (s) {
159
 
    // LoadingGameFromStream adds itself to the callstack of |machine| due to
160
 
    // subtle timing issues.
161
 
    new LoadingGameFromStream(machine, s);
162
 
  }
163
 
}
164
 
 
165
 
int System::isSyscomEnabled(int syscom) {
166
 
  checkSyscomIndex(syscom, "System::is_syscom_enabled");
167
 
 
168
 
  // Special cases where state of the interpreter would override the
169
 
  // programmatically set (or user set) values.
170
 
  if (syscom == SYSCOM_SET_SKIP_MODE && !text().kidokuRead()) {
171
 
    // Skip mode should be grayed out when there's no text to read
172
 
    if (syscom_status_[syscom] == SYSCOM_VISIBLE)
173
 
      return SYSCOM_GREYED_OUT;
174
 
  } else if (syscom == SYSCOM_RETURN_TO_PREVIOUS_SELECTION) {
175
 
    if (syscom_status_[syscom] == SYSCOM_VISIBLE)
176
 
      return previous_selection_.get() ? SYSCOM_VISIBLE : SYSCOM_GREYED_OUT;
177
 
  }
178
 
 
179
 
  return syscom_status_[syscom];
180
 
}
181
 
 
182
 
void System::hideSyscom() {
183
 
  fill(syscom_status_, syscom_status_ + NUM_SYSCOM_ENTRIES, SYSCOM_INVISIBLE);
184
 
}
185
 
 
186
 
void System::hideSyscomEntry(int syscom) {
187
 
  checkSyscomIndex(syscom, "System::hide_system");
188
 
  syscom_status_[syscom] = SYSCOM_INVISIBLE;
189
 
}
190
 
 
191
 
void System::enableSyscom() {
192
 
  fill(syscom_status_, syscom_status_ + NUM_SYSCOM_ENTRIES, SYSCOM_VISIBLE);
193
 
}
194
 
 
195
 
void System::enableSyscomEntry(int syscom) {
196
 
  checkSyscomIndex(syscom, "System::enable_system");
197
 
  syscom_status_[syscom] = SYSCOM_VISIBLE;
198
 
}
199
 
 
200
 
void System::disableSyscom() {
201
 
  fill(syscom_status_, syscom_status_ + NUM_SYSCOM_ENTRIES, SYSCOM_GREYED_OUT);
202
 
}
203
 
 
204
 
void System::disableSyscomEntry(int syscom) {
205
 
  checkSyscomIndex(syscom, "System::disable_system");
206
 
  syscom_status_[syscom] = SYSCOM_GREYED_OUT;
207
 
}
208
 
 
209
 
int System::readSyscom(int syscom) {
210
 
  throw rlvm::Exception("ReadSyscom unimplemented!");
211
 
}
212
 
 
213
 
void System::showSyscomMenu(RLMachine& machine) {
214
 
  Gameexe& gexe = machine.system().gameexe();
215
 
 
216
 
  if (gexe("CANCELCALL_MOD") == 1) {
217
 
    if (!in_menu_) {
218
 
      // Multiple right clicks shouldn't spawn multiple copies of the menu
219
 
      // system on top of each other.
220
 
      in_menu_ = true;
221
 
      machine.pushLongOperation(new MenuReseter(*this));
222
 
 
223
 
      vector<int> cancelcall = gexe("CANCELCALL");
224
 
      machine.farcall(cancelcall.at(0), cancelcall.at(1));
225
 
    }
226
 
  } else if (platform_) {
227
 
    platform_->showNativeSyscomMenu(machine);
228
 
  } else {
229
 
    cerr << "(We don't deal with non-custom SYSCOM calls yet.)" << endl;
230
 
  }
231
 
}
232
 
 
233
 
void System::invokeSyscom(RLMachine& machine, int syscom) {
234
 
  switch (syscom) {
235
 
  case SYSCOM_SAVE:
236
 
    invokeSaveOrLoad(machine, syscom, "SYSTEMCALL_SAVE_MOD", "SYSTEMCALL_SAVE");
237
 
    break;
238
 
  case SYSCOM_LOAD:
239
 
    invokeSaveOrLoad(machine, syscom, "SYSTEMCALL_LOAD_MOD", "SYSTEMCALL_LOAD");
240
 
    break;
241
 
  case SYSCOM_MESSAGE_SPEED:
242
 
  case SYSCOM_WINDOW_ATTRIBUTES:
243
 
  case SYSCOM_VOLUME_SETTINGS:
244
 
  case SYSCOM_MISCELLANEOUS_SETTINGS:
245
 
  case SYSCOM_VOICE_SETTINGS:
246
 
  case SYSCOM_FONT_SELECTION:
247
 
  case SYSCOM_BGM_FADE:
248
 
  case SYSCOM_BGM_SETTINGS:
249
 
  case SYSCOM_AUTO_MODE_SETTINGS:
250
 
  case SYSCOM_USE_KOE:
251
 
  case SYSCOM_DISPLAY_VERSION: {
252
 
    if (platform_)
253
 
      platform_->invokeSyscomStandardUI(machine, syscom);
254
 
    break;
255
 
  }
256
 
  case SYSCOM_RETURN_TO_PREVIOUS_SELECTION:
257
 
    restoreSelectionSnapshot(machine);
258
 
    break;
259
 
  case SYSCOM_SHOW_WEATHER:
260
 
    graphics().setShowWeather(!graphics().showWeather());
261
 
    break;
262
 
  case SYSCOM_SHOW_OBJECT_1:
263
 
    graphics().setShowObject1(!graphics().showObject1());
264
 
    break;
265
 
  case SYSCOM_SHOW_OBJECT_2:
266
 
    graphics().setShowObject2(!graphics().showObject2());
267
 
    break;
268
 
  case SYSCOM_CLASSIFY_TEXT:
269
 
    cerr << "We have no idea what classifying text even means!" << endl;
270
 
    break;
271
 
  case SYSCOM_OPEN_MANUAL_PATH:
272
 
    cerr << "Opening manual path..." << endl;
273
 
    break;
274
 
  case SYSCOM_SET_SKIP_MODE:
275
 
    text().setSkipMode(!text().skipMode());
276
 
    break;
277
 
  case SYSCOM_AUTO_MODE:
278
 
    text().setAutoMode(!text().autoMode());
279
 
    break;
280
 
  case SYSCOM_MENU_RETURN:
281
 
    // This is a hack since we probably have a bunch of crap on the stack.
282
 
    machine.clearLongOperationsOffBackOfStack();
283
 
 
284
 
    // Simulate a MenuReturn.
285
 
    Sys_MenuReturn()(machine);
286
 
    break;
287
 
  case SYSCOM_EXIT_GAME:
288
 
    machine.halt();
289
 
    break;
290
 
  case SYSCOM_SHOW_BACKGROUND:
291
 
    graphics().toggleInterfaceHidden();
292
 
    break;
293
 
  case SYSCOM_HIDE_MENU:
294
 
    // Do nothing. The menu will be hidden on its own.
295
 
    break;
296
 
  case SYSCOM_GENERIC_1:
297
 
  case SYSCOM_GENERIC_2:
298
 
  case SYSCOM_SCREEN_MODE:
299
 
  case SYSCOM_WINDOW_DECORATION_STYLE:
300
 
    cerr << "No idea what to do!" << endl;
301
 
    break;
302
 
  };
303
 
}
304
 
 
305
 
void System::showSystemInfo(RLMachine& machine) {
306
 
  if (platform_) {
307
 
    RlvmInfo info;
308
 
 
309
 
    string regname = gameexe()("REGNAME").to_string("");
310
 
    size_t pos = regname.find('\\');
311
 
    if (pos != string::npos) {
312
 
      info.game_brand = regname.substr(0, pos);
313
 
      info.game_name = regname.substr(pos + 1);
314
 
    } else {
315
 
      info.game_brand = "";
316
 
      info.game_name = regname;
317
 
    }
318
 
 
319
 
    info.game_version = gameexe()("VERSION_STR").to_string("");
320
 
    info.game_path = gameexe()("__GAMEPATH").to_string("");
321
 
    info.rlvm_version = rlvm_version();
322
 
    info.rlbabel_loaded = machine.dllLoaded("rlBabel");
323
 
    info.text_transformation = machine.getTextEncoding();
324
 
 
325
 
    platform_->showSystemInfo(machine, info);
326
 
  }
327
 
}
328
 
 
329
 
boost::filesystem::path System::findFile(
330
 
    const std::string& file_name,
331
 
    const std::vector<std::string>& extensions) {
332
 
  if (filesystem_cache_.empty())
333
 
    buildFileSystemCache();
334
 
 
335
 
  // Hack to get around fileNames like "REALNAME?010", where we only
336
 
  // want REALNAME.
337
 
  string lower_name =
338
 
    string(file_name.begin(), find(file_name.begin(), file_name.end(), '?'));
339
 
  to_lower(lower_name);
340
 
 
341
 
  std::pair<FileSystemCache::const_iterator, FileSystemCache::const_iterator>
342
 
      ret = filesystem_cache_.equal_range(lower_name);
343
 
  for (vector<string>::const_iterator ext = extensions.begin();
344
 
       ext != extensions.end(); ++ext) {
345
 
    for (FileSystemCache::const_iterator it = ret.first;
346
 
         it != ret.second; ++it) {
347
 
      if (*ext == it->second.first) {
348
 
        return it->second.second;
349
 
      }
350
 
    }
351
 
  }
352
 
 
353
 
  // Error.
354
 
  return fs::path();
355
 
}
356
 
 
357
 
void System::reset() {
358
 
  in_menu_ = false;
359
 
  previous_selection_.reset();
360
 
 
361
 
  enableSyscom();
362
 
 
363
 
  sound().reset();
364
 
  graphics().reset();
365
 
  text().reset();
366
 
}
367
 
 
368
 
std::string System::regname() {
369
 
  Gameexe& gexe = gameexe();
370
 
  string regname = gexe("REGNAME");
371
 
  replace_all(regname, "\\", "_");
372
 
 
373
 
  // Note that we assume the Gameexe file is written in Shift-JIS. I don't
374
 
  // think you can write it in anyhting else.
375
 
  return cp932toUTF8(regname, 0);
376
 
}
377
 
 
378
 
boost::filesystem::path System::gameSaveDirectory() {
379
 
  fs::path base_dir = getHomeDirectory() / ".rlvm" / regname();
380
 
  fs::create_directories(base_dir);
381
 
 
382
 
  return base_dir;
383
 
}
384
 
 
385
 
bool System::fastForward() {
386
 
  return (event().ctrlPressed() && text().ctrlKeySkip()) ||
387
 
    text().currentlySkipping() ||
388
 
    force_fast_forward_;
389
 
}
390
 
 
391
 
void System::dumpRenderTree(RLMachine& machine) {
392
 
  ostringstream oss;
393
 
  oss << "Dump_SEEN" << setw(4) << setfill('0') << machine.sceneNumber()
394
 
      << "_Line" << machine.lineNumber() << ".txt";
395
 
 
396
 
  ofstream tree(oss.str().c_str());
397
 
  graphics().refresh(&tree);
398
 
}
399
 
 
400
 
boost::filesystem::path System::getHomeDirectory() {
401
 
  string drive, home;
402
 
  char *homeptr     = getenv("HOME");
403
 
  char *driveptr    = getenv("HOMEDRIVE");
404
 
  char *homepathptr = getenv("HOMEPATH");
405
 
  char *profileptr  = getenv("USERPROFILE");
406
 
  if (homeptr != 0 && (home = homeptr) != "") {
407
 
    // UN*X like home directory
408
 
    return fs::path(home);
409
 
  } else if (driveptr != 0 &&
410
 
             homepathptr !=0 &&
411
 
             (drive = driveptr) != "" &&
412
 
             (home  = homepathptr) != "") {
413
 
    // Windows.
414
 
    return fs::path(drive) / fs::path(home);
415
 
  } else if (profileptr != 0 && (home = profileptr) != "") {
416
 
    // Windows?
417
 
    return fs::path(home);
418
 
  } else {
419
 
    throw SystemError("Could not find location of home directory.");
420
 
  }
421
 
}
422
 
 
423
 
void System::invokeSaveOrLoad(RLMachine& machine,
424
 
                              int syscom,
425
 
                              const std::string& mod_key,
426
 
                              const std::string& location) {
427
 
  GameexeInterpretObject save_mod = gameexe()(mod_key);
428
 
  GameexeInterpretObject save_loc = gameexe()(location);
429
 
 
430
 
  if (save_mod.exists() && save_loc.exists() && save_mod == 1) {
431
 
    vector<int> raw_ints = save_loc;
432
 
    int scenario = raw_ints.at(0);
433
 
    int entrypoint = raw_ints.at(1);
434
 
 
435
 
    text().setSystemVisible(false);
436
 
    machine.pushLongOperation(new RestoreTextSystemVisibility);
437
 
    machine.farcall(scenario, entrypoint);
438
 
  } else if (platform_) {
439
 
    platform_->invokeSyscomStandardUI(machine, syscom);
440
 
  }
441
 
}
442
 
 
443
 
void System::checkSyscomIndex(int index, const char* function) {
444
 
  if (index < 0 || index >= NUM_SYSCOM_ENTRIES) {
445
 
    ostringstream oss;
446
 
    oss << "Illegal syscom index #" << index << " in " << function;
447
 
    throw std::runtime_error(oss.str());
448
 
  }
449
 
}
450
 
 
451
 
void System::buildFileSystemCache() {
452
 
  // First retrieve all the directories defined in the #FOLDNAME section.
453
 
  std::vector<std::string> valid_directories;
454
 
  Gameexe& gexe = gameexe();
455
 
  GameexeFilteringIterator it = gexe.filtering_begin("FOLDNAME");
456
 
  GameexeFilteringIterator end = gexe.filtering_end();
457
 
  for (; it != end; ++it) {
458
 
    std::string dir = it->to_string();
459
 
    if (!dir.empty()) {
460
 
      to_lower(dir);
461
 
      valid_directories.push_back(dir);
462
 
    }
463
 
  }
464
 
 
465
 
  fs::path gamepath(gexe("__GAMEPATH").to_string());
466
 
  fs::directory_iterator dir_end;
467
 
  for (fs::directory_iterator dir(gamepath); dir != dir_end; ++dir) {
468
 
    if (fs::is_directory(dir->status())) {
469
 
      std::string lowername = dir->path().filename();
470
 
      to_lower(lowername);
471
 
      if (find(valid_directories.begin(), valid_directories.end(), lowername) !=
472
 
          valid_directories.end()) {
473
 
        addDirectoryToCache(dir->path());
474
 
      }
475
 
    }
476
 
  }
477
 
}
478
 
 
479
 
void System::addDirectoryToCache(const fs::path& directory) {
480
 
  fs::directory_iterator dir_end;
481
 
  for (fs::directory_iterator dir(directory); dir != dir_end; ++dir) {
482
 
    if (fs::is_directory(dir->status())) {
483
 
      addDirectoryToCache(dir->path());
484
 
    } else {
485
 
      std::string extension = dir->path().extension();
486
 
      if (extension.size() > 1 && extension[0] == '.')
487
 
        extension = extension.substr(1);
488
 
      to_lower(extension);
489
 
 
490
 
      if (find(ALL_FILETYPES.begin(), ALL_FILETYPES.end(), extension) !=
491
 
          ALL_FILETYPES.end()) {
492
 
        std::string stem = dir->path().stem();
493
 
        to_lower(stem);
494
 
 
495
 
        filesystem_cache_.insert(
496
 
            make_pair(stem,
497
 
                      make_pair(extension, dir->path())));
498
 
      }
499
 
    }
500
 
  }
501
 
}
502
 
 
503
 
std::string rlvm_version() {
504
 
  return "Version 0.12";
505
 
}