changeset 56:c7bcc0ec2267

* replaced Grp and Text classes by the TextImpl and GrpImpl ones * splitted scn2k.h into smaller header files * moved some definitions from scn2k_*.cc to the header files * moved opcode implementation to scn2k_*impl.cc
author thib
date Thu, 30 Apr 2009 19:05:09 +0000
parents f1a27ee7e03c
children 6d9146f56ccf
files THANKS scn2k/Makefile.am scn2k/scn2k.h scn2k/scn2k_cmd.h scn2k/scn2k_flags.h scn2k/scn2k_grp.cc scn2k/scn2k_grp.h scn2k/scn2k_grpimpl.cc scn2k/scn2k_text.cc scn2k/scn2k_text.h scn2k/scn2k_textimpl.cc system/system_config.h window/Makefile.am window/render.cc window/render.h window/surface.h window/system.h
diffstat 17 files changed, 2273 insertions(+), 2064 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,3 @@
+- Jagarl for his work on xclannad, and his help at the starting of OtakuNoRaifu
+- Elliot Glaysher for his help, aswell as for his work on rlvm
+- Haeleth, for his work on rldev and all his doc about RealLive
--- a/scn2k/Makefile.am
+++ b/scn2k/Makefile.am
@@ -1,5 +1,8 @@
 noinst_LIBRARIES = libscn2k.a
-libscn2k_a_SOURCES = scn2k_cmd.cc scn2k_text.cc scn2k_grp.cc scn2k_impl.cc \
+libscn2k_a_SOURCES = scn2k_cmd.cc scn2k_cmd.h scn2k_flags.h\
+                     scn2k_text.cc scn2k_text.h scn2k_textimpl.cc\
+                     scn2k_grp.cc scn2k_grp.h scn2k_grpimpl.cc\
+                     scn2k_impl.cc \
                      command_handler.cc \
                      scn2k.h scn2k_impl.h
 
--- a/scn2k/scn2k.h
+++ b/scn2k/scn2k.h
@@ -33,6 +33,10 @@
 #include <map>
 #include <set>
 
+#include "scn2k_cmd.h"
+#include "scn2k_grp.h"
+#include "scn2k_text.h"
+
 /*
 namespace Widget {
 	class Text;
@@ -59,238 +63,6 @@ class PicContainer;
 class AyuSysConfig;
 class Surface;
 
-void dprintf(const char* fmt, ...);
-void eprintf(const char* fmt, ...);
-
-struct VarInfo {
-#define TYPE_NONSYSVARMAX 5
-#define TYPE_VARMAX 9
-#define TYPE_VARLOCSTR 10
-#define TYPE_VARSYSSTR 12
-#define TYPE_VARSTR 18
-#define TYPE_STR 58
-#define TYPE_VAL 68
-#define TYPE_SYS 0xc8
-#define TYPE_END 0x7f
-
-#define TYPE_SYS_SYS 0
-#define TYPE_SYS_SKIPMODE 1
-	int type;
-	int number;
-	int value;
-	VarInfo() { type = TYPE_VAL; value = 0;}
-	VarInfo(int n) { type = TYPE_VAL; value = n;}
-	VarInfo(const VarInfo& i) { type = i.type; number = i.number; value = i.value;}
-};
-
-
-class Flags {
-/* flag:
-**  type 0-5 : ローカル整数、各2000個
-**  type 6, 25 : グローバル整数、2000個
-**      type 10,11: ローカル整数??、各2000個
-**	type 12 : グローバル文字列、2000個 (今は無視しても良いが)
-**	type 18 : ローカル文字列、2000個
-**	type 25: システム変数(マウス座標など?) 1000 個?
-**  type 26-32, 51 : 1-bit access to 0-6, 25
-**  type 52-58, 77 : 2-bit access to 0-6, 25
-**  type 78-84, 103 : 4-bit access to 0-6, 25
-**  type 104-110, 129 : 8-bit access to 0-6, 25
-*/
-	private:
-		typedef unsigned int uint;
-		int sys;
-		int var[TYPE_VARMAX+1][2000];
-		std::string str[2000];
-		std::string sys_str[2000];
-		std::string loc_str[3];
-	public:
-		Flags(void);
-		int operator () () const;
-		int operator () (VarInfo info) const;
-		void Str(int type, unsigned int number, char* buf, int sz) const;
-		std::string Str(int type, unsigned int number) const;
-		std::set<int> cgm_data;
-
-		bool IsInt(int type) const;
-		int MaxIndex(int type) const;
-
-		void Set(VarInfo info, int value);
-		int Get(int type, int number) const;
-		void SetSys(int value);
-		void SetStr(VarInfo info, std::string val);
-
-		bool Exec(class Cmd& cmd);
-
-		void Save(std::string& str);
-		void Load(const char* str);
-
-		void SaveSys(std::string& str);
-		void LoadSys(const char* str);
-};
-
-/* commands */
-#define STRHEAP_SIZE 10000
-enum Cmdtype {
-	CMD_NOP, CMD_FLAGS, CMD_JMP, CMD_TEXT, CMD_OTHER, CMD_SYSVAR,
-	CMD_TEXTEND,
-	CMD_SAVECMDGRP, CMD_SAVECMDGRP_START, CMD_SAVECMDGRP_ONCE, CMD_SAVECMD_ONCE, CMD_WAITFRAMEUPDATE,CMD_SAVEPOINT, CMD_ROLLBACKPOINT,
-	CMD_SAVEREQ, CMD_SAVE,
-	CMD_LOADREQ, CMD_LOAD,
-	CMD_MENUREQ,
-	CMD_BACKLOGREQ, CMD_BACKLOGREQ_FWD,
-	CMD_END};
-
-struct CmdSimplified { // Cmd 保存用
-	int type, cmd1, cmd2, cmd3, cmd4, argc;
-	char* args;
-	void Save(std::string& save);
-	void Load(const char* save, char*& args_buffer);
-	void copy(const CmdSimplified& from, char*& args_buffer);
-};
-
-class SimpleCmd {
-	public:
-		SimpleCmd(int a, int b, int c);
-		SimpleCmd();
-
-		bool operator==(const SimpleCmd& cmd) const;
-		bool operator<(const SimpleCmd& cmd) const;
-
-	public:
-		int cmd1, cmd2, cmd3;
-};
-
-class Cmd : public SimpleCmd{
-	public:
-		Cmdtype cmd_type;
-		int cmd4;
-		int argc;
-		int pos, scn;
-		const char* rawdata;
-		char cmdstr[1024];
-		std::vector<VarInfo> args;
-
-	private:
-		const Flags& flags;
-		bool errorflag;
-		int system_version;
-
-		int GetArgs(const char*& d);
-		int GetArgsSpecial(int normal_args,const char*& d);
-		void GetSelection(const char*& d);
-		int GetSwitch(const char*& d);
-		int GetSimpleSwitch(const char*& d);
-		int GetExpression(const char*& d, struct VarInfo* info = 0);
-		int GetExpressionCond(const char*& d);
-		int GetLeftToken(const char*& d, struct VarInfo& info);
-		int GetString(const char*& d);
-		int CopyString(const char* d);
-		int StrVar(int type, int number);
-		static char strtype[256];
-		static int StrType(const char* d) { return strtype[*(unsigned const char*)d];}
-
-	public:
-		const char* Str(const VarInfo& info) const;
-		int AddStr(char* s);
-
-	private:
-		char strheap[STRHEAP_SIZE];
-		int strend;
-		void SetError(void) { errorflag = true;}
-		void ResetString(void) {
-			strend = 0;
-		}
-
-	public:
-		void GetCmd(Flags& f, const char*& d);
-		void SetSysvar(int n, int v);
-		void SetSysvar(int v) { SetSysvar(TYPE_SYS_SYS, v); }
-		void SetFlagvar(VarInfo info, int v);
-		void SetStrvar(VarInfo info, const std::string& s);
-		bool IsError() { return errorflag;}
-		void clear(void);
-		virtual const char * CmdDescr(int, int, int, int) { return "Not supported"; }
-		Cmd(const Flags& f, int _sys_ver);
-		void read(const CmdSimplified& cmd);
-		void write(CmdSimplified& cmd, char*& args_buffer) const;
-};
-
-class CommandHandler {
-	public:
-		typedef void (CommandHandler::*CmdImpl)(Cmd& cmd);
-		typedef struct {
-			const char* descr;
-			CmdImpl function;
-		} CommandInfo;
-		void RegisterCommand(int cmd1, int cmd2, int cmd3, const char* descr, CmdImpl func);
-		bool Exec(Cmd& cmd);
-		void PrintCmd(Cmd& cmd);
-
-	private:
-		typedef std::map<SimpleCmd, CommandInfo> CommandMap;
-		CommandMap command_map;
-};
-
-enum SkipMode {
-	SKIP_NO=0, SKIP_TEXT=1, SKIP_GRP_FAST=16, SKIP_GRP_NOEFFEC=32,
-	SKIP_GRP_NODRAW=64, SKIPEND_TEXT=256, SKIPEND_KEY=512, SKIP_IN_MENU=1024
-};
-
-#include "font/text.h"
-
-struct BacklogItem {
-	enum {SaveSelect = -2};
-	int scn, pos;
-	int koe;
-	std::string face;
-	struct TextStream text;
-	BacklogItem(void);
-	void Clear(void);
-	void AddTextPos(Cmd&);
-	void DeleteTextPos();
-	void SetSavepos(int pos);
-	BacklogItem& operator =(const BacklogItem&);
-};
-
-class Text {
-	private:
-		class TextImpl* pimpl;
-	public:
-		std::vector<BacklogItem> backlog;
-		BacklogItem backlog_item;
-		Text(Event::Container& _event, PicContainer& _parent);
-		~Text();
-		void InitWindow(void);
-		void Exec(Cmd& cmd);
-		bool Wait(unsigned int current_time, Cmd& cmd);
-		void SetSkipMode(SkipMode mode);
-		void hide(void);
-		void show(void);
-		void show(int num);
-		void Save(std::string& str, bool rollback_save);
-		void Load(const char* str);
-		void DrawBacklog(BacklogItem& item, Cmd& cmd);
-};
-
-#include "../window/rect.h"
-
-class Grp {
-	private:
-		class GrpImpl* pimpl;
-	public:
-		Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, std::set<int>& _cgm_data);
-		~Grp();
-		bool Wait(unsigned int current_time, Cmd& cmd);
-		void Exec(Cmd& cmd);
-		void SetSkipMode(SkipMode mode);
-		void InitSel(void);
-		void Save(std::string& str);
-		void Load(const char* str);
-		void SaveSys(std::string& str);
-		void LoadSys(const char* str);
-};
-
 void dprintf(const char* fmt, ...); // debug 用
 void eprintf(const char* fmt, ...); // コマンド実行(XXXexec)追跡用
 #endif
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_cmd.h
@@ -0,0 +1,117 @@
+#ifndef __SCN2K_CMD_H__
+#define __SCN2K_CMD_H__
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include "scn2k_flags.h"
+
+#define STRHEAP_SIZE 10000
+enum Cmdtype {
+	CMD_NOP, CMD_FLAGS, CMD_JMP, CMD_TEXT, CMD_OTHER, CMD_SYSVAR,
+	CMD_TEXTEND,
+	CMD_SAVECMDGRP, CMD_SAVECMDGRP_START, CMD_SAVECMDGRP_ONCE, CMD_SAVECMD_ONCE, CMD_WAITFRAMEUPDATE,CMD_SAVEPOINT, CMD_ROLLBACKPOINT,
+	CMD_SAVEREQ, CMD_SAVE,
+	CMD_LOADREQ, CMD_LOAD,
+	CMD_MENUREQ,
+	CMD_BACKLOGREQ, CMD_BACKLOGREQ_FWD,
+	CMD_END};
+
+enum SkipMode {
+	SKIP_NO=0, SKIP_TEXT=1, SKIP_GRP_FAST=16, SKIP_GRP_NOEFFEC=32,
+	SKIP_GRP_NODRAW=64, SKIPEND_TEXT=256, SKIPEND_KEY=512, SKIP_IN_MENU=1024
+};
+
+struct CmdSimplified { // Cmd 転
+	int type, cmd1, cmd2, cmd3, cmd4, argc;
+	char* args;
+	void Save(std::string& save);
+	void Load(const char* save, char*& args_buffer);
+	void copy(const CmdSimplified& from, char*& args_buffer);
+};
+
+class SimpleCmd {
+	public:
+		SimpleCmd(int a, int b, int c);
+		SimpleCmd();
+
+		bool operator==(const SimpleCmd& cmd) const;
+		bool operator<(const SimpleCmd& cmd) const;
+
+	public:
+		int cmd1, cmd2, cmd3;
+};
+
+class Cmd : public SimpleCmd{
+	public:
+		Cmdtype cmd_type;
+		int cmd4;
+		int argc;
+		int pos, scn;
+		const char* rawdata;
+		char cmdstr[1024];
+		std::vector<VarInfo> args;
+
+	private:
+		const Flags& flags;
+		bool errorflag;
+		int system_version;
+
+		int GetArgs(const char*& d);
+		int GetArgsSpecial(int normal_args,const char*& d);
+		void GetSelection(const char*& d);
+		int GetSwitch(const char*& d);
+		int GetSimpleSwitch(const char*& d);
+		int GetExpression(const char*& d, struct VarInfo* info = 0);
+		int GetExpressionCond(const char*& d);
+		int GetLeftToken(const char*& d, struct VarInfo& info);
+		int GetString(const char*& d);
+		int CopyString(const char* d);
+		int StrVar(int type, int number);
+		static char strtype[256];
+		static int StrType(const char* d) { return strtype[*(unsigned const char*)d];}
+
+	public:
+		const char* Str(const VarInfo& info) const;
+		int AddStr(char* s);
+
+	private:
+		char strheap[STRHEAP_SIZE];
+		int strend;
+		void SetError(void) { errorflag = true;}
+		void ResetString(void) {
+			strend = 0;
+		}
+
+	public:
+		void GetCmd(Flags& f, const char*& d);
+		void SetSysvar(int n, int v);
+		void SetSysvar(int v) { SetSysvar(TYPE_SYS_SYS, v); }
+		void SetFlagvar(VarInfo info, int v);
+		void SetStrvar(VarInfo info, const std::string& s);
+		bool IsError() { return errorflag;}
+		void clear(void);
+		virtual const char * CmdDescr(int, int, int, int) { return "Not supported"; }
+		Cmd(const Flags& f, int _sys_ver);
+		void read(const CmdSimplified& cmd);
+		void write(CmdSimplified& cmd, char*& args_buffer) const;
+};
+
+class CommandHandler {
+	public:
+		typedef void (CommandHandler::*CmdImpl)(Cmd& cmd);
+		typedef struct {
+			const char* descr;
+			CmdImpl function;
+		} CommandInfo;
+		void RegisterCommand(int cmd1, int cmd2, int cmd3, const char* descr, CmdImpl func);
+		bool Exec(Cmd& cmd);
+		void PrintCmd(Cmd& cmd);
+
+	private:
+		typedef std::map<SimpleCmd, CommandInfo> CommandMap;
+		CommandMap command_map;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_flags.h
@@ -0,0 +1,73 @@
+#ifndef __SCN2K_FLAGS_H__
+#define __SCN2K_FLAGS_H__
+
+#include <set>
+#include <string>
+
+struct VarInfo {
+#define TYPE_NONSYSVARMAX 5
+#define TYPE_VARMAX 9
+#define TYPE_VARLOCSTR 10
+#define TYPE_VARSYSSTR 12
+#define TYPE_VARSTR 18
+#define TYPE_STR 58
+#define TYPE_VAL 68
+#define TYPE_SYS 0xc8
+#define TYPE_END 0x7f
+
+#define TYPE_SYS_SYS 0
+#define TYPE_SYS_SKIPMODE 1
+	int type;
+	int number;
+	int value;
+	VarInfo() { type = TYPE_VAL; value = 0;}
+	VarInfo(int n) { type = TYPE_VAL; value = n;}
+	VarInfo(const VarInfo& i) { type = i.type; number = i.number; value = i.value;}
+};
+
+class Flags {
+/* flag:
+**  type 0-5 : 促鱈臓促束促谷属多担臓蔵続2000転
+**  type 6, 25 : 促属促鱈臓促促谷属多担臓蔵2000転
+**      type 10,11: 促鱈臓促束促谷属多担??臓蔵続2000転
+**	type 12 : 促属促鱈臓促促谷転損炭テ蛎‖2000転 (尊贈袖損谷揃但テ測)
+**	type 18 : 促鱈臓促束促谷転損炭テ蛎‖2000転
+**	type 25: 促揃促孫促促多担臓促促促孫尊転臓息臓 1000 転臓息
+**  type 26-32, 51 : 1-bit access to 0-6, 25
+**  type 52-58, 77 : 2-bit access to 0-6, 25
+**  type 78-84, 103 : 4-bit access to 0-6, 25
+**  type 104-110, 129 : 8-bit access to 0-6, 25
+*/
+	private:
+		typedef unsigned int uint;
+		int sys;
+		int var[TYPE_VARMAX+1][2000];
+		std::string str[2000];
+		std::string sys_str[2000];
+		std::string loc_str[3];
+	public:
+		Flags(void);
+		int operator () () const;
+		int operator () (VarInfo info) const;
+		void Str(int type, unsigned int number, char* buf, int sz) const;
+		std::string Str(int type, unsigned int number) const;
+		std::set<int> cgm_data;
+
+		bool IsInt(int type) const;
+		int MaxIndex(int type) const;
+
+		void Set(VarInfo info, int value);
+		int Get(int type, int number) const;
+		void SetSys(int value);
+		void SetStr(VarInfo info, std::string val);
+
+		bool Exec(class Cmd& cmd);
+
+		void Save(std::string& str);
+		void Load(const char* str);
+
+		void SaveSys(std::string& str);
+		void LoadSys(const char* str);
+};
+
+#endif
--- a/scn2k/scn2k_grp.cc
+++ b/scn2k/scn2k_grp.cc
@@ -26,229 +26,14 @@
  */
 
 #include "scn2k.h"
-#include "window/widget.h"
 #include "system/file.h"
 #include "system/system_config.h"
 #include "font/text.h"
-#include <set>
-
-using namespace std;
+#include "window/render.h"
 
-extern void DSurfaceFill(Surface* dest, const Rect& rect, int r, int g, int b, int a=0xff);
-extern void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstpos);
-extern Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
-        Surface* dst, const Rect& dstrect);
 extern XKFont::HorizLayout* DefaultLayout(int text_size);
 
 /*******************************************************************
-** GrpObj(interface)
-*/
-
-struct SEL {
-	Rect from;
-	Rect to;
-	int time;
-	int sel_no;
-	int args[8];
-	SEL() : from(0,0), to(0,0) {}
-};
-
-struct GrpObj;
-typedef std::map<int, GrpObj> GrpObjMap;
-
-struct GrpObj {
-	string name;
-	string gan_name;
-	PicContainer* pic_parent;
-	PicBase* picture;
-	WidAnmTime* anm;
-	int _posx, _posy;
-	int posx[9], posy[9];
-	Rect clip_area;
-	unsigned char alpha;
-	int order;
-	int surface_num;
-
-	GrpObjMap children_obj;
-
-	string print_moji;
-	int print_size, print_r, print_b, print_g;
-
-	int dig_number, dig_digit;
-
-	// zoom / rotate 関係
-	int zoom; // 256 で 1 倍
-	int rotate; // 0-360度
-
-	vector<Rect> src_pos;
-	enum GrpType { FILLRECT = 1, FILE = 2, GAN = 3, MOJI = 4, DIGIT = 5} gtype;
-	enum Attribute { NONE=0, WIPEON=1, SATURATE=2, HIDDEN=4,
-		UPDATE_PICTURE = 16, UPDATE_POS = 32, UPDATE_ALPHA = 64, UPDATE_SNUM = 128, UPDATE_CLIP = 256, UPDATE_VISIBLE = 512,
-		UPDATE_ALL = (UPDATE_PICTURE | UPDATE_POS | UPDATE_ALPHA | UPDATE_SNUM | UPDATE_CLIP | UPDATE_VISIBLE),
-		ANM_PLAYSTART = 0x8000, ANM_PLAYING = 0x10000,
-		DIG_ZERO = 0x10000*2, DIG_SIGN = 0x10000*4, DIG_PACK=0x10000*8,DIG_SPACE=0x10000*16
-		};
-	Attribute attr;
-
-	GrpObj(void);
-	~GrpObj(void);
-
-	void SetPos(int index, int x, int y);
-	void GetPos(int index, int& x, int& y);
-	int PosX(void);
-	int PosY(void);
-	void SetAlpha(void);
-	void SetAlpha(int alpha);
-	void SetSurfaceNum(int num = -1);
-	void SetZoomRotate(int zoom=-1, int rotate=-1);
-	void SetClipArea(int x, int y, int width, int height);
-	void GetSrcGeom(int& width, int& height);
-	void SetUpdate(void);
-	void UpdateMoji(void);
-	void UpdateDigit(void);
-	void UpdateSurface(void);
-	void ZoomRotate(void);
-	void Refresh(GrpObj& parent_obj);
-	void _debug_Dump(int, int);
-	void Update(void);
-	void CreateSurface(PicContainer* parent);
-	void CreateGan(Event::Container& event, int event_number);
-	void CreateGanSpecial(Event::Container& event, int event_number, int time);
-	PicBase* DeletePic(void);
-};
-
-/*******************************************************************
-** GrpObj(interface)
-*/
-
-class GrpImpl : public CommandHandler {
-#define MAXPDT 256
-#define WORKPDT 255
-	private:
-		void CreateObj(int number);
-		void CreateSubObj(int grp_num, int number);
-		void ZMoveObj(int number);
-		void SetObjChanged(int number);
-		void SwapObj(int a1, int a2);
-		void DeleteObjPic(int num);// object の surface のみ削除
-		void DeleteSubObjPic(int grp_num, int num);
-		void DeleteObj(int num);
-		void DeleteSubObj(int grp_num, int num);
-		void RefreshObj(void);
-
-		Surface* Dsurface(int pdt);
-		Surface* Ssurface(int pdt);
-
-		// cgmode 用画像処理関連
-		void LoadCgm(void);
-
-	public:
-		GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& _flag, set<int>& _cgm_data);
-		~GrpImpl();
-		bool Wait(unsigned int current_time, Cmd& cmd);
-		void Exec(Cmd& cmd);
-		void InitSel(void);
-		void Save(std::string& str);
-		void Load(const char* str);
-		void SaveSys(std::string& str);
-		void LoadSys(const char* str);
-		void SetSkipMode(SkipMode _mode);
-		void LoadSurface(const char* str, int pdt);
-
-	private:
-		void LoadSurface(const char* str);
-		void LoadSurface(void);
-		void AddSurface(const char* str);
-
-		void StartAnm(int type);
-		void StartShake(int total, const int* pattern);
-		void AbortAnm(void);
-		static bool Pressed(int x, int y, void* pointer);
-
-		GrpObj* GetGraphicObj(int grp, bool fg=true);
-		GrpObj* GetGraphicObj(int grp, int index, bool fg=true);
-		GrpObj* GetGraphicObjVarMode(Cmd& cmd, int &base_arg, bool fg=true);
-
-		// Opcode handling
-		void impl_stackClear(Cmd& cmd);
-		void impl_grpBuffer(Cmd& cmd);
-		void impl_grpMulti(Cmd &cmd);
-		void impl_grpOpen(Cmd &cmd);
-		void impl_shake(Cmd &cmd);
-		void impl_grpCopy(Cmd &cmd);
-		void impl_recFill(Cmd &cmd);
-		void impl_recCopy(Cmd &cmd);
-		void impl_recAdd(Cmd &cmd);
-		void impl_grpPan(Cmd &cmd);
-		void impl_snmPlay(Cmd &cmd);
-		void impl_snmBgScroll(Cmd &cmd);
-		void impl_cgGet(Cmd &cmd);
-		void impl_cgStatus(Cmd &cmd);
-		void impl_objClear(Cmd &cmd);
-		void impl_createObj(Cmd &cmd);
-		void impl_gan(Cmd &cmd);
-		void impl_objSetPos(Cmd &cmd);
-		void impl_objAlpha(Cmd &cmd);
-		void impl_objShow(Cmd &cmd);
-		void impl_objColour(Cmd &cmd);
-		void impl_objComposite(Cmd &cmd);
-		void impl_objSetText(Cmd &cmd);
-		void impl_objTextOpts(Cmd &cmd);
-		void impl_objOrder(Cmd &cmd);
-		void impl_objDispArea(Cmd &cmd);
-		void impl_objSetDigits(Cmd &cmd);
-		void impl_objNumOpts(Cmd &cmd);
-		void impl_objPattNo(Cmd &cmd);
-		void impl_objScale(Cmd &cmd);
-		void impl_objRotate(Cmd &cmd);
-		void impl_objPosDims(Cmd &cmd);
-		void impl_refresh(Cmd &cmd);
-		void impl_bgmLoop(Cmd &cmd);
-		void impl_bgmStop(Cmd &cmd);
-		void impl_playWav(Cmd &cmd);
-		void impl_playSE(Cmd &cmd);
-		void impl_stopWav(Cmd &cmd);
-		void impl_SetVolMod(Cmd &cmd);
-		void impl_GetVolMod(Cmd &cmd);
-		void impl_koePlay(Cmd &cmd);
-		void impl_movPlay(Cmd &cmd);
-
-	public:
-		AyuSysConfig *config;
-
-	private:
-		Event::Container& event;
-		const Flags& flags;
-		PicBase* screen;
-		PicBase* screen_front;
-		Surface* surface, *surface_update;
-
-		Surface* dsurface[MAXPDT]; // 書き込み可能な Surface
-		Surface* ssurface[MAXPDT]; // ファイルの内容等、読み込みのみ可能な状態の Surface
-		PicContainer& parent;
-
-		// 画像効果の保存用
-		WidAnmTime* anm1, *anm2;
-		typedef enum { NORMAL, WAIT_ANM, WAIT_SHAKE, WAIT_SE, WAIT_MOVIE} Status;
-		Status status;
-		SkipMode skip_mode;
-
-		std::string bg_name;
-		std::map<int, SEL> anmtype;
-		GrpObjMap grpobj;
-		GrpObjMap bs_obj;
-
-		std::map<std::string, int> cgm_info;
-		set<int>& cgm_data;
-		int cgm_size;
-
-		class MuSys *music;
-
-		std::set<int> changed_obj;
-		string reserved_load_surface0;
-		vector<PicBase*> deleted_pic;
-};
-/*******************************************************************
 ** GrpObj(implementation)
 */
 
@@ -752,14 +537,7 @@ void GrpObj::_debug_Dump(int id, int ind
 **	class ScnGrp*
 */
 /* Princess Bride: 背景画の一部のみ移動、の実装 */
-struct ScnGrpMove : public WidAnmTime {
-	Surface* dest;
-	Surface* src;
-	PicRoot& root;
-	Rect dest_r, from, to;
-	ScnGrpMove(Event::Container& container, PicBase* _pic, PicRoot& root, Surface* dest, const Rect& _dest_r, Surface* src, const Rect& from, const Rect& to, int total_time);
-	void Exec(int count);
-};
+
 ScnGrpMove::ScnGrpMove(Event::Container& container, PicBase* _pic, PicRoot& _root, Surface* _dest, const Rect& _dest_r, Surface* _src, const Rect& _from, const Rect& _to, int total_time) :
 	WidAnmTime(container, _pic, total_time),
 	dest(_dest), src(_src), root(_root),dest_r(_dest_r), from(_from), to(_to) {
@@ -785,23 +563,6 @@ void ScnGrpMove::Exec(int count) {
 		(*it)->SetSurface(dest, 0, 0);
 }
 
-/* Princess Bride: カードがおちるアニメーション */
-
-struct ScnGrpAnmAtom {
-	string name;
-	int time;
-	ScnGrpAnmAtom(const char* _n, int _t) : name(_n), time(_t) {}
-};
-
-struct ScnGrpAnm : public WidAnmTime, vector<ScnGrpAnmAtom> {
-	GrpImpl& owner;
-	ScnGrpAnm(Event::Container& container, PicBase* _pic, GrpImpl& _owner) :
-		WidAnmTime(container, _pic, 0), owner(_owner) {
-	}
-	void CalcTotal(void);
-	void Exec(int count);
-};
-
 void ScnGrpAnm::CalcTotal(void) {
 	/* total time を計算 */
 	if (empty()) return;
@@ -825,13 +586,13 @@ void ScnGrpAnm::Exec(int count) {
 
 /*****************************************************
 *
-*  GrpImpl(implementation) : 定義
+*  Grp
 *
 */
 
 #include "music2/music.h"
 
-GrpImpl::GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm_data):
+Grp::Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm_data):
 	event(_event),
 	flags(f), 
 	parent(_parent),
@@ -861,76 +622,75 @@ GrpImpl::GrpImpl(Event::Container& _even
 
 	LoadCgm();
 
-	RegisterCommand(1, 30, 0, "stackClear", (CmdImpl) &GrpImpl::impl_stackClear);
-	RegisterCommand(1, 33, 70, "grpBuffer", (CmdImpl) &GrpImpl::impl_grpBuffer);
-	RegisterCommand(1, 33, 73, "grpOpenBG", (CmdImpl) &GrpImpl::impl_grpOpen);
-	RegisterCommand(1, 33, 75, "grpMulti", (CmdImpl) &GrpImpl::impl_grpMulti); //FIXME: or not...
-	RegisterCommand(1, 33, 76, "grpOpen", (CmdImpl) &GrpImpl::impl_grpOpen);
-	RegisterCommand(1, 33, 32, "shake", (CmdImpl) &GrpImpl::impl_shake);
-	RegisterCommand(1, 33, 100, "grpCopy", (CmdImpl) &GrpImpl::impl_grpCopy);
-	RegisterCommand(1, 33, 1201, "recFill", (CmdImpl) &GrpImpl::impl_recFill);
-	RegisterCommand(1, 33, 1100, "recCopy", (CmdImpl) &GrpImpl::impl_recCopy);
+	RegisterCommand(1, 30, 0, "stackClear", (CmdImpl) &Grp::impl_stackClear);
+	RegisterCommand(1, 33, 70, "grpBuffer", (CmdImpl) &Grp::impl_grpBuffer);
+	RegisterCommand(1, 33, 73, "grpOpenBG", (CmdImpl) &Grp::impl_grpOpen);
+	RegisterCommand(1, 33, 75, "grpMulti", (CmdImpl) &Grp::impl_grpMulti); //FIXME: or not...
+	RegisterCommand(1, 33, 76, "grpOpen", (CmdImpl) &Grp::impl_grpOpen);
+	RegisterCommand(1, 33, 32, "shake", (CmdImpl) &Grp::impl_shake);
+	RegisterCommand(1, 33, 100, "grpCopy", (CmdImpl) &Grp::impl_grpCopy);
+	RegisterCommand(1, 33, 1201, "recFill", (CmdImpl) &Grp::impl_recFill);
+	RegisterCommand(1, 33, 1100, "recCopy", (CmdImpl) &Grp::impl_recCopy);
 	RegisterCommand(1, 33, 1101, "recMaskCopy", NULL); //FIXME
-	RegisterCommand(1, 33, 1600, "recAdd", (CmdImpl) &GrpImpl::impl_recAdd);
-	RegisterCommand(1, 33, 406, "grpPan", (CmdImpl) &GrpImpl::impl_grpPan);
+	RegisterCommand(1, 33, 1600, "recAdd", (CmdImpl) &Grp::impl_recAdd);
+	RegisterCommand(1, 33, 406, "grpPan", (CmdImpl) &Grp::impl_grpPan);
 
-	RegisterCommand(1, 34, 3120, "snmBgScroll", (CmdImpl) &GrpImpl::impl_snmBgScroll);
-	RegisterCommand(1, 34, 3100, "snmBgPlay", (CmdImpl) &GrpImpl::impl_snmPlay);
-	RegisterCommand(1, 34, 2100, "snmPlay", (CmdImpl) &GrpImpl::impl_snmPlay);
-	RegisterCommand(1, 34, 2101, "snmPlayEx", (CmdImpl) &GrpImpl::impl_snmPlay);
+	RegisterCommand(1, 34, 3120, "snmBgScroll", (CmdImpl) &Grp::impl_snmBgScroll);
+	RegisterCommand(1, 34, 3100, "snmBgPlay", (CmdImpl) &Grp::impl_snmPlay);
+	RegisterCommand(1, 34, 2100, "snmPlay", (CmdImpl) &Grp::impl_snmPlay);
+	RegisterCommand(1, 34, 2101, "snmPlayEx", (CmdImpl) &Grp::impl_snmPlay);
 
-	RegisterCommand(1, 4, 1500, "cgGetTotal", (CmdImpl) &GrpImpl::impl_cgGet);
-	RegisterCommand(1, 4, 1501, "cgGetViewed", (CmdImpl) &GrpImpl::impl_cgGet);
-	RegisterCommand(1, 4, 1502, "cgGetViewedPcnt", (CmdImpl) &GrpImpl::impl_cgGet);
-	RegisterCommand(1, 4, 1503, "cgGetFlag", (CmdImpl) &GrpImpl::impl_cgStatus);
-	RegisterCommand(1, 4, 1504, "cgStatus", (CmdImpl) &GrpImpl::impl_cgStatus);
+	RegisterCommand(1, 4, 1500, "cgGetTotal", (CmdImpl) &Grp::impl_cgGet);
+	RegisterCommand(1, 4, 1501, "cgGetViewed", (CmdImpl) &Grp::impl_cgGet);
+	RegisterCommand(1, 4, 1502, "cgGetViewedPcnt", (CmdImpl) &Grp::impl_cgGet);
+	RegisterCommand(1, 4, 1503, "cgGetFlag", (CmdImpl) &Grp::impl_cgStatus);
+	RegisterCommand(1, 4, 1504, "cgStatus", (CmdImpl) &Grp::impl_cgStatus);
 
 	RegisterCommand(1, 4, 0x6a4, "CreateInput", NULL);
 	RegisterCommand(1, 4, 0x6ae, "SetInput", NULL);
 
-	RegisterCommand(1, 61, 10, "objClear", (CmdImpl) &GrpImpl::impl_objClear);
-	RegisterCommand(1, 61, 11, "objDelete", (CmdImpl) &GrpImpl::impl_objClear);
+	RegisterCommand(1, 61, 10, "objClear", (CmdImpl) &Grp::impl_objClear);
+	RegisterCommand(1, 61, 11, "objDelete", (CmdImpl) &Grp::impl_objClear);
 
-	RegisterCommand(1, 71, 1000, "createObjG00", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 71, 1003, "createObjGAN", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 71, 1100, "createObjRect", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 71, 1200, "createObjText", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 71, 1300, "createObjWeaver", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 71, 1400, "createObjDigit", (CmdImpl) &GrpImpl::impl_createObj);
+	RegisterCommand(1, 71, 1000, "objOfFile", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 71, 1003, "objOfFileGan", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 71, 1100, "objOfArea", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 71, 1200, "objOfText", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 71, 1300, "objDriftOfFile", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 71, 1400, "objOfDigits", (CmdImpl) &Grp::impl_createObj);
 
-	RegisterCommand(2, 71, 1000, "createSubObjG00", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(2, 71, 1003, "createSubObjGAN", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(2, 71, 1100, "createSubObjRect", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(2, 71, 1200, "createSubObjText", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(2, 71, 1300, "createSubObjWeaver", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(2, 71, 1400, "createSubObjDigit", (CmdImpl) &GrpImpl::impl_createObj);
+	RegisterCommand(2, 71, 1000, "subObjOfFile", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(2, 71, 1003, "subObjOfGan", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(2, 71, 1100, "subObjOfArea", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(2, 71, 1200, "subObjOfText", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(2, 71, 1300, "subObjDriftOfFile", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(2, 71, 1400, "subObjOfDigits", (CmdImpl) &Grp::impl_createObj);
 
 	//I suppose it's the same thing as createObj*, but I didn't see it in action. For now, mark it unhandled.
-	RegisterCommand(1, 72, 1000, "createBgObjG00", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 72, 1003, "createBgObjGAN", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 72, 1100, "createBgObjRect", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 72, 1200, "createBgObjText", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 72, 1300, "createBgObjWeaver", (CmdImpl) &GrpImpl::impl_createObj);
-	RegisterCommand(1, 72, 1400, "createBgObjDigit", (CmdImpl) &GrpImpl::impl_createObj);
+	RegisterCommand(1, 72, 1000, "objBgOfFile", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 72, 1003, "objBgOfFileGan", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 72, 1100, "objBgOfArea", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 72, 1200, "objBgOfText", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 72, 1300, "objBgDriftOfFile", (CmdImpl) &Grp::impl_createObj);
+	RegisterCommand(1, 72, 1400, "objBgOfDigits", (CmdImpl) &Grp::impl_createObj);
 
-	RegisterCommand(2, 72, 1000, "createBgSubObjG00", NULL);//FIXME
-	RegisterCommand(2, 72, 1003, "createBgSubObjGAN", NULL);//FIXME
-	RegisterCommand(2, 72, 1100, "createBgSubObjRect", NULL);//FIXME
-	RegisterCommand(2, 72, 1200, "createBgSubObjText", NULL);//FIXME
-	RegisterCommand(2, 72, 1300, "createBgSubObjWeaver", NULL);//FIXME
-	RegisterCommand(2, 72, 1400, "createBgSubObjDigit", NULL);//FIXME
-
+	RegisterCommand(2, 72, 1000, "subObjBgOfFile", NULL);//FIXME
+	RegisterCommand(2, 72, 1003, "subObjBgOfGan", NULL);//FIXME
+	RegisterCommand(2, 72, 1100, "subObjBgOfArea", NULL);//FIXME
+	RegisterCommand(2, 72, 1200, "subObjBgOfText", NULL);//FIXME
+	RegisterCommand(2, 72, 1300, "subObjBgDriftOfFile", NULL);//FIXME
+	RegisterCommand(2, 72, 1400, "subObjBgOfDigits", NULL);//FIXME;
 
 	RegisterCommand(1, 73, 0, "ganStop?", NULL); //That's what xclannad says, but I'm not sure...
-	RegisterCommand(1, 73, 1000, "ganStop", (CmdImpl) &GrpImpl::impl_gan); //That's what rldev says
-	RegisterCommand(1, 73, 3, "ganIsPlaying", (CmdImpl) &GrpImpl::impl_gan);
-	RegisterCommand(1, 73, 2003, "objPlay", (CmdImpl) &GrpImpl::impl_gan);
-	RegisterCommand(1, 73, 1001, "ganLoop", (CmdImpl) &GrpImpl::impl_gan);
-	RegisterCommand(1, 73, 1003, "ganPlay", (CmdImpl) &GrpImpl::impl_gan);
-	RegisterCommand(1, 73, 1005, "ganPlayOnce", (CmdImpl) &GrpImpl::impl_gan);
-	RegisterCommand(1, 73, 3001, "ganLoop2", (CmdImpl) &GrpImpl::impl_gan);
-	RegisterCommand(1, 73, 3003, "ganPlay2", (CmdImpl) &GrpImpl::impl_gan);
-	RegisterCommand(1, 73, 3005, "ganPlayOnce2", (CmdImpl) &GrpImpl::impl_gan);
+	RegisterCommand(1, 73, 1000, "ganStop", (CmdImpl) &Grp::impl_gan); //That's what rldev says
+	RegisterCommand(1, 73, 3, "ganIsPlaying", (CmdImpl) &Grp::impl_gan);
+	RegisterCommand(1, 73, 2003, "objPlay", (CmdImpl) &Grp::impl_gan);
+	RegisterCommand(1, 73, 1001, "ganLoop", (CmdImpl) &Grp::impl_gan);
+	RegisterCommand(1, 73, 1003, "ganPlay", (CmdImpl) &Grp::impl_gan);
+	RegisterCommand(1, 73, 1005, "ganPlayOnce", (CmdImpl) &Grp::impl_gan);
+	RegisterCommand(1, 73, 3001, "ganLoop2", (CmdImpl) &Grp::impl_gan);
+	RegisterCommand(1, 73, 3003, "ganPlay2", (CmdImpl) &Grp::impl_gan);
+	RegisterCommand(1, 73, 3005, "ganPlayOnce2", (CmdImpl) &Grp::impl_gan);
 
 	RegisterCommand(2, 73, 0, "ganSubStop?", NULL); //FIXME
 	RegisterCommand(2, 73, 1000, "ganSubStop", NULL); //FIXME
@@ -939,33 +699,33 @@ GrpImpl::GrpImpl(Event::Container& _even
 	RegisterCommand(2, 73, 1001, "ganSubLoop", NULL); //FIXME
 	RegisterCommand(2, 73, 1003, "ganSubPlay", NULL); //FIXME
 	RegisterCommand(2, 73, 1005, "ganSubPlayOnce", NULL); //FIXME
-	RegisterCommand(2, 73, 3001, "ganSubLoop2", (CmdImpl) &GrpImpl::impl_gan); //FIXME
+	RegisterCommand(2, 73, 3001, "ganSubLoop2", (CmdImpl) &Grp::impl_gan); //FIXME
 	RegisterCommand(2, 73, 3003, "ganSubPlay2", NULL); //FIXME
 	RegisterCommand(2, 73, 3005, "ganSubPlayOnce2", NULL); //FIXME
 
 
-	RegisterCommand(1, 81, 1000, "objMove", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(1, 82, 1000, "objBgMove", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(1, 81, 1001, "objLeft", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(1, 82, 1001, "objBgLeft", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(1, 81, 1002, "objTop", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(1, 82, 1002, "objBgTop", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(1, 81, 1003, "objAlpha", (CmdImpl) &GrpImpl::impl_objAlpha);
-	RegisterCommand(1, 82, 1003, "objBgAlpha", (CmdImpl) &GrpImpl::impl_objAlpha);
-	RegisterCommand(1, 81, 1004, "objShow", (CmdImpl) &GrpImpl::impl_objShow);
-	RegisterCommand(1, 82, 1004, "objBgShow", (CmdImpl) &GrpImpl::impl_objShow);
+	RegisterCommand(1, 81, 1000, "objMove", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(1, 82, 1000, "objBgMove", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(1, 81, 1001, "objLeft", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(1, 82, 1001, "objBgLeft", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(1, 81, 1002, "objTop", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(1, 82, 1002, "objBgTop", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(1, 81, 1003, "objAlpha", (CmdImpl) &Grp::impl_objAlpha);
+	RegisterCommand(1, 82, 1003, "objBgAlpha", (CmdImpl) &Grp::impl_objAlpha);
+	RegisterCommand(1, 81, 1004, "objShow", (CmdImpl) &Grp::impl_objShow);
+	RegisterCommand(1, 82, 1004, "objBgShow", (CmdImpl) &Grp::impl_objShow);
 	RegisterCommand(1, 81, 1005, "objDispArea", NULL);
 	RegisterCommand(1, 82, 1005, "objBgDispArea", NULL);
-	RegisterCommand(1, 81, 1006, "objAdjust", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(1, 82, 1006, "objBgAdjust", NULL); //FIXME: (CmdImpl) &GrpImpl::impl_objSetPos);
+	RegisterCommand(1, 81, 1006, "objAdjust", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(1, 82, 1006, "objBgAdjust", NULL); //FIXME: (CmdImpl) &Grp::impl_objSetPos);
 	RegisterCommand(1, 81, 1007, "objAdjustX", NULL);
 	RegisterCommand(1, 82, 1007, "objBgAdjustX", NULL);
 	RegisterCommand(1, 81, 1008, "objAdjustY", NULL);
 	RegisterCommand(1, 82, 1008, "objBgAdjustY", NULL);
-	RegisterCommand(1, 81, 2006, "objAdjust2?", NULL); //FIXME: (CmdImpl) &GrpImpl::impl_objSetPos); I don't know if it is usefull or properly implemented
-	RegisterCommand(1, 82, 2006, "objBgAdjust2?", NULL); //FIXME: (CmdImpl) &GrpImpl::impl_objSetPos); See above
-	RegisterCommand(1, 81, 1016, "objColour", NULL); //FIXME: (CmdImpl) &GrpImpl::impl_objColour);
-	RegisterCommand(1, 82, 1016, "objBgColour", NULL); //FIXME: (CmdImpl) &GrpImpl::impl_objColour);
+	RegisterCommand(1, 81, 2006, "objAdjust2?", NULL); //FIXME: (CmdImpl) &Grp::impl_objSetPos); I don't know if it is usefull or properly implemented
+	RegisterCommand(1, 82, 2006, "objBgAdjust2?", NULL); //FIXME: (CmdImpl) &Grp::impl_objSetPos); See above
+	RegisterCommand(1, 81, 1016, "objColour", NULL); //FIXME: (CmdImpl) &Grp::impl_objColour);
+	RegisterCommand(1, 82, 1016, "objBgColour", NULL); //FIXME: (CmdImpl) &Grp::impl_objColour);
 	RegisterCommand(1, 81, 1017, "objColR", NULL);
 	RegisterCommand(1, 82, 1017, "objBgColR", NULL);
 	RegisterCommand(1, 81, 1018, "objColG", NULL);
@@ -974,43 +734,43 @@ GrpImpl::GrpImpl(Event::Container& _even
 	RegisterCommand(1, 82, 1019, "objBgColB", NULL);
 	RegisterCommand(1, 81, 1020, "objColLevel", NULL);
 	RegisterCommand(1, 82, 1020, "objBgColLevel", NULL);
-	RegisterCommand(1, 81, 1021, "objComposite", NULL);//(CmdImpl) &GrpImpl::impl_objComposite); //FIXME: May be broken
-	RegisterCommand(1, 82, 1021, "objBgComposite", (CmdImpl) &GrpImpl::impl_objComposite);
-	RegisterCommand(1, 81, 1024, "objSetText", (CmdImpl) &GrpImpl::impl_objSetText);
-	RegisterCommand(1, 82, 1024, "objBgSetText", (CmdImpl) &GrpImpl::impl_objSetText);
-	RegisterCommand(1, 81, 1025, "objTextOpts", (CmdImpl) &GrpImpl::impl_objTextOpts); //FIXME: Incomplete
-	RegisterCommand(1, 82, 1025, "objBgTextOpts", (CmdImpl) &GrpImpl::impl_objTextOpts);
-	RegisterCommand(1, 81, 1032, "objOrder", (CmdImpl) &GrpImpl::impl_objOrder);
-	RegisterCommand(1, 82, 1032, "objBgOrder", (CmdImpl) &GrpImpl::impl_objOrder);
-	RegisterCommand(1, 81, 1034, "objDispRect", (CmdImpl) &GrpImpl::impl_objDispArea);
-	RegisterCommand(1, 82, 1034, "objBgDispRect", (CmdImpl) &GrpImpl::impl_objDispArea);
-	RegisterCommand(1, 81, 1037, "objSetDigits", (CmdImpl) &GrpImpl::impl_objSetDigits);
-	RegisterCommand(1, 82, 1037, "objBgSetDigits", (CmdImpl) &GrpImpl::impl_objSetDigits);
-	RegisterCommand(1, 81, 1038, "objNumOpts", (CmdImpl) &GrpImpl::impl_objNumOpts);
-	RegisterCommand(1, 82, 1038, "objBgNumOpts", (CmdImpl) &GrpImpl::impl_objNumOpts);
-	RegisterCommand(1, 81, 1039, "objPattNo", (CmdImpl) &GrpImpl::impl_objPattNo);
-	RegisterCommand(1, 82, 1039, "objBgPattNo", (CmdImpl) &GrpImpl::impl_objPattNo);
-	RegisterCommand(1, 81, 1046, "objScale", (CmdImpl) &GrpImpl::impl_objScale); //FIXME: Broken behaviour
-	RegisterCommand(1, 82, 1046, "objBgScale", (CmdImpl) &GrpImpl::impl_objScale);
+	RegisterCommand(1, 81, 1021, "objComposite", NULL);//(CmdImpl) &Grp::impl_objComposite); //FIXME: May be broken
+	RegisterCommand(1, 82, 1021, "objBgComposite", (CmdImpl) &Grp::impl_objComposite);
+	RegisterCommand(1, 81, 1024, "objSetText", (CmdImpl) &Grp::impl_objSetText);
+	RegisterCommand(1, 82, 1024, "objBgSetText", (CmdImpl) &Grp::impl_objSetText);
+	RegisterCommand(1, 81, 1025, "objTextOpts", (CmdImpl) &Grp::impl_objTextOpts); //FIXME: Incomplete
+	RegisterCommand(1, 82, 1025, "objBgTextOpts", (CmdImpl) &Grp::impl_objTextOpts);
+	RegisterCommand(1, 81, 1032, "objOrder", (CmdImpl) &Grp::impl_objOrder);
+	RegisterCommand(1, 82, 1032, "objBgOrder", (CmdImpl) &Grp::impl_objOrder);
+	RegisterCommand(1, 81, 1034, "objDispRect", (CmdImpl) &Grp::impl_objDispArea);
+	RegisterCommand(1, 82, 1034, "objBgDispRect", (CmdImpl) &Grp::impl_objDispArea);
+	RegisterCommand(1, 81, 1037, "objSetDigits", (CmdImpl) &Grp::impl_objSetDigits);
+	RegisterCommand(1, 82, 1037, "objBgSetDigits", (CmdImpl) &Grp::impl_objSetDigits);
+	RegisterCommand(1, 81, 1038, "objNumOpts", (CmdImpl) &Grp::impl_objNumOpts);
+	RegisterCommand(1, 82, 1038, "objBgNumOpts", (CmdImpl) &Grp::impl_objNumOpts);
+	RegisterCommand(1, 81, 1039, "objPattNo", (CmdImpl) &Grp::impl_objPattNo);
+	RegisterCommand(1, 82, 1039, "objBgPattNo", (CmdImpl) &Grp::impl_objPattNo);
+	RegisterCommand(1, 81, 1046, "objScale", (CmdImpl) &Grp::impl_objScale); //FIXME: Broken behaviour
+	RegisterCommand(1, 82, 1046, "objBgScale", (CmdImpl) &Grp::impl_objScale);
 	RegisterCommand(1, 81, 1047, "objWidth", NULL);
 	RegisterCommand(1, 82, 1047, "objBgWidth", NULL);
-	RegisterCommand(1, 81, 1049, "objRotate", (CmdImpl) &GrpImpl::impl_objRotate);
-	RegisterCommand(1, 82, 1049, "objBgRotate", (CmdImpl) &GrpImpl::impl_objRotate);
+	RegisterCommand(1, 81, 1049, "objRotate", (CmdImpl) &Grp::impl_objRotate);
+	RegisterCommand(1, 82, 1049, "objBgRotate", (CmdImpl) &Grp::impl_objRotate);
 
-	RegisterCommand(2, 81, 1000, "childObjMove", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(2, 82, 1000, "childObjBgMove", (CmdImpl) &GrpImpl::impl_objSetPos);
+	RegisterCommand(2, 81, 1000, "childObjMove", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(2, 82, 1000, "childObjBgMove", (CmdImpl) &Grp::impl_objSetPos);
 	RegisterCommand(2, 81, 1001, "childObjLeft", NULL);
 	RegisterCommand(2, 82, 1001, "childObjBgLeft", NULL);
 	RegisterCommand(2, 81, 1002, "childObjTop", NULL);
 	RegisterCommand(2, 82, 1002, "childObjBgTop", NULL);
-	RegisterCommand(2, 81, 1003, "childObjAlpha", (CmdImpl) &GrpImpl::impl_objAlpha);
-	RegisterCommand(2, 82, 1003, "childObjBgAlpha", (CmdImpl) &GrpImpl::impl_objAlpha);
-	RegisterCommand(2, 81, 1004, "childObjShow", (CmdImpl) &GrpImpl::impl_objShow);
-	RegisterCommand(2, 82, 1004, "childObjBgShow", (CmdImpl) &GrpImpl::impl_objShow);
+	RegisterCommand(2, 81, 1003, "childObjAlpha", (CmdImpl) &Grp::impl_objAlpha);
+	RegisterCommand(2, 82, 1003, "childObjBgAlpha", (CmdImpl) &Grp::impl_objAlpha);
+	RegisterCommand(2, 81, 1004, "childObjShow", (CmdImpl) &Grp::impl_objShow);
+	RegisterCommand(2, 82, 1004, "childObjBgShow", (CmdImpl) &Grp::impl_objShow);
 	RegisterCommand(2, 81, 1005, "childObjDispArea", NULL);
 	RegisterCommand(2, 82, 1005, "childObjBgDispArea", NULL);
-	RegisterCommand(2, 81, 1006, "childObjAdjust", (CmdImpl) &GrpImpl::impl_objSetPos);
-	RegisterCommand(2, 82, 1006, "childObjBgAdjust", (CmdImpl) &GrpImpl::impl_objSetPos);
+	RegisterCommand(2, 81, 1006, "childObjAdjust", (CmdImpl) &Grp::impl_objSetPos);
+	RegisterCommand(2, 82, 1006, "childObjBgAdjust", (CmdImpl) &Grp::impl_objSetPos);
 	RegisterCommand(2, 81, 1007, "childObjAdjustX", NULL);
 	RegisterCommand(2, 82, 1007, "childObjBgAdjustX", NULL);
 	RegisterCommand(2, 81, 1008, "childObjAdjustY", NULL);
@@ -1029,69 +789,69 @@ GrpImpl::GrpImpl(Event::Container& _even
 	RegisterCommand(2, 82, 1020, "childObjBgColLevel", NULL);
 	RegisterCommand(2, 81, 1021, "childObjComposite", NULL);
 	RegisterCommand(2, 82, 1021, "childObjBgComposite", NULL);
-	RegisterCommand(2, 81, 1024, "childObjSetText", (CmdImpl) &GrpImpl::impl_objSetText);
-	RegisterCommand(2, 82, 1024, "childObjBgSetText", (CmdImpl) &GrpImpl::impl_objSetText);
-	RegisterCommand(2, 81, 1025, "childObjTextOpts", (CmdImpl) &GrpImpl::impl_objTextOpts);
-	RegisterCommand(2, 82, 1025, "childObjBgTextOpts", (CmdImpl) &GrpImpl::impl_objTextOpts);
+	RegisterCommand(2, 81, 1024, "childObjSetText", (CmdImpl) &Grp::impl_objSetText);
+	RegisterCommand(2, 82, 1024, "childObjBgSetText", (CmdImpl) &Grp::impl_objSetText);
+	RegisterCommand(2, 81, 1025, "childObjTextOpts", (CmdImpl) &Grp::impl_objTextOpts);
+	RegisterCommand(2, 82, 1025, "childObjBgTextOpts", (CmdImpl) &Grp::impl_objTextOpts);
 	RegisterCommand(2, 81, 1032, "childObjOrder", NULL);
 	RegisterCommand(2, 82, 1032, "childObjBgOrder", NULL);
 	RegisterCommand(2, 81, 1034, "childObjDispRect", NULL);
 	RegisterCommand(2, 82, 1034, "childObjBgDispRect", NULL);
-	RegisterCommand(2, 81, 1037, "childObjSetDigits", (CmdImpl) &GrpImpl::impl_objSetDigits);
-	RegisterCommand(2, 82, 1037, "childObjBgSetDigits", (CmdImpl) &GrpImpl::impl_objSetDigits);
-	RegisterCommand(2, 81, 1038, "childObjNumOpts", (CmdImpl) &GrpImpl::impl_objNumOpts);
-	RegisterCommand(2, 82, 1038, "childObjBgNumOpts", (CmdImpl) &GrpImpl::impl_objNumOpts);
-	RegisterCommand(2, 81, 1039, "childObjPattNo", (CmdImpl) &GrpImpl::impl_objPattNo);
-	RegisterCommand(2, 82, 1039, "childObjBgPattNo", (CmdImpl) &GrpImpl::impl_objPattNo);
-	RegisterCommand(2, 81, 1046, "childObjScale", (CmdImpl) &GrpImpl::impl_objScale);
-	RegisterCommand(2, 82, 1046, "childObjBgScale", (CmdImpl) &GrpImpl::impl_objScale);
+	RegisterCommand(2, 81, 1037, "childObjSetDigits", (CmdImpl) &Grp::impl_objSetDigits);
+	RegisterCommand(2, 82, 1037, "childObjBgSetDigits", (CmdImpl) &Grp::impl_objSetDigits);
+	RegisterCommand(2, 81, 1038, "childObjNumOpts", (CmdImpl) &Grp::impl_objNumOpts);
+	RegisterCommand(2, 82, 1038, "childObjBgNumOpts", (CmdImpl) &Grp::impl_objNumOpts);
+	RegisterCommand(2, 81, 1039, "childObjPattNo", (CmdImpl) &Grp::impl_objPattNo);
+	RegisterCommand(2, 82, 1039, "childObjBgPattNo", (CmdImpl) &Grp::impl_objPattNo);
+	RegisterCommand(2, 81, 1046, "childObjScale", (CmdImpl) &Grp::impl_objScale);
+	RegisterCommand(2, 82, 1046, "childObjBgScale", (CmdImpl) &Grp::impl_objScale);
 	RegisterCommand(2, 81, 1047, "childObjWidth", NULL);
 	RegisterCommand(2, 82, 1047, "childObjBgWidth", NULL);
 	RegisterCommand(2, 81, 1049, "childObjRotate", NULL);
 	RegisterCommand(2, 82, 1049, "childObjBgRotate", NULL);
 
-	RegisterCommand(1, 84, 1000, "objGetPos", (CmdImpl) &GrpImpl::impl_objPosDims);
-	RegisterCommand(1, 84, 1100, "objGetDims", (CmdImpl) &GrpImpl::impl_objPosDims);
+	RegisterCommand(1, 84, 1000, "objGetPos", (CmdImpl) &Grp::impl_objPosDims);
+	RegisterCommand(1, 84, 1100, "objGetDims", (CmdImpl) &Grp::impl_objPosDims);
 
-	RegisterCommand(2, 84, 1000, "childObjGetPos", (CmdImpl) &GrpImpl::impl_objPosDims);
-	RegisterCommand(2, 84, 1100, "childObjGetDims", (CmdImpl) &GrpImpl::impl_objPosDims);
+	RegisterCommand(2, 84, 1000, "childObjGetPos", (CmdImpl) &Grp::impl_objPosDims);
+	RegisterCommand(2, 84, 1100, "childObjGetDims", (CmdImpl) &Grp::impl_objPosDims);
 
-	RegisterCommand(1, 31, 0, "refresh", (CmdImpl) &GrpImpl::impl_refresh);
+	RegisterCommand(1, 31, 0, "refresh", (CmdImpl) &Grp::impl_refresh);
 
-	RegisterCommand(1, 20, 0, "bgmLoop", (CmdImpl) &GrpImpl::impl_bgmLoop);
-	RegisterCommand(1, 20, 1, "bgmPlayEx", (CmdImpl) &GrpImpl::impl_bgmLoop); //FIXME: wait
-	RegisterCommand(1, 20, 2, "bgmPlay", (CmdImpl) &GrpImpl::impl_bgmLoop);
-	RegisterCommand(1, 20, 5, "bgmStop", (CmdImpl) &GrpImpl::impl_bgmStop);
-	RegisterCommand(1, 20, 105, "bgmFadeOut", (CmdImpl) &GrpImpl::impl_bgmStop);
+	RegisterCommand(1, 20, 0, "bgmLoop", (CmdImpl) &Grp::impl_bgmLoop);
+	RegisterCommand(1, 20, 1, "bgmPlayEx", (CmdImpl) &Grp::impl_bgmLoop); //FIXME: wait
+	RegisterCommand(1, 20, 2, "bgmPlay", (CmdImpl) &Grp::impl_bgmLoop);
+	RegisterCommand(1, 20, 5, "bgmStop", (CmdImpl) &Grp::impl_bgmStop);
+	RegisterCommand(1, 20, 105, "bgmFadeOut", (CmdImpl) &Grp::impl_bgmStop);
 
-	RegisterCommand(1, 21, 0, "wavPlay", (CmdImpl) &GrpImpl::impl_playWav);
-	RegisterCommand(1, 21, 1, "wavPlayEx", (CmdImpl) &GrpImpl::impl_playWav);
-	RegisterCommand(1, 21, 2, "wavLoop", (CmdImpl) &GrpImpl::impl_playWav);
+	RegisterCommand(1, 21, 0, "wavPlay", (CmdImpl) &Grp::impl_playWav);
+	RegisterCommand(1, 21, 1, "wavPlayEx", (CmdImpl) &Grp::impl_playWav);
+	RegisterCommand(1, 21, 2, "wavLoop", (CmdImpl) &Grp::impl_playWav);
 	RegisterCommand(1, 21, 3, "wavWait", NULL);
 	RegisterCommand(1, 21, 4, "wavPlaying", NULL);
-	RegisterCommand(1, 21, 5, "wavStop", (CmdImpl) &GrpImpl::impl_stopWav);
-	RegisterCommand(1, 21, 105, "wavFadeout", (CmdImpl) &GrpImpl::impl_stopWav);
+	RegisterCommand(1, 21, 5, "wavStop", (CmdImpl) &Grp::impl_stopWav);
+	RegisterCommand(1, 21, 105, "wavFadeout", (CmdImpl) &Grp::impl_stopWav);
 
-	RegisterCommand(1, 22, 0, "sePlay", (CmdImpl) &GrpImpl::impl_playSE);
+	RegisterCommand(1, 22, 0, "sePlay", (CmdImpl) &Grp::impl_playSE);
 
-	RegisterCommand(1, 4, 2230, "SetBgmVolMod", (CmdImpl) &GrpImpl::impl_SetVolMod);
-	RegisterCommand(1, 4, 2231, "SetKoeVolMod", (CmdImpl) &GrpImpl::impl_SetVolMod);
-	RegisterCommand(1, 4, 2232, "SetPCMVolMod", (CmdImpl) &GrpImpl::impl_SetVolMod);
-	RegisterCommand(1, 4, 2233, "SetSeVolMod", (CmdImpl) &GrpImpl::impl_SetVolMod);
-	RegisterCommand(1, 4, 2330, "BgmVolMod", (CmdImpl) &GrpImpl::impl_GetVolMod);
-	RegisterCommand(1, 4, 2331, "KoeVolMod", (CmdImpl) &GrpImpl::impl_GetVolMod);
-	RegisterCommand(1, 4, 2332, "PCMVolMod", (CmdImpl) &GrpImpl::impl_GetVolMod);
-	RegisterCommand(1, 4, 2333, "SeVolMod", (CmdImpl) &GrpImpl::impl_GetVolMod);
+	RegisterCommand(1, 4, 2230, "SetBgmVolMod", (CmdImpl) &Grp::impl_SetVolMod);
+	RegisterCommand(1, 4, 2231, "SetKoeVolMod", (CmdImpl) &Grp::impl_SetVolMod);
+	RegisterCommand(1, 4, 2232, "SetPCMVolMod", (CmdImpl) &Grp::impl_SetVolMod);
+	RegisterCommand(1, 4, 2233, "SetSeVolMod", (CmdImpl) &Grp::impl_SetVolMod);
+	RegisterCommand(1, 4, 2330, "BgmVolMod", (CmdImpl) &Grp::impl_GetVolMod);
+	RegisterCommand(1, 4, 2331, "KoeVolMod", (CmdImpl) &Grp::impl_GetVolMod);
+	RegisterCommand(1, 4, 2332, "PCMVolMod", (CmdImpl) &Grp::impl_GetVolMod);
+	RegisterCommand(1, 4, 2333, "SeVolMod", (CmdImpl) &Grp::impl_GetVolMod);
 
-	RegisterCommand(1, 23, 0, "koePlay", (CmdImpl) &GrpImpl::impl_koePlay);
-	RegisterCommand(1, 23, 1, "koePlayEx", (CmdImpl) &GrpImpl::impl_koePlay); //FIXME
-	RegisterCommand(1, 23, 7, "koePlayExC", (CmdImpl) &GrpImpl::impl_koePlay); //FIXME
-	RegisterCommand(1, 23, 8, "koeDoPlay", (CmdImpl) &GrpImpl::impl_koePlay); //FIXME
-	RegisterCommand(1, 23, 9, "koeDoPlayEx", (CmdImpl) &GrpImpl::impl_koePlay); //FIXME
-	RegisterCommand(1, 23, 10, "koeDoPlayExC", (CmdImpl) &GrpImpl::impl_koePlay); //FIXME
+	RegisterCommand(1, 23, 0, "koePlay", (CmdImpl) &Grp::impl_koePlay);
+	RegisterCommand(1, 23, 1, "koePlayEx", (CmdImpl) &Grp::impl_koePlay); //FIXME
+	RegisterCommand(1, 23, 7, "koePlayExC", (CmdImpl) &Grp::impl_koePlay); //FIXME
+	RegisterCommand(1, 23, 8, "koeDoPlay", (CmdImpl) &Grp::impl_koePlay); //FIXME
+	RegisterCommand(1, 23, 9, "koeDoPlayEx", (CmdImpl) &Grp::impl_koePlay); //FIXME
+	RegisterCommand(1, 23, 10, "koeDoPlayExC", (CmdImpl) &Grp::impl_koePlay); //FIXME
 
-	RegisterCommand(1, 26, 1, "movPlayEx", (CmdImpl) &GrpImpl::impl_movPlay);
-	RegisterCommand(1, 26, 20, "movPlayExC", (CmdImpl) &GrpImpl::impl_movPlay);
+	RegisterCommand(1, 26, 1, "movPlayEx", (CmdImpl) &Grp::impl_movPlay);
+	RegisterCommand(1, 26, 20, "movPlayExC", (CmdImpl) &Grp::impl_movPlay);
 
 	RegisterCommand(1, 61, 14, "objSwap?", NULL);
 	RegisterCommand(1, 62, 14, "objSwap?", NULL);
@@ -1104,8 +864,7 @@ GrpImpl::GrpImpl(Event::Container& _even
 	anm2 = NULL;
 }
 
-GrpImpl::~GrpImpl() {
-
+Grp::~Grp() {
 	map<int,GrpObj>::iterator it;
 	for (it=grpobj.begin(); it!=grpobj.end(); it++) {
 		PicBase* p = it->second.DeletePic();
@@ -1123,7 +882,7 @@ GrpImpl::~GrpImpl() {
 	}
 }
 
-Surface* GrpImpl::Dsurface(int pdt) {
+Surface* Grp::Dsurface(int pdt) {
 	if (pdt == 0) return surface;
 	if (dsurface[pdt] == 0) { // とりあえず画面の大きさということにする
 		if (pdt == WORKPDT)
@@ -1139,19 +898,19 @@ Surface* GrpImpl::Dsurface(int pdt) {
 	return dsurface[pdt];
 }
 
-GrpObj* GrpImpl::GetGraphicObj(int grp, bool fg) {
+GrpObj* Grp::GetGraphicObj(int grp, bool fg) {
 	if (fg)
 		return &grpobj[grp];
 	else
 		return &bs_obj[grp];
 }
 
-GrpObj* GrpImpl::GetGraphicObj(int grp, int index, bool fg) {
+GrpObj* Grp::GetGraphicObj(int grp, int index, bool fg) {
 	GrpObj* g = GetGraphicObj(grp, fg);
 	return &g->children_obj[index];
 }
 
-GrpObj* GrpImpl::GetGraphicObjVarMode(Cmd& cmd, int &base_arg, bool fg) {
+GrpObj* Grp::GetGraphicObjVarMode(Cmd& cmd, int &base_arg, bool fg) {
 	GrpObj* g;
 	if (cmd.cmd1 == 2) {
 		g = GetGraphicObj(cmd.args[base_arg].value, cmd.args[base_arg+1].value, fg);
@@ -1163,7 +922,7 @@ GrpObj* GrpImpl::GetGraphicObjVarMode(Cm
 }
 
 #include <SDL.h>
-Surface* GrpImpl::Ssurface(int pdt) {
+Surface* Grp::Ssurface(int pdt) {
 	if (pdt == 0) return surface;
 	if (ssurface[pdt]) {
 		return ssurface[pdt];
@@ -1171,7 +930,7 @@ Surface* GrpImpl::Ssurface(int pdt) {
 	return Dsurface(pdt);
 }
 
-void GrpImpl::LoadSurface(const char* str, int pdt) {
+void Grp::LoadSurface(const char* str, int pdt) {
 	string s = str;
 	if (cgm_info.find(s) != cgm_info.end()) {
 		cgm_data.insert(cgm_info[s]);
@@ -1201,7 +960,7 @@ void GrpImpl::LoadSurface(const char* st
 	}
 }
 
-void GrpImpl::InitSel(void) {
+void Grp::InitSel(void) {
 	int i;
 	int args[16];
 	char key[10];
@@ -1228,7 +987,7 @@ void GrpImpl::InitSel(void) {
 	}
 }
 
-void GrpImpl::SetSkipMode(SkipMode _mode) {
+void Grp::SetSkipMode(SkipMode _mode) {
 	if ( (skip_mode & SKIP_IN_MENU) && (_mode & SKIP_IN_MENU) == 0) {
 		RefreshObj();
 	} else if ( (skip_mode & SKIP_IN_MENU) == 0 && (_mode & SKIP_IN_MENU) ) {
@@ -1236,11 +995,11 @@ void GrpImpl::SetSkipMode(SkipMode _mode
 	skip_mode = _mode;
 }
 
-void GrpImpl::SetObjChanged(int num) {
+void Grp::SetObjChanged(int num) {
 	changed_obj.insert(num);
 }
 
-void GrpImpl::RefreshObj(void) {
+void Grp::RefreshObj(void) {
 	if (!deleted_pic.empty()) {
 		vector<PicBase*>::iterator it;
 		for (it=deleted_pic.begin(); it!=deleted_pic.end(); it++) {
@@ -1266,7 +1025,7 @@ void GrpImpl::RefreshObj(void) {
 
 
 #include <SDL.h>
-void GrpImpl::StartAnm(int type) {
+void Grp::StartAnm(int type) {
 	SEL sel;
 
 	if (anmtype.find(type) == anmtype.end()) {
@@ -1348,7 +1107,7 @@ void GrpImpl::StartAnm(int type) {
 	if (skip_mode & SKIP_GRP_NOEFFEC) AbortAnm();
 }
 
-void GrpImpl::StartShake(int total, const int* pattern) {
+void Grp::StartShake(int total, const int* pattern) {
 	if (anm2) {
 		fprintf(stderr,"Warning: StartShake() called before another animation finished\n");
 		anm2->Abort();
@@ -1371,7 +1130,7 @@ void GrpImpl::StartShake(int total, cons
 	anm2 = new_anm;
 }
 
-void GrpImpl::AbortAnm(void) {
+void Grp::AbortAnm(void) {
 	if (anm1 == NULL) return;
 	anm1->Abort();
 	delete anm1;
@@ -1392,18 +1151,18 @@ void GrpImpl::AbortAnm(void) {
 	return;
 }
 
-void GrpImpl::LoadSurface(const char* str) {
+void Grp::LoadSurface(const char* str) {
 	if (anm1 != NULL) AbortAnm(); // 前の描画が終わってなければ強制終了
 	LoadSurface(str, 1);
 	bg_name = str;
 }
 
-void GrpImpl::LoadSurface(void) {
+void Grp::LoadSurface(void) {
 	if (anm1 != NULL) AbortAnm(); // 前の描画が終わってなければ強制終了
 	LoadSurface(bg_name.c_str(), 1);
 }
 
-void GrpImpl::AddSurface(const char* str) {
+void Grp::AddSurface(const char* str) {
 	if (anm1 != NULL) AbortAnm(); // 前の描画が終わってなければ強制終了
 	LoadSurface(bg_name.c_str());
 
@@ -1421,7 +1180,7 @@ void GrpImpl::AddSurface(const char* str
 	}
 }
 
-void GrpImpl::CreateObj(int index) {
+void Grp::CreateObj(int index) {
 	GrpObjMap::iterator cur = grpobj.find(index);
 	if (cur == grpobj.end()) return;
 	GrpObj& g = grpobj[index];
@@ -1433,7 +1192,7 @@ void GrpImpl::CreateObj(int index) {
 	ZMoveObj(index);
 }
 
-void GrpImpl::CreateSubObj(int grp_index, int index) {
+void Grp::CreateSubObj(int grp_index, int index) {
 	GrpObjMap::iterator cur = grpobj.find(grp_index);
 	if (cur == grpobj.end()) return;
 	GrpObj* g = &grpobj[grp_index];
@@ -1449,7 +1208,7 @@ void GrpImpl::CreateSubObj(int grp_index
 	/*ZMoveObj(index);*/
 }
 
-void GrpImpl::ZMoveObj(int index) {
+void Grp::ZMoveObj(int index) {
 	GrpObjMap::iterator cur = grpobj.find(index);
 	if (cur == grpobj.end()) return;
 	GrpObj& g = grpobj[index];
@@ -1476,7 +1235,7 @@ void GrpImpl::ZMoveObj(int index) {
 	}
 }
 
-void GrpImpl::SwapObj(int index1, int index2) {
+void Grp::SwapObj(int index1, int index2) {
 	// デフォルト値から order が変更されていた場合のみ、order は保存される
 	// まずは両方のobjectをswap
 	if (grpobj.find(index1) == grpobj.end()) {
@@ -1511,8 +1270,8 @@ void GrpImpl::SwapObj(int index1, int in
 	}
 }
 
-bool GrpImpl::Pressed(int x, int y, void* pointer) { // マウスクリックでキャンセル
-	GrpImpl* g = (GrpImpl*)pointer;
+bool Grp::Pressed(int x, int y, void* pointer) { // マウスクリックでキャンセル
+	Grp* g = (Grp*)pointer;
 	if (g->status == WAIT_MOVIE)
 		g->music->StopMovie();
 	if (g->status == WAIT_ANM)
@@ -1561,7 +1320,7 @@ static unsigned char decode_char[256] = 
 	0xff, 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00, 0x76
 };
 
-void GrpImpl::LoadCgm() {
+void Grp::LoadCgm() {
 	/* cgm ファイル読み込み */
 	const char* fname = config->GetParaStr("#CGTABLE_FILE");
 	if (fname == NULL) return;
@@ -1601,13 +1360,13 @@ void GrpImpl::LoadCgm() {
 
 /*****************************************************
 *
-*   GrpImpl :: Save, Load : セーブファイル処理
+*   Grp :: Save, Load : セーブファイル処理
 *
 */
-void GrpImpl::Save(std::string& str) {
+void Grp::Save(std::string& str) {
 }
 
-void GrpImpl::Load(const char* str) {
+void Grp::Load(const char* str) {
 	status = NORMAL;
 	if (anm1 != NULL) {
 		AbortAnm();
@@ -1628,7 +1387,7 @@ void GrpImpl::Load(const char* str) {
 	music->StopCDROM(100);
 }
 
-void GrpImpl::SaveSys(string& save) {
+void Grp::SaveSys(string& save) {
 	char buf[1024];
 	save = "\n[Graphics]\n";
 	save += "CGM_CG=";
@@ -1641,7 +1400,7 @@ void GrpImpl::SaveSys(string& save) {
 	save += "\n";
 }
 
-void GrpImpl::LoadSys(const char* save) {
+void Grp::LoadSys(const char* save) {
 	cgm_data.clear();
 	save = strstr(save, "\n[Graphics]\n");
 
@@ -1668,13 +1427,13 @@ void GrpImpl::LoadSys(const char* save) 
 
 /*****************************************************
 *
-*   GrpImpl :: Wait , Exec : コマンド実行部
+*   Grp :: Wait , Exec : コマンド実行部
 *
 */
 static vector<int> drawn_images;
 static int draw_n = 0;
 extern bool grpdump_req;
-bool GrpImpl::Wait(unsigned int current_time, Cmd& cmd) {
+bool Grp::Wait(unsigned int current_time, Cmd& cmd) {
 	if (grpdump_req) {
 		grpdump_req = 0;
 		GrpObjMap::iterator it;
@@ -1751,18 +1510,18 @@ bool GrpImpl::Wait(unsigned int current_
 	return false;
 }
 
-void GrpImpl::DeleteObjPic(int num) { // object の surface のみ削除
+void Grp::DeleteObjPic(int num) { // object の surface のみ削除
 	if (grpobj.find(num) == grpobj.end()) return;
 	deleted_pic.push_back(grpobj[num].DeletePic());
 }
 
-void GrpImpl::DeleteSubObjPic(int num_grp, int num) {
+void Grp::DeleteSubObjPic(int num_grp, int num) {
 	if (grpobj.find(num_grp) == grpobj.end()) return;
 	if (grpobj[num_grp].children_obj.find(num) == grpobj[num_grp].children_obj.end()) return;
 	deleted_pic.push_back(grpobj[num_grp].children_obj[num].DeletePic());
 }
 
-void GrpImpl::DeleteObj(int num) {
+void Grp::DeleteObj(int num) {
 	if (grpobj.find(num) == grpobj.end()) return;
 	deleted_pic.push_back(grpobj[num].DeletePic());
 	GrpObjMap::iterator it;
@@ -1772,749 +1531,14 @@ void GrpImpl::DeleteObj(int num) {
 	grpobj.erase(num);
 }
 
-void GrpImpl::DeleteSubObj(int num_grp, int num) {
+void Grp::DeleteSubObj(int num_grp, int num) {
 	if (grpobj.find(num_grp) == grpobj.end()) return;
 	if (grpobj[num_grp].children_obj.find(num) == grpobj[num_grp].children_obj.end()) return;
 	deleted_pic.push_back(grpobj[num_grp].children_obj[num].DeletePic());
 	grpobj[num_grp].children_obj.erase(num);
 }
 
-void GrpImpl::impl_stackClear (Cmd& cmd) {
-	cmd.cmd_type = CMD_SAVECMDGRP_START;
-}
-
-void GrpImpl::impl_grpBuffer (Cmd& cmd) {
-	const char* name = cmd.Str(cmd.args[0]);
-	int pdt = cmd.args[1].value;
-	eprintf("load surface %s pdt %d\n",name, pdt);
-	if (pdt == 0)
-		reserved_load_surface0 = name; // 画像読み込みは 01-1f:0000 まで待つ
-	else if (pdt == 1)
-		LoadSurface(name); // 背景絵読み込み?
-	else
-		LoadSurface(name, pdt);
-	cmd.cmd_type = CMD_SAVECMDGRP;
-}
-
-void GrpImpl::impl_grpMulti(Cmd& cmd) {
-	int pos = cmd.args[0].value;
-	const char* name = cmd.Str(cmd.args[1]);
-	int sel = cmd.args[2].value;
-	eprintf("set foreground %s sel %d pos %d\n",name, sel, pos);
-	AddSurface(name);
-	StartAnm(sel);
-	event.RegisterGlobalPressFunc(&Pressed, (void*)this);
-	status = WAIT_ANM;
-	cmd.cmd_type = CMD_SAVECMDGRP_ONCE;
-}
-
-void GrpImpl::impl_grpOpen(Cmd& cmd) {
-	const char* name = cmd.Str(cmd.args[0]);
-	int sel = cmd.args[1].value;
-
-	if (name[0] == '?')
-		LoadSurface();
-	else if(cmd.cmd3 == 73)
-		LoadSurface(name, 1);
-	else
-		LoadSurface(name);
-
-	StartAnm(sel);
-	status = WAIT_ANM;
-	event.RegisterGlobalPressFunc(&Pressed, (void*)this);
-
-	if (name[0] == '?')
-		cmd.cmd_type = CMD_SAVECMDGRP_ONCE;
-	else
-		cmd.cmd_type = CMD_SAVECMDGRP_START;
-}
-
-void GrpImpl::impl_shake(Cmd& cmd) {
-	// shake screen
-	char key[11];
-	sprintf(key, "#SHAKE.%03d", cmd.args[0].value);
-	if (config->SearchParam(key) != 2) {
-		fprintf(stderr,"Cannot find shake pattern %d; use default pattern\n",cmd.args[0].value);
-		strcpy(key, "#SHAKE.000"); // default key
-	}
-	int num;
-	const int* pattern;
-	pattern = config->GetParamArray(key, num);
-	if (pattern) {
-		StartShake(num, pattern);
-		status = WAIT_SHAKE;
-	}
-	cmd.clear();
-}
-
-void GrpImpl::impl_grpCopy(Cmd& cmd) {
-	if (cmd.cmd4 == 2) { // copy (KANOGI)
-		int sx = cmd.args[0].value;
-		int sy = cmd.args[1].value;
-		int w = cmd.args[2].value - sx;
-		int h = cmd.args[3].value - sy;
-		Rect rect(sx, sy, sx+w, sy+h);
-		int src = cmd.args[4].value;
-		int dx = cmd.args[5].value;
-		int dy = cmd.args[6].value;
-		int dest = cmd.args[7].value;
-		unsigned char alpha;
-		eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
-		printf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
-		if (src == dest) {
-			DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
-			src = WORKPDT;
-		}
-		parent.Root().BlitSurface(Ssurface(src), rect, Dsurface(dest), Rect(dx,dy));
-		if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
-		cmd.clear();
-	}
-}
-
-void GrpImpl::impl_recFill(Cmd& cmd) {
-	int x = cmd.args[0].value;
-	int y = cmd.args[1].value;
-	int w = cmd.args[2].value;
-	int h = cmd.args[3].value;
-	Rect rect(x, y, x+w, y+w);
-	int pdt = cmd.args[4].value;
-	int r = cmd.args[5].value;
-	int g = cmd.args[6].value;
-	int b = cmd.args[7].value;
-
-	if (cmd.cmd4 == 2) {
-		eprintf("clear %d:(%d,%d) size (%d,%d) r %d g %d b %d\n",pdt,x,y,w,h,r,g,b);
-		DSurfaceFill(Dsurface(pdt), rect, r, g, b);
-		// if (pdt == 0) screen->ReBlit(rect);
-		cmd.cmd_type = CMD_SAVECMDGRP;
-	}
-	else if (cmd.cmd4 == 3) { // alpha つきfill
-		int a = cmd.args[8].value;
-		eprintf("alpha-clear %d:(%d,%d) size (%d,%d) r %d g %d b %d a %d\n",pdt,x,y,w,h,r,g,b,a);
-		if (a <= 0) ;
-		else if (a >= 255) DSurfaceFill(Dsurface(pdt), rect, r, g, b);
-		else {
-			DSurfaceFill(Dsurface(WORKPDT), rect, r, g, b, a);
-			parent.Root().BlitSurface(Dsurface(WORKPDT), rect, Dsurface(pdt), rect);
-		}
-		// if (pdt == 0) screen->ReBlit(rect);
-		cmd.clear();
-	}
-}
-
-void GrpImpl::impl_recCopy(Cmd& cmd) {
-	int sx = cmd.args[0].value;
-	int sy = cmd.args[1].value;
-	int w = cmd.args[2].value;
-	int h = cmd.args[3].value;
-	Rect rect(sx, sy, sx + w, sy + h);
-	int src = cmd.args[4].value;
-	int dx = cmd.args[5].value;
-	int dy = cmd.args[6].value;
-	int dest = cmd.args[7].value;
-
-	if (cmd.cmd4 == 2) {
-		eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
-		parent.Root().BlitSurface(Ssurface(src), rect, Dsurface(dest), Rect(dx,dy));
-		//DSurfaceMove(Ssurface(src), Rect(sx,sy,sx+w,sy+h), Dsurface(dest), Rect(dx,dy));
-		// if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
-		cmd.cmd_type = CMD_SAVECMDGRP;
-	}
-
-	else if (cmd.cmd4 == 3) { // alpha つきcopy
-		unsigned char alpha;
-		if (cmd.args[8].value < 0) alpha = 0;
-		else if (cmd.args[8].value > 255) alpha = 255;
-		else alpha = cmd.args[8].value;
-		eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
-		if (src == dest) {
-			DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
-			src = WORKPDT;
-		}
-		if (alpha != 0)
-			parent.Root().BlitSurface(Ssurface(src), rect, &alpha, Rect(0,0,1,1), Dsurface(dest), Rect(dx,dy), 0);
-		// if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
-		cmd.clear();
-	}
-}
-
-void GrpImpl::impl_recAdd(Cmd& cmd) {
-	if (cmd.cmd4 == 3) { // saturate mode で alpha 付き copy
-		int sx = cmd.args[0].value;
-		int sy = cmd.args[1].value;
-		int w = cmd.args[2].value;
-		int h = cmd.args[3].value;
-		Rect rect(sx, sy, sx+w, sy+h);
-		int src = cmd.args[4].value;
-		int dx = cmd.args[5].value;
-		int dy = cmd.args[6].value;
-		int dest = cmd.args[7].value;
-		unsigned char alpha;
-		if (cmd.args[8].value < 0) alpha = 0;
-		else if (cmd.args[8].value > 255) alpha = 255;
-		else alpha = cmd.args[8].value;
-		eprintf("copy surface w/ saturate %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
-		if (src == dest) {
-			DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
-			src = WORKPDT;
-		}
-		if (alpha != 0) {
-			// saturate mode : screen (picture) を一時的に作成
-			PicBase* screen_tmp = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
-			screen_tmp->SetSurface(Ssurface(src), 0, 0, PicBase::BLIT_SATURATE);
-			screen_tmp->SetSurfaceRect(rect);
-			screen_tmp->Move(dx, dy);
-			screen_tmp->SetSurfaceAlpha(&alpha, Rect(0,0,1,1));
-			screen_tmp->SimpleBlit(Dsurface(dest));
-			delete screen_tmp;
-		}
-		cmd.clear();
-	}
-}
-
-void GrpImpl::impl_grpPan(Cmd& cmd) {
-	if (cmd.cmd4 == 0) {
-		Rect r_from(cmd.args[0].value, cmd.args[1].value);
-		Rect r_to(cmd.args[2].value, cmd.args[3].value);
-		int src_pdt = cmd.args[4].value;
-		Rect r(cmd.args[5].value,cmd.args[6].value,cmd.args[7].value+1,cmd.args[8].value+1);
-		int tm = cmd.args[9].value;
-		fprintf(stderr,"??? cmd time %d\n",tm);
-		// anm1 = new ScnGrpMove(event, screen, parent.Root(), surface, r, Ssurface(2), r_from, r_to, tm);
-		// status = WAIT_ANM;
-	}
-}
-
-void GrpImpl::impl_snmBgScroll(Cmd& cmd) {
-	if (cmd.cmd4 == 0) { // スクロールする画像効果(Princess Bride)
-		if (anm2 != NULL) {
-			anm2->Abort();
-			delete anm2;
-			anm2 = NULL;
-		}
-		PicBase* pic; Surface* s;
-		Rect r(cmd.args[1].value, cmd.args[2].value, cmd.args[3].value+1, cmd.args[4].value+1);
-		const char* name = cmd.Str(cmd.args[5]);
-		Rect sr_start(cmd.args[6].value,cmd.args[7].value);
-		Rect sr_end(cmd.args[8].value,cmd.args[9].value);
-		int tm = cmd.args[10].value;
-		LoadSurface(name, 2); /* PDT2 に読み込み、と決め打ち */
-
-		anm2 = new ScnGrpMove(event, screen, parent.Root(), Dsurface(1), r, Ssurface(2), sr_start, sr_end, tm);
-		cmd.cmd_type = CMD_SAVECMDGRP;
-	}
-}
-
-void GrpImpl::impl_snmPlay(Cmd& cmd) {
-	if (cmd.cmd4 == 0) {
-		// カードが落ちるアニメーション
-		int i;
-		ScnGrpAnm* new_anm = new ScnGrpAnm(event, screen, *this);
-		if (cmd.cmd3 == 0x834 || cmd.cmd3 == 0x835) {
-			AbortAnm();
-			anm1 = new_anm;
-			if (cmd.cmd3 == 0x835) {
-				status = WAIT_ANM;
-				event.RegisterGlobalPressFunc(&Pressed, (void*)this);
-			}
-		} else {
- 			anm2 = new_anm;
-		}
-		for (i=0; i<cmd.argc; i++) {
-			const char* name = cmd.Str(cmd.args[i*3+1]);
-			int tm = cmd.args[i*3+2].value;
-			new_anm->push_back(ScnGrpAnmAtom(name,tm));
-		}
-		new_anm->CalcTotal();
-		cmd.clear();
-	}
-}
-
-void GrpImpl::impl_cgGet(Cmd& cmd) {
-	if (cmd.cmd3 == 0x5dc) // Total number of CG
-		cmd.SetSysvar(cgm_size);
-
-	if (cmd.cmd3 == 0x5dd) // Number of CG viewed
-		cmd.SetSysvar(cgm_data.size());
-
-	if (cmd.cmd3 == 0x5de) // Percentage of CG viewed
-		cmd.SetSysvar(cgm_data.size() * 100 / cgm_size);
-}
-
-void GrpImpl::impl_cgStatus(Cmd& cmd) {
-	string s = cmd.Str(cmd.args[0]);
-	if (cgm_info.find(s) == cgm_info.end()) {
-		fprintf(stderr,"cmd 01-04:05e0 : cannot find cgm-info of '%s'\n",s.c_str());
-		cmd.SetSysvar(-1);
-	}
-	else {
-		int n = cgm_info[s];
-		if (cmd.cmd3 == 1503) cmd.SetSysvar(n);
-		else {
-			if (cgm_data.find(n) == cgm_data.end()) cmd.SetSysvar(0);
-			else cmd.SetSysvar(1);
-		}
-	}
-}
-
-void GrpImpl::impl_objClear(Cmd& cmd) { //FIXME: may be broken (doesn't reflect what Haeleth says)
-	if (cmd.cmd1 == 1)
-		DeleteObj(cmd.args[0].value);
-	if (cmd.cmd1 == 2)
-		DeleteSubObj(cmd.args[0].value, cmd.args[1].value);
-	cmd.clear();
-}
-
-void GrpImpl::impl_createObj(Cmd& cmd) {
-	/**************:
-	0x47 : オブジェクト内容の設定
-			1100: G00 file
-			1003: GAN file
-			1100: rect
-			1200: string
-			1300: weather effects
-			1400: number
-	*/
-	int base_argc = 0;
-
-	if (cmd.cmd1 == 1) { // 1: group object
-		DeleteObjPic(cmd.args[0].value); // 旧ファイル名のsurfaceを削除
-		if (cmd.cmd2 == 71)
-			DeleteObjPic(cmd.args[0].value); // 旧ファイル名のsurfaceを削除
-	}
-	else { // 2: single object in group
-		DeleteSubObjPic(cmd.args[0].value, cmd.args[1].value); // 旧ファイル名のsurfaceを削除
-		if (cmd.cmd2 == 71)
-			DeleteSubObjPic(cmd.args[0].value, cmd.args[1].value); // 旧ファイル名のsurfaceを削除
-	}
-
-	GrpObj* g = (cmd.cmd2 == 71) ? &grpobj[cmd.args[0].value] : &bs_obj[cmd.args[0].value];
-	if (cmd.cmd1 == 2) // 2: single object in a group
-		g = &g->children_obj[cmd.args[1].value];
-
-	if (cmd.cmd1 == 2)
-		base_argc = 1;
-
-	if (cmd.cmd3 == 1000) { /* ファイル名設定 */
-		g->gtype = GrpObj::FILE; //FIXME: Strange thing in the main menu; that happens with objComposite
-		string name = cmd.Str(cmd.args[base_argc + 1]);
-		if (name.find('?') != -1) {
-			//Maybe it's for shading or something like that?
-			printf("Warning: the part after the '?' was removed: '%s'\n", name.c_str());
-			name.erase(name.find('?')); // '?' 以降の意味がわからない
-		}
-		g->name = name;
-	} else if (cmd.cmd3 == 1003) { /* ファイル名設定(GAN含む) */
-		g->gtype = GrpObj::GAN;
-		if (cmd.Str(cmd.args[base_argc + 1]) == string("???"))
-			g->name = cmd.Str(cmd.args[base_argc + 2]);
-		else
-			g->name = cmd.Str(cmd.args[base_argc + 1]);
-		g->gan_name = cmd.Str(cmd.args[base_argc + 2]);
-
-		if (cmd.cmd4 >= 1 && cmd.args[base_argc + 3].value == 0)
-			g->attr =  GrpObj::Attribute(g->attr | GrpObj::HIDDEN);
-		else
-			g->attr =  GrpObj::Attribute(g->attr & ~(GrpObj::HIDDEN));
-
-		if (cmd.argc >= base_argc + 5)
-			g->SetPos(1, cmd.args[base_argc + 4].value, -cmd.args[base_argc + 5].value);
-
-		if (g->name.find('?') != -1) {
-			g->name.erase(g->name.find('?'));
-			g->gan_name = cmd.Str(cmd.args[base_argc + 2]);
-		}
-	} else if (cmd.cmd3 == 1200) { // 画像を文字列として指定
-		g->gtype = GrpObj::MOJI;
-		g->print_moji = cmd.Str(cmd.args[base_argc + 1]);
-		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::HIDDEN)); // 常に表示がデフォルト?
-		cmd.clear();
-	} else if (cmd.cmd3 == 1400) { // 数値を画像として表示
-		g->gtype = GrpObj::DIGIT;
-		g->name = cmd.Str(cmd.args[base_argc + 1]);
-	}
-
-	CreateObj(cmd.args[0].value);
-	if (cmd.cmd1 == 2)
-		CreateSubObj(cmd.args[0].value, cmd.args[1].value);
-
-	if (cmd.cmd3 == 1000 || cmd.cmd3 == 1003 || cmd.cmd3 == 1200 || cmd.cmd3 == 1400) {
-		// FILE, GAN, MOJI, DIGIT ならば座標等の設定を行う
-		if (cmd.cmd4 >= 1) {
-			if (cmd.args[2+base_argc].value == 0) {
-				g->attr = GrpObj::Attribute(g->attr | GrpObj::HIDDEN);
-			} else {
-				g->attr = GrpObj::Attribute(g->attr & (~GrpObj::HIDDEN));
-			}
-			SetObjChanged(cmd.args[0].value);
-		}
-		if (cmd.cmd4 >= 2) { // 座標等も設定
-			g->SetPos(0, cmd.args[3+base_argc].value, cmd.args[4+base_argc].value);
-		}
-		if ( (cmd.cmd3 == 1000 || cmd.cmd3 == 1003) && cmd.cmd4 >= 3) { // pattern 番号も設定
-			g->SetSurfaceNum(cmd.args[5+base_argc].value);
-			base_argc++; // 1000 (FILE) / 1003 (GAN) の場合のみこのオプションは存在する
-		}
-		cmd.clear();
-	} else {
-		fprintf(stderr,"CreateObj : cmd.cmd3 = %04x ; not supported!\n",cmd.cmd3);
-	}
-}
-
-void GrpImpl::impl_gan(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg);
-
-	if (cmd.cmd3 == 3) { // ganIsPlaying
-		if (g->anm == NULL || g->anm->IsEnd())
-			cmd.SetSysvar(0);
-		else
-			cmd.SetSysvar(1);
-	}
-	else if (cmd.cmd3 == 1000) { // ganStop
-		if (g->anm == NULL || g->anm->IsEnd())
-			g->SetSurfaceNum(cmd.args[1].value);
-		else {
-			g->anm->Abort();
-			g->SetSurfaceNum(cmd.args[1].value);
-		}
-		SetObjChanged(cmd.args[0].value);
-		cmd.clear();
-	}
-	else if (cmd.cmd3 == 2003) { // objPlay
-		g->CreateGanSpecial(event, 0, cmd.args[1].value);
-		// g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
-		SetObjChanged(cmd.args[0].value);
-		cmd.clear();
-	}
-	else if (cmd.cmd3 == 3001 || cmd.cmd3 == 3003 || cmd.cmd3 == 3005 ||
-			 cmd.cmd3 == 1001 || cmd.cmd3 == 1003 || cmd.cmd3 == 1005) { // ganPlay*
-		g->CreateGan(event, cmd.args[1].value);
-		// g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
-		SetObjChanged(cmd.args[0].value);
-		cmd.clear();
-	}
-}
-
-void GrpImpl::impl_objSetPos(Cmd& cmd) {
-	//obj or objBg
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	int index, x, y;
-	if (cmd.cmd3 == 1006 || cmd.cmd3 == 2006) { //objAdjust
-		index = cmd.args[1+base_arg].value + 1;
-		x = cmd.args[2+base_arg].value;
-		y = cmd.args[3+base_arg].value;
-	}
-	else {
-		index = 0;
-		if (cmd.cmd3 == 1000) {
-			x = cmd.args[1+base_arg].value;
-			y = cmd.args[2+base_arg].value;
-		}
-		else {
-			g->GetPos(index, x, y);
-			if (cmd.cmd3 == 1001)
-				x = cmd.args[1+base_arg].value;
-			else
-				y = cmd.args[1+base_arg].value;
-		}
-	}
-
-	g->SetPos(index, x, y);
-	cmd.clear();
-}
-
-void GrpImpl::impl_objAlpha(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	g->SetAlpha(cmd.args[base_arg + 1].value);
-	cmd.clear();
-}
-
-void GrpImpl::impl_objShow(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	if (cmd.args[base_arg + 1].value)
-		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::HIDDEN));
-	else
-		g->attr = GrpObj::Attribute(g->attr | GrpObj::HIDDEN);
-
-	g->attr = GrpObj::Attribute(g->attr | GrpObj::UPDATE_VISIBLE);
-		// グループ単位で次の RefreshObj で表示・消去
-	if (cmd.cmd2 == 0x51) //not Bg
-		SetObjChanged(cmd.args[0].value);
-	cmd.clear();
-}
-
-void GrpImpl::impl_objColour(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	g->print_r = cmd.args[base_arg+1].value;
-	g->print_g = cmd.args[base_arg+2].value;
-	g->print_b = cmd.args[base_arg+3].value;
-	g->SetUpdate();
-	cmd.clear();
-}
-
-void GrpImpl::impl_objComposite(Cmd& cmd) {//FIXME
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	if (cmd.args[base_arg + 1].value == 1) {
-		g->attr = GrpObj::Attribute(g->attr | GrpObj::SATURATE);
-		cmd.clear();
-	} else if (cmd.args[base_arg + 1].value == 0) {
-		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::SATURATE));
-		cmd.clear();
-	}
-	g->SetUpdate();
-}
-
-void GrpImpl::impl_objSetText(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	g->print_moji = cmd.Str(cmd.args[base_arg + 1]);
-	g->SetUpdate();
-	cmd.clear();
-}
-
-void GrpImpl::impl_objTextOpts(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	// 画像を文字列として設定:文字の大きさなど
-	g->print_size = cmd.args[base_arg + 1].value;
-	/* 前景色を得る */
-	int cr, cg, cb;
-	char key[17];
-	sprintf(key, "#COLOR_TABLE.%03d", cmd.args[base_arg + 5].value);
-	if (config->GetParam(key, 3, &cr, &cg, &cb)) { // color not found
-		cr = cg = cb = 0;
-	}
-	g->print_r = cr;
-	g->print_g = cg;
-	g->print_b = cb;
-	g->SetUpdate();
-	cmd.clear();
-}
-
-void GrpImpl::impl_objOrder(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	int order = cmd.args[base_arg + 1].value;
-	g->order = order;
-	ZMoveObj(cmd.args[0].value);
-	cmd.clear();
-}
-
-void GrpImpl::impl_objDispArea(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	// オブジェクトのどの部分を画面に表示するか(クリップ領域)の設定
-	int rx, ry, w, h;
-	if (cmd.args.size() == base_arg + 5) {
-		int rx = cmd.args[base_arg + 1].value;
-		int ry = cmd.args[base_arg + 2].value;
-		int w = cmd.args[base_arg + 3].value;
-		int h = cmd.args[base_arg + 4].value;
-		if (cmd.cmd3 == 1005) {
-			w -= rx;
-			h -= ry;
-		}
-	}
-	else {
-		rx = ry = 0;
-		w = screen->Width();
-		h = screen->Height();
-	}
-	g->SetClipArea(rx, ry, w, h); //TODO: case when cmd.args.size() == 1
-	cmd.clear();
-}
-
-void GrpImpl::impl_objSetDigits(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	g->dig_number = cmd.args[base_arg + 1].value;
-	g->SetUpdate();
-	cmd.clear();
-}
-
-void GrpImpl::impl_objNumOpts(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	g->dig_digit = cmd.args[base_arg + 1].value;
-	int attr = g->attr;
-	attr &= ~(GrpObj::DIG_ZERO | GrpObj::DIG_SIGN | GrpObj::DIG_PACK);
-	if (cmd.args[base_arg + 2].value) attr |= GrpObj::DIG_ZERO;
-	if (cmd.args[base_arg + 3].value) attr |= GrpObj::DIG_SIGN;
-	if (cmd.args[base_arg + 4].value) attr |= GrpObj::DIG_PACK;
-	g->attr = GrpObj::Attribute(attr);
-	g->SetUpdate();
-	cmd.clear();
-}
-
-void GrpImpl::impl_objPattNo(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	g->SetSurfaceNum(cmd.args[base_arg + 1].value);
-	cmd.clear();
-}
-
-void GrpImpl::impl_objScale(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	int zoom = (cmd.args[base_arg + 1].value + cmd.args[base_arg + 2].value)/2; //FIXME: eurk
-	zoom = zoom*256/100;
-	g->SetZoomRotate(zoom, -1);
-	cmd.clear();
-}
-
-void GrpImpl::impl_objRotate(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
-	int angle = cmd.args[base_arg + 1].value;
-	angle /= 10;
-	if (angle < 0) {
-		angle %= 360;
-		angle += 360;
-	}
-	angle %= 360;
-	g->SetZoomRotate(-1, angle);
-	cmd.clear();
-}
-
-void GrpImpl::impl_objPosDims(Cmd& cmd) {
-	int base_arg = 0;
-	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, true);
-
-	VarInfo arg1 = cmd.args[base_arg + 1];
-	VarInfo arg2 = cmd.args[base_arg + 2];
-
-	int val1, val2;
-
-	if (cmd.cmd3 == 1000)
-		g->GetPos(0, val1, val2);
-	else if (cmd.cmd3 == 1100)
-		g->GetSrcGeom(val1, val2);
-
-	cmd.SetFlagvar(arg1, val1);
-	cmd.SetFlagvar(arg2, val2);
-}
-
-void GrpImpl::impl_refresh(Cmd& cmd) {
-	// 本来は grpstack clear らしい
-	RefreshObj();
-	// Princess Bride の中途 Staff roll
-	// このタイミングで描画するのが都合がいいので、
-	//シナリオループを抜けて描画を起動
-	cmd.cmd_type = CMD_WAITFRAMEUPDATE;
-}
-
-void GrpImpl::impl_bgmLoop(Cmd& cmd) {
-	if (cmd.cmd4 == 0 || cmd.cmd4 == 2) {
-		int count = 8000;
-		if (cmd.cmd3 == 2)
-			count = 0; //bgmPlay, play once
-		music->PlayCDROM((char*)cmd.Str(cmd.args[0]), count);
-		cmd.cmd_type = CMD_SAVECMD_ONCE;
-	}
-}
-
-void GrpImpl::impl_bgmStop(Cmd& cmd) {
-	if (cmd.cmd4 == 0) {
-		if (cmd.cmd3 == 5)
-			music->StopCDROM(0);
-		else if (cmd.cmd3 == 105)
-			music->StopCDROM(cmd.args[0].value);
-		cmd.cmd_type = CMD_SAVECMD_ONCE;
-	}
-}
-
-void GrpImpl::impl_playWav(Cmd& cmd) {
-	if (cmd.cmd3 == 2) {
-		music->PlaySE(cmd.Str(cmd.args[0]), 1); //loop
-		cmd.cmd_type = CMD_SAVECMD_ONCE;
-	}
-	else {
-		music->PlaySE(cmd.Str(cmd.args[0]));
-		cmd.clear();
-	}
-	if (cmd.cmd3 == 1)
-		status = WAIT_SE;
-}
-
-void GrpImpl::impl_playSE(Cmd& cmd) {
-	music->PlaySE(cmd.args[0].value);
-	cmd.clear();
-}
-
-void GrpImpl::impl_stopWav(Cmd& cmd) {
-	if (cmd.cmd3 == 5)
-		music->StopSE();
-	else if (cmd.cmd3 == 105)
-		music->StopSE(cmd.args[0].value);
-
-	cmd.cmd_type = CMD_SAVECMD_ONCE;
-}
-
-void GrpImpl::impl_SetVolMod(Cmd& cmd) {
-	music->volmod[cmd.cmd3-0x8b6] = cmd.args[0].value;
-	config->SetParam("#VOLMOD", 4, music->volmod[0], music->volmod[1], music->volmod[2], music->volmod[3]);
-	cmd.clear();
-}
-
-void GrpImpl::impl_GetVolMod(Cmd& cmd) {
-	cmd.SetSysvar(music->volmod[cmd.cmd3-0x91a]);
-}
-
-void GrpImpl::impl_koePlay(Cmd& cmd) {
-	eprintf("play koe %d",cmd.args[0].value);
-	if (cmd.cmd4 == 1) {
-		eprintf(", para? %d",cmd.args[1].value);
-	}
-	eprintf("\n");
-	char buf[1024]; sprintf(buf, "%d",cmd.args[0].value);
-	if ( !(skip_mode & SKIP_TEXT)) music->PlayKoe(buf);
-	cmd.clear();
-}
-
-/*It may be useful... or not.
-void GrpImpl::impl_objSwap(Cmd& cmd) {
-	if (cmd.cmd1 == 1 && cmd.args.size() == 2) {
-		SwapObj(cmd.args[0].value, cmd.args[1].value);
-	}
-	cmd.clear();
-}*/
-
-void GrpImpl::impl_movPlay(Cmd& cmd) {
-	if ( cmd.cmd4 == 0) {
-		const char* str = cmd.Str(cmd.args[0]);
-		int x = cmd.args[1].value;
-		int y = cmd.args[2].value;
-		int x2 = cmd.args[3].value;
-		int y2 = cmd.args[4].value;
-		eprintf("play movie ; name %s pos %d,%d - %d,%d\n",str,x,y,x2,y2);
-		music->PlayMovie(str, x, y, x2, y2,1);
-		status = WAIT_MOVIE;
-		event.RegisterGlobalPressFunc(&Pressed, (void*)this);
-		cmd.clear();
-	}
-}
-
-void GrpImpl::Exec(Cmd& cmd) {
+void Grp::Exec(Cmd& cmd) {
 	if (cmd.cmd_type == CMD_TEXTEND) {
 		music->StopKoe(500); // テキスト終了で声を止める
 		cmd.clear();
@@ -2555,47 +1579,3 @@ void GrpImpl::Exec(Cmd& cmd) {
 	}
 }
 
-
-/********************************************************
-**
-**	class Grp
-*/
-
-Grp::Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm) {
-	pimpl = new GrpImpl(_event, _parent, f, _cgm);
-}
-
-Grp::~Grp() {
-	delete pimpl;
-}
-
-bool Grp::Wait(unsigned int current_time, Cmd& cmd) {
-	return pimpl->Wait(current_time, cmd);
-}
-
-void Grp::Exec(Cmd& cmd) {
-	pimpl->Exec(cmd);
-}
-
-void Grp::SetSkipMode(SkipMode mode) {
-	pimpl->SetSkipMode(mode);
-}
-
-void Grp::InitSel(void) {
-	pimpl->InitSel();
-}
-
-void Grp::Save(std::string& str) {
-	pimpl->Save(str);
-}
-
-void Grp::Load(const char* str) {
-	pimpl->Load(str);
-}
-void Grp::SaveSys(std::string& str) {
-	pimpl->SaveSys(str);
-}
-
-void Grp::LoadSys(const char* str) {
-	pimpl->LoadSys(str);
-}
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_grp.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2009 Thibaut GIRKA
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SCN2K_GRP_H__
+#define __SCN2K_GRP_H__
+
+#include <set>
+
+#include "scn2k_cmd.h"
+#include "window/widget.h"
+
+using namespace std;
+
+void dprintf(const char* fmt, ...); //FIXME
+void eprintf(const char* fmt, ...); //FIXME
+
+struct SEL {
+	Rect from;
+	Rect to;
+	int time;
+	int sel_no;
+	int args[8];
+	SEL() : from(0,0), to(0,0) {}
+};
+
+struct GrpObj;
+typedef std::map<int, GrpObj> GrpObjMap;
+
+/*******************************************************************
+** GrpObj(interface)
+*/
+
+struct GrpObj {
+	string name;
+	string gan_name;
+	PicContainer* pic_parent;
+	PicBase* picture;
+	WidAnmTime* anm;
+	int _posx, _posy;
+	int posx[9], posy[9];
+	Rect clip_area;
+	unsigned char alpha;
+	int order;
+	int surface_num;
+
+	GrpObjMap children_obj;
+
+	string print_moji;
+	int print_size, print_r, print_b, print_g;
+
+	int dig_number, dig_digit;
+
+	// zoom / rotate ≫
+	int zoom; // 256  1 
+	int rotate; // 0-360綺
+
+	vector<Rect> src_pos;
+	enum GrpType { FILLRECT = 1, FILE = 2, GAN = 3, MOJI = 4, DIGIT = 5} gtype;
+	enum Attribute { NONE=0, WIPEON=1, SATURATE=2, HIDDEN=4,
+		UPDATE_PICTURE = 16, UPDATE_POS = 32, UPDATE_ALPHA = 64, UPDATE_SNUM = 128, UPDATE_CLIP = 256, UPDATE_VISIBLE = 512,
+		UPDATE_ALL = (UPDATE_PICTURE | UPDATE_POS | UPDATE_ALPHA | UPDATE_SNUM | UPDATE_CLIP | UPDATE_VISIBLE),
+		ANM_PLAYSTART = 0x8000, ANM_PLAYING = 0x10000,
+		DIG_ZERO = 0x10000*2, DIG_SIGN = 0x10000*4, DIG_PACK=0x10000*8,DIG_SPACE=0x10000*16
+		};
+	Attribute attr;
+
+	GrpObj(void);
+	~GrpObj(void);
+
+	void SetPos(int index, int x, int y);
+	void GetPos(int index, int& x, int& y);
+	int PosX(void);
+	int PosY(void);
+	void SetAlpha(void);
+	void SetAlpha(int alpha);
+	void SetSurfaceNum(int num = -1);
+	void SetZoomRotate(int zoom=-1, int rotate=-1);
+	void SetClipArea(int x, int y, int width, int height);
+	void GetSrcGeom(int& width, int& height);
+	void SetUpdate(void);
+	void UpdateMoji(void);
+	void UpdateDigit(void);
+	void UpdateSurface(void);
+	void ZoomRotate(void);
+	void Refresh(GrpObj& parent_obj);
+	void _debug_Dump(int, int);
+	void Update(void);
+	void CreateSurface(PicContainer* parent);
+	void CreateGan(Event::Container& event, int event_number);
+	void CreateGanSpecial(Event::Container& event, int event_number, int time);
+	PicBase* DeletePic(void);
+};
+
+
+/*******************************************************************
+** Grp
+*/
+
+class Grp : public CommandHandler {
+#define MAXPDT 256
+#define WORKPDT 255
+	private:
+		void CreateObj(int number);
+		void CreateSubObj(int grp_num, int number);
+		void ZMoveObj(int number);
+		void SetObjChanged(int number);
+		void SwapObj(int a1, int a2);
+		void DeleteObjPic(int num);// object  surface 水
+		void DeleteSubObjPic(int grp_num, int num);
+		void DeleteObj(int num);
+		void DeleteSubObj(int grp_num, int num);
+		void RefreshObj(void);
+
+		Surface* Dsurface(int pdt);
+		Surface* Ssurface(int pdt);
+
+		// cgmode 糸∫
+		void LoadCgm(void);
+
+	public:
+		Grp(Event::Container& _event, PicContainer& _parent, const Flags& _flag, set<int>& _cgm_data);
+		~Grp();
+		bool Wait(unsigned int current_time, Cmd& cmd);
+		void Exec(Cmd& cmd);
+		void InitSel(void);
+		void Save(std::string& str);
+		void Load(const char* str);
+		void SaveSys(std::string& str);
+		void LoadSys(const char* str);
+		void SetSkipMode(SkipMode _mode);
+		void LoadSurface(const char* str, int pdt);
+
+	private:
+		void LoadSurface(const char* str);
+		void LoadSurface(void);
+		void AddSurface(const char* str);
+
+		void StartAnm(int type);
+		void StartShake(int total, const int* pattern);
+		void AbortAnm(void);
+		static bool Pressed(int x, int y, void* pointer);
+
+		GrpObj* GetGraphicObj(int grp, bool fg=true);
+		GrpObj* GetGraphicObj(int grp, int index, bool fg=true);
+		GrpObj* GetGraphicObjVarMode(Cmd& cmd, int &base_arg, bool fg=true);
+
+		// Opcode handling
+		void impl_stackClear(Cmd& cmd);
+		void impl_grpBuffer(Cmd& cmd);
+		void impl_grpMulti(Cmd &cmd);
+		void impl_grpOpen(Cmd &cmd);
+		void impl_shake(Cmd &cmd);
+		void impl_grpCopy(Cmd &cmd);
+		void impl_recFill(Cmd &cmd);
+		void impl_recCopy(Cmd &cmd);
+		void impl_recAdd(Cmd &cmd);
+		void impl_grpPan(Cmd &cmd);
+		void impl_snmPlay(Cmd &cmd);
+		void impl_snmBgScroll(Cmd &cmd);
+		void impl_cgGet(Cmd &cmd);
+		void impl_cgStatus(Cmd &cmd);
+		void impl_objClear(Cmd &cmd);
+		void impl_createObj(Cmd &cmd);
+		void impl_gan(Cmd &cmd);
+		void impl_objSetPos(Cmd &cmd);
+		void impl_objAlpha(Cmd &cmd);
+		void impl_objShow(Cmd &cmd);
+		void impl_objColour(Cmd &cmd);
+		void impl_objComposite(Cmd &cmd);
+		void impl_objSetText(Cmd &cmd);
+		void impl_objTextOpts(Cmd &cmd);
+		void impl_objOrder(Cmd &cmd);
+		void impl_objDispArea(Cmd &cmd);
+		void impl_objSetDigits(Cmd &cmd);
+		void impl_objNumOpts(Cmd &cmd);
+		void impl_objPattNo(Cmd &cmd);
+		void impl_objScale(Cmd &cmd);
+		void impl_objRotate(Cmd &cmd);
+		void impl_objPosDims(Cmd &cmd);
+		void impl_refresh(Cmd &cmd);
+		void impl_bgmLoop(Cmd &cmd);
+		void impl_bgmStop(Cmd &cmd);
+		void impl_playWav(Cmd &cmd);
+		void impl_playSE(Cmd &cmd);
+		void impl_stopWav(Cmd &cmd);
+		void impl_SetVolMod(Cmd &cmd);
+		void impl_GetVolMod(Cmd &cmd);
+		void impl_koePlay(Cmd &cmd);
+		void impl_movPlay(Cmd &cmd);
+
+	public:
+		class AyuSysConfig *config;
+
+	private:
+		Event::Container& event;
+		const Flags& flags;
+		PicBase* screen;
+		PicBase* screen_front;
+		Surface* surface, *surface_update;
+
+		Surface* dsurface[MAXPDT]; // 吾莨若水純 Surface
+		Surface* ssurface[MAXPDT]; // <ゃ絎合茯粋昭帥水純倶 Surface
+		PicContainer& parent;
+
+		// 糸号篆絖
+		WidAnmTime* anm1, *anm2;
+		typedef enum { NORMAL, WAIT_ANM, WAIT_SHAKE, WAIT_SE, WAIT_MOVIE} Status;
+		Status status;
+		SkipMode skip_mode;
+
+		std::string bg_name;
+		std::map<int, SEL> anmtype;
+		GrpObjMap grpobj;
+		GrpObjMap bs_obj;
+
+		std::map<std::string, int> cgm_info;
+		set<int>& cgm_data;
+		int cgm_size;
+
+		class MuSys *music;
+
+		std::set<int> changed_obj;
+		string reserved_load_surface0;
+		vector<PicBase*> deleted_pic;
+};
+
+
+/******************************************************************
+**
+**	class ScnGrp*
+*/
+/* Princess Bride: 祉筝睡Щ絎茖 */
+
+struct ScnGrpMove : public WidAnmTime {
+	Surface* dest;
+	Surface* src;
+	PicRoot& root;
+	Rect dest_r, from, to;
+	ScnGrpMove(Event::Container& container, PicBase* _pic, PicRoot& root, Surface* dest, const Rect& _dest_r, Surface* src, const Rect& from, const Rect& to, int total_time);
+	void Exec(int count);
+};
+
+/* Princess Bride: 若<≪<若激с */
+
+struct ScnGrpAnmAtom {
+	string name;
+	int time;
+	ScnGrpAnmAtom(const char* _n, int _t) : name(_n), time(_t) {}
+};
+
+struct ScnGrpAnm : public WidAnmTime, vector<ScnGrpAnmAtom> {
+	Grp& owner;
+	ScnGrpAnm(Event::Container& container, PicBase* _pic, Grp& _owner) :
+		WidAnmTime(container, _pic, 0), owner(_owner) {
+	}
+	void CalcTotal(void);
+	void Exec(int count);
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_grpimpl.cc
@@ -0,0 +1,767 @@
+/*
+ * Copyright (c) 2009 Thibaut GIRKA
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "scn2k_grp.h"
+#include "system/system_config.h"
+#include "music2/music.h"
+#include "window/render.h"
+
+void Grp::impl_stackClear (Cmd& cmd) {
+	cmd.cmd_type = CMD_SAVECMDGRP_START;
+}
+
+void Grp::impl_grpBuffer (Cmd& cmd) {
+	const char* name = cmd.Str(cmd.args[0]);
+	int pdt = cmd.args[1].value;
+	eprintf("load surface %s pdt %d\n",name, pdt);
+	if (pdt == 0)
+		reserved_load_surface0 = name; // 糸顄粋昭帥 01-1f:0000 障у
+	else if (pdt == 1)
+		LoadSurface(name); // 腟笈粋昭随
+	else
+		LoadSurface(name, pdt);
+	cmd.cmd_type = CMD_SAVECMDGRP;
+}
+
+void Grp::impl_grpMulti(Cmd& cmd) {
+	int pos = cmd.args[0].value;
+	const char* name = cmd.Str(cmd.args[1]);
+	int sel = cmd.args[2].value;
+	eprintf("set foreground %s sel %d pos %d\n",name, sel, pos);
+	AddSurface(name);
+	StartAnm(sel);
+	event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+	status = WAIT_ANM;
+	cmd.cmd_type = CMD_SAVECMDGRP_ONCE;
+}
+
+void Grp::impl_grpOpen(Cmd& cmd) {
+	const char* name = cmd.Str(cmd.args[0]);
+	int sel = cmd.args[1].value;
+
+	if (name[0] == '?')
+		LoadSurface();
+	else if(cmd.cmd3 == 73)
+		LoadSurface(name, 1);
+	else
+		LoadSurface(name);
+
+	StartAnm(sel);
+	status = WAIT_ANM;
+	event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+
+	if (name[0] == '?')
+		cmd.cmd_type = CMD_SAVECMDGRP_ONCE;
+	else
+		cmd.cmd_type = CMD_SAVECMDGRP_START;
+}
+
+void Grp::impl_shake(Cmd& cmd) {
+	// shake screen
+	char key[11];
+	sprintf(key, "#SHAKE.%03d", cmd.args[0].value);
+	if (config->SearchParam(key) != 2) {
+		fprintf(stderr,"Cannot find shake pattern %d; use default pattern\n",cmd.args[0].value);
+		strcpy(key, "#SHAKE.000"); // default key
+	}
+	int num;
+	const int* pattern;
+	pattern = config->GetParamArray(key, num);
+	if (pattern) {
+		StartShake(num, pattern);
+		status = WAIT_SHAKE;
+	}
+	cmd.clear();
+}
+
+void Grp::impl_grpCopy(Cmd& cmd) {
+	if (cmd.cmd4 == 2) { // copy (KANOGI)
+		int sx = cmd.args[0].value;
+		int sy = cmd.args[1].value;
+		int w = cmd.args[2].value - sx;
+		int h = cmd.args[3].value - sy;
+		Rect rect(sx, sy, sx+w, sy+h);
+		int src = cmd.args[4].value;
+		int dx = cmd.args[5].value;
+		int dy = cmd.args[6].value;
+		int dest = cmd.args[7].value;
+		unsigned char alpha;
+		eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+		printf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+		if (src == dest) {
+			DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
+			src = WORKPDT;
+		}
+		parent.Root().BlitSurface(Ssurface(src), rect, Dsurface(dest), Rect(dx,dy));
+		if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
+		cmd.clear();
+	}
+}
+
+void Grp::impl_recFill(Cmd& cmd) {
+	int x = cmd.args[0].value;
+	int y = cmd.args[1].value;
+	int w = cmd.args[2].value;
+	int h = cmd.args[3].value;
+	Rect rect(x, y, x+w, y+w);
+	int pdt = cmd.args[4].value;
+	int r = cmd.args[5].value;
+	int g = cmd.args[6].value;
+	int b = cmd.args[7].value;
+
+	if (cmd.cmd4 == 2) {
+		eprintf("clear %d:(%d,%d) size (%d,%d) r %d g %d b %d\n",pdt,x,y,w,h,r,g,b);
+		DSurfaceFill(Dsurface(pdt), rect, r, g, b);
+		// if (pdt == 0) screen->ReBlit(rect);
+		cmd.cmd_type = CMD_SAVECMDGRP;
+	}
+	else if (cmd.cmd4 == 3) { // alpha ゃfill
+		int a = cmd.args[8].value;
+		eprintf("alpha-clear %d:(%d,%d) size (%d,%d) r %d g %d b %d a %d\n",pdt,x,y,w,h,r,g,b,a);
+		if (a <= 0) ;
+		else if (a >= 255) DSurfaceFill(Dsurface(pdt), rect, r, g, b);
+		else {
+			DSurfaceFill(Dsurface(WORKPDT), rect, r, g, b, a);
+			parent.Root().BlitSurface(Dsurface(WORKPDT), rect, Dsurface(pdt), rect);
+		}
+		// if (pdt == 0) screen->ReBlit(rect);
+		cmd.clear();
+	}
+}
+
+void Grp::impl_recCopy(Cmd& cmd) {
+	int sx = cmd.args[0].value;
+	int sy = cmd.args[1].value;
+	int w = cmd.args[2].value;
+	int h = cmd.args[3].value;
+	Rect rect(sx, sy, sx + w, sy + h);
+	int src = cmd.args[4].value;
+	int dx = cmd.args[5].value;
+	int dy = cmd.args[6].value;
+	int dest = cmd.args[7].value;
+
+	if (cmd.cmd4 == 2) {
+		eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+		parent.Root().BlitSurface(Ssurface(src), rect, Dsurface(dest), Rect(dx,dy));
+		//DSurfaceMove(Ssurface(src), Rect(sx,sy,sx+w,sy+h), Dsurface(dest), Rect(dx,dy));
+		// if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
+		cmd.cmd_type = CMD_SAVECMDGRP;
+	}
+
+	else if (cmd.cmd4 == 3) { // alpha ゃcopy
+		unsigned char alpha;
+		if (cmd.args[8].value < 0) alpha = 0;
+		else if (cmd.args[8].value > 255) alpha = 255;
+		else alpha = cmd.args[8].value;
+		eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+		if (src == dest) {
+			DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
+			src = WORKPDT;
+		}
+		if (alpha != 0)
+			parent.Root().BlitSurface(Ssurface(src), rect, &alpha, Rect(0,0,1,1), Dsurface(dest), Rect(dx,dy), 0);
+		// if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
+		cmd.clear();
+	}
+}
+
+void Grp::impl_recAdd(Cmd& cmd) {
+	if (cmd.cmd4 == 3) { // saturate mode  alpha 篁 copy
+		int sx = cmd.args[0].value;
+		int sy = cmd.args[1].value;
+		int w = cmd.args[2].value;
+		int h = cmd.args[3].value;
+		Rect rect(sx, sy, sx+w, sy+h);
+		int src = cmd.args[4].value;
+		int dx = cmd.args[5].value;
+		int dy = cmd.args[6].value;
+		int dest = cmd.args[7].value;
+		unsigned char alpha;
+		if (cmd.args[8].value < 0) alpha = 0;
+		else if (cmd.args[8].value > 255) alpha = 255;
+		else alpha = cmd.args[8].value;
+		eprintf("copy surface w/ saturate %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+		if (src == dest) {
+			DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
+			src = WORKPDT;
+		}
+		if (alpha != 0) {
+			// saturate mode : screen (picture) 筝篏
+			PicBase* screen_tmp = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
+			screen_tmp->SetSurface(Ssurface(src), 0, 0, PicBase::BLIT_SATURATE);
+			screen_tmp->SetSurfaceRect(rect);
+			screen_tmp->Move(dx, dy);
+			screen_tmp->SetSurfaceAlpha(&alpha, Rect(0,0,1,1));
+			screen_tmp->SimpleBlit(Dsurface(dest));
+			delete screen_tmp;
+		}
+		cmd.clear();
+	}
+}
+
+void Grp::impl_grpPan(Cmd& cmd) {
+	if (cmd.cmd4 == 0) {
+		Rect r_from(cmd.args[0].value, cmd.args[1].value);
+		Rect r_to(cmd.args[2].value, cmd.args[3].value);
+		int src_pdt = cmd.args[4].value;
+		Rect r(cmd.args[5].value,cmd.args[6].value,cmd.args[7].value+1,cmd.args[8].value+1);
+		int tm = cmd.args[9].value;
+		fprintf(stderr,"??? cmd time %d\n",tm);
+		// anm1 = new ScnGrpMove(event, screen, parent.Root(), surface, r, Ssurface(2), r_from, r_to, tm);
+		// status = WAIT_ANM;
+	}
+}
+
+void Grp::impl_snmBgScroll(Cmd& cmd) {
+	if (cmd.cmd4 == 0) { // 鴻若糸号(Princess Bride)
+		if (anm2 != NULL) {
+			anm2->Abort();
+			delete anm2;
+			anm2 = NULL;
+		}
+		PicBase* pic; Surface* s;
+		Rect r(cmd.args[1].value, cmd.args[2].value, cmd.args[3].value+1, cmd.args[4].value+1);
+		const char* name = cmd.Str(cmd.args[5]);
+		Rect sr_start(cmd.args[6].value,cmd.args[7].value);
+		Rect sr_end(cmd.args[8].value,cmd.args[9].value);
+		int tm = cmd.args[10].value;
+		LoadSurface(name, 2); /* PDT2 茯粋昭帥羆冴 */
+
+		anm2 = new ScnGrpMove(event, screen, parent.Root(), Dsurface(1), r, Ssurface(2), sr_start, sr_end, tm);
+		cmd.cmd_type = CMD_SAVECMDGRP;
+	}
+}
+
+void Grp::impl_snmPlay(Cmd& cmd) {
+	if (cmd.cmd4 == 0) {
+		// 若純<≪<若激с
+		int i;
+		ScnGrpAnm* new_anm = new ScnGrpAnm(event, screen, *this);
+		if (cmd.cmd3 == 0x834 || cmd.cmd3 == 0x835) {
+			AbortAnm();
+			anm1 = new_anm;
+			if (cmd.cmd3 == 0x835) {
+				status = WAIT_ANM;
+				event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+			}
+		} else {
+ 			anm2 = new_anm;
+		}
+		for (i=0; i<cmd.argc; i++) {
+			const char* name = cmd.Str(cmd.args[i*3+1]);
+			int tm = cmd.args[i*3+2].value;
+			new_anm->push_back(ScnGrpAnmAtom(name,tm));
+		}
+		new_anm->CalcTotal();
+		cmd.clear();
+	}
+}
+
+void Grp::impl_cgGet(Cmd& cmd) {
+	if (cmd.cmd3 == 0x5dc) // Total number of CG
+		cmd.SetSysvar(cgm_size);
+
+	if (cmd.cmd3 == 0x5dd) // Number of CG viewed
+		cmd.SetSysvar(cgm_data.size());
+
+	if (cmd.cmd3 == 0x5de) // Percentage of CG viewed
+		cmd.SetSysvar(cgm_data.size() * 100 / cgm_size);
+}
+
+void Grp::impl_cgStatus(Cmd& cmd) {
+	string s = cmd.Str(cmd.args[0]);
+	if (cgm_info.find(s) == cgm_info.end()) {
+		fprintf(stderr,"cmd 01-04:05e0 : cannot find cgm-info of '%s'\n",s.c_str());
+		cmd.SetSysvar(-1);
+	}
+	else {
+		int n = cgm_info[s];
+		if (cmd.cmd3 == 1503) cmd.SetSysvar(n);
+		else {
+			if (cgm_data.find(n) == cgm_data.end()) cmd.SetSysvar(0);
+			else cmd.SetSysvar(1);
+		}
+	}
+}
+
+void Grp::impl_objClear(Cmd& cmd) { //FIXME: may be broken (doesn't reflect what Haeleth says)
+	if (cmd.cmd1 == 1)
+		DeleteObj(cmd.args[0].value);
+	if (cmd.cmd1 == 2)
+		DeleteSubObj(cmd.args[0].value, cmd.args[1].value);
+	cmd.clear();
+}
+
+void Grp::impl_createObj(Cmd& cmd) {
+	/**************:
+	0x47 : 吾с絎鴻荐絎
+			1100: G00 file
+			1003: GAN file
+			1100: rect
+			1200: string
+			1300: weather effects
+			1400: number
+	*/
+	int base_argc = 0;
+
+	if (cmd.cmd1 == 1) { // 1: group object
+		DeleteObjPic(cmd.args[0].value); // с<ゃsurface
+		if (cmd.cmd2 == 71)
+			DeleteObjPic(cmd.args[0].value); // с<ゃsurface
+	}
+	else { // 2: single object in group
+		DeleteSubObjPic(cmd.args[0].value, cmd.args[1].value); // с<ゃsurface
+		if (cmd.cmd2 == 71)
+			DeleteSubObjPic(cmd.args[0].value, cmd.args[1].value); // с<ゃsurface
+	}
+
+	GrpObj* g = (cmd.cmd2 == 71) ? &grpobj[cmd.args[0].value] : &bs_obj[cmd.args[0].value];
+	if (cmd.cmd1 == 2) // 2: single object in a group
+		g = &g->children_obj[cmd.args[1].value];
+
+	if (cmd.cmd1 == 2)
+		base_argc = 1;
+
+	if (cmd.cmd3 == 1000) { /* <ゃ荐絎 */
+		g->gtype = GrpObj::FILE; //FIXME: Strange thing in the main menu; that happens with objComposite
+		string name = cmd.Str(cmd.args[base_argc + 1]);
+		if (name.find('?') != -1) {//TODO
+			//Used for shading, with DAT/tcdata.tcc or other filename provided by #TONECURVE_FILENAME
+			printf("Warning: the part after the '?' was removed: '%s'\n", name.c_str());
+			name.erase(name.find('?')); // '?' 篁ラ潟
+		}
+		g->name = name;
+	} else if (cmd.cmd3 == 1003) { /* <ゃ荐絎(GAN) */
+		g->gtype = GrpObj::GAN;
+		if (cmd.Str(cmd.args[base_argc + 1]) == string("???"))
+			g->name = cmd.Str(cmd.args[base_argc + 2]);
+		else
+			g->name = cmd.Str(cmd.args[base_argc + 1]);
+		g->gan_name = cmd.Str(cmd.args[base_argc + 2]);
+
+		if (cmd.cmd4 >= 1 && cmd.args[base_argc + 3].value == 0)
+			g->attr =  GrpObj::Attribute(g->attr | GrpObj::HIDDEN);
+		else
+			g->attr =  GrpObj::Attribute(g->attr & ~(GrpObj::HIDDEN));
+
+		if (cmd.argc >= base_argc + 5)
+			g->SetPos(1, cmd.args[base_argc + 4].value, -cmd.args[base_argc + 5].value);
+
+		if (g->name.find('?') != -1) {
+			g->name.erase(g->name.find('?'));
+			g->gan_name = cmd.Str(cmd.args[base_argc + 2]);
+		}
+	} else if (cmd.cmd3 == 1200) { // 糸絖絎
+		g->gtype = GrpObj::MOJI;
+		g->print_moji = cmd.Str(cmd.args[base_argc + 1]);
+		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::HIDDEN)); // 絽吾茵腓冴鐚
+		cmd.clear();
+	} else if (cmd.cmd3 == 1400) { // 医ゃ糸茵腓
+		g->gtype = GrpObj::DIGIT;
+		g->name = cmd.Str(cmd.args[base_argc + 1]);
+	}
+
+	CreateObj(cmd.args[0].value);
+	if (cmd.cmd1 == 2)
+		CreateSubObj(cmd.args[0].value, cmd.args[1].value);
+
+	if (cmd.cmd3 == 1000 || cmd.cmd3 == 1003 || cmd.cmd3 == 1200 || cmd.cmd3 == 1400) {
+		// FILE, GAN, MOJI, DIGIT 医婚罔膈荐絎茵
+		if (cmd.cmd4 >= 1) {
+			if (cmd.args[2+base_argc].value == 0) {
+				g->attr = GrpObj::Attribute(g->attr | GrpObj::HIDDEN);
+			} else {
+				g->attr = GrpObj::Attribute(g->attr & (~GrpObj::HIDDEN));
+			}
+			SetObjChanged(cmd.args[0].value);
+		}
+		if (cmd.cmd4 >= 2) { // 綺ф膈荐絎
+			g->SetPos(0, cmd.args[3+base_argc].value, cmd.args[4+base_argc].value);
+		}
+		if ( (cmd.cmd3 == 1000 || cmd.cmd3 == 1003) && cmd.cmd4 >= 3) { // pattern 垩荐絎
+			g->SetSurfaceNum(cmd.args[5+base_argc].value);
+			base_argc++; // 1000 (FILE) / 1003 (GAN) 翫帥激с潟絖
+		}
+		cmd.clear();
+	} else {
+		fprintf(stderr,"CreateObj : cmd.cmd3 = %04x ; not supported!\n",cmd.cmd3);
+	}
+}
+
+void Grp::impl_gan(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg);
+
+	if (cmd.cmd3 == 3) { // ganIsPlaying
+		if (g->anm == NULL || g->anm->IsEnd())
+			cmd.SetSysvar(0);
+		else
+			cmd.SetSysvar(1);
+	}
+	else if (cmd.cmd3 == 1000) { // ganStop
+		if (g->anm == NULL || g->anm->IsEnd())
+			g->SetSurfaceNum(cmd.args[1].value);
+		else {
+			g->anm->Abort();
+			g->SetSurfaceNum(cmd.args[1].value);
+		}
+		SetObjChanged(cmd.args[0].value);
+		cmd.clear();
+	}
+	else if (cmd.cmd3 == 2003) { // objPlay
+		g->CreateGanSpecial(event, 0, cmd.args[1].value);
+		// g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
+		SetObjChanged(cmd.args[0].value);
+		cmd.clear();
+	}
+	else if (cmd.cmd3 == 3001 || cmd.cmd3 == 3003 || cmd.cmd3 == 3005 ||
+			 cmd.cmd3 == 1001 || cmd.cmd3 == 1003 || cmd.cmd3 == 1005) { // ganPlay*
+		g->CreateGan(event, cmd.args[1].value);
+		// g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
+		SetObjChanged(cmd.args[0].value);
+		cmd.clear();
+	}
+}
+
+void Grp::impl_objSetPos(Cmd& cmd) {
+	//obj or objBg
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	int index, x, y;
+	if (cmd.cmd3 == 1006 || cmd.cmd3 == 2006) { //objAdjust
+		index = cmd.args[1+base_arg].value + 1;
+		x = cmd.args[2+base_arg].value;
+		y = cmd.args[3+base_arg].value;
+	}
+	else {
+		index = 0;
+		if (cmd.cmd3 == 1000) {
+			x = cmd.args[1+base_arg].value;
+			y = cmd.args[2+base_arg].value;
+		}
+		else {
+			g->GetPos(index, x, y);
+			if (cmd.cmd3 == 1001)
+				x = cmd.args[1+base_arg].value;
+			else
+				y = cmd.args[1+base_arg].value;
+		}
+	}
+
+	g->SetPos(index, x, y);
+	cmd.clear();
+}
+
+void Grp::impl_objAlpha(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	g->SetAlpha(cmd.args[base_arg + 1].value);
+	cmd.clear();
+}
+
+void Grp::impl_objShow(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	if (cmd.args[base_arg + 1].value)
+		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::HIDDEN));
+	else
+		g->attr = GrpObj::Attribute(g->attr | GrpObj::HIDDEN);
+
+	g->attr = GrpObj::Attribute(g->attr | GrpObj::UPDATE_VISIBLE);
+		// 違若篏ф< RefreshObj ц;腓冴紙サ
+	if (cmd.cmd2 == 0x51) //not Bg
+		SetObjChanged(cmd.args[0].value);
+	cmd.clear();
+}
+
+void Grp::impl_objColour(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	g->print_r = cmd.args[base_arg+1].value;
+	g->print_g = cmd.args[base_arg+2].value;
+	g->print_b = cmd.args[base_arg+3].value;
+	g->SetUpdate();
+	cmd.clear();
+}
+
+void Grp::impl_objComposite(Cmd& cmd) {//FIXME
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	if (cmd.args[base_arg + 1].value == 1) {
+		g->attr = GrpObj::Attribute(g->attr | GrpObj::SATURATE);
+		cmd.clear();
+	} else if (cmd.args[base_arg + 1].value == 0) {
+		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::SATURATE));
+		cmd.clear();
+	}
+	g->SetUpdate();
+}
+
+void Grp::impl_objSetText(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	g->print_moji = cmd.Str(cmd.args[base_arg + 1]);
+	g->SetUpdate();
+	cmd.clear();
+}
+
+void Grp::impl_objTextOpts(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	// 糸絖荐絎鐚絖紊с
+	g->print_size = cmd.args[base_arg + 1].value;
+	/* 蚊緇 */
+	int cr, cg, cb;
+	char key[17];
+	sprintf(key, "#COLOR_TABLE.%03d", cmd.args[base_arg + 5].value);
+	if (config->GetParam(key, 3, &cr, &cg, &cb)) { // color not found
+		cr = cg = cb = 0;
+	}
+	g->print_r = cr;
+	g->print_g = cg;
+	g->print_b = cb;
+	g->SetUpdate();
+	cmd.clear();
+}
+
+void Grp::impl_objOrder(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	int order = cmd.args[base_arg + 1].value;
+	g->order = order;
+	ZMoveObj(cmd.args[0].value);
+	cmd.clear();
+}
+
+void Grp::impl_objDispArea(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	// 吾с脂≪茵腓冴鐚鐚荐絎
+	int rx, ry, w, h;
+	if (cmd.args.size() == base_arg + 5) {
+		int rx = cmd.args[base_arg + 1].value;
+		int ry = cmd.args[base_arg + 2].value;
+		int w = cmd.args[base_arg + 3].value;
+		int h = cmd.args[base_arg + 4].value;
+		if (cmd.cmd3 == 1005) {
+			w -= rx;
+			h -= ry;
+		}
+	}
+	else {
+		rx = ry = 0;
+		w = screen->Width();
+		h = screen->Height();
+	}
+	g->SetClipArea(rx, ry, w, h); //TODO: case when cmd.args.size() == 1
+	cmd.clear();
+}
+
+void Grp::impl_objSetDigits(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	g->dig_number = cmd.args[base_arg + 1].value;
+	g->SetUpdate();
+	cmd.clear();
+}
+
+void Grp::impl_objNumOpts(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	g->dig_digit = cmd.args[base_arg + 1].value;
+	int attr = g->attr;
+	attr &= ~(GrpObj::DIG_ZERO | GrpObj::DIG_SIGN | GrpObj::DIG_PACK);
+	if (cmd.args[base_arg + 2].value) attr |= GrpObj::DIG_ZERO;
+	if (cmd.args[base_arg + 3].value) attr |= GrpObj::DIG_SIGN;
+	if (cmd.args[base_arg + 4].value) attr |= GrpObj::DIG_PACK;
+	g->attr = GrpObj::Attribute(attr);
+	g->SetUpdate();
+	cmd.clear();
+}
+
+void Grp::impl_objPattNo(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	g->SetSurfaceNum(cmd.args[base_arg + 1].value);
+	cmd.clear();
+}
+
+void Grp::impl_objScale(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	int zoom = (cmd.args[base_arg + 1].value + cmd.args[base_arg + 2].value)/2; //FIXME: eurk
+	zoom = zoom*256/100;
+	g->SetZoomRotate(zoom, -1);
+	cmd.clear();
+}
+
+void Grp::impl_objRotate(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
+
+	int angle = cmd.args[base_arg + 1].value;
+	angle /= 10;
+	if (angle < 0) {
+		angle %= 360;
+		angle += 360;
+	}
+	angle %= 360;
+	g->SetZoomRotate(-1, angle);
+	cmd.clear();
+}
+
+void Grp::impl_objPosDims(Cmd& cmd) {
+	int base_arg = 0;
+	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, true);
+
+	VarInfo arg1 = cmd.args[base_arg + 1];
+	VarInfo arg2 = cmd.args[base_arg + 2];
+
+	int val1, val2;
+
+	if (cmd.cmd3 == 1000)
+		g->GetPos(0, val1, val2);
+	else if (cmd.cmd3 == 1100)
+		g->GetSrcGeom(val1, val2);
+
+	cmd.SetFlagvar(arg1, val1);
+	cmd.SetFlagvar(arg2, val2);
+}
+
+void Grp::impl_refresh(Cmd& cmd) {
+	// ャ grpstack clear 
+	RefreshObj();
+	// Princess Bride 筝 Staff roll
+	// 帥ゃ潟違ф祉遵с
+	//激若祉莎桁
+	cmd.cmd_type = CMD_WAITFRAMEUPDATE;
+}
+
+void Grp::impl_bgmLoop(Cmd& cmd) {
+	if (cmd.cmd4 == 0 || cmd.cmd4 == 2) {
+		int count = 8000;
+		if (cmd.cmd3 == 2)
+			count = 0; //bgmPlay, play once
+		music->PlayCDROM((char*)cmd.Str(cmd.args[0]), count);
+		cmd.cmd_type = CMD_SAVECMD_ONCE;
+	}
+}
+
+void Grp::impl_bgmStop(Cmd& cmd) {
+	if (cmd.cmd4 == 0) {
+		if (cmd.cmd3 == 5)
+			music->StopCDROM(0);
+		else if (cmd.cmd3 == 105)
+			music->StopCDROM(cmd.args[0].value);
+		cmd.cmd_type = CMD_SAVECMD_ONCE;
+	}
+}
+
+void Grp::impl_playWav(Cmd& cmd) {
+	if (cmd.cmd3 == 2) {
+		music->PlaySE(cmd.Str(cmd.args[0]), 1); //loop
+		cmd.cmd_type = CMD_SAVECMD_ONCE;
+	}
+	else {
+		music->PlaySE(cmd.Str(cmd.args[0]));
+		cmd.clear();
+	}
+	if (cmd.cmd3 == 1)
+		status = WAIT_SE;
+}
+
+void Grp::impl_playSE(Cmd& cmd) {
+	music->PlaySE(cmd.args[0].value);
+	cmd.clear();
+}
+
+void Grp::impl_stopWav(Cmd& cmd) {
+	if (cmd.cmd3 == 5)
+		music->StopSE();
+	else if (cmd.cmd3 == 105)
+		music->StopSE(cmd.args[0].value);
+
+	cmd.cmd_type = CMD_SAVECMD_ONCE;
+}
+
+void Grp::impl_SetVolMod(Cmd& cmd) {
+	music->volmod[cmd.cmd3-0x8b6] = cmd.args[0].value;
+	config->SetParam("#VOLMOD", 4, music->volmod[0], music->volmod[1], music->volmod[2], music->volmod[3]);
+	cmd.clear();
+}
+
+void Grp::impl_GetVolMod(Cmd& cmd) {
+	cmd.SetSysvar(music->volmod[cmd.cmd3-0x91a]);
+}
+
+void Grp::impl_koePlay(Cmd& cmd) {
+	eprintf("play koe %d",cmd.args[0].value);
+	if (cmd.cmd4 == 1) {
+		eprintf(", para? %d",cmd.args[1].value);
+	}
+	eprintf("\n");
+	char buf[1024]; sprintf(buf, "%d",cmd.args[0].value);
+	if ( !(skip_mode & SKIP_TEXT)) music->PlayKoe(buf);
+	cmd.clear();
+}
+
+/*It may be useful... or not.
+void Grp::impl_objSwap(Cmd& cmd) {
+	if (cmd.cmd1 == 1 && cmd.args.size() == 2) {
+		SwapObj(cmd.args[0].value, cmd.args[1].value);
+	}
+	cmd.clear();
+}*/
+
+void Grp::impl_movPlay(Cmd& cmd) {
+	if ( cmd.cmd4 == 0) {
+		const char* str = cmd.Str(cmd.args[0]);
+		int x = cmd.args[1].value;
+		int y = cmd.args[2].value;
+		int x2 = cmd.args[3].value;
+		int y2 = cmd.args[4].value;
+		eprintf("play movie ; name %s pos %d,%d - %d,%d\n",str,x,y,x2,y2);
+		music->PlayMovie(str, x, y, x2, y2,1);
+		status = WAIT_MOVIE;
+		event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+		cmd.clear();
+	}
+}
--- a/scn2k/scn2k_text.cc
+++ b/scn2k/scn2k_text.cc
@@ -9,7 +9,7 @@ TODO:
 			Start すると文字を描画開始する。クリックで全描画。
 			Flush するとバッファ内の文字をすべて描画する
 			Wait すると全描画後、クリックされるまでカーソルを表示するまで待つ
-		TextImpl 側の状態としては Wait のみを持つ (PREPAREに戻るのを待つ)
+		Text 側の状態としては Wait のみを持つ (PREPAREに戻るのを待つ)
 		ただし、Skip の権利はどっちがもつ?(現状は?)
 
 	GrpObj: NextObj と GrpObj を分離。CreateObj は現状通り、Visible=1 時に行う。
@@ -55,219 +55,24 @@ DONE:
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "window/event.h"
-#include "window/picture.h"
-#include "window/widget.h"
+#include "scn2k_text.h"
+
 #include "system/file.h"
-#include "system/system_config.h"
 #include "scn2k.h"
 
 #include <string>
 using namespace std;
 
-// kanji conv : デバッグ表示用
-void kconv(const unsigned char* src, unsigned char* dest);
-void kconv_rev(const unsigned char* src, unsigned char* dest);
-string kconv(const string& s);
-string kconv_rev(const string& s);
-// render.cc
-void DSurfaceFillA(Surface* src, const Rect& rect, int r, int g, int b, int a); // テキストウィンドウ背景の設定
-void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect); // コピー
+#include "window/render.h"
 
 /**************************************************************::
 **
-**	TextImpl(interface)
+**	Text(implementation)
 */
-struct TimerAtom {
-	int from;
-	int to;
-	unsigned int start_time;
-	unsigned int total_time;
-};
-
-struct TextWindow {
-/* @@@ : SetWindowColor での surface 再設定に注意 */
-	WidText* wid;
-	bool name_visible;
-	WidLabel* name;
-	PicContainer* name_container;
-	PicBase* face;
-	PicBase* face_pics[8];
-	TextWindow(PicContainer& parent, Event::Container& event, int window_no, void* callback);
-	~TextWindow() {
-		if (name_container != NULL) {
-			delete name_container;
-			name_container = NULL;
-		}
-		int i;
-		for (i=0; i<8; i++) {
-			if (face_pics[i] != NULL) {
-				delete face_pics[i];
-				face_pics[i] = NULL;
-			}
-		}
-		if (wid != NULL) {
-			delete wid;
-			wid = NULL;
-		}
-	}
-	Rect WakuSize(PicContainer& pic, int waku_no);
-	void MakeWaku(PicContainer& pic, Event::Container& event, int waku_no,int window_no, bool* use_btn, void* callback);
-	void show(void) {
-		wid->show();
-		if (name_container && name_visible) name_container->show();
-		if (face) face->show();
-	}
-	void hide(void) {
-		wid->hide();
-		if (name_container) name_container->hide();
-		if (face) face->hide();
-	}
-	void ShowFace(const char* path) {
-		if (!face) return;
-		face->SetSurface( path, 0,0);
-	}
-	void ResetFace(void) {
-		if (!face) return;
-		face->SetSurface( (Surface*)0, 0,0);
-	}
-	void StartText(const TextStream& _stream) {
-		wid->Clear();
-		wid->stream = _stream;
-		if (name_container) {
-			char namestr[1024];
-			namestr[0] = 0;
-			wid->stream.RemoveName(namestr, 1024);
-			if (namestr[0] == 0) {
-				name_container->hide();
-			} else {
-				if (name) {
-					name_container->show_all();
-					name->SetText(namestr);
-				}
-			}
-		}
-		wid->Start();
-	}
-	void SetName(const char* n) {
-		if (name_container && name) {
-			if (n[0]) {
-				name_container->show();
-				name->SetText(n);
-				name_visible = true;
-			} else {
-				name_container->hide();
-				name_visible = false;
-			}
-		}
-	}
-};
-
-class TextImpl : public CommandHandler {
-	public:
-		TextImpl(Event::Container& _event, PicContainer& _parent, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item);
-		~TextImpl();
-		void InitWindow(void);
-		void SetWindowColor(int r, int g, int b, int a, bool is_transparent);
-		void SetTextSpeed(int new_speed);
-		void SetTextWait(int new_wait);
-		void CreateSelect(Cmd& cmd);
-		void Exec(Cmd& cmd);
-		bool Wait(unsigned int current_time, Cmd& cmd);
-		void hide(void);
-		void show(void) { show(text_window_number); }
-		void show(int num);
-		void DrawBacklog(BacklogItem& item, Cmd& cmd);
-		void Save(std::string& str, bool select_save);
-		void Load(const char* str);
-		void SetSkipMode(SkipMode _mode);
-		void CreateSelBG(void);
-
-		void AddText(const char* str);
-
-		static void PressFuncSkip(void* pointer, WidButton* from);
-		static void PressFuncLoad(void* pointer, WidButton* from);
-		static void PressFuncSave(void* pointer, WidButton* from);
-		static void PressFuncBacklog(void* pointer, WidButton* from);
-		static void PressFuncBacklogFwd(void* pointer, WidButton* from);
-
-	private:
-		static void PressFuncButton(void* pointer, WidButton* from);
-		static bool PressFunc(int x, int y, void* pointer);
-		void SetCursor(int num);
-
-	public:
-		TextWindow* text;
-		typedef enum {NORMAL=0, WAIT_TEXT=1, WAIT=2,
-			WAIT_CLICK=3, WAIT_ABORT=4, WAIT_CLICK_MOUSEPOS = 5,
-			WAIT_CLICK_MOUSEPOSEND_L = 6, WAIT_CLICK_MOUSEPOSEND_R = 7,
-			WAIT_SELECT_INBOX = 10, WAIT_SELECT_OUTBOX=11, WAIT_SELECT_VALUE = 12,
-			WAIT_EXTRN_MASK = 64, SAVEMASK = 128, LOADMASK = 256, SKIPMASK = 512,
-			CLEARSCR_MASK = 1024, STATSAVE_MASK = 2048, CLEARSCR_WAIT_MASK=(1<<12),
-			SKIPEND_MASK = (1<<13), BACKLOG_MASK=(1<<14), BACKLOG_MASK_FWD=(1<<15),
-			BACKLOG_MASK_KOE=(1<<16), BACKLOG_WAIT_MASK=(1<<17),
-			ALLMASK = (CLEARSCR_MASK | WAIT_EXTRN_MASK | SAVEMASK |
-						LOADMASK | SKIPMASK | BACKLOG_MASK | BACKLOG_MASK_FWD |
-						BACKLOG_MASK_KOE | BACKLOG_WAIT_MASK | STATSAVE_MASK |
-						CLEARSCR_WAIT_MASK | SKIPEND_MASK)
-		} Status;
-		Status status, status_saved, status_mask;
-
-	private:
-		std::string ruby_text;
-		bool ruby_text_flag;
-		unsigned int wait_time;
-		unsigned int old_time;
-		unsigned int base_time;
-		int text_window_number;
-		bool text_parsing;
-		TextStream text_stream;
-		SkipMode skip_mode;
-		int save_selectcount;
-
-		std::map<int, TimerAtom> timer_var;
-		std::vector<WidTextButton*> selects;
-		std::vector<int> sel_backlog_pos;
-		string replace_name[26];
-		string replace_name2[26];
-		PicContainer* sel_widget;
-		PicWidget* backlog_widget;
-
-		vector<BacklogItem>& backlog;
-		BacklogItem& backlog_item;
-		BacklogItem cur_backlog_item;
-		BacklogItem drawn_backlog_item;
-
-		TextWindow* widgets[32];
-		WidTimeCursor* kcursor;
-		Surface* sel_bg1;
-		Surface* sel_bg2;
-		Rect sel_bg_rect;
-
-		VarInfo wait_savedvar[2];
-
-		AyuSysConfig *config;
-
-		Event::Container& event;
-		PicContainer& parent;
-
-		//Opcode handling
-		void impl_txtClear(Cmd& cmd);
-		void impl_logKoe(Cmd& cmd);
-		void impl_pause(Cmd& cmd);
-		void impl_br(Cmd& cmd);
-		void impl_FaceOpen(Cmd& cmd);
-		void impl_FaceClear(Cmd& cmd);
-};
-
-/**************************************************************::
-**
-**	TextImpl(implementation)
-*/
-TextImpl::TextImpl(Event::Container& _event, PicContainer& _parent, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item) :
-	text(0),status(TextImpl::NORMAL), status_saved(TextImpl::NORMAL), status_mask(TextImpl::NORMAL), ruby_text_flag(false),
+Text::Text(Event::Container& _event, PicContainer& _parent) :
+	text(0),status(Text::NORMAL), status_saved(Text::NORMAL), status_mask(Text::NORMAL), ruby_text_flag(false),
 	old_time(0), base_time(0), text_window_number(0), text_parsing(false), skip_mode(SKIP_NO), save_selectcount(0), sel_widget(0),
-	backlog_widget(0), backlog(parent_backlog), backlog_item(parent_backlog_item), parent(_parent), event(_event),
+	backlog_widget(0), parent(_parent), event(_event),
 	kcursor(0), sel_bg1(0), sel_bg2(0), sel_bg_rect(0,0,0,0) {
 	config = AyuSysConfig::GetInstance();
 	int i;
@@ -277,35 +82,54 @@ TextImpl::TextImpl(Event::Container& _ev
 	text_stream.kanji_type = TextStream::sjis;
 	event.RegisterGlobalPressFunc(&PressFunc, (void*)this);
 
-	RegisterCommand(1, 33, 73, "grpOpenBg", (CmdImpl) &TextImpl::impl_txtClear);
-	RegisterCommand(1, 33, 75, "grpMulti", (CmdImpl) &TextImpl::impl_txtClear);
-	RegisterCommand(1, 33, 76, "grpOpen", (CmdImpl) &TextImpl::impl_txtClear);
+	RegisterCommand(1, 33, 73, "grpOpenBg", (CmdImpl) &Text::impl_txtClear);
+	RegisterCommand(1, 33, 75, "grpMulti", (CmdImpl) &Text::impl_txtClear);
+	RegisterCommand(1, 33, 76, "grpOpen", (CmdImpl) &Text::impl_txtClear);
 
-	RegisterCommand(1, 23, 0, "koePlay", (CmdImpl) &TextImpl::impl_logKoe);
-	RegisterCommand(1, 23, 8, "koeDoPlay", (CmdImpl) &TextImpl::impl_logKoe);
+	RegisterCommand(1, 23, 0, "koePlay", (CmdImpl) &Text::impl_logKoe);
+	RegisterCommand(1, 23, 8, "koeDoPlay", (CmdImpl) &Text::impl_logKoe);
 
-	RegisterCommand(0, 3, 151, "msgHide", (CmdImpl) &TextImpl::impl_txtClear);
-	RegisterCommand(0, 3, 17, "pause", (CmdImpl) &TextImpl::impl_pause);
-	RegisterCommand(0, 3, 3, "par", (CmdImpl) &TextImpl::impl_br); //FIXME
-	RegisterCommand(0, 3, 201, "br", (CmdImpl) &TextImpl::impl_br);
-	RegisterCommand(0, 3, 1000, "FaceOpen", (CmdImpl) &TextImpl::impl_FaceOpen);
-	RegisterCommand(0, 3, 1001, "FaceClear", (CmdImpl) &TextImpl::impl_FaceClear);
+	RegisterCommand(0, 3, 151, "msgHide", (CmdImpl) &Text::impl_txtClear);
+	RegisterCommand(0, 3, 17, "pause", (CmdImpl) &Text::impl_pause);
+	RegisterCommand(0, 3, 3, "par", (CmdImpl) &Text::impl_br); //FIXME
+	RegisterCommand(0, 3, 201, "br", (CmdImpl) &Text::impl_br);
+	RegisterCommand(0, 3, 1000, "FaceOpen", (CmdImpl) &Text::impl_FaceOpen);
+	RegisterCommand(0, 3, 1001, "FaceClear", (CmdImpl) &Text::impl_FaceClear);
+	RegisterCommand(0, 3, 120, "__doruby", (CmdImpl) &Text::impl_doRuby); //FIXME: I don't know how it works
+	RegisterCommand(0, 3, 102, "TextWindow", (CmdImpl) &Text::impl_TextWindow);
+	RegisterCommand(0, 3, 103, "FastText", NULL);//FIXME: (CmdImpl) &Text::impl_FastText);
+	RegisterCommand(0, 3, 104, "NormalText", NULL);
+	RegisterCommand(0, 3, 152, "msgClear", (CmdImpl) &Text::impl_msgClear);
+
+	RegisterCommand(0, 2, 1, "select", (CmdImpl) &Text::impl_createSelect);
+	RegisterCommand(0, 2, 3, "select2?", (CmdImpl) &Text::impl_createSelect); //What difference with select?
+
+	RegisterCommand(0, 4, 1000, "ShowBackground", (CmdImpl) &Text::impl_ShowBackground);
+	RegisterCommand(0, 4, 1100, "SetSkipMode", (CmdImpl) &Text::impl_SetSkipMode);
+	RegisterCommand(1, 4, 100, "wait", (CmdImpl) &Text::impl_Wait);
+	RegisterCommand(1, 4, 111, "time", (CmdImpl) &Text::impl_Wait);
+	RegisterCommand(1, 4, 121, "timeEx", (CmdImpl) &Text::impl_Wait);
 }
 
-TextImpl::~TextImpl() {
-	if (sel_widget) delete sel_widget;
+Text::~Text() {
+	if (sel_widget != NULL)
+		delete sel_widget;
 	int i;
 	for (i=0; i<32; i++) {
-		if (widgets[i]) delete widgets[i];
+		if (widgets[i] != NULL)
+			delete widgets[i];
 	}
-	if (backlog_widget) delete backlog_widget;
-	if (sel_bg1) parent.Root().DeleteSurface(sel_bg1);
-	if (sel_bg2) parent.Root().DeleteSurface(sel_bg2);
+	if (backlog_widget != NULL)
+		delete backlog_widget;
+	if (sel_bg1 != NULL)
+		parent.Root().DeleteSurface(sel_bg1);
+	if (sel_bg2 != NULL)
+		parent.Root().DeleteSurface(sel_bg2);
 	event.DeleteGlobalPressFunc(&PressFunc, (void*)this);
 }
 
-bool TextImpl::PressFunc(int x, int y, void* pointer) {
-	TextImpl* t = (TextImpl*)pointer;
+bool Text::PressFunc(int x, int y, void* pointer) {
+	Text* t = (Text*)pointer;
 	if (t->status == WAIT_CLICK) {
 		t->status = WAIT_ABORT;
 	} else if (t->status == WAIT_CLICK_MOUSEPOS) {
@@ -328,8 +152,9 @@ bool TextImpl::PressFunc(int x, int y, v
 	}
 	return true; // event not deleted
 }
-void TextImpl::PressFuncButton(void* pointer, WidButton* from) {
-	TextImpl* t = (TextImpl*)pointer;
+
+void Text::PressFuncButton(void* pointer, WidButton* from) {
+	Text* t = (Text*)pointer;
 	if (t->status != WAIT_SELECT_INBOX && t->status != WAIT_SELECT_OUTBOX) return;
 	vector<WidTextButton*>::iterator it;
 	int sel = 0;
@@ -337,14 +162,13 @@ void TextImpl::PressFuncButton(void* poi
 		if (from == *it) break;
 	}
 	if (it == t->selects.end()) {
-		fprintf(stderr,"TextImpl::PressFuncButton: Cannot find select widget\n");
+		fprintf(stderr,"Text::PressFuncButton: Cannot find select widget\n");
 		return;
 	}
 	t->status = Status(WAIT_SELECT_VALUE + sel);
-	return;
 }
 
-void TextImpl::SetSkipMode(SkipMode _mode) {
+void Text::SetSkipMode(SkipMode _mode) {
 	if ( (skip_mode & SKIP_IN_MENU) && (_mode & SKIP_IN_MENU) == 0) {
 		if (status_mask & BACKLOG_WAIT_MASK) { // backlog mode から復帰
 			status_mask = Status(status_mask & (~(BACKLOG_MASK|BACKLOG_MASK_FWD|BACKLOG_MASK_KOE|BACKLOG_WAIT_MASK)));
@@ -375,67 +199,50 @@ void TextImpl::SetSkipMode(SkipMode _mod
 	skip_mode = _mode;
 }
 
-/* hash_map が欲しい……*/
-#include <map>
-#include <list>
-struct SaveFaceHash { // バックログセーブ時の顔画像管理を行う
-	map<string, int> facetonum;
-	typedef pair<string,int> Node;
-	typedef list<Node> List;
-	List container;
-	int id_max;
-	static int size_max;
-	SaveFaceHash() : id_max(0) {
-	}
-	void NewNode(string face, int face_id) {
-		facetonum[face] = face_id;
-		container.push_front(Node(face, face_id));
-		if (container.size() > size_max) {
-			Node remove = container.back();
-			container.pop_back();
-			facetonum.erase(remove.first);
+void Text::InitWindow(void) {
+	int i;
+	int w;
+	std::string str;
+
+	for (w=0; w<32; w++) {
+		widgets[w] = new TextWindow(parent, event, w, (void*)this);
+		if (widgets[w]->wid == 0) {
+			delete widgets[w];
+			widgets[w] = NULL;
 		}
 	}
-	int Add(string face) {
-		int id; int ret = -1;
-		int i; List::iterator it;
-		if (face.empty()) return -1;
-		if (facetonum.find(face) == facetonum.end()) {
-			id = ++id_max;
-			NewNode(face, id);
-			ret = -1;
-		} else {
-			id = facetonum[face];
-			for (i=0, it=container.begin(); it != container.end(); i++, it++) {
-				if (it->second == id) {
-					ret = i;
-					Node n = *it;
-					container.erase(it);
-					container.push_front(n);
-					break;
-				}
-			}
-		}
-		return ret;
+	SetCursor(0);
+	for (i=0; i<26; i++) {
+		char buf[1024];
+		sprintf(buf, "#NAME.%c", i+'A');
+		const char* s = config->GetParaStr(buf);
+		if (s != NULL) replace_name[i] = s;
 	}
-	string Get(int num) {
-		if (num < 0) return "";
-		List::iterator it = container.begin();
-		for (; it != container.end(); it++) {
-			if (num == 0) return it->first;
-			num--;
-		}
-		return "";
-	}
-};
+	// replace_name2 : 初期設定
+	// 渚、秋生、渚 (CLANNAD)
+	char name_nagisa[3] = {'\x8f', '\x8d', '\0'};
+	char name_akio[5] = {'\x8f', '\x48', '\x90', '\xb6', '\0'};
+	replace_name2[0] = name_nagisa;
+	replace_name2[1] = name_akio;
+	replace_name2[2] = name_nagisa;
+	text = NULL;
+	/* テキスト速度の設定 */
+	int speed, mod, wait, auto_mod;
+	config->GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
+	config->GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &mod);
+	config->GetParam("#MESSAGE_KEY_WAIT_USE", 1, &auto_mod);
+	config->GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
+	if (mod) speed = -1;
+	if (!auto_mod) wait = -1;
+	SetTextSpeed(speed);
+	SetTextWait(wait);
+}
 
-int SaveFaceHash::size_max = 20;
-
-void TextImpl::Save(string& str, bool rollback_save) {
+void Text::Save(string& str, bool rollback_save) {
 	char buf[1024];
 	str = "\n";
-	str += "[TextImpl Window]\n";
-	sprintf(buf, "TextImplWindow=%d\n",text_window_number);
+	str += "[Text Window]\n";
+	sprintf(buf, "TextWindow=%d\n",text_window_number);
 	str += buf;
 	if (rollback_save) {
 		++save_selectcount;
@@ -458,53 +265,55 @@ void TextImpl::Save(string& str, bool ro
 	if (!rollback_save) {
 		SaveFaceHash face_log;
 		do {
-		int cur_scn = -1; int cur_pos = -1;
-		sprintf(buf, "Backlog.%d=",++cnt);
-		str += buf;
-		for (; it != backlog.end(); it++) {
-			buf[0] = 0; int buflen = 0;
-			if (it->scn == -1) continue;
-			if (it->pos == -1 && it->scn != 0) continue;
+			int cur_scn = -1; int cur_pos = -1;
+			sprintf(buf, "Backlog.%d=",++cnt);
+			str += buf;
+			for (; it != backlog.end(); it++) {
+				buf[0] = 0;
+				int buflen = 0;
+				if (it->scn == -1)
+					continue;
+				if (it->pos == -1 && it->scn != 0)
+					continue;
 
-			buf[buflen++] = ';';
-			if (it->scn == 0 && it->pos == -1) {
-				buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\".", it->text.Save().c_str());
-			} else {
-				if (cur_scn != -1 && cur_scn != it->scn) break; // scn change
-				if (cur_pos != -1 && cur_pos/5000 != it->pos/5000) break; // pos exceeded
-				if (!it->text.container.empty()) {
-					buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\"", it->text.Save().c_str());
+				buf[buflen++] = ';';
+				if (it->scn == 0 && it->pos == -1)
+					buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\".", it->text.Save().c_str());
+				else {
+					if (cur_scn != -1 && cur_scn != it->scn) break; // scn change
+					if (cur_pos != -1 && cur_pos/5000 != it->pos/5000) break; // pos exceeded
+					if (!it->text.container.empty()) {
+						buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\"", it->text.Save().c_str());
+					}
+					if (cur_scn == -1) { // scene change
+						buflen += snprintf(buf+buflen, 1000-buflen, ":%d:%d",it->scn,it->pos);
+						cur_scn = it->scn;
+					}
+					else
+						buflen += snprintf(buf+buflen, 1000-buflen, "%d",it->pos);
+					cur_pos = it->pos;
 				}
-				if (cur_scn == -1) { // scene change
-					buflen += snprintf(buf+buflen, 1000-buflen, ":%d:%d",it->scn,it->pos);
-					cur_scn = it->scn;
-				} else {
-					buflen += snprintf(buf+buflen, 1000-buflen, "%d",it->pos);
+				if (it->koe != -1)
+					buflen += snprintf(buf+buflen, 1000-buflen, ",%d",it->koe);
+				if (!it->face.empty()) {
+					if (it->koe == -1) buf[buflen++] = ',';
+					int face_num = face_log.Add(it->face);
+					if (face_num >= 0 && face_num < 20)
+						buflen += snprintf(buf+buflen, 1000-buflen, ",%c", 'A'+face_num);
+					else
+						buflen += snprintf(buf+buflen, 1000-buflen, ",\"%s\"", it->face.c_str());
 				}
-				cur_pos = it->pos;
+				buf[buflen++] = '\0';
+				if (buflen >= 1000) { // 万が一、バックログ1アイテムの大きさが 1000byte を越えるとき
+					fprintf(stderr,"Fatal : Cannot save backlog crrectly; Please send bug report to the author.\n");
+				} else str += buf;
 			}
-			if (it->koe != -1)
-				buflen += snprintf(buf+buflen, 1000-buflen, ",%d",it->koe);
-			if (!it->face.empty()) {
-				if (it->koe == -1) buf[buflen++] = ',';
-				int face_num = face_log.Add(it->face);
-				if (face_num >= 0 && face_num < 20)
-					buflen += snprintf(buf+buflen, 1000-buflen, ",%c", 'A'+face_num);
-				else
-					buflen += snprintf(buf+buflen, 1000-buflen, ",\"%s\"", it->face.c_str());
-			}
-			buf[buflen++] = '\0';
-			if (buflen >= 1000) { // 万が一、バックログ1アイテムの大きさが 1000byte を越えるとき
-				fprintf(stderr,"Fatal : Cannot save backlog crrectly; Please send bug report to the author.\n");
-			} else str += buf;
-		}
-		str += "\n";
-	} while(it != backlog.end());
+			str += "\n";
+		} while(it != backlog.end());
 	}
-	return;
 }
 
-void TextImpl::Load(const char* str) {
+void Text::Load(const char* str) {
 	if (text) text->wid->Clear();
 	hide();
 	text_window_number = 0;
@@ -530,11 +339,11 @@ void TextImpl::Load(const char* str) {
 	cur_backlog_item.Clear();
 	drawn_backlog_item.Clear();
 
-	str = strstr(str, "\n[TextImpl Window]\n");
+	str = strstr(str, "\n[Text Window]\n");
 
 	if (str) {
 		SaveFaceHash face_log;
-		str += strlen("\n[TextImpl Window]\n");
+		str += strlen("\n[Text Window]\n");
 		const char* strend = str;
 		do {
 			str = strend;
@@ -544,7 +353,7 @@ void TextImpl::Load(const char* str) {
 			else strend++;
 
 			if (str[0] == '[') break; // next section
-			if (strncmp(str, "TextImplWindow=",15) == 0) {
+			if (strncmp(str, "TextWindow=",15) == 0) {
 				str += 15;
 				sscanf(str, "%d", &text_window_number);
 			} else if (strncmp(str, "SaveSelectCount=",16) == 0) {
@@ -632,12 +441,12 @@ void TextImpl::Load(const char* str) {
 	// backlog.clear();
 }
 
-void TextImpl::hide(void) {
+void Text::hide(void) {
 	if (text) text->hide();
 	if (kcursor) kcursor->hide();
 	text = NULL;
 }
-void TextImpl::show(int num) {
+void Text::show(int num) {
 	if (num != text_window_number) {
 		hide();
 		if (num >= 0 && num < 32 && widgets[num] != 0) {
@@ -660,7 +469,7 @@ void TextImpl::show(int num) {
 	}
 }
 
-void TextImpl::DrawBacklog(BacklogItem& item, Cmd& cmd) {
+void Text::DrawBacklog(BacklogItem& item, Cmd& cmd) {
 	show();
 	text->wid->deactivate();
 	status_mask = Status(status_mask | BACKLOG_WAIT_MASK);
@@ -681,7 +490,7 @@ void TextImpl::DrawBacklog(BacklogItem& 
 	if (kcursor) kcursor->hide();
 }
 
-void TextImpl::CreateSelBG(void) {
+void Text::CreateSelBG(void) {
 	if (sel_bg1 != NULL || sel_bg2 != NULL) return;
 
 	const char* btnfile1 = config->GetParaStr("#SELBTN.000.NAME");
@@ -704,8 +513,8 @@ void TextImpl::CreateSelBG(void) {
 	if (sel_bg2) sel_bg_rect.join(Rect(*sel_bg2));
 }
 
-void TextImpl::CreateSelect(Cmd& cmd) {
-	char key[1024];
+void Text::CreateSelect(Cmd& cmd) {
+	char key[23];
 	sprintf(key, "#WINDOW.%03d.SELCOM_USE",text_window_number);
 	int sel_type = 0;
 	if (cmd.cmd3 == 1) config->GetParam(key, 1, &sel_type);
@@ -825,7 +634,7 @@ External_select:
 	}
 }
 
-void TextImpl::AddText(const char* str_o) {
+void Text::AddText(const char* str_o) {
 	char str[10001];
 	if (text == NULL) return;
 	/* まず、replace string を変換 */
@@ -890,67 +699,7 @@ void TextImpl::AddText(const char* str_o
 	text_stream.Add(str_top);
 }
 
-void TextImpl::impl_txtClear(Cmd& cmd) {
-	if (text != NULL) {
-		text->ResetFace();
-		if (cmd.cmd2 == 3 && cmd.cmd3 == 151)
-			text->wid->Clear();
-	}
-	cur_backlog_item.face = "";
-	if (cmd.cmd2 == 3 && cmd.cmd3 == 151)
-		text_stream.Clear();
-	hide();
-}
-
-void TextImpl::impl_logKoe(Cmd& cmd) {
-	// PlayKoe ; 声出力コマンドをチェックする */
-	cur_backlog_item.koe = cmd.args[0].value;
-}
-
-void TextImpl::impl_pause(Cmd& cmd) {
-	if (text != NULL) {
-		eprintf("start\n");
-		text->StartText(text_stream);
-		if (skip_mode & SKIP_TEXT) text->wid->Flush();
-		else if (kcursor) kcursor->show();
-		status = WAIT_TEXT;
-		text_parsing = false;
-	}
-	backlog_item = cur_backlog_item;
-	if (cur_backlog_item.scn == 0 && cur_backlog_item.pos == -1) backlog_item.text = text_stream;
-	cur_backlog_item.Clear();
-
-	cmd.clear();
-	cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため)
-}
-
-void TextImpl::impl_br(Cmd& cmd) {
-	text_stream.AddReturn();
-	cur_backlog_item.DeleteTextPos();
-	cmd.clear();
-}
-
-void TextImpl::impl_FaceOpen(Cmd& cmd) {
-	if (text == NULL)
-		show();
-	string s = cmd.Str(cmd.args[0]);
-	s += ".g00";
-	if (text != NULL)
-		text->ShowFace(s.c_str());
-	cur_backlog_item.face = s;
-	cmd.cmd_type = CMD_SAVECMD_ONCE;
-}
-
-void TextImpl::impl_FaceClear(Cmd& cmd) {
-	if (text == NULL)
-		show();
-	if (text)
-		text->ResetFace();
-	cur_backlog_item.face = "";
-	cmd.cmd_type = CMD_SAVECMD_ONCE;
-}
-
-void TextImpl::Exec(Cmd& cmd) {
+void Text::Exec(Cmd& cmd) {
 	if (cmd.cmd_type == CMD_TEXT) {
 		if (text == NULL) {
 			show();
@@ -979,95 +728,9 @@ void TextImpl::Exec(Cmd& cmd) {
 
 	CommandHandler::Exec(cmd);
 
-	if (cmd.cmd1 == 0 && cmd.cmd2 == 3) {
-		if (cmd.cmd3 == 0x78) { // ルビ関連
-			if (text == NULL) {
-				show();
-			}
-			if (cmd.cmd4 == 1) {
-				ruby_text_flag = true;
-				eprintf("SetRubyTextImpl.");
-				cmd.clear();
-			} else if (cmd.cmd4 == 0) {
-				if (ruby_text.length() == 0) { // ルビを振るテキストがない
-					eprintf("Cannot find ruby text.\n");
-					return;
-				}
-				if (cmd.args.size() != 1) return;
-				char debug1[1024], debug2[1024];
-				kconv( (unsigned char*)ruby_text.c_str(), (unsigned char*)debug1);
-				kconv( (unsigned char*)cmd.Str(cmd.args[0]), (unsigned char*)debug2);
-				eprintf("SetRuby. %s, %s",debug1, debug2);
-				text_stream.AddRuby(ruby_text.c_str(), cmd.Str(cmd.args[0]));
-				cur_backlog_item.DeleteTextPos();
-				cmd.clear();
-			}
-		} else if (cmd.cmd3 == 0x66) { // テキストウィンドウの形
-			if (cmd.cmd4 == 0) {
-				eprintf("set text window <- %d\n",cmd.args[0].value);
-				if (text) show(cmd.args[0].value);
-				else text_window_number = cmd.args[0].value;
-			} else if (cmd.cmd4 == 1) { // default value
-				eprintf("set text window <- default\n");
-				if (text) show(0);
-				else text_window_number = 0;
-			}
-			cmd.clear();
-		} else if (cmd.cmd3 == 0x67) { // テキストウィンドウ表示?
-			show();
-// 表示の際はテキストをクリアしない?
-//			if (text) text->wid->Clear();
-//			text_stream.Clear();
-			cmd.clear();
-		} else if (cmd.cmd3 == 0x68) { // テキスト表示?
-			// 全テキスト表示
-			if (text) {
-				text->StartText(text_stream);
-				text->wid->Flush();
-			}
-			cmd.clear();
-		} else if (cmd.cmd3 == 0x98) { // テキストウィンドウクリア?
-			show();
-			if (text) text->wid->Clear();
-			text_stream.Clear();
-			cmd.clear();
-		}
-	} else if (cmd.cmd1 == 0 && cmd.cmd2 == 2 && (cmd.cmd3 == 1 || cmd.cmd3 == 3) && cmd.cmd4 == 0) {
-		// 選択肢
-		CreateSelect(cmd);
-		//FIXME: Check if it's really clean
-		if (text_parsing) {
-			show();
-			text->StartText(text_stream);
-			if (skip_mode & SKIP_TEXT) text->wid->Flush();
-			else if (kcursor) kcursor->hide();
-			text_parsing = false;
-			text_stream.Clear();
-		}
-		cmd.cmd_type = CMD_ROLLBACKPOINT; /* 選択肢はセーブ位置 / シナリオ巻き戻し位置 */
-		// cmd.clear();
-	} else if (cmd.cmd1 == 0 && cmd.cmd2 == 4) {
-		if (cmd.cmd3 == 0x44c) { // テキストスキップ開始
-			status_mask = Status(SKIPMASK | status_mask);
-			cmd.clear();
-		} else if (cmd.cmd3 == 0x3e8) { // ウィンドウ消去
-			status_mask = Status(CLEARSCR_MASK | status_mask);
-			cmd.clear();
-		}
-	} else if (cmd.cmd1 == 1 && cmd.cmd2 == 0x04) {
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 4) {
 		/* ウェイト関連命令 */
-		if (cmd.cmd3 == 0x64 || cmd.cmd3 == 0x6f || cmd.cmd3 == 0x79) {
-			eprintf("wait %dmsec\n",cmd.args[0].value);
-			if (cmd.cmd3 == 0x64 && text) {
-				/* 0x64 だと文字描画中の待ちに使うことがある */
-				text->StartText(text_stream);
-				text->wid->Flush();
-			}
-			if (cmd.cmd3 == 0x6f || cmd.cmd3 == 0x79) wait_time = base_time + cmd.args[0].value;
-			else wait_time = old_time + cmd.args[0].value;
-			status = WAIT;
-			cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため)
-		} else if (cmd.cmd3 == 0x65 || cmd.cmd3 == 0x70) {
+		if (cmd.cmd3 == 0x65 || cmd.cmd3 == 0x70) {
 			eprintf("wait %dmsec(click stop)\n",cmd.args[0].value);
 			if (cmd.cmd3 == 0x70) wait_time = base_time + cmd.args[0].value;
 			else wait_time = old_time + cmd.args[0].value;
@@ -1374,7 +1037,7 @@ else fprintf(stderr,"AUTO %d,%d <- wait 
 }
 
 extern int print_blit;
-bool TextImpl::Wait(unsigned int current_time, Cmd& cmd) {
+bool Text::Wait(unsigned int current_time, Cmd& cmd) {
 	if (current_time != Event::Time::NEVER_WAKE) old_time = current_time;
 /*
 if (event.presscount(MOUSE_UP)) {
@@ -1560,40 +1223,40 @@ print_blit^=1;
 
 void clearbtn_press(void* pointer, WidButton* button) {
 	if (pointer == NULL) return;
-	TextImpl* t = (TextImpl*)pointer;
-	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::CLEARSCR_MASK);
-	return;
+	Text* t = (Text*)pointer;
+	t->status_mask = Text::Status(t->status_mask | Text::CLEARSCR_MASK);
 }
-void TextImpl::PressFuncSkip(void* pointer, WidButton* from) {
+
+void Text::PressFuncSkip(void* pointer, WidButton* from) {
 	if (pointer == NULL) return;
-	TextImpl* t = (TextImpl*)pointer;
-	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::SKIPMASK);
-	return;
-}
-void TextImpl::PressFuncLoad(void* pointer, WidButton* from) {
-	if (pointer == NULL) return;
-	TextImpl* t = (TextImpl*)pointer;
-	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::LOADMASK);
+	Text* t = (Text*)pointer;
+	t->status_mask = Text::Status(t->status_mask | Text::SKIPMASK);
 	return;
 }
-void TextImpl::PressFuncSave(void* pointer, WidButton* from) {
+void Text::PressFuncLoad(void* pointer, WidButton* from) {
 	if (pointer == NULL) return;
-	TextImpl* t = (TextImpl*)pointer;
-	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::SAVEMASK);
-	return;
+	Text* t = (Text*)pointer;
+	t->status_mask = Text::Status(t->status_mask | Text::LOADMASK);
 }
-void TextImpl::PressFuncBacklog(void* pointer, WidButton* from) {
+
+void Text::PressFuncSave(void* pointer, WidButton* from) {
 	if (pointer == NULL) return;
-	TextImpl* t = (TextImpl*)pointer;
-	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::BACKLOG_MASK);
-	return;
+	Text* t = (Text*)pointer;
+	t->status_mask = Text::Status(t->status_mask | Text::SAVEMASK);
 }
-void TextImpl::PressFuncBacklogFwd(void* pointer, WidButton* from) {
+
+void Text::PressFuncBacklog(void* pointer, WidButton* from) {
 	if (pointer == NULL) return;
-	TextImpl* t = (TextImpl*)pointer;
-	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::BACKLOG_MASK_FWD);
-	return;
+	Text* t = (Text*)pointer;
+	t->status_mask = Text::Status(t->status_mask | Text::BACKLOG_MASK);
 }
+
+void Text::PressFuncBacklogFwd(void* pointer, WidButton* from) {
+	if (pointer == NULL) return;
+	Text* t = (Text*)pointer;
+	t->status_mask = Text::Status(t->status_mask | Text::BACKLOG_MASK_FWD);
+}
+
 void movebtn_drag(int from_x, int from_y, int x, int y, void* pointer, WidButton* button) {
 	if (pointer == NULL) return;
 	fprintf(stderr,"drag.\n");
@@ -1619,14 +1282,14 @@ static int btnpos[BTNCNT] = { // g00 ファイル内のボタン情報の位置
 };
 
 static WidButton::PressFunc btnpress[BTNCNT] = {
-	0, clearbtn_press, &TextImpl::PressFuncSkip,0,&TextImpl::PressFuncBacklogFwd,&TextImpl::PressFuncBacklog,&TextImpl::PressFuncBacklogFwd,&TextImpl::PressFuncSave,&TextImpl::PressFuncLoad,0
+	0, clearbtn_press, &Text::PressFuncSkip,0,&Text::PressFuncBacklogFwd,&Text::PressFuncBacklog,&Text::PressFuncBacklogFwd,&Text::PressFuncSave,&Text::PressFuncLoad,0
 };
 
 static WidButton::DragFunc btndrag[BTNCNT] = {
 	movebtn_drag, 0,0,0,0, 0,0,0,0, 0
 };
 
-void TextImpl::SetTextSpeed(int speed) {
+void Text::SetTextSpeed(int speed) {
 	// 100 : 10char / sec
 	// 10 : 100char / sec
 	// text widget:
@@ -1638,13 +1301,13 @@ void TextImpl::SetTextSpeed(int speed) {
 		if (widgets[i]) widgets[i]->wid->SetSpeed(speed);
 }
 
-void TextImpl::SetTextWait(int wait) {
+void Text::SetTextWait(int wait) {
 	int i;
 	for (i=0; i<32; i++)
 		if (widgets[i]) widgets[i]->wid->SetWait(wait);
 }
 
-void TextImpl::SetWindowColor(int r, int g, int b, int a, bool is_transparent) {
+void Text::SetWindowColor(int r, int g, int b, int a, bool is_transparent) {
 	char key[1024];
 	int w;
 
@@ -1668,7 +1331,7 @@ void TextImpl::SetWindowColor(int r, int
 	}
 }
 
-void TextImpl::SetCursor(int cursor_no) {
+void Text::SetCursor(int cursor_no) {
 	char key[1024];
 	sprintf(key, "#CURSOR.%03d.NAME", cursor_no);
 	string path = config->GetParaStr(key);
@@ -1773,59 +1436,6 @@ string kconv_rev(const string& s) {
 
 /**************************************************************::
 **
-**	Text
-*/
-Text::Text(Event::Container& _event, PicContainer& _parent) {
-	pimpl = new TextImpl(_event, _parent, backlog, backlog_item);
-}
-
-Text::~Text() {
-	delete pimpl;
-	pimpl = NULL;
-}
-
-void Text::InitWindow(void) {
-	pimpl->InitWindow();
-}
-
-void Text::Exec(Cmd& cmd) {
-	pimpl->Exec(cmd);
-}
-
-bool Text::Wait(unsigned int current_time, Cmd& cmd) {
-	return pimpl->Wait(current_time, cmd);
-}
-
-void Text::SetSkipMode(SkipMode mode) {
-	pimpl->SetSkipMode(mode);
-}
-
-void Text::Save(std::string& str, bool select_save) {
-	pimpl->Save(str, select_save);
-}
-
-void Text::Load(const char* str) {
-	pimpl->Load(str);
-}
-
-void Text::hide(void) {
-	pimpl->hide();
-}
-
-void Text::show(void) {
-	pimpl->show();
-}
-
-void Text::show(int num) {
-	pimpl->show(num);
-}
-
-void Text::DrawBacklog(BacklogItem& item, Cmd& cmd) {
-	pimpl->DrawBacklog(item, cmd);
-}
-
-/**************************************************************::
-**
 **	BacklogItem
 */
 
@@ -1872,6 +1482,12 @@ void BacklogItem::SetSavepos(int p) {
 	pos = p;
 }
 
+
+/**************************************************************::
+**
+**	TextWindow
+*/
+
 Rect TextWindow::WakuSize(PicContainer& pic, int waku_no) {
 	char key[1024];
 	sprintf(key, "#WAKU.%03d.000.NAME", waku_no);
@@ -2075,42 +1691,144 @@ TextWindow::TextWindow(PicContainer& par
 	MakeWaku(*wid->PicNode(), event,waku_no, win_no, use_btn, callback);
 }
 
-void TextImpl::InitWindow(void) {
+TextWindow::~TextWindow()
+{
+	if (name_container != NULL) {
+		delete name_container;
+		name_container = NULL;
+	}
 	int i;
-	int w;
-	std::string str;
+	for (i=0; i<8; i++) {
+		if (face_pics[i] != NULL) {
+			delete face_pics[i];
+			face_pics[i] = NULL;
+		}
+	}
+	if (wid != NULL) {
+		delete wid;
+		wid = NULL;
+	}
+}
+
+void TextWindow::show(void)
+{
+	wid->show();
+	if (name_container != NULL && name_visible)
+		name_container->show();
+	if (face != NULL)
+		face->show();
+}
 
-	for (w=0; w<32; w++) {
-		widgets[w] = new TextWindow(parent, event, w, (void*)this);
-		if (widgets[w]->wid == 0) {
-			delete widgets[w];
-			widgets[w] = NULL;
+void TextWindow::hide(void)
+{
+	wid->hide();
+	if (name_container != NULL)
+		name_container->hide();
+	if (face != NULL)
+		face->hide();
+}
+
+void TextWindow::ShowFace(const char* path)
+{
+	if (face == NULL)
+		return;
+	face->SetSurface(path, 0, 0);
+}
+
+void TextWindow::ResetFace(void) {
+	if (face == NULL)
+		return;
+	face->SetSurface((Surface*) NULL, 0, 0);
+}
+
+void TextWindow::StartText(const TextStream& _stream)
+{
+	wid->Clear();
+	wid->stream = _stream;
+	if (name_container != NULL) {
+		char namestr[1024];
+		namestr[0] = 0;
+		wid->stream.RemoveName(namestr, 1024);
+		if (namestr[0] == 0) {
+			name_container->hide();
+		}
+		else {
+			if (name != NULL) {
+				name_container->show_all();
+				name->SetText(namestr);
+			}
 		}
 	}
-	SetCursor(0);
-	for (i=0; i<26; i++) {
-		char buf[1024];
-		sprintf(buf, "#NAME.%c", i+'A');
-		const char* s = config->GetParaStr(buf);
-		if (s != NULL) replace_name[i] = s;
+	wid->Start();
+}
+
+void TextWindow::SetName(const char* n)
+{
+	if (name_container != NULL && name != NULL) {
+		if (n[0]) {
+			name_container->show();
+			name->SetText(n);
+			name_visible = true;
+		}
+		else {
+			name_container->hide();
+			name_visible = false;
+		}
+	}
+}
+
+/**************************************************************::
+**
+** SaveFaceHash
+*/
+
+void SaveFaceHash::NewNode(string face, int face_id)
+{
+	facetonum[face] = face_id;
+	container.push_front(Node(face, face_id));
+	if (container.size() > size_max) {
+		Node remove = container.back();
+		container.pop_back();
+		facetonum.erase(remove.first);
 	}
-	// replace_name2 : 初期設定
-	// 渚、秋生、渚 (CLANNAD)
-	char name_nagisa[3] = {'\x8f', '\x8d', '\0'};
-	char name_akio[5] = {'\x8f', '\x48', '\x90', '\xb6', '\0'};
-	replace_name2[0] = name_nagisa;
-	replace_name2[1] = name_akio;
-	replace_name2[2] = name_nagisa;
-	text = NULL;
-	/* テキスト速度の設定 */
-	int speed, mod, wait, auto_mod;
-	config->GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
-	config->GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &mod);
-	config->GetParam("#MESSAGE_KEY_WAIT_USE", 1, &auto_mod);
-	config->GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
-	if (mod) speed = -1;
-	if (!auto_mod) wait = -1;
-	SetTextSpeed(speed);
-	SetTextWait(wait);
-	return;
 }
+
+int SaveFaceHash::Add(string face)
+{
+	int id;
+	int ret = -1;
+	int i;
+	List::iterator it;
+	if (face.empty()) return -1;
+	if (facetonum.find(face) == facetonum.end()) {
+		id = ++id_max;
+		NewNode(face, id);
+		ret = -1;
+	}
+	else {
+		id = facetonum[face];
+		for (i=0, it=container.begin(); it != container.end(); i++, it++) {
+			if (it->second == id) {
+				ret = i;
+				Node n = *it;
+				container.erase(it);
+				container.push_front(n);
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+string SaveFaceHash::Get(int num) {
+	if (num < 0) return "";
+	List::iterator it = container.begin();
+	for (; it != container.end(); it++) {
+		if (num == 0) return it->first;
+		num--;
+	}
+	return "";
+}
+
+int SaveFaceHash::size_max = 20;
+
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_text.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2009 Thibaut GIRKA
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SCN2K_TEXT_H__
+#define __SCN2K_TEXT_H__
+
+#include <vector>
+#include <map>
+#include <list>
+
+#include "scn2k_cmd.h"
+
+#include "window/event.h"
+#include "window/picture.h"
+#include "window/widget.h"
+
+#include "font/text.h"
+
+#include "system/system_config.h"
+
+using namespace std;
+
+void dprintf(const char* fmt, ...); //FIXME
+void eprintf(const char* fmt, ...); //FIXME
+
+// kanji conv : 域;腓榊
+void kconv(const unsigned char* src, unsigned char* dest);
+void kconv_rev(const unsigned char* src, unsigned char* dest);
+string kconv(const string& s);
+string kconv_rev(const string& s);
+
+/**************************************************************::
+**
+** TimerAtom
+*/
+
+struct TimerAtom {
+	int from;
+	int to;
+	unsigned int start_time;
+	unsigned int total_time;
+};
+
+
+/**************************************************************::
+**
+** BacklogItem
+*/
+
+struct BacklogItem {
+	enum {SaveSelect = -2};
+	int scn, pos;
+	int koe;
+	std::string face;
+	struct TextStream text;
+	BacklogItem(void);
+	void Clear(void);
+	void AddTextPos(Cmd&);
+	void DeleteTextPos();
+	void SetSavepos(int pos);
+	BacklogItem& operator =(const BacklogItem&);
+};
+
+/**************************************************************::
+**
+** TextWindow
+*/
+
+struct TextWindow {
+/* @@@ : SetWindowColor с surface 荐絎羈 */
+	WidText* wid;
+	bool name_visible;
+	WidLabel* name;
+	PicContainer* name_container;
+	PicBase* face;
+	PicBase* face_pics[8];
+	TextWindow(PicContainer& parent, Event::Container& event, int window_no, void* callback);
+	~TextWindow();
+	Rect WakuSize(PicContainer& pic, int waku_no);
+	void MakeWaku(PicContainer& pic, Event::Container& event, int waku_no,int window_no, bool* use_btn, void* callback);
+	void show(void);
+	void hide(void);
+	void ShowFace(const char* path);
+	void ResetFace(void);
+	void StartText(const TextStream& _stream);
+	void SetName(const char* n);
+};
+
+/**************************************************************::
+**
+** SaveFaceHash
+*/
+
+struct SaveFaceHash { // 違祉若蕁糸靃∞茵
+	map<string, int> facetonum;
+	typedef pair<string,int> Node;
+	typedef list<Node> List;
+	List container;
+	int id_max;
+	static int size_max;
+	SaveFaceHash() : id_max(0) {}
+	void NewNode(string face, int face_id);
+	int Add(string face);
+	string Get(int num);
+};
+
+
+/**************************************************************::
+**
+** Text
+*/
+
+class Text : public CommandHandler {
+	public:
+		Text(Event::Container& _event, PicContainer& _parent);
+		~Text();
+		void InitWindow(void);
+		void Exec(Cmd& cmd);
+		bool Wait(unsigned int current_time, Cmd& cmd);
+		void SetSkipMode(SkipMode _mode);
+		void hide(void);
+		void show(void) { show(text_window_number); }
+		void show(int num);
+		void Save(std::string& str, bool select_save);
+		void Load(const char* str);
+		void DrawBacklog(BacklogItem& item, Cmd& cmd);
+
+		static void PressFuncSkip(void* pointer, WidButton* from);
+		static void PressFuncLoad(void* pointer, WidButton* from);
+		static void PressFuncSave(void* pointer, WidButton* from);
+		static void PressFuncBacklog(void* pointer, WidButton* from);
+		static void PressFuncBacklogFwd(void* pointer, WidButton* from);
+
+	private:
+		void SetWindowColor(int r, int g, int b, int a, bool is_transparent);
+		void SetTextSpeed(int new_speed);
+		void SetTextWait(int new_wait);
+
+		void CreateSelect(Cmd& cmd);
+		void CreateSelBG(void);
+
+		void AddText(const char* str);
+
+		static void PressFuncButton(void* pointer, WidButton* from);
+		static bool PressFunc(int x, int y, void* pointer);
+
+		void SetCursor(int num);
+
+	public:
+		vector<BacklogItem> backlog;
+		BacklogItem backlog_item;
+		TextWindow* text;
+		typedef enum {NORMAL=0, WAIT_TEXT=1, WAIT=2,
+			WAIT_CLICK=3, WAIT_ABORT=4, WAIT_CLICK_MOUSEPOS = 5,
+			WAIT_CLICK_MOUSEPOSEND_L = 6, WAIT_CLICK_MOUSEPOSEND_R = 7,
+			WAIT_SELECT_INBOX = 10, WAIT_SELECT_OUTBOX=11, WAIT_SELECT_VALUE = 12,
+			WAIT_EXTRN_MASK = 64, SAVEMASK = 128, LOADMASK = 256, SKIPMASK = 512,
+			CLEARSCR_MASK = 1024, STATSAVE_MASK = 2048, CLEARSCR_WAIT_MASK=(1<<12),
+			SKIPEND_MASK = (1<<13), BACKLOG_MASK=(1<<14), BACKLOG_MASK_FWD=(1<<15),
+			BACKLOG_MASK_KOE=(1<<16), BACKLOG_WAIT_MASK=(1<<17),
+			ALLMASK = (CLEARSCR_MASK | WAIT_EXTRN_MASK | SAVEMASK |
+						LOADMASK | SKIPMASK | BACKLOG_MASK | BACKLOG_MASK_FWD |
+						BACKLOG_MASK_KOE | BACKLOG_WAIT_MASK | STATSAVE_MASK |
+						CLEARSCR_WAIT_MASK | SKIPEND_MASK)
+		} Status;
+		Status status, status_saved, status_mask;
+
+	private:
+		std::string ruby_text;
+		bool ruby_text_flag;
+		unsigned int wait_time;
+		unsigned int old_time;
+		unsigned int base_time;
+		int text_window_number;
+		bool text_parsing;
+		TextStream text_stream;
+		SkipMode skip_mode;
+		int save_selectcount;
+
+		std::map<int, TimerAtom> timer_var;
+		std::vector<WidTextButton*> selects;
+		std::vector<int> sel_backlog_pos;
+		string replace_name[26];
+		string replace_name2[26];
+		PicContainer* sel_widget;
+		PicWidget* backlog_widget;
+
+		BacklogItem cur_backlog_item;
+		BacklogItem drawn_backlog_item;
+
+		TextWindow* widgets[32];
+		WidTimeCursor* kcursor;
+		Surface* sel_bg1;
+		Surface* sel_bg2;
+		Rect sel_bg_rect;
+
+		VarInfo wait_savedvar[2];
+
+		AyuSysConfig *config;
+
+		Event::Container& event;
+		PicContainer& parent;
+
+		//Opcode handling
+		void impl_txtClear(Cmd& cmd);
+		void impl_logKoe(Cmd& cmd);
+		void impl_pause(Cmd& cmd);
+		void impl_br(Cmd& cmd);
+		void impl_FaceOpen(Cmd& cmd);
+		void impl_FaceClear(Cmd& cmd);
+		void impl_doRuby(Cmd& cmd);
+		void impl_TextWindow(Cmd& cmd);
+		void impl_msgClear(Cmd& cmd);
+		void impl_FastText(Cmd& cmd);
+		void impl_createSelect(Cmd& cmd);
+		void impl_ShowBackground(Cmd& cmd);
+		void impl_SetSkipMode(Cmd& cmd);
+		void impl_Wait(Cmd& cmd);
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_textimpl.cc
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2009 Thibaut GIRKA
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "scn2k_text.h"
+
+void Text::impl_txtClear(Cmd& cmd) {
+	if (text != NULL) {
+		text->ResetFace();
+		if (cmd.cmd2 == 3 && cmd.cmd3 == 151)
+			text->wid->Clear();
+	}
+	cur_backlog_item.face = "";
+	if (cmd.cmd2 == 3 && cmd.cmd3 == 151)
+		text_stream.Clear();
+	hide();
+}
+
+void Text::impl_logKoe(Cmd& cmd) {
+	// PlayKoe ; 紕医阪潟潟с */
+	cur_backlog_item.koe = cmd.args[0].value;
+}
+
+void Text::impl_pause(Cmd& cmd) {
+	if (text != NULL) {
+		eprintf("start\n");
+		text->StartText(text_stream);
+		if (skip_mode & SKIP_TEXT) text->wid->Flush();
+		else if (kcursor) kcursor->show();
+		status = WAIT_TEXT;
+		text_parsing = false;
+	}
+	backlog_item = cur_backlog_item;
+	if (cur_backlog_item.scn == 0 && cur_backlog_item.pos == -1) backlog_item.text = text_stream;
+	cur_backlog_item.Clear();
+
+	cmd.clear();
+	cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 糸祉祉(skip鴻祉)
+}
+
+void Text::impl_br(Cmd& cmd) {
+	text_stream.AddReturn();
+	cur_backlog_item.DeleteTextPos();
+	cmd.clear();
+}
+
+void Text::impl_FaceOpen(Cmd& cmd) {
+	if (text == NULL)
+		show();
+	string s = cmd.Str(cmd.args[0]);
+	s += ".g00";
+	if (text != NULL)
+		text->ShowFace(s.c_str());
+	cur_backlog_item.face = s;
+	cmd.cmd_type = CMD_SAVECMD_ONCE;
+}
+
+void Text::impl_FaceClear(Cmd& cmd) {
+	if (text == NULL)
+		show();
+	if (text)
+		text->ResetFace();
+	cur_backlog_item.face = "";
+	cmd.cmd_type = CMD_SAVECMD_ONCE;
+}
+
+void Text::impl_doRuby(Cmd& cmd) {
+	if (text == NULL) {
+		show();
+	}
+	if (cmd.cmd4 == 1) {
+		ruby_text_flag = true;
+		eprintf("SetRubyText.");
+		cmd.clear();
+	} else if (cmd.cmd4 == 0) {
+		if (ruby_text.length() == 0) { // 鴻
+			eprintf("Cannot find ruby text.\n");
+			return;
+		}
+		if (cmd.args.size() != 1) return;
+		char debug1[1024], debug2[1024];
+		kconv( (unsigned char*)ruby_text.c_str(), (unsigned char*)debug1);
+		kconv( (unsigned char*)cmd.Str(cmd.args[0]), (unsigned char*)debug2);
+		eprintf("SetRuby. %s, %s",debug1, debug2);
+		text_stream.AddRuby(ruby_text.c_str(), cmd.Str(cmd.args[0]));
+		cur_backlog_item.DeleteTextPos();
+		cmd.clear();
+	}
+}
+
+void Text::impl_TextWindow(Cmd& cmd) {
+	if (cmd.cmd4 == 0) {
+		eprintf("set text window <- %d\n",cmd.args[0].value);
+		if (text != NULL) show(cmd.args[0].value);
+		else text_window_number = cmd.args[0].value;
+	} else if (cmd.cmd4 == 1) { // default value
+		eprintf("set text window <- default\n");
+		if (text != NULL) show(0);
+		else text_window_number = 0;
+	}
+	cmd.clear();
+}
+
+void Text::impl_FastText(Cmd& cmd) {
+	//I think it's broken. For now, it's disabled.
+	if (cmd.cmd3 == 103) {
+		// 鴻c潟茵腓削
+		show();
+// 茵腓冴鴻≪鐚
+//		if (text) text->wid->Clear();
+//		text_stream.Clear();
+		cmd.clear();
+	}
+	else if (cmd.cmd3 == 104) { // 鴻茵腓削
+		// 鴻茵腓
+		if (text != NULL) {
+			text->StartText(text_stream);
+			text->wid->Flush();
+		}
+		cmd.clear();
+	}
+}
+
+void Text::impl_msgClear(Cmd& cmd) {
+	show();
+	if (text != NULL) text->wid->Clear();
+	text_stream.Clear();
+	cmd.clear();
+}
+
+void Text::impl_createSelect(Cmd& cmd) {
+	if (cmd.cmd4 == 0) {
+		// 御
+		CreateSelect(cmd);
+		//FIXME: Check if it's really clean
+		if (text_parsing) {
+			show();
+			text->StartText(text_stream);
+			if (skip_mode & SKIP_TEXT) text->wid->Flush();
+			else if (kcursor) kcursor->hide();
+			text_parsing = false;
+				text_stream.Clear();
+		}
+		cmd.cmd_type = CMD_ROLLBACKPOINT; /* 御≪祉若篏臀 / 激綏祉祉篏臀 */
+		// cmd.clear();
+	}
+	else
+		PrintCmd(cmd); //FIXME
+}
+
+void Text::impl_ShowBackground(Cmd& cmd) {
+	status_mask = Status(CLEARSCR_MASK | status_mask);
+	cmd.clear();
+}
+
+void Text::impl_SetSkipMode(Cmd& cmd) {
+	status_mask = Status(SKIPMASK | status_mask);
+	cmd.clear();
+}
+
+void Text::impl_Wait(Cmd& cmd) {
+	eprintf("wait %dmsec\n",cmd.args[0].value);
+	if (cmd.cmd3 == 100 && text != NULL) {
+		/* 0x64 絖私賢緇<篏帥 */
+		text->StartText(text_stream);
+		text->wid->Flush();
+	}
+	if (cmd.cmd3 == 111 || cmd.cmd3 == 121)
+		wait_time = base_time + cmd.args[0].value; //FIXME: second argument, counter
+	else
+		wait_time = old_time + cmd.args[0].value;
+	status = WAIT;
+	cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 糸祉祉(skip鴻祉)
+}
--- a/system/system_config.h
+++ b/system/system_config.h
@@ -22,6 +22,9 @@
  *
 */
 
+#ifndef __SYSTEM_CONFIG_H__
+#define __SYSTEM_CONFIG_H__
+
 #include <string>
 
 /* CD Track 名 <-> Track 番号の変換を行う */
@@ -111,3 +114,5 @@ class AyuSysConfig {
 		static AyuSysConfig* _singleton;
 };
 
+#endif
+
--- a/window/Makefile.am
+++ b/window/Makefile.am
@@ -1,7 +1,7 @@
 noinst_LIBRARIES = libwindow.a
 libwindow_a_SOURCES = render.cc event.cc system.cc picture.cc widget.cc \
                       button.cc menuitem.cc rect.cc \
-                      event.h menuitem.h picture.h rect.h \
+                      event.h menuitem.h picture.h rect.h render.h \
                       surface.h system.h widget.h
 
 INCLUDES = @SDL_CFLAGS@
--- a/window/render.cc
+++ b/window/render.cc
@@ -27,20 +27,12 @@
 
 #include "font/font.h"
 #include "font/text.h"
+#include "SDL.h"
+#include "render.h"
 #include "rect.h"
-#include "SDL.h"
 #include "surface.h"
 #include <stdio.h>
 
-Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
-	Surface* dst, const Rect& dstrect); // 文字描画
-void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a); // クリア
-void DSurfaceFillA(Surface* src, const Rect& rect, int r, int g, int b, int a); // テキストウィンドウ背景の設定
-void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect); // コピー
-void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect);
-void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
-void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o);
-
 #ifndef ALPHA_MAX
 #define ALPHA_MAX 255
 #endif
new file mode 100644
--- /dev/null
+++ b/window/render.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009 Thibaut GIRKA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RENDER_H__
+#define __RENDER_H__
+
+#include "rect.h"
+#include "surface.h"
+
+Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
+						Surface* dst, const Rect& dstrect); // 転損炭族竪
+
+void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a=0xff); // 促俗促棚促蔵
+void DSurfaceFillA(Surface* src, const Rect& rect, int r, int g, int b, int a=0xff); // 促促足促孫促促促贈促坦促促揃テ棚
+void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect); // 促続促臓
+void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect);
+void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
+void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o);
+
+#endif
--- a/window/surface.h
+++ b/window/surface.h
@@ -28,8 +28,8 @@
 #ifndef __SURFACE_H__
 #define __SURFACE_H__
 
-#include<SDL.h>
-#include"rect.h"
+#include <SDL.h>
+#include "rect.h"
 
 struct Surface : public SDL_Surface {
 	char* mem(const Rect& r) {
--- a/window/system.h
+++ b/window/system.h
@@ -34,24 +34,30 @@
 #include "widget.h"
 
 namespace System {
-	struct Main {
-		int framerate;
-		static int event_filter(const SDL_Event* event);
-		static bool is_exit;
-		static bool is_video_update;
-		static Main* instance;
-		WidMouseCursor* cursor;
-	public:
-		Event::Container event;
-		PicRoot root;
-		Main(void);
-		~Main();
-		void Mainloop(void);
-		static void Quit(void);
-		static void DisableVideo(void);
-		static void EnableVideo(void);
+	class Main {
+		public:
+			Main(void);
+			~Main();
+			void Mainloop(void);
+			static void Quit(void);
+			static void DisableVideo(void);
+			static void EnableVideo(void);
 #define DEFAULT_MOUSECURSOR (Surface*)0xffff0000 //FIXME: WTF?!?
-		static void SetCursor(Surface* s, const Rect& r);
+			static void SetCursor(Surface* s, const Rect& r);
+
+		private:
+			static int event_filter(const SDL_Event* event);
+
+		public:
+			Event::Container event;
+			PicRoot root;
+
+		private:
+			int framerate;
+			static bool is_exit;
+			static bool is_video_update;
+			static Main* instance;
+			WidMouseCursor* cursor;
 	};
 }