Mercurial > otakunoraifu
view scn2k/scn2k_grp.cc @ 54:d7cde171a1de
* scn2k_grp.cc now handles commands in a cleanier way \o/
* some cleaning
author | thib |
---|---|
date | Mon, 20 Apr 2009 16:18:55 +0000 |
parents | ddbcbd000206 |
children | f1a27ee7e03c |
line wrap: on
line source
/* * 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.h" #include "window/widget.h" #include "system/file.h" #include "system/system_config.h" #include "font/text.h" #include <set> using namespace std; 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 { 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; 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, HIDDEN_GROUP=8, UPDATE_PICTURE = 16, UPDATE_POS = 32, UPDATE_ALPHA = 64, UPDATE_SNUM = 128, UPDATE_CLIP = 256, UPDATE_VISIBLE = 512, UPDATE_ALL = (16|32|64|128|256|512), ANM_PLAYSTART = 0x8000, ANM_PLAYING = 0x10000, DIG_ZERO = 0x10000*2, DIG_SIGN = 0x10000*4, DIG_PACK=0x10000*8,DIG_SPACE=0x10000*16 }; Attribute attr; GrpImpl* parent_pimpl; 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 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) */ struct GrpObjMap : std::map<int, GrpObj> { typedef pair<const int, GrpObj> value_type; class GrpImpl* parent; GrpObj& operator[](const int& k) { iterator it = lower_bound(k); if (it == end() || it->first != k) { GrpObj obj; obj.parent_pimpl = parent; it = insert(it, value_type(k, obj)); } return it->second; } GrpObjMap(class GrpImpl* p) { parent = p; } }; class GrpImpl : public CommandHandler { #define MAXPDT 256 #define WORKPDT 255 private: void CreateObj(int number); void ZMoveObj(int number); void SetObjChanged(int number); void SwapObj(int a1, int a2); void DeleteObjPic(int num);// object の surface のみ削除 void DeleteObj(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); // 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) */ GrpObj::GrpObj(void) : name(""), gan_name(""), pic_parent(0), picture(0), anm(0), _posx(0), _posy(0), clip_area(0,0,0,0), alpha(255), order(0), surface_num(0), print_moji(""), print_size(0), print_r(-1),print_g(-1),print_b(-1), dig_number(0), dig_digit(0), zoom(-1), rotate(-1), attr(GrpObj::HIDDEN), parent_pimpl(NULL) { int i; for (i=0; i<9; i++) { posx[i] = posy[i] = 0; } } GrpObj::~GrpObj() { if (picture) delete picture; if (parent_pimpl == NULL) { fprintf(stderr,"\n**************\nFATAL : UNINITIALIZED GrpObj IS FOUND!!! \n**************\n"); } } int GrpObj::PosX() { return _posx; } int GrpObj::PosY() { return _posy; } void GrpObj::SetUpdate(void) { attr = Attribute (attr | UPDATE_PICTURE); //Update(); //FIXME } void GrpObj::SetPos(int index, int x, int y) { if (index < 0 || index > 8) { fprintf(stderr,"GrpObj::SetPos: Invalid index %d <- %d,%d\n",index,x,y); return; } if (x == posx[index] && y == posy[index]) return; attr = Attribute(attr | UPDATE_POS); _posx += x-posx[index]; _posy += y-posy[index]; posx[index] = x; posy[index] = y; } void GrpObj::GetPos(int index, int& x, int& y) { if (index < 0 || index > 8) { fprintf(stderr,"GrpObj::GetPos: Invalid index %d\n",index); x = 0; y = 0; return; } x = posx[index]; y = posy[index]; return; } void GrpObj::SetAlpha(int new_alpha) { if (alpha == new_alpha) return; alpha = new_alpha; attr = Attribute(attr | UPDATE_ALPHA); return; } void GrpObj::SetSurfaceNum(int num) { if (num != -1) { if (surface_num == num) return; surface_num = num; } attr = Attribute(attr | UPDATE_SNUM); return; } void GrpObj::SetClipArea(int x, int y, int w, int h) { Rect new_clip(x,y,x+w,y+h); if (clip_area == new_clip) return; clip_area = new_clip; attr = Attribute(attr | UPDATE_CLIP); return; } PicBase* GrpObj::DeletePic(void) { PicBase* p = picture; anm = 0; picture = 0; src_pos.clear(); attr = Attribute(attr & (HIDDEN | HIDDEN_GROUP)); return p; } void GrpObj::GetSrcGeom(int& width, int& height) { if (src_pos.empty()) { width = 0; height = 0; if (name.length() == 0) { return; } /* ボタンの位置情報を求める */ /* g00 ファイルのヘッダ部分に位置情報は入っている */ string path(name); path += ".g00"; ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::PDT, path.c_str(), "g00"); if (info == NULL) { // ファイルが見つからない fprintf(stderr, "GrpObj::GetSrcGeom : Cannot find file %s\n", path.c_str()); return; } const char* data = info->Read(); if (data != NULL && *data == 2) { // 画像ファイル内にボタン情報が存在する int srclen = read_little_endian_int(data+5); int i; for (i=0; i<srclen; i++) { int x1 = read_little_endian_int(data+9+i*24+0); int y1 = read_little_endian_int(data+9+i*24+4); int x2 = read_little_endian_int(data+9+i*24+8); int y2 = read_little_endian_int(data+9+i*24+12); src_pos.push_back(Rect(x1, y1, x2+1, y2+1)); if (width < src_pos.back().width()) width = src_pos.back().width(); if (height < src_pos.back().height()) height = src_pos.back().height(); } } else { // 画像ファイルから大きさ取得 width = read_little_endian_short(data+1); height = read_little_endian_short(data+3); src_pos.push_back(Rect(0,0,width,height)); } delete info; } int sn = surface_num; if (sn < 0 || sn > src_pos.size()) sn = 0; width = src_pos[sn].width(); height = src_pos[sn].height(); return; } void GrpObj::Update(void) { if (attr & UPDATE_PICTURE) { UpdateSurface(); attr = Attribute( (attr | UPDATE_ALL) & (~UPDATE_PICTURE)); } if (picture == 0) return; if (attr & UPDATE_POS) { if ( (attr & SATURATE) || zoom != -1) { int w=0, h=0; GetSrcGeom(w,h); picture->Move(_posx-w/2, _posy-h/2); } else { picture->Move(_posx, _posy); } } if (attr & UPDATE_ALPHA) { if (alpha <= 0) { picture->SetSurfaceAlpha(0, Rect(0,0)); picture->hide(); } else if (alpha >= ALPHA_MAX) { picture->SetSurfaceAlpha(0, Rect(0,0)); if (attr & HIDDEN) picture->hide(); else picture->show(); } else { picture->SetSurfaceAlpha(&alpha, Rect(0,0,1,1)); if (attr & HIDDEN) picture->hide(); else picture->show(); } } if ( (attr & UPDATE_SNUM) && (!src_pos.empty())) { if (surface_num < 0 || surface_num >= src_pos.size()) surface_num = 0; picture->SetSurfacePos(src_pos[surface_num].lx, src_pos[surface_num].ty); } if (attr & UPDATE_CLIP) { picture->SetClipArea(clip_area); } attr = Attribute(attr & (~UPDATE_ALL)); if (attr & ANM_PLAYSTART) { if (anm != NULL) { anm->Play(); attr = Attribute(attr | ANM_PLAYING); } attr = Attribute(attr & (~ANM_PLAYSTART)); } } void GrpObj::CreateSurface(PicContainer* parent) { if (picture != NULL) { PicBase* p = DeletePic(); delete p; } src_pos.clear(); // picture を作成 pic_parent = parent; picture = parent->create_leaf(Rect(_posx,_posy,_posx+1,_posy+1), 0); picture->hide(); UpdateSurface(); } void GrpObj::UpdateSurface(void) { if (pic_parent == NULL || picture == NULL) return; int width = 0, height = 0; if (gtype == FILE || gtype == GAN) { if (name.length() == 0) return; // ファイル名が存在する場合、ファイルを読み込み GetSrcGeom(width, height); if (width <= 0 || height <= 0) return; // surface の設定 if (surface_num == 0 && ( (zoom > 0 && zoom != 256) || rotate > 0)) { ZoomRotate(); } else { // 普通に surface を設定 string path(name); path += ".g00"; picture->SetSurface(path.c_str(), 0, 0); picture->SetSurfaceRect(Rect(0,0,width,height)); } if (attr & SATURATE) picture->SetSurfaceAttribute(PicBase::BLIT_SATURATE); } else if (gtype == MOJI) { // テキスト描画 if (print_moji.length() == 0) return; UpdateMoji(); } else if (gtype == DIGIT) { // 数値を画像表示 UpdateDigit(); } } void GrpObj::ZoomRotate(void) { picture->SetSurface( (Surface*)0, 0, 0); // 回転、縮小拡大は座標原点が画像の中心になる string path(name); path += ".g00"; Surface* surface_orig = pic_parent->Root().NewSurface(path.c_str()); if (surface_orig == NULL) return; Surface* zoom_surface = pic_parent->Root().RotZoomSurface(surface_orig, double(zoom)/256.0, rotate); Rect zoom_r (*zoom_surface); picture->SetSurface(zoom_surface, 0, 0); picture->SetSurfaceFreeFlag(); //picture->Move(PosX() + - zoom_r.width()/2, PosY() + - zoom_r.height()/2); // 中心座標がわからん・・・ picture->Move(320 - zoom_r.width()/2, 240 - zoom_r.height()/2); picture->SetSurfaceRect(Rect(0, 0, zoom_r.width(), zoom_r.height())); pic_parent->Root().DeleteSurface(surface_orig); } void GrpObj::UpdateMoji(void) { // 文字の大きさ、色などを変更 if (print_moji.length() == 0 || print_size <= 2) return; if (pic_parent == 0) return; /* テキストの大きさを得る */ int r, g, b; if (print_r == -1 || print_g == -1 || print_b == -1) {// 色設定なし r = g = b = 0; // とりあえず黒(clannad のSave/Loadメニュー用) } else { r = print_r; g = print_g; b = print_b; } TextStream ts = TextStream::ParseMoji(print_moji.c_str(), r, g, b, print_size); TextGlyphStream gs; vector<int> lh; // とりあえず drawable width は充分に大きく(2048)取る DefaultLayout(print_size-2)->Layout(ts, gs, lh, 2048); // print_size そのままだと弱干大きすぎるので -2 int width = gs.width(); int height = gs.height(); Surface* surface = pic_parent->Root().NewSurface(width, height, ALPHA_MASK); DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0); DSurfaceRenderText(gs.begin(), gs.end(), Rect(0, 0, width, height), surface, Rect(0,0)); picture->SetSurface(surface, 0, 0); picture->SetSurfaceRect(Rect(0,0,width,height)); picture->SetSurfaceFreeFlag(); } void GrpObj::UpdateDigit(void) { // 画像表示の数値文字列を表示する if (name.length() == 0) return; // ファイル名が存在する場合、ファイルを読み込み string path(name); path += ".g00"; Surface* surface_orig = pic_parent->Root().NewSurface(path.c_str()); if (surface_orig == NULL) return; int width, height; int i; GetSrcGeom(width, height); if (width <= 0 || height <= 0) return; if (src_pos.size() < 14) { // 必要な数の object がない // 表示できない分の空の rect を追加しておく for (i=src_pos.size(); i<14; i++) src_pos.push_back(Rect(0,0,0,0)); pic_parent->Root().DeleteSurface(surface_orig); return; } // 桁数の計算 char num_str[20]; if (dig_number < 0) sprintf(num_str, "%d", -dig_number); else sprintf(num_str, "%d", dig_number); int sign_count = 0; int space_count = 0; int total_count; int dig_count = strlen(num_str); if (dig_number < 0 && (attr&DIG_SIGN) == 0) dig_count++; if (dig_count < dig_digit) space_count = dig_digit - dig_count; if (attr & DIG_SIGN) sign_count = 1; total_count = dig_count + space_count + sign_count; Surface* surface = pic_parent->Root().NewSurface(width*total_count, height, ALPHA_MASK); DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0); /* surface にコピーする */ int cur_x = 0; if ( (attr & DIG_PACK) && !(attr & DIG_ZERO)) { // 始めに空白を挿入 cur_x += space_count * width; } int plus = 10, minus = 11, plusminus = 12; if (dig_number < 0) { DSurfaceMove(surface, src_pos[minus], surface, Rect(cur_x,0)); cur_x += width; } else if (attr & DIG_SIGN) { if (dig_number == 0) DSurfaceMove(surface, src_pos[plusminus], surface, Rect(cur_x,0)); else DSurfaceMove(surface, src_pos[plus], surface, Rect(cur_x,0)); cur_x += width; } if (attr & DIG_ZERO) { // ゼロ・パディング for (i=0; i<space_count; i++) { DSurfaceMove(surface, src_pos[0], surface, Rect(cur_x, 0)); cur_x += width;; } } else if (!(attr & DIG_PACK)) { // PACK オプションなし cur_x += space_count * width; } for (i=0; num_str[i] != 0; i++) { DSurfaceMove(surface_orig, src_pos[num_str[i]-'0'], surface, Rect(cur_x, 0)); cur_x += width; } /* picture に設定 */ picture->SetSurface(surface, 0, 0); picture->SetSurfaceRect(Rect(0,0,width*total_count,height)); picture->SetSurfaceFreeFlag(); pic_parent->Root().DeleteSurface(surface_orig); } void GrpObj::CreateGan(Event::Container& event, int event_number) { if (picture == NULL) { fprintf(stderr,"GrpObj::CreateGan() is called before Create()\n"); return; } if (anm != NULL) { anm->Abort(); delete anm; anm = NULL; } if (gan_name.empty()) return; /* アニーメション情報 (.GAN ファイル)を求める */ string path(gan_name); path += ".gan"; ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::GAN, path.c_str(), "gan"); if (info == NULL) { fprintf(stderr,"GrpObj::CreateGan: Cannot Find 'GAN' file %s\n", path.c_str()); return; } const char* data = info->Read(); if (read_little_endian_int(data) != 10000 || read_little_endian_int(data+4) != 10000) { fprintf(stderr,"GrpObj::CreateGan: Invalid'GAN' file %s\n", path.c_str()); delete info; return; } picture->SetSurfaceAttribute(PicBase::BLIT_SATURATE); attr = Attribute(attr | UPDATE_POS | SATURATE); const char* buf = data + 16; buf += strlen(buf) + 1; // 画像ファイル名が入っている buf += 4; // 定数 20000 int pics = read_little_endian_int(buf); buf += 4; // 複数のアニメーション情報が入っている場合、情報数 // 以下、pics 回繰り返し // アニメーションを行う実体を作成 AnmAlphaMove* wid = new AnmAlphaMove(event, picture); if (event_number && event_number < pics) { // 複数のアニメーション情報がある場合、先の情報を読み飛ばす */ int i; for (i=0; i<event_number; i++) { buf += 4; // 定数 30000 int ptns = read_little_endian_int(buf); buf += 4; buf += ptns*52; } } buf += 4; // 定数 30000 int ptns = read_little_endian_int(buf); buf += 4; int total_time = 0; int i; for (i=0; i<ptns; i++) { int p = read_little_endian_int(buf+i*52+0*8+4); int x = read_little_endian_int(buf+i*52+1*8+4); int y = read_little_endian_int(buf+i*52+2*8+4); int t = read_little_endian_int(buf+i*52+3*8+4); int a = read_little_endian_int(buf+i*52+4*8+4); x += PosX(); y += PosY(); if (p == -1) { a = 0; p = 0; } // p == -1 ならなにも表示しない if (p >= src_pos.size()) { fprintf(stderr,"Reading GAN file %s (G00 %s) : not enough pictures in .G00 file\n", path.c_str(), name.c_str()); a = 0; p = 0; } total_time += t; wid->ptns.push_back(AnmAlphaMove::Ptn(Rect(x,y), src_pos[p], a, total_time)); } wid->SetPtn(); // パターン登録終了 attr = Attribute(attr | ANM_PLAYSTART); anm = wid; } void GrpObj::CreateGanSpecial(Event::Container& event, int event_number, int time) { if (picture == NULL) { fprintf(stderr,"GrpObj::CreateGan() is called before Create()\n"); return; } if (anm != NULL) { anm->Abort(); delete anm; anm = NULL; } // アニメーションを行う実体を作成 AnmAlphaMove* wid = new AnmAlphaMove(event, picture); int i; switch(event_number) { case 0: // pattern を 0 から最後まで変化させる for (i=0; i<src_pos.size(); i++) { wid->ptns.push_back(AnmAlphaMove::Ptn(Rect(PosX(), PosY()), src_pos[i], 255, time*i)); } wid->SetPtn(); // パターン登録終了 anm = wid; attr = Attribute(attr | ANM_PLAYSTART); break; default: break; } } void GrpObj::SetZoomRotate(int new_zoom, int new_rotate) { if (zoom == new_zoom && rotate == new_rotate) return; if ( zoom == -1 || new_zoom == -1) { attr = Attribute(attr | UPDATE_POS); // centering する } zoom = new_zoom; if (new_rotate != -1) rotate = new_rotate; if (zoom < 0) zoom = 256; if (rotate < 0) rotate = 0; else if (rotate > 360) rotate %= 360; attr = Attribute(attr | UPDATE_PICTURE); } /****************************************************************** ** ** 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) { int dx = to.lx - from.lx; int dy = to.ty - from.ty; if (dx < 0) dx = -dx; if (dy < 0) dy = -dy; if (dx < dy) dx = dy; if (dx == 0) dx = 1; SetAllCount(dx); } void ScnGrpMove::Exec(int count) { Rect r(0,0,dest_r.width(),dest_r.height()); int dx = to.lx - from.lx; int dy = to.ty - from.ty; int x = dx*count/all_count + from.lx; int y = dy*count/all_count + from.ty; r.rmove(x, y); root.BlitSurface(src, r, dest, dest_r); iterator it; for (it=pic.begin(); it!=pic.end(); it++) (*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; int tm = 0; vector<ScnGrpAnmAtom>::iterator it; for (it=begin(); it != end(); it++) tm += it->time; total_time = tm; SetAllCount(tm); } void ScnGrpAnm::Exec(int count) { int tm = 0; vector<ScnGrpAnmAtom>::iterator it; for (it=begin(); it != end(); it++) { tm += it->time; if (count < tm) break; } if (it == end()) it--; owner.LoadSurface(it->name.c_str(), 0); } /***************************************************** * * GrpImpl(implementation) : 定義 * */ #include "music2/music.h" GrpImpl::GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm_data): event(_event), flags(f), parent(_parent), status(NORMAL), skip_mode(SKIP_NO), cgm_data(_cgm_data), grpobj(this), bs_obj(this) { int i; for (i=0; i<MAXPDT; i++) { ssurface[i] = 0; dsurface[i] = 0; } music = MuSys::GetInstance(); config = AyuSysConfig::GetInstance(); screen = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0); screen_front = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0); surface = parent.Root().NewSurface(parent.Width(), parent.Height(), NO_MASK); surface_update = parent.Root().NewSurface(parent.Width(), parent.Height(), NO_MASK); DSurfaceFill(surface, Rect(*surface), 0, 0, 0); DSurfaceFill(surface_update, Rect(*surface), 0, 0, 0); screen->SetSurface(surface, 0, 0); screen->show(); screen_front->hide(); screen_front->ZMove(screen); 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, 33, 1600, "recAdd", (CmdImpl) &GrpImpl::impl_recAdd); RegisterCommand(1, 33, 406, "grpPan", (CmdImpl) &GrpImpl::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, 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, 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, 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); //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, 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, 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, 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, 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, 1017, "objColR", NULL); RegisterCommand(1, 82, 1017, "objBgColR", NULL); RegisterCommand(1, 81, 1018, "objColG", NULL); RegisterCommand(1, 82, 1018, "objBgColG", NULL); RegisterCommand(1, 81, 1019, "objColB", NULL); RegisterCommand(1, 82, 1019, "objBgColB", NULL); RegisterCommand(1, 81, 1020, "objColLevel", NULL); RegisterCommand(1, 82, 1020, "objBgColLevel", NULL); RegisterCommand(1, 81, 1021, "objComposite", (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, 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, 84, 1000, "objGetPos", (CmdImpl) &GrpImpl::impl_objPosDims); RegisterCommand(1, 84, 1100, "objGetDims", (CmdImpl) &GrpImpl::impl_objPosDims); RegisterCommand(1, 31, 0, "refresh", (CmdImpl) &GrpImpl::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, 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, 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, 22, 0, "sePlay", (CmdImpl) &GrpImpl::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, 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, 26, 1, "movPlayEx", (CmdImpl) &GrpImpl::impl_movPlay); RegisterCommand(1, 26, 20, "movPlayExC", (CmdImpl) &GrpImpl::impl_movPlay); RegisterCommand(1, 61, 14, "objSwap?", NULL); RegisterCommand(1, 62, 14, "objSwap?", NULL); anm1 = NULL; anm2 = NULL; } GrpImpl::~GrpImpl() { map<int,GrpObj>::iterator it; for (it=grpobj.begin(); it!=grpobj.end(); it++) { PicBase* p = it->second.DeletePic(); delete p; } delete screen; delete screen_front; parent.Root().DeleteSurface(surface); parent.Root().DeleteSurface(surface_update); int i; for (i=0; i<MAXPDT; i++) { if (ssurface[i]) parent.Root().DeleteSurface(ssurface[i]); if (dsurface[i]) parent.Root().DeleteSurface(dsurface[i]); } } Surface* GrpImpl::Dsurface(int pdt) { if (pdt == 0) return surface; if (dsurface[pdt] == 0) { // とりあえず画面の大きさということにする if (pdt == WORKPDT) dsurface[pdt] = parent.Root().NewSurface(parent.Width(), parent.Height(), ALPHA_MASK); else dsurface[pdt] = parent.Root().NewSurface(parent.Width(), parent.Height(), NO_MASK); } if (ssurface[pdt]) { // ssurface が存在すれば、dsurface にコピーして返す DSurfaceMove(ssurface[pdt], Rect(*ssurface[pdt]), dsurface[pdt], Rect(0,0)); parent.Root().DeleteSurface(ssurface[pdt]); ssurface[pdt] = 0; } return dsurface[pdt]; } #include <SDL.h> Surface* GrpImpl::Ssurface(int pdt) { if (pdt == 0) return surface; if (ssurface[pdt]) { return ssurface[pdt]; } return Dsurface(pdt); } void GrpImpl::LoadSurface(const char* str, int pdt) { string s = str; if (cgm_info.find(s) != cgm_info.end()) { cgm_data.insert(cgm_info[s]); } Surface* bg = parent.Root().NewSurface(s.c_str()); if (bg == NULL) { s += ".g00"; bg = parent.Root().NewSurface(s.c_str()); } if (bg != NULL) { if (ssurface[pdt]) parent.Root().DeleteSurface(ssurface[pdt]); ssurface[pdt] = bg; if (pdt == 0) { /* とりあえず Princess Bride のアニメーション効果専用 */ Rect r(*ssurface[0]); Rect dr(*surface); int x = (dr.width()-r.width())/2; int y = (dr.height()-r.height())/2; DSurfaceMove(ssurface[0], r, surface, Rect(x,y)); parent.Root().DeleteSurface(ssurface[0]); ssurface[0] = NULL; screen->SetSurface(surface, 0, 0); } } else { if (str[0] != 0) fprintf(stderr,"Cannot find surface %d <- '%s'\n",pdt,str); } } void GrpImpl::InitSel(void) { int i; int args[16]; char key[10]; for (i=0; i<999; i++) { sprintf(key, "#SEL.%03d",i); if (config->GetParam(key, 15, &args[0], &args[1], &args[2], &args[3], &args[4], &args[5], &args[6], &args[7], &args[8], &args[9], &args[10], &args[11], &args[12], &args[13], &args[14])) { sprintf(key, "#SELR.%03d", i); if (config->GetParam(key, 16, &args[0], &args[1], &args[2], &args[3], &args[4], &args[5], &args[6], &args[7], &args[8], &args[9], &args[10], &args[11], &args[12], &args[13], &args[14], &args[15])) continue; } SEL& s = anmtype[i]; s.from = Rect(args[0], args[1], args[2]+1, args[3]+1); s.to = Rect(args[4], args[5]); s.time = args[6]; s.sel_no = args[7]; int j; for (j=0; j<8; j++) s.args[j] = args[8+j]; } } void GrpImpl::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) ) { } skip_mode = _mode; } void GrpImpl::SetObjChanged(int num) { changed_obj.insert(num); } void GrpImpl::RefreshObj(void) { if (!deleted_pic.empty()) { vector<PicBase*>::iterator it; for (it=deleted_pic.begin(); it!=deleted_pic.end(); it++) { if (*it) delete *it; } deleted_pic.clear(); } if (!changed_obj.empty()) { set<int>::iterator it; for (it=changed_obj.begin(); it != changed_obj.end(); it++) { if (grpobj.find(*it) == grpobj.end()) continue; GrpObj& obj = grpobj[*it]; if (obj.picture == NULL) continue; if (obj.alpha == 0 || (obj.attr & GrpObj::HIDDEN)) { if (obj.attr & GrpObj::ANM_PLAYING) { obj.attr = GrpObj::Attribute(obj.attr & ~(GrpObj::ANM_PLAYING)); if (obj.anm) obj.anm->Abort(); } obj.picture->hide(); } else { obj.Update(); obj.picture->show(); } } changed_obj.clear(); } if (reserved_load_surface0.length() != 0) { LoadSurface(reserved_load_surface0.c_str(), 0); reserved_load_surface0 = ""; } screen->ReBlit(); } #include <SDL.h> void GrpImpl::StartAnm(int type) { SEL sel; if (anmtype.find(type) == anmtype.end()) { if (anmtype.find(0) == anmtype.end()) { sel.sel_no = 1; sel.from = Rect(*surface); sel.to = Rect(0,0); sel.time = 0; } else { sel = anmtype[0]; } } else { sel = anmtype[type]; } if (anm1 != NULL) { fprintf(stderr,"Warning: StartAnm() called before anm1 finished\n"); anm1->Abort(); delete anm1; anm1 = NULL; } map<int,GrpObj>::iterator it; // 現在表示中のobjectを消去 deleted_pic.push_back(screen); for (it=grpobj.begin(); it!=grpobj.end(); it++) { if (! (it->second.attr & GrpObj::WIPEON)) { // 画像切り替え時に object 削除 deleted_pic.push_back(it->second.DeletePic()); } else { GrpObj& new_obj = bs_obj[it->first]; if (new_obj.name.empty()) { // 新しい object が存在しなければ内容を引き継ぐ new_obj = it->second; it->second.DeletePic(); } else { new_obj.attr = GrpObj::Attribute(new_obj.attr | GrpObj::WIPEON); deleted_pic.push_back(it->second.DeletePic()); } } } grpobj.clear(); // 全オブジェクト削除 // 全画像オブジェクトの前にscreen 移動 // 新しい screen_front を作成しておく screen = screen_front; screen->hide(); screen->SetSurface(surface_update, 0, 0); parent.Root().BlitSurface(Dsurface(1), Rect(*surface_update), surface_update, Rect(0,0)); screen_front = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0); screen_front->hide(); screen_front->ZMove(screen); // 新しい object へ更新、surface_update へ新しい object を表示 // (object 作成時は picture は hide されている) for (it=bs_obj.begin(); it!=bs_obj.end(); it++) { grpobj[it->first] = it->second; it->second.DeletePic(); CreateObj(it->first); GrpObj& g = grpobj[it->first]; if (g.picture) { g.Update(); if (g.alpha == 0 || (g.attr & GrpObj::HIDDEN)) ; else g.picture->SimpleBlit(surface_update); g.picture->hide(); } } bs_obj.clear(); // 画像効果開始 switch(sel.sel_no) { default: case 0: case 50: // 0 と 50 の違いが良くわからない if (skip_mode & SKIP_GRP_NOEFFEC) anm1 = new WidAnmAlpha(event, screen, ALPHA_MAX, ALPHA_MAX, 0); else if (skip_mode & SKIP_GRP_FAST) anm1 = new WidAnmAlpha(event, screen, 0, ALPHA_MAX, sel.time/4); else anm1 = new WidAnmAlpha(event, screen, 0, ALPHA_MAX, sel.time); break; } if (anm1) anm1->Play(); if (skip_mode & SKIP_GRP_NOEFFEC) AbortAnm(); } void GrpImpl::StartShake(int total, const int* pattern) { if (anm2) { fprintf(stderr,"Warning: StartShake() called before another animation finished\n"); anm2->Abort(); delete anm2; anm2 = NULL; } if (skip_mode & SKIP_GRP_NOEFFEC) return; AnmAlphaMove* new_anm = new AnmAlphaMove(event, &parent); // shake screen では元画面の座標を揺らす int i; int tm = 0; for (i=0; i<total; i+=3) { int x = pattern[i]; int y = pattern[i+1]; new_anm->ptns.push_back(AnmAlphaMove::Ptn(Rect(x,y), Rect(0,0), 255, tm)); tm += pattern[i+2]; } new_anm->ptns.push_back(AnmAlphaMove::Ptn(Rect(0,0), Rect(0,0), 255, tm)); new_anm->SetPtn(); // パターン登録終了 new_anm->Play(); anm2 = new_anm; } void GrpImpl::AbortAnm(void) { if (anm1 == NULL) return; anm1->Abort(); delete anm1; anm1 = NULL; /* 画像効果終了 */ /* 古い画面への画像効果があれば消去 */ if (anm2 && anm2->pic[0] != screen) { anm2->Abort(); delete anm2; anm2 = NULL; } /* pdt1 -> pdt0 へコピー */ DSurfaceMove(dsurface[1], Rect(*dsurface[1]), surface, Rect(0,0)); screen->SetSurface(surface, 0, 0); // 画像効果開始時に存在したobjectを消去 // 新しい object 表示 RefreshObj(); return; } void GrpImpl::LoadSurface(const char* str) { if (anm1 != NULL) AbortAnm(); // 前の描画が終わってなければ強制終了 LoadSurface(str, 1); bg_name = str; } void GrpImpl::LoadSurface(void) { if (anm1 != NULL) AbortAnm(); // 前の描画が終わってなければ強制終了 LoadSurface(bg_name.c_str(), 1); } void GrpImpl::AddSurface(const char* str) { if (anm1 != NULL) AbortAnm(); // 前の描画が終わってなければ強制終了 LoadSurface(bg_name.c_str()); string s = str; Surface* front = parent.Root().NewSurface(s.c_str()); if (front == NULL) { s += ".g00"; front = parent.Root().NewSurface(s.c_str()); } if (front != NULL) { parent.Root().BlitSurface(front, Rect(*front), Dsurface(1), Rect(0,0)); parent.Root().DeleteSurface(front); } else { fprintf(stderr,"Cannot find surface %s\n",str); } } void GrpImpl::CreateObj(int index) { std::map<int, GrpObj>::iterator cur = grpobj.find(index); if (cur == grpobj.end()) return; GrpObj& g = grpobj[index]; g.CreateSurface(&parent); g.order = index; if (g.picture == NULL) return; // エラー:surface が存在しない g.picture->hide(); SetObjChanged(index); ZMoveObj(index); } void GrpImpl::ZMoveObj(int index) { std::map<int, GrpObj>::iterator cur = grpobj.find(index); if (cur == grpobj.end()) return; GrpObj& g = grpobj[index]; if (g.picture == NULL) return; // 自分より前に object があれば、その前に表示 // そうでなければ screen の前に表示 std::map<int, GrpObj>::iterator cur_backobj = grpobj.end(); std::map<int, GrpObj>::iterator it; for (it = grpobj.begin(); it != grpobj.end(); it++) { if (it == cur) continue; if (it->second.picture == NULL) continue; if (it->second.order < g.order) { if (cur_backobj == grpobj.end()) { cur_backobj = it; } else if (cur_backobj->second.order < it->second.order) { cur_backobj = it; } } } if (cur_backobj == grpobj.end()) { g.picture->ZMove(screen); } else { g.picture->ZMove(cur_backobj->second.picture); } } void GrpImpl::SwapObj(int index1, int index2) { // デフォルト値から order が変更されていた場合のみ、order は保存される // まずは両方のobjectをswap if (grpobj.find(index1) == grpobj.end()) { if (grpobj.find(index2) == grpobj.end()) return; // どちらの object も存在しない grpobj[index1] = grpobj[index2]; if (grpobj[index1].order == index2) grpobj[index1].order = index1; grpobj[index2].DeletePic(); grpobj.erase(index2); ZMoveObj(index1); return; } else if (grpobj.find(index2) == grpobj.end()) { // index2 が存在しない場合 grpobj[index2] = grpobj[index1]; if (grpobj[index2].order == index1) grpobj[index2].order = index2; grpobj[index1].DeletePic(); grpobj.erase(index1); ZMoveObj(index2); return; } else { GrpObj obj = grpobj[index1]; grpobj[index1] = grpobj[index2]; grpobj[index2].DeletePic(); if (grpobj[index1].order == index2) grpobj[index1].order = index1; ZMoveObj(index1); grpobj[index2] = obj; if (grpobj[index2].order == index1) grpobj[index2].order = index2; ZMoveObj(index2); obj.DeletePic(); } } bool GrpImpl::Pressed(int x, int y, void* pointer) { // マウスクリックでキャンセル GrpImpl* g = (GrpImpl*)pointer; if (g->status == WAIT_MOVIE) g->music->StopMovie(); if (g->status == WAIT_ANM) g->AbortAnm(); if (g->status == WAIT_SHAKE && g->anm2 != NULL) { g->anm2->Abort(); delete g->anm2; g->anm2 = NULL; } return false; // event deleted } /* mode.cgm の decode 用 */ static unsigned char decode_char[256] = { 0x8b, 0xe5, 0x5d, 0xc3, 0xa1, 0xe0, 0x30, 0x44, 0x00, 0x85, 0xc0, 0x74, 0x09, 0x5f, 0x5e, 0x33, 0xc0, 0x5b, 0x8b, 0xe5, 0x5d, 0xc3, 0x8b, 0x45, 0x0c, 0x85, 0xc0, 0x75, 0x14, 0x8b, 0x55, 0xec, 0x83, 0xc2, 0x20, 0x52, 0x6a, 0x00, 0xe8, 0xf5, 0x28, 0x01, 0x00, 0x83, 0xc4, 0x08, 0x89, 0x45, 0x0c, 0x8b, 0x45, 0xe4, 0x6a, 0x00, 0x6a, 0x00, 0x50, 0x53, 0xff, 0x15, 0x34, 0xb1, 0x43, 0x00, 0x8b, 0x45, 0x10, 0x85, 0xc0, 0x74, 0x05, 0x8b, 0x4d, 0xec, 0x89, 0x08, 0x8a, 0x45, 0xf0, 0x84, 0xc0, 0x75, 0x78, 0xa1, 0xe0, 0x30, 0x44, 0x00, 0x8b, 0x7d, 0xe8, 0x8b, 0x75, 0x0c, 0x85, 0xc0, 0x75, 0x44, 0x8b, 0x1d, 0xd0, 0xb0, 0x43, 0x00, 0x85, 0xff, 0x76, 0x37, 0x81, 0xff, 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00, 0x76, 0x43, 0x8b, 0x45, 0xf8, 0x8d, 0x55, 0xfc, 0x52, 0x68, 0x00, 0x00, 0x04, 0x00, 0x56, 0x50, 0xff, 0x15, 0x2c, 0xb1, 0x43, 0x00, 0x6a, 0x05, 0xff, 0xd3, 0xa1, 0xe0, 0x30, 0x44, 0x00, 0x81, 0xef, 0x00, 0x00, 0x04, 0x00, 0x81, 0xc6, 0x00, 0x00, 0x04, 0x00, 0x85, 0xc0, 0x74, 0xc5, 0x8b, 0x5d, 0xf8, 0x53, 0xe8, 0xf4, 0xfb, 0xff, 0xff, 0x8b, 0x45, 0x0c, 0x83, 0xc4, 0x04, 0x5f, 0x5e, 0x5b, 0x8b, 0xe5, 0x5d, 0xc3, 0x8b, 0x55, 0xf8, 0x8d, 0x4d, 0xfc, 0x51, 0x57, 0x56, 0x52, 0xff, 0x15, 0x2c, 0xb1, 0x43, 0x00, 0xeb, 0xd8, 0x8b, 0x45, 0xe8, 0x83, 0xc0, 0x20, 0x50, 0x6a, 0x00, 0xe8, 0x47, 0x28, 0x01, 0x00, 0x8b, 0x7d, 0xe8, 0x89, 0x45, 0xf4, 0x8b, 0xf0, 0xa1, 0xe0, 0x30, 0x44, 0x00, 0x83, 0xc4, 0x08, 0x85, 0xc0, 0x75, 0x56, 0x8b, 0x1d, 0xd0, 0xb0, 0x43, 0x00, 0x85, 0xff, 0x76, 0x49, 0x81, 0xff, 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00, 0x76 }; void GrpImpl::LoadCgm() { /* cgm ファイル読み込み */ const char* fname = config->GetParaStr("#CGTABLE_FILE"); if (fname == NULL) return; ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::ALL, fname, ""); if (info == NULL) return; char* data = info->CopyRead(); int sz = info->Size(); delete info; if ( strncmp(data, "CGTABLE", 7) != 0) { delete[] data; return; } cgm_size = read_little_endian_int(data+0x10); int i, j; // xor 解除 for (i=0; i < sz-0x20; i++) { data[i+0x20]^=decode_char[i&0xff]; } // 展開 int dest_size = cgm_size * 36; char* dest = new char[dest_size+1024]; char* src = data + 0x28; char* dest_orig = dest; ARCINFO::Extract2k(dest,src,dest+dest_size,data+sz); dest = dest_orig; for (i=0; i<cgm_size; i++) { char* s = dest + i * 36; int n = read_little_endian_int(dest + i * 36 + 32); cgm_info[s] = n; } delete[] data; delete[] dest_orig; } /***************************************************** * * GrpImpl :: Save, Load : セーブファイル処理 * */ void GrpImpl::Save(std::string& str) { } void GrpImpl::Load(const char* str) { status = NORMAL; if (anm1 != NULL) { AbortAnm(); } if (anm2 != NULL) { anm2->Abort(); delete anm2; anm2 = NULL; } map<int,GrpObj>::iterator it; for (it=grpobj.begin(); it!=grpobj.end(); it++) { PicBase* p = it->second.DeletePic(); delete p; } grpobj.clear(); bg_name = ""; music->StopCDROM(100); } void GrpImpl::SaveSys(string& save) { char buf[1024]; save = "\n[Graphics]\n"; save += "CGM_CG="; set<int>::iterator it; for (it=cgm_data.begin(); it != cgm_data.end(); it++) { sprintf(buf,"%d,",*it); save += buf; } save += "\n"; } void GrpImpl::LoadSys(const char* save) { cgm_data.clear(); save = strstr(save, "\n[Graphics]\n"); if (save) { save += strlen("\n[Graphics]\n"); do { if (save[0] == '[') break; // next section if (strncmp(save, "CGM_CG=",7) == 0) { save += 7; while(isdigit(*save)) { int n = atoi(save); cgm_data.insert(n); save = strchr(save, ','); if (save) save++; } } save = strchr(save, '\n'); if (save) save++; } while (save); } return; } /***************************************************** * * GrpImpl :: 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) { if (grpdump_req) { grpdump_req = 0; std::map<int,GrpObj>::iterator it; fprintf(stderr,"front %p(%d) / %p(%d)\n",screen,screen->IsHidden(),screen_front,screen_front->IsHidden()); for (it=grpobj.begin(); it != grpobj.end(); it++) { GrpObj& obj = it->second; if (obj.picture) { if (!obj.name.empty()) { fprintf(stderr,"obj %06d(%p): name %10s pos %d,%d alpha %d (%d/%d/%d)\n", it->first,obj.picture,obj.name.c_str(), obj.PosX(),obj.PosY(),obj.alpha,obj.attr&GrpObj::HIDDEN ? 1 : 0, 0, obj.picture->IsHidden()); } else if (!obj.print_moji.empty()) { fprintf(stderr,"obj %06d(%p): name %10s pos %d,%d alpha %d (%d/%d/%d)\n", it->first,obj.picture,obj.print_moji.c_str(), obj.PosX(),obj.PosY(),obj.alpha,obj.attr&GrpObj::HIDDEN ? 1 : 0, 0, obj.picture->IsHidden()); } else { fprintf(stderr,"obj %06d(%p): name %10s pos %d,%d alpha %d (%d/%d/%d)\n", it->first,obj.picture,"<EMPTY>", obj.PosX(),obj.PosY(),obj.alpha,obj.attr&GrpObj::HIDDEN ? 1 : 0, 0, obj.picture->IsHidden()); } } } std::list<PicBase*>::iterator it2; for (it2=parent.children.begin(); it2!=parent.children.end();it2++) { fprintf(stderr,"%p(%d)\n",*it2,(*it2)->IsHidden()); } RefreshObj(); } #if 0 if (event.presscount(MOUSE_UP)) { std::list<PicBase*>::iterator lit; draw_n++; int i=0; for (lit=parent.children.end(); lit!=parent.children.begin(); ) { lit--; (*lit)->hide(); i++; if (i >= draw_n) break; } if (drawn_images.empty()) { map<int, GrpObj>::iterator it; for (it=grpobj.begin(); it!=grpobj.end(); it++) { if (it->second.picture) { drawn_images.push_back(it->first); PicBase* p = it->second.DeletePic(); delete p; } } } else { vector<int>::iterator it; for (it=drawn_images.begin(); it!=drawn_images.end(); it++) { CreateObj(*it); } drawn_images.clear(); } } #endif if (status == WAIT_ANM) { if (anm1 != NULL) { if (!anm1->IsEnd()) return true; //FIXME: Handle animation loops AbortAnm(); } } else if (status == WAIT_SHAKE) { if (anm2 != NULL) { if (!anm2->IsEnd()) return true; delete anm2; anm2 = NULL; } status = NORMAL; } else if (status == WAIT_SE) { if (music->IsStopSE()) status = NORMAL; return true; } else if (status == WAIT_MOVIE) { if (music->IsStopMovie()) { music->StopMovie(); status = NORMAL; screen->ReBlit(); } return true; } if (anm2 != NULL) { if (anm2->IsEnd()) { delete anm2; anm2 = NULL; } } return false; } void GrpImpl::DeleteObjPic(int num) { // object の surface のみ削除 if (grpobj.find(num) == grpobj.end()) return; deleted_pic.push_back(grpobj[num].DeletePic()); } void GrpImpl::DeleteObj(int num) { if (grpobj.find(num) == grpobj.end()) return; deleted_pic.push_back(grpobj[num].DeletePic()); grpobj.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) DeleteObj(cmd.args[0].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; DeleteObjPic(cmd.args[0].value); // 旧ファイル名のsurfaceを削除 if (cmd.cmd2 == 71) DeleteObjPic(cmd.args[0].value); // 旧ファイル名のsurfaceを削除 GrpObj& g = (cmd.cmd2 == 71) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; if (cmd.cmd3 == 1000) { /* ファイル名設定 */ g.gtype = GrpObj::FILE; //FIXME: Strange thing in the main menu string name = cmd.Str(cmd.args[1]); if (name.find('?') != -1) { name.erase(name.find('?')); // '?' 以降の意味がわからない } g.name = name; } else if (cmd.cmd3 == 1003) { /* ファイル名設定(GAN含む) */ g.gtype = GrpObj::GAN; if (cmd.Str(cmd.args[1]) == string("???")) g.name = cmd.Str(cmd.args[2]); else g.name = cmd.Str(cmd.args[1]); g.gan_name = cmd.Str(cmd.args[2]); if (cmd.cmd4 >= 1 && cmd.args[3].value == 0) g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN); else g.attr = GrpObj::Attribute(g.attr & ~(GrpObj::HIDDEN)); if (cmd.argc >= 5) g.SetPos(1, cmd.args[4].value, -cmd.args[5].value); if (g.name.find('?') != -1) { g.name.erase(g.name.find('?')); g.gan_name = cmd.Str(cmd.args[2]); } } else if (cmd.cmd3 == 1200) { // 画像を文字列として指定 g.gtype = GrpObj::MOJI; g.print_moji = cmd.Str(cmd.args[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[1]); } CreateObj(cmd.args[0].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) { if (cmd.cmd1 == 1) g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP); else g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN); } else { if (cmd.cmd1 == 1) g.attr = GrpObj::Attribute(g.attr & (~(GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP))); else g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN)); } if (cmd.cmd1 == 1) 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) { GrpObj& g = grpobj[cmd.args[0].value]; 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 GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; int index, x, y; if (cmd.cmd3 == 1006 || cmd.cmd3 == 2006) { //objAdjust index = cmd.args[1].value + 1; x = cmd.args[2].value; y = cmd.args[3].value; } else { index = 0; if (cmd.cmd3 == 1000) { x = cmd.args[1].value; y = cmd.args[2].value; } else { g.GetPos(index, x, y); if (cmd.cmd3 == 1001) x = cmd.args[1].value; else y = cmd.args[1].value; } } g.SetPos(index, x, y); cmd.clear(); } void GrpImpl::impl_objAlpha(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; g.SetAlpha(cmd.args[1].value); cmd.clear(); } void GrpImpl::impl_objShow(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; if (cmd.cmd1 == 1) { if (cmd.args[1].value) g.attr = GrpObj::Attribute(g.attr & (~(GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP))); else g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP); } else { if (cmd.args[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) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; g.print_r = cmd.args[1].value; g.print_g = cmd.args[2].value; g.print_b = cmd.args[3].value; g.SetUpdate(); // grpobj[cmd.args[0].value].print_a = cmd.args[4].value; /* args:229,18,minus-1,0,99,255,-1 */ /* args:102,26,minus-1,0,99,0,255 */ cmd.clear(); } void GrpImpl::impl_objComposite(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; // centering mode などを設定? if (cmd.args[1].value == 1) { g.attr = GrpObj::Attribute(g.attr | GrpObj::SATURATE); cmd.clear(); } else if (cmd.args[1].value == 0) { g.attr = GrpObj::Attribute(g.attr & (~GrpObj::SATURATE)); cmd.clear(); } g.SetUpdate(); } void GrpImpl::impl_objSetText(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; g.print_moji = cmd.Str(cmd.args[1]); g.SetUpdate(); cmd.clear(); } void GrpImpl::impl_objTextOpts(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; // 画像を文字列として設定:文字の大きさなど g.print_size = cmd.args[1].value; /* 前景色を得る */ int cr, cg, cb; char key[17]; sprintf(key, "#COLOR_TABLE.%03d", cmd.args[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) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; int order = cmd.args[1].value; g.order = order; ZMoveObj(cmd.args[0].value); cmd.clear(); } void GrpImpl::impl_objDispArea(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; // オブジェクトのどの部分を画面に表示するか(クリップ領域)の設定 int rx, ry, w, h; if (cmd.args.size() == 5) { int rx = cmd.args[1].value; int ry = cmd.args[2].value; int w = cmd.args[3].value; int h = cmd.args[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) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; g.dig_number = cmd.args[1].value; g.SetUpdate(); cmd.clear(); } void GrpImpl::impl_objNumOpts(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; g.dig_digit = cmd.args[1].value; int attr = g.attr; attr &= ~(GrpObj::DIG_ZERO | GrpObj::DIG_SIGN | GrpObj::DIG_PACK); if (cmd.args[2].value) attr |= GrpObj::DIG_ZERO; if (cmd.args[3].value) attr |= GrpObj::DIG_SIGN; if (cmd.args[4].value) attr |= GrpObj::DIG_PACK; g.attr = GrpObj::Attribute(attr); g.SetUpdate(); cmd.clear(); } void GrpImpl::impl_objPattNo(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; g.SetSurfaceNum(cmd.args[1].value); cmd.clear(); } void GrpImpl::impl_objScale(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; int zoom = (cmd.args[1].value + cmd.args[2].value)/2; //FIXME: eurk zoom = zoom*256/100; g.SetZoomRotate(zoom, -1); cmd.clear(); } void GrpImpl::impl_objRotate(Cmd& cmd) { GrpObj& g = (cmd.cmd2 == 0x51) ? grpobj[cmd.args[0].value] : bs_obj[cmd.args[0].value]; int angle = cmd.args[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) { GrpObj& obj = grpobj[cmd.args[0].value]; VarInfo arg1 = cmd.args[1]; VarInfo arg2 = cmd.args[2]; int val1, val2; if (cmd.cmd3 == 1000) obj.GetPos(0, val1, val2); else if (cmd.cmd3 == 1100) obj.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) { if (cmd.cmd_type == CMD_TEXTEND) { music->StopKoe(500); // テキスト終了で声を止める cmd.clear(); return; } if (cmd.cmd_type == CMD_WAITFRAMEUPDATE) { // wait する場合は RefreshObj() しておく RefreshObj(); } if (cmd.cmd_type != CMD_OTHER) return; CommandHandler::Exec(cmd); //TODO: ??? if (cmd.cmd1 == 1 && cmd.cmd2 == 0x3c && cmd.cmd3 == 0) { // ??? : KANOGI : 画像オブジェクトの削除? DeleteObjPic(cmd.args[0].value); // 旧ファイル名のsurfaceを削除 GrpObj& g = grpobj[cmd.args[0].value]; g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN); cmd.clear(); } //TODO: ??? if ( (cmd.cmd1 == 1 || cmd.cmd1 == 2) && cmd.cmd2 == 0x51) { GrpObj& g = grpobj[cmd.args[0].value]; if (g.attr & GrpObj::UPDATE_ALL) { SetObjChanged(cmd.args[0].value); } } } /******************************************************** ** ** 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); }