src/map/atcommand.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/map/battle.c | 4 ++
src/map/chat.c | 20 ++++++++
src/map/chat.h | 2 +
src/map/clif.c | 2 +
src/map/map.c | 3 ++
src/map/mob.c | 40 ++++++++++++++++
src/map/mob.h | 5 ++
src/map/pc.h | 2 +
src/map/status.c | 4 ++
10 files changed, 213 insertions(+)
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index b788c6c..b8744ea 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -3636,6 +3636,11 @@ void atcommand_raise_sub(struct map_session_data* sd) {
if (pl_sd->st && pl_sd->st->state != END)
pl_sd->st->state = END;
}
+ if ( pl_sd->market_clone_id ) {
+ status->damage( NULL, map->id2bl( pl_sd->market_clone_id ), 100, 0, 0, 5 );
+ pl_sd->market_clone_id = 0;
+ pl_sd->market_clone_delay = (int)time(NULL);
+ }
}
mapit->free(iter);
@@ -9374,6 +9378,131 @@ static inline void atcmd_channel_help(int fd, const char *command, bool can_crea
clif->message(fd,atcmd_output);
return true;
}
+
+ACMD(market){
+ char title[CHAT_SIZE_MAX], msg[CHAT_SIZE_MAX];
+ int clone_delay = 10; // 10 seconds
+ if ( sd->market_clone_id ) {
+ clif->message( fd, "You already have a Market clone summoned. Type '@marketkill' to remove that clone.");
+ return false;
+ }
+ if ( sd->market_clone_delay + clone_delay > (int)time(NULL) ) {
+ safesnprintf( atcmd_output, CHAT_SIZE_MAX, "You must wait %d seconds before using this command again.", sd->market_clone_delay + clone_delay - (int)time(NULL) );
+ clif->message( fd, atcmd_output );
+ return false;
+ }
+ if ( !map->list[sd->bl.m].flag.town ) {
+ clif->message( fd, "You can only use @market in a town.");
+ return false;
+ }
+ if ( map->getcell( sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOCHAT ) ) {
+ clif->message( fd, "You cannot use @market in this area.");
+ return false;
+ }
+ if ( pc_isdead(sd) ) {
+ clif->message( fd, "You can't create a Market clone while you are dead." );
+ return false;
+ }
+ if ( npc->isnear( &sd->bl ) ) {
+ clif->message( fd, "You can't create a Market clone too near to an npc." );
+ return false;
+ }
+ if ( !message || !*message ) {
+ clif->message( fd, "Syntax: @market \"<Title>\" \"<Message>\"");
+ return false;
+ }
+// if ( sscanf( message, "\"%[^\"]\" \"%[^\"]\"", title, msg ) < 2 ) {
+// clif->message( fd, "Remember the Quotation Mark -> \"");
+// clif->message( fd, "Syntax: @market \"<Title>\" \"<Message>\"");
+// return false;
+// } no more f*cking sscanf
+ { // say hello to the dirties string calculation ~ Hooray ~ !!
+ int i = 0, j = 0, l = strlen( message ) +1;
+ char *temp = (char*)aMalloc( strlen( message ) +1 );
+ if ( message[0] != '\"' ) {
+ clif->message( fd, "Remember the <Title> should start with a Quotation Mark -> \"");
+ clif->message( fd, "Syntax: @market \"<Title>\" \"<Message>\"");
+ return false;
+ }
+ i = 1;
+ while ( i <= l ) {
+ if ( message[i] == '\"' || message[i] == '\0' )
+ break;
+ else
+ temp[j++] = message[i];
+ i++;
+ }
+ if ( message[i] != '\"' ) {
+ clif->message( fd, "Remember the <Title> should end with a Quotation Mark -> \"");
+ clif->message( fd, "Syntax: @market \"<Title>\" \"<Message>\"");
+ return false;
+ }
+ temp[j] = '\0';
+ safestrncpy( title, temp, CHAT_SIZE_MAX );
+ i++;
+ if ( message[i] != ' ' ) {
+ clif->message( fd, "Remember the [Space] between the <Title> and <Message>.");
+ clif->message( fd, "Syntax: @market \"<Title>\" \"<Message>\"");
+ return false;
+ }
+ i++;
+ if ( message[i] != '\"' ) {
+ clif->message( fd, "Remember the <Message> should start with a Quotation Mark -> \"");
+ clif->message( fd, "Syntax: @market \"<Title>\" \"<Message>\"");
+ return false;
+ }
+ i++;
+ j = 0;
+ while ( i <= l ) {
+ if ( message[i] == '\"' || message[i] == '\0' )
+ break;
+ else
+ temp[j++] = message[i];
+ i++;
+ }
+ if ( message[i] != '\"' ) {
+ clif->message( fd, "Remember the <Message> should end with a Quotation Mark -> \"");
+ clif->message( fd, "Syntax: @market \"<Title>\" \"<Message>\"");
+ return false;
+ }
+ temp[j] = '\0';
+ safestrncpy( msg, temp, CHAT_SIZE_MAX );
+ aFree( temp );
+ }
+ if ( strlen( title ) < 4 ) {
+ clif->message( fd, "The Title must more than 4 characters." );
+ return false;
+ }
+ if ( strlen( title ) >= CHATROOM_TITLE_SIZE ) {
+ safesnprintf( atcmd_output, CHAT_SIZE_MAX, "The Title must not more than %d characters.", CHATROOM_TITLE_SIZE );
+ clif->message( fd, atcmd_output );
+ return false;
+ }
+ if ( strlen( msg ) < 4 ) {
+ clif->message( fd, "The Message must more than 4 characters." );
+ return false;
+ }
+ sd->market_clone_id = mob->clone_spawn_market( sd, sd->bl.m, sd->bl.x, sd->bl.y, title, msg );
+ if ( !sd->market_clone_id ) {
+ clif->message( fd, "Market clone Cannot be Created." );
+ return false;
+ }
+ clif->message( fd, "Market clone Created." );
+ return true;
+}
+
+ACMD(marketkill){
+ if ( !sd->market_clone_id ) {
+ clif->message( fd, "You don't have a market clone yet. Type '@market \"<title>\" \"<message>\"' to create one.");
+ return false;
+ }
+ status->damage( NULL, map->id2bl( sd->market_clone_id ), 100, 0, 0, 5 );
+ clif->message( fd, "Your market clone has removed." );
+ sd->market_clone_id = 0;
+ sd->market_clone_delay = (int)time(NULL);
+ return true;
+}
+
/**
* Fills the reference of available commands in atcommand DBMap
**/
@@ -9384,6 +9513,8 @@ void atcommand_basecommands(void) {
* Command reference list, place the base of your commands here
**/
AtCommandInfo atcommand_base[] = {
+ ACMD_DEF(market),
+ ACMD_DEF(marketkill),
ACMD_DEF2("warp", mapmove),
ACMD_DEF(where),
ACMD_DEF(jumpto),
diff --git a/src/map/battle.c b/src/map/battle.c
index fa388fc..dc5a319 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -6112,6 +6112,10 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
if( (s_bl = battle->get_master(src)) == NULL )
s_bl = src;
+ if ( target->type == BL_MOB )
+ if ( ((TBL_MOB*)target)->market_chat_id )
+ return -1;
+
if ( s_bl->type == BL_PC ) {
switch( t_bl->type ) {
case BL_MOB: // Source => PC, Target => MOB
diff --git a/src/map/chat.c b/src/map/chat.c
index cd7b5f8..c1e82e6 100644
--- a/src/map/chat.c
+++ b/src/map/chat.c
@@ -125,6 +125,26 @@ bool chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) {
return false;
}
+ if ( cd->owner->type == BL_MOB ) {
+ struct mob_data *md = (TBL_MOB*)cd->owner;
+ if ( md->market_chat_id ) {
+ short msg_len = 0;
+ int color = 0xFFC0CB; // PINK !
+ int colorcode = (color & 0x0000FF) << 16 | (color & 0x00FF00) | (color & 0xFF0000) >> 16;
+ char output[CHAT_SIZE_MAX];
+ safesnprintf( output, CHAT_SIZE_MAX, "%s : %s", md->name, md->market_message );
+ msg_len = strlen( output )+1;
+ WFIFOHEAD( sd->fd, msg_len + 12 );
+ WFIFOW( sd->fd, 0 ) = 0x2C1;
+ WFIFOW( sd->fd, 2 ) = msg_len + 12;
+ WFIFOL( sd->fd, 4 ) = 0;
+ WFIFOL( sd->fd, 8 ) = colorcode;
+ safestrncpy( (char*)WFIFOP( sd->fd,12 ), output, msg_len );
+ WFIFOSET( sd->fd, msg_len + 12 );
+ return true;
+ }
+ }
+
if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) )
{
clif->joinchatfail(sd,1); // wrong password
diff --git a/src/map/chat.h b/src/map/chat.h
index e055c04..1f6bf4d 100644
--- a/src/map/chat.h
+++ b/src/map/chat.h
@@ -6,6 +6,8 @@
#define MAP_CHAT_H
#include "map.h" // struct block_list, CHATROOM_TITLE_SIZE
+#include "mob.h"
+#include "../common/socket.h"
#include "../common/cbasetypes.h"
#include "../common/db.h"
diff --git a/src/map/clif.c b/src/map/clif.c
index 308f419..033ae73 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -4367,6 +4367,8 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) {
}
}
#endif
+ if ( md->market_chat_id )
+ clif->dispchat( (struct chat_data*)map->id2bl( md->market_chat_id ), sd->fd );
}
break;
case BL_PET:
diff --git a/src/map/map.c b/src/map/map.c
index 0c8c2d9..4cd1dd4 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1670,6 +1670,9 @@ void map_deliddb(struct block_list *bl)
int map_quit(struct map_session_data *sd) {
int i;
+ if ( sd->market_clone_id )
+ status->damage( NULL, map->id2bl( sd->market_clone_id ), 100, 0, 0, 5 );
+
if(!sd->state.active) { //Removing a player that is not active.
struct auth_node *node = chrif->search(sd->status.account_id);
if (node && node->char_id == sd->status.char_id &&
diff --git a/src/map/mob.c b/src/map/mob.c
index fd2c421..11df8cf 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -3531,6 +3531,45 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
return md->bl.id;
}
+int mob_clone_spawn_market( struct map_session_data *sd, int16 m, int16 x, int16 y, char market_title[], char market_msg[] ) { //Copy of mob_clone_spawn with some modification.
+ int class_;
+ struct mob_data *md;
+ struct mob_db* db;
+ struct status_data *mstatus;
+ struct chat_data* cd;
+
+ ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, class_, mob->db_data[class_] == NULL );
+ if ( class_ >= MOB_CLONE_END )
+ return 0;
+
+ db = mob->db_data[class_] = (struct mob_db*)aCalloc( 1, sizeof(struct mob_db) );
+ mstatus = &db->status;
+ safestrncpy( db->sprite, sd->status.name, NAME_LENGTH );
+ safestrncpy( db->name, sd->status.name, NAME_LENGTH );
+ safestrncpy( db->jname, sd->status.name, NAME_LENGTH );
+ db->lv = status->get_lv(&sd->bl);
+ memcpy( mstatus, &sd->base_status, sizeof( struct status_data ) );
+ mstatus->rhw.atk = mstatus->rhw.atk2 = mstatus->lhw.atk = mstatus->lhw.atk2 = mstatus->hp = mstatus->max_hp = mstatus->sp = mstatus->max_sp = 1;
+ mstatus->mode = 0;
+ memcpy( &db->vd, &sd->vd, sizeof( struct view_data ) );
+ db->base_exp = db->job_exp = db->range2 = db->range3 = 1;
+ db->option = 0;
+
+ md = mob->once_spawn_sub( &sd->bl, m, x, y, sd->status.name, class_, "", SZ_SMALL, AI_NONE );
+ if ( !md )
+ return 0;
+ md->special_state.clone = 1;
+ mob->spawn(md);
+ unit->setdir( &md->bl, 4 );
+ cd = chat->create( &md->bl, market_title, "", 1, false, 0, "", 0, 1, MAX_LEVEL );
+ if ( !cd )
+ return 0;
+ md->market_chat_id = cd->bl.id;
+ safestrncpy( md->market_message, market_msg, CHAT_SIZE_MAX );
+ clif->dispchat( cd, 0 );
+ return md->bl.id;
+}
+
int mob_clone_delete(struct mob_data *md)
{
const int class_ = md->class_;
@@ -4806,6 +4845,7 @@ void mob_defaults(void) {
mob->skill_event = mobskill_event;
mob->is_clone = mob_is_clone;
mob->clone_spawn = mob_clone_spawn;
+ mob->clone_spawn_market = mob_clone_spawn_market;
mob->clone_delete = mob_clone_delete;
mob->drop_adjust = mob_drop_adjust;
mob->item_dropratio_adjust = item_dropratio_adjust;
diff --git a/src/map/mob.h b/src/map/mob.h
index 728f3d8..9b71a6b 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -8,6 +8,7 @@
#include "map.h" // struct status_data, struct view_data, struct mob_skill
#include "status.h" // struct status_data, struct status_change
#include "unit.h" // struct unit_data
+#include "chat.h"
#include "../common/cbasetypes.h"
#include "../common/mmo.h" // struct item
@@ -185,6 +186,9 @@ struct mob_data {
* MvP Tombstone NPC ID
**/
int tomb_nid;
+
+ int market_chat_id;
+ char market_message[CHAT_SIZE_MAX];
};
@@ -338,6 +342,7 @@ struct mob_interface {
int (*skill_event) (struct mob_data *md, struct block_list *src, int64 tick, int flag);
int (*is_clone) (int class_);
int (*clone_spawn) (struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, int mode, int flag, unsigned int duration);
+ int (*clone_spawn_market) ( struct map_session_data *sd, int16 m, int16 x, int16 y, char market_title[], char market_msg[] );
int (*clone_delete) (struct mob_data *md);
unsigned int (*drop_adjust) (int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max);
void (*item_dropratio_adjust) (int nameid, int mob_id, int *rate_adjust);
diff --git a/src/map/pc.h b/src/map/pc.h
index bec4522..267a24f 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -547,6 +547,8 @@ struct map_session_data {
const char* delunit_prevfile;
int delunit_prevline;
+ int market_clone_id;
+ int market_clone_delay;
};
#define EQP_WEAPON EQP_HAND_R
diff --git a/src/map/status.c b/src/map/status.c
index 8393a6c..71ebdc1 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -1441,6 +1441,10 @@ int status_percent_change(struct block_list *src,struct block_list *target,signe
st = status->get_status_data(target);
+ if ( target->type == BL_MOB )
+ if ( ((TBL_MOB*)target)->market_chat_id )
+ return 0;
+
if (hp_rate > 100)
hp_rate = 100;
else if (hp_rate < -100)