view scn2k/scn2k_textimpl.cc @ 67:419761c8d9b9

Add configure option to build scn2kdump.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 23 Feb 2011 01:48:51 +0100
parents 36d92d21300f
children 043d5db57474
line wrap: on
line source

/*
 * 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_PauseCursor(Cmd& cmd)
{
	/* なんかよくわからないけどカーソル形状変更にしとく */
	SetCursor(cmd.args[0].value);
	cmd.clear();
}

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) {
		// テキストウィンドウ表示?
		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 == 112 || cmd.cmd3 == 121)
	{
		int index;
		if (cmd.cmd4 == 1)
			index = 0;
		else
			index = cmd.args[1].value;
		wait_time = timer_var[index].start_time + cmd.args[0].value;
	}
	else
		wait_time = old_time + cmd.args[0].value;

	if (cmd.cmd3 == 101 || cmd.cmd3 == 112)
		status = WAIT_CLICK;
	else
		status = WAIT;

	cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため)
}

void Text::impl_GetClick(Cmd& cmd) {
	eprintf("wait and get mouse pos at click\n");
	wait_time = old_time + 1000 * 1000;
	status = WAIT_CLICK_MOUSEPOS;
	wait_savedvar[0] = cmd.args[0];
	wait_savedvar[1] = cmd.args[1];
	cmd.clear();
}

void Text::impl_ResetTimer(Cmd& cmd) {
	int index;

	if (cmd.cmd4 == 1)
		index = 0;
	else
		index = cmd.args[0].value;

	eprintf("set basetime (%d)\n",index);
	//TODO: Handle EX timer set
	TimerAtom& atom = timer_var[index];
	atom.start_time = old_time;

	cmd.clear();
}

void Text::impl_Timer(Cmd& cmd) {
	int index;

	if (cmd.cmd4 == 1)
		index = 0;
	else
		index = cmd.args[0].value;

	eprintf("get time %dth\n",index);
	if (timer_var.find(index) == timer_var.end())
		cmd.SetSysvar(0);
	else
		cmd.SetSysvar(old_time - timer_var[index].start_time);
}

void Text::impl_ReadFrame(Cmd& cmd) {
	eprintf("get timer value[%d]\n", cmd.args[0].value);
	if (frame_var.find(cmd.args[0].value) == frame_var.end())
		cmd.SetSysvar(0);
	else {
		FrameTimerAtom& atom = frame_var[cmd.args[0].value];
		if (atom.total_time <= 0) atom.total_time = 1;
		int cur_tm = old_time - atom.start_time;
		if (cur_tm < 0) cur_tm = atom.total_time; // エラーなら最終時間に合わせる
		if (cur_tm > atom.total_time) cur_tm = atom.total_time;
		// use 'long long'(64bit) or 'double'(80bit) type, since total_time, to and from is 32 bit.
		int v = atom.from + (long long)(atom.to - atom.from)*cur_tm/int(atom.total_time);
		cmd.SetSysvar(v);
	}
}

void Text::impl_InitFrame(Cmd& cmd) {
	FrameTimerAtom& atom = frame_var[cmd.args[0].value];
	atom.from = cmd.args[1].value;
	atom.to = cmd.args[2].value;
	atom.total_time = cmd.args[3].value;
	atom.start_time = old_time;
	cmd.clear();
}

void Text::impl_InitFrames(Cmd& cmd) {
	int i, j = 0;
	for (i = 0; i < cmd.argc; i++)
	{
		int cnt = cmd.args[j++].value; // £³€Ê€Î€Ç̵»ë
		int num = cmd.args[j++].value;
		FrameTimerAtom& atom = frame_var[num];
		atom.from = cmd.args[j++].value;
		atom.to = cmd.args[j++].value;
		atom.total_time = cmd.args[j++].value;
		atom.start_time = old_time;
	}
	cmd.clear();
}

void Text::impl_ReadFrames(Cmd& cmd) {
	vector<VarInfo> args = cmd.args;
	vector<VarInfo>::iterator it = args.begin();
	int argc = cmd.argc;
	int timers_active = 0;
	int i;
	for (i=0; i < argc; i++)
	{
		int cnt = (it++)->value;
		int num = (it++)->value;

		if (frame_var.find(num) == frame_var.end()) {
			cmd.SetFlagvar(*it++, 0);
		}
		else
		{
			FrameTimerAtom& atom = frame_var[num];
			if (atom.total_time <= 0)
				atom.total_time = 1;
			int cur_tm = old_time - atom.start_time;
			if (cur_tm < 0)
				cur_tm = atom.total_time; // ¥š¥é¡Œ€Ê€éºÇœª»þŽÖ€Ë¹ç€ï€»€ë
			if (cur_tm > atom.total_time)
				cur_tm = atom.total_time;
			// use 'long long'(64bit) or 'double'(80bit) type, since total_time, to and from is 32 bit.
			int v = atom.from + (long long)(atom.to-atom.from)*cur_tm/int(atom.total_time);
			cmd.SetFlagvar(*it++, v);
			if (atom.total_time != -1 && cur_tm < atom.total_time)
				timers_active = 1;
		}
	}
	cmd.SetSysvar(timers_active);
}

#include "math.h"

void Text::impl_rnd(Cmd& cmd)
{
	/* rand() */
	int min, max;
	if (cmd.args.size() == 2)
	{
		min = cmd.args[0].value;
		max = cmd.args[1].value;
	}
	else
	{
		min = 0;
		max = cmd.args[0].value;
	}
	if (min > max)
	{
		int tmp = max;
		max = min;
		min = tmp;
	}
	int r = random();
	if (min == max)
		r = min;
	else
		r = (r % (max-min)) + min;
	cmd.SetSysvar(r);
}

void Text::impl_pcnt(Cmd& cmd)
{
	cmd.SetSysvar(100 * cmd.args[0].value / cmd.args[1].value);
}

void Text::impl_abs(Cmd& cmd)
{
	cmd.SetSysvar(abs(cmd.args[0].value));
}

void Text::impl_power(Cmd& cmd)
{
	cmd.SetSysvar(pow(cmd.args[0].value, cmd.args[1].value));
}

void Text::impl_sin(Cmd& cmd)
{
	cmd.SetSysvar(sin(cmd.args[0].value * M_PI / 180) * 32640 / cmd.args[1].value);
}

void Text::impl_min(Cmd& cmd)
{
	int a = cmd.args[0].value;
	int b = cmd.args[1].value;
	cmd.SetSysvar((a < b) ? a : b);
}

void Text::impl_max(Cmd& cmd)
{
	int a = cmd.args[0].value;
	int b = cmd.args[1].value;
	cmd.SetSysvar((a > b) ? a : b);
}

void Text::impl_index_series(Cmd& cmd)
{
	//TODO: This one is not fully documented in
	// http://dev.haeleth.net/rldev/manual.html
	// Try to figure out what's it...

	/* range conversion : 比率に丸める */
	// アルゴリズムは間違えてるような気がする
	// 
	if (cmd.args.size() >= 7)
	{
		int val = cmd.args[0].value;
		int offset = cmd.args[1].value;
		int r_min = cmd.args[2].value;
		int v_min = cmd.args[3].value;
		int v_max = cmd.args[4].value;
		int r_max = cmd.args[5].value;
		int mode = cmd.args[6].value;
		// rldev : mode == 1,3 : 'acceralating curve', 2,3: 'decelerating curve'
		// 複数の引数リスト(r_minからmodeまでのリスト)もつこともあり、その場合は
		// "cancel out in some way" らしい
		if (mode == 1 || mode == 3)
			val += offset;
		else if (mode == 2 || mode == 4)
			val -= offset;
if (cmd.args.size() != 7)
	fprintf(stderr,"\n%d/%d: cmd 01-04:0320 : XXXX NOT SUPPORTED LIST : DOUBLE RANGE CONVERSION!   XXXXXXXXXXX\n",cmd.scn,cmd.pos);
		if (val < v_min)
			val = v_min;
		if (val > v_max)
			val = v_max;
		val = (r_max-r_min)*(val-v_min)/(v_max-v_min) + r_min;
		cmd.SetSysvar(val);
	}
}

void Text::impl_constrain(Cmd& cmd)
{
	/* range 内に丸める */
	int min = cmd.args[0].value;
	int val = cmd.args[1].value;
	int max = cmd.args[2].value;
	if (min > max) {
		max = cmd.args[0].value;
		min = cmd.args[2].value;
	}
	if (val < min)
		val = min;
	if (val > max)
		val = max;
	cmd.SetSysvar(val);
}


void Text::impl_load(Cmd& cmd)
{
	// メニューからのロード
	cmd.cmd_type = CMD_LOADREQ;
}

void Text::impl_GetWindowAttr(Cmd& cmd)
{
	// テキストウィンドウの色設定
	int r, g, b, a, flag;

	if (cmd.cmd3 == 2617) // 元設定を取り出す
		config->GetOriginalParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);
	else
		config->GetParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);

	if (cmd.args.size() != 5) {
		fprintf(stderr,"cmd 01-04:%4d : invalid arg size\n", cmd.cmd3);
	} else {
		vector<VarInfo> args(cmd.args);
		cmd.SetFlagvar(args[0], r);
		cmd.SetFlagvar(args[1], g);
		cmd.SetFlagvar(args[2], b);
		cmd.SetFlagvar(args[3], a);
		cmd.SetFlagvar(args[4], flag);
	}
}

void Text::impl_SetWindowAttr(Cmd& cmd)
{
	int r, g, b, a, flag;
	config->GetParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);

	switch(cmd.cmd3) {
		case 2260:
			r = cmd.args[0].value;
			break;
		case 2261:
			g = cmd.args[0].value;
			break;
		case 2262:
			b = cmd.args[0].value;
			break;
		case 2263:
			a = cmd.args[0].value;
			break;
		case 2264:
			flag = cmd.args[0].value;
			break;
		case 2267: 
			r = cmd.args[0].value;
			g = cmd.args[1].value;
			b = cmd.args[2].value;
			a = cmd.args[3].value;
			flag = cmd.args[4].value;
			break;
	}
	config->SetParam("#WINDOW_ATTR", 5, r, g, b, a, flag);
	SetWindowColor(r, g, b, a, flag);
	cmd.clear();
}

void Text::impl_GetDefConfig(Cmd& cmd)
{
	int v = 0;
	switch(cmd.cmd3) {
		case 2600:
		case 2605:
			config->GetOriginalParam("#INIT_MESSAGE_SPEED", 1, &v);
			break;
		case 2601:
			config->GetOriginalParam("#INIT_MESSAGE_SPEED_MOD", 1, &v);
			break;
		case 2604:
			config->GetOriginalParam("#MESSAGE_KEY_WAIT_USE", 1, &v);
			break;
		case 2606:
			config->GetOriginalParam("#MESSAGE_KEY_WAIT_TIME", 1, &v);
			break;
	}
	cmd.SetSysvar(v);
}

void Text::impl_GetConfig(Cmd& cmd)
{
	int v;
	switch (cmd.cmd3)
	{
		case 2323:
		case 2351:
			config->GetParam("#INIT_MESSAGE_SPEED", 1, &v);
			break;
		case 2324:
			config->GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &v);
			break;
		case 2350:
			config->GetParam("#MESSAGE_KEY_WAIT_USE", 1, &v);
			break;
		case 2352:
			config->GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &v);
			break;
	}

	cmd.SetSysvar(v);
}

void Text::impl_SetConfig(Cmd& cmd)
{
	int speed, use_speed_mod, wait, use_wait_mod;
	config->GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
	config->GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &use_speed_mod);
	config->GetParam("#MESSAGE_KEY_WAIT_USE", 1, &use_wait_mod);
	config->GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
	switch (cmd.cmd3)
	{
		case 2223:
		case 2251:
			speed = cmd.args[0].value;
			if (speed < 10) //FIXME: ??? 0 ???
				speed = 10;
			if (speed > 10000) //FIXME: ??? 255 ???
				speed = 10000;
			config->SetParam("#INIT_MESSAGE_SPEED", 1, speed);
			break;
		case 2224:
			use_speed_mod = cmd.args[0].value;
			config->SetParam("#INIT_MESSAGE_SPEED_MOD", 1, use_speed_mod);
			break;
		case 2250:
			use_wait_mod = cmd.args[0].value;
			config->SetParam("#MESSAGE_KEY_WAIT_USE", 1, use_wait_mod);
			break;
		case 2252:
			int wait = cmd.args[0].value;
			if (wait < 0)
				wait = 0;
			else if (wait > 60000)
				wait = 60000;
			config->SetParam("#MESSAGE_KEY_WAIT_TIME", 1, wait);
			break;
	}

	if (use_speed_mod) // FIXME: Not the other way around?
		SetTextSpeed(-1);
	else
		SetTextSpeed(speed);

	if (use_wait_mod)
		SetTextWait(wait);
	else
		SetTextWait(-1);

	cmd.clear();
}

void Text::impl_GetName(Cmd& cmd)
{
	// replace_name を得る
	int n = cmd.args[0].value;
	if (n >= 0 && n < 26) // FIXME: Should go up to 702, but otakunoraifu is not ready for that yet
		cmd.SetStrvar(cmd.args[1], replace_name[n]);
	else
		cmd.SetStrvar(cmd.args[1], "");
}

void Text::impl_SetName(Cmd& cmd)
{
	// replace_name を得る
	int n = cmd.args[0].value;
	if (n >= 0 && n < 26) // FIXME: Should go up to 702, but otakunoraifu is not ready for that yet
		replace_name[n] = cmd.Str(cmd.args[1]);
}

void Text::impl_GetLocalName(Cmd& cmd)
{
	// replace_name2 を得る
	int n = cmd.args[0].value;
	if (n >= 0 && n < 26) // FIXME: Should go up to 702, but otakunoraifu is not ready for that yet
		cmd.SetStrvar(cmd.args[1], replace_name2[n]);
	else
		cmd.SetStrvar(cmd.args[1], "");
}

void Text::impl_SetLocalName(Cmd& cmd)
{
	// replace_name2 の設定
	int n = cmd.args[0].value;
	if (n >= 0 && n < 26) // FIXME: Should go up to 702, but otakunoraifu is not ready for that yet
		replace_name2[n] = cmd.Str(cmd.args[1]);

	cmd.clear();
}