/** The Mana World Copyright 2004 The Mana World Development Team This file is part of The Mana World. The Mana World is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. The Mana World is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with The Mana World; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** Simple ChatLog Object v0.5 (i'd say...) Bestviewd w/ Bitstream Vera Sans Mono @ 9pt and a tab-width of 2 spaces Author: kth5 aka Alexander Baldeck pipe your questions, suggestions and flames to: kth5@gawab.com */ #include "../main.h" #include "chat.h" #include #include #include using namespace std; Chat::Chat(const char * logfile, int item_num) { chatlog_file.open(logfile, ios::out | ios::app); items = 0; items_keep = item_num; } Chat::~Chat() { chatlog_file.flush(); chatlog_file.close(); } void Chat::chat_dlgrsize(int) { } /** adds a line of text to our message list string line -> message text int own -> type of message (usually the owner-type) ALFONT_FONT * font -> font that'll be used to draw the text later NOTE: to all of you who wonder why the font needs to be passed, simple. i already store the width in pixel in the list rather than calculating it again and again on every draw event. ;-) */ void Chat::chat_log(string line, int own, ALFONT_FONT * font) { int pos; CHATLOG tmp; if(items<=items_keep) items++; // delete overhead from the end of the list else chatlog.pop_back(); pos = 0; pos = (int)line.find(" : ", 0); if(pos > 0) { tmp.nick = line.substr(0,pos); switch(own) { case ACT_IS : tmp.nick += CAT_IS; break; case ACT_WHISPER : tmp.nick += CAT_WHISPER; break; default : tmp.nick += CAT_NORMAL; } tmp.width = TEXT_GETWIDTH(tmp.nick.c_str())+2; line.erase(0,pos+3); }else { tmp.nick = ""; tmp.width = 1; } tmp.own = own; tmp.text = line; chatlog_file << tmp.nick << tmp.text << "\n"; chatlog_file.flush(); chatlog.push_front(tmp); } void Chat::chat_log(CHATSKILL action, ALFONT_FONT * font) { chat_log(const_msg(action), BY_SERVER, font); } /** draw first n lines of the list onto a Allegro type bitmap buffer using Alfont BITMAP * bmp -> Allegro type bitmap buffer to draw onto int n -> number of lines to be drawn ALFONT_FONT * font -> font to use NOTE: take great care using this, make sure the buffer passed is empty! ;-) anyway, line wrapping is not supported yet. */ void Chat::chat_draw(BITMAP * bmp, int n, ALFONT_FONT * font) { int y = 600-35, i = 0; CHATLOG line; n -= 1; for(iter = chatlog.begin(); iter != chatlog.end(); iter++) { line = *iter; y -=11; switch(line.own) { case BY_GM : alfont_textprintf_aa(bmp, font, 1, y, COLOR_BLUE, "Global announcement: "); alfont_textprintf_aa(bmp, font, TEXT_GETWIDTH("Global announcement: "), y, COLOR_GREEN, line.text.c_str()); break; case BY_PLAYER : alfont_textprintf_aa(bmp, font, 1, y, COLOR_YELLOW, line.nick.c_str()); alfont_textprintf_aa(bmp, font, line.width, y, COLOR_WHITE, line.text.c_str()); break; case BY_OTHER : alfont_textprintf_aa(bmp, font, 1, y, COLOR_GREEN, line.nick.c_str()); alfont_textprintf_aa(bmp, font, line.width, y, COLOR_WHITE, line.text.c_str()); break; default : alfont_textprintf_aa(bmp, font, 1, y, COLOR_LIGHTBLUE, line.text.c_str()); } if(i>=n) return; i++; } } /** determines wether to send a command or an ordinary message, then contructs packets & sends them string nick -> the character's name to display infront string msg -> the message's text which is to be send. NOTE: the nickname is required by the server, if not specified the message may not be sent unless a command was intended which requires another packet to be constructed! you can achieve this by putting a slash ("/") infront of the message followed by the command name and the message. of course all slash-commands need implemented handler- routines. ;-) remember, a line starting w/ "@" is not a command that needs to be parsed rather is sent using the normal chat-packet. EXAMPLE: // for an global announcement /- command chatlog.chat_send("", "/announce Hello to all logged in users!"); // for simple message by a user /- message chatlog.chat_send("Zaeiru", "Hello to all users on the screen!"); */ char * Chat::chat_send(string nick, string msg) { short packid; // prepare command if(msg.substr(0,1)=="/") { // global announcement if(msg.substr(0,IS_ANNOUNCE_LENGTH) == IS_ANNOUNCE) { msg.erase(0,IS_ANNOUNCE_LENGTH); packid = 0x0099; } else { packid = 0x008c; } // prepare ordinary message } else { // temporary hack to make messed-up-keyboard-ppl able to send GM commands if(msg.substr(0,1)=="#") msg.replace(0,1,"@"); // end temp. hack XD nick += " : "; nick += msg; msg = nick; packid = 0x008c; } msg += "\0"; // send processed message WFIFOW(0) = net_w_value(packid); WFIFOW(2) = net_w_value(msg.length()+4); memcpy(WFIFOP(4), msg.c_str(), msg.length()); WFIFOSET(msg.length()+4); nick = msg = ""; return ""; } /** PRIVATE : NOTE: these usually will be left undocumented coz u can't call them directly anyway. ;-) */ /** constructs failed messages for actions */ string Chat::const_msg(CHATSKILL action) { string msg; if(action.success == SKILL_FAILED && action.skill == SKILL_BASIC) { switch(action.bskill) { case BSKILL_TRADE : msg = "Trade failed!"; break; case BSKILL_EMOTE : msg = "Emote failed!"; break; case BSKILL_SIT : msg = "Sit failed!"; break; case BSKILL_CREATECHAT : msg = "Chat creating failed!"; break; case BSKILL_JOINPARTY : msg = "Could not join party!"; break; case BSKILL_SHOUT : msg = "Cannot shout!"; break; } switch(action.reason) { case RFAIL_SKILLDEP : msg += " You have not yet reached a high enough lvl!"; break; case RFAIL_INSUFHP : msg += " Insufficient HP!"; break; case RFAIL_INSUFSP : msg += " Insufficient SP!"; break; case RFAIL_NOMEMO : msg += " You have no memos!"; break; case RFAIL_SKILLDELAY : msg += " You cannot do that right now!"; break; case RFAIL_ZENY : msg += " Seems you need more Zeny... ;-)"; break; case RFAIL_WEAPON : msg += " You cannot use this skill with that kind of weapon!"; break; case RFAIL_REDGEM : msg += " You need another red gem!"; break; case RFAIL_BLUEGEM : msg += " You need another blue gem!"; break; case RFAIL_OVERWEIGHT : msg += " You're carrying to much to do this!"; break; default : msg += " Huh? What's that?"; break; } }else{ switch(action.skill) { case SKILL_WARP : msg = "Warp failed..."; break; case SKILL_STEAL : msg = "Could not steal anything..."; break; case SKILL_ENVENOM : msg = "Poison had no effect..."; break; } } return msg; } string const_msg(int own) { string msg; return msg; }