diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/atcommand.c | 22 | ||||
-rw-r--r-- | src/map/clif.c | 23 | ||||
-rw-r--r-- | src/map/clif.h | 1 | ||||
-rw-r--r-- | src/map/mob.c | 132 | ||||
-rw-r--r-- | src/map/mob.h | 7 | ||||
-rw-r--r-- | src/map/skill.c | 1 | ||||
-rw-r--r-- | src/map/skill.h | 6 |
7 files changed, 182 insertions, 10 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c index ceb8ddb42..7424d1ab0 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -6343,20 +6343,31 @@ int atcommand_cleanmap(const int fd, struct map_session_data* sd, const char* co /*========================================== * make a NPC/PET talk + * @npctalkc [SnakeDrak] *------------------------------------------*/ int atcommand_npctalk(const int fd, struct map_session_data* sd, const char* command, const char* message) { char name[NAME_LENGTH],mes[100],temp[100]; struct npc_data *nd; + bool ifcolor=(*(command + 8) != 'c' && *(command + 8) != 'C')?0:1; + unsigned long color=0; if (sd->sc.count && //no "chatting" while muted. (sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return -1; - if (!message || !*message || sscanf(message, "%23[^,], %99[^\n]", name, mes) < 2) { - clif_displaymessage(fd, "Please, enter the correct info (usage: @npctalk <npc name>, <message>)."); - return -1; + if(!ifcolor) { + if (!message || !*message || sscanf(message, "%23[^,], %99[^\n]", name, mes) < 2) { + clif_displaymessage(fd, "Please, enter the correct info (usage: @npctalk <npc name>, <message>)."); + return -1; + } + } + else { + if (!message || !*message || sscanf(message, "%lx %23[^,], %99[^\n]", &color, name, mes) < 3) { + clif_displaymessage(fd, "Please, enter the correct info (usage: @npctalkc <color> <npc name>, <message>)."); + return -1; + } } if (!(nd = npc_name2id(name))) { @@ -6366,7 +6377,9 @@ int atcommand_npctalk(const int fd, struct map_session_data* sd, const char* com strtok(name, "#"); // discard extra name identifier if present snprintf(temp, sizeof(temp), "%s : %s", name, mes); - clif_message(&nd->bl, temp); + + if(ifcolor) clif_messagecolor(&nd->bl,color,temp); + else clif_message(&nd->bl, temp); return 0; } @@ -8733,6 +8746,7 @@ AtCommandInfo atcommand_info[] = { { "mobsearch", 10,10, atcommand_mobsearch }, { "cleanmap", 40,40, atcommand_cleanmap }, { "npctalk", 20,20, atcommand_npctalk }, + { "npctalkc", 20,20, atcommand_npctalk }, { "pettalk", 10,10, atcommand_pettalk }, { "users", 40,40, atcommand_users }, { "reset", 40,40, atcommand_reset }, diff --git a/src/map/clif.c b/src/map/clif.c index 1d8c2e752..7d14ac446 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -7381,6 +7381,29 @@ void clif_specialeffect_single(struct block_list* bl, int type, int fd) WFIFOSET(fd,10); } +/****************************************************** + * W.<packet> W.<LENGTH> L.<ID> L.<COLOR> S.<TEXT> + * Mob/NPC Color Talk [SnakeDrak] + ******************************************************/ +int clif_messagecolor(struct block_list* bl, unsigned long color, const char* msg) +{ + unsigned short msg_len = strlen(msg) + 1; + uint8 buf[256]; + color = (color & 0x0000FF) << 16 | (color & 0x00FF00) | (color & 0xFF0000) >> 16; // RGB to BGR + + nullpo_retr(0, bl); + + WBUFW(buf,0) = 0x2C1; + WBUFW(buf,2) = msg_len + 12; + WBUFL(buf,4) = bl->id; + WBUFL(buf,8) = color; + memcpy(WBUFP(buf,12), msg, msg_len); + + clif_send(buf, WBUFW(buf,2), bl, AREA_CHAT_WOC); + + return 0; +} + // messages (from mobs/npcs) [Valaris] int clif_message(struct block_list* bl, const char* msg) { diff --git a/src/map/clif.h b/src/map/clif.h index 2a7007e2b..605bbd762 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -371,6 +371,7 @@ int clif_mob_hp(struct mob_data *md); void clif_weather(int m); // [Valaris] int clif_specialeffect(struct block_list* bl, int type, enum send_target target); // special effects [Valaris] void clif_specialeffect_single(struct block_list* bl, int type, int fd); +int clif_messagecolor(struct block_list* bl, unsigned long color, const char* msg); // Mob/Npc color talk [SnakeDrak] int clif_message(struct block_list *bl, const char* msg); // messages (from mobs/npcs) [Valaris] int clif_GM_kickack(struct map_session_data *sd,int id); diff --git a/src/map/mob.c b/src/map/mob.c index a0066bfa3..afe8adf5b 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -51,6 +51,7 @@ #define MOB_MAX_DELAY (24*3600*1000) #define MAX_MINCHASE 30 //Max minimum chase value to use for mobs. #define RUDE_ATTACKED_COUNT 2 //After how many rude-attacks should the skill be used? +#define MAX_MOB_CHAT 250 //Max Skill's messages //Dynamic mob database, allows saving of memory when there's big gaps in the mob_db [Skotlex] struct mob_db *mob_db_data[MAX_MOB_DB+1]; @@ -58,6 +59,10 @@ struct mob_db *mob_dummy = NULL; //Dummy mob to be returned when a non-existant struct mob_db *mob_db(int index) { if (index < 0 || index > MAX_MOB_DB || mob_db_data[index] == NULL) return mob_dummy; return mob_db_data[index]; } +//Dynamic mob chat database +struct mob_chat *mob_chat_db[MAX_MOB_CHAT+1]; +struct mob_chat *mob_chat(short id) { if(id<=0 || id>MAX_MOB_CHAT || mob_chat_db[id]==NULL) return (struct mob_chat*)NULL; return mob_chat_db[id]; } + static struct eri *item_drop_ers; //For loot drops delay structures. static struct eri *item_drop_list_ers; @@ -2978,6 +2983,13 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) if (!flag) continue; //Skill requisite failed to be fulfilled. + if (ms[i].msg_id){ //Display color message [SnakeDrak] + struct mob_chat *mc = mob_chat(ms[i].msg_id); + char temp[CHAT_SIZE_MAX]; + snprintf(temp, sizeof temp,"%s : %s", md->name, mc->msg); + clif_messagecolor(&md->bl, mc->color, temp); + } + //Execute skill if (skill_get_casttype(ms[i].skill_id) == CAST_GROUND) { //Ground skill. @@ -3869,6 +3881,103 @@ static int mob_read_randommonster(void) } /*========================================== + * processes one mob_chat_db entry [SnakeDrak] + * @param last_msg_id ensures that only one error message per mob id is printed + *------------------------------------------*/ +static bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_msg_id) +{ + struct mob_chat *ms; + int msg_id; + + msg_id = atoi(str[0]); + + if (msg_id <= 0 || msg_id > MAX_MOB_CHAT) + { + if (msg_id != *last_msg_id) { + ShowError("mob_chat: Invalid chat ID: %d at %s, line %d\n", msg_id, source, line); + *last_msg_id = msg_id; + } + return false; + } + + if (mob_chat_db[msg_id] == NULL) + mob_chat_db[msg_id] = (struct mob_chat*)aCalloc(1, sizeof (struct mob_chat)); + + ms = mob_chat_db[msg_id]; + //MSG ID + ms->msg_id=msg_id; + //Color + ms->color=strtoul(str[1],NULL,0); + //Message + if(strlen(str[2])>(CHAT_SIZE_MAX-1)){ + if (msg_id != *last_msg_id) { + ShowError("mob_chat: readdb: Message too long! Line %d, id: %d\n", line, msg_id); + *last_msg_id = msg_id; + } + return false; + } + strncpy(ms->msg, str[2], CHAT_SIZE_MAX); + + return true; +} + +/*========================================== + * mob_chat_db.txt reading [SnakeDrak] + *-------------------------------------------------------------------------*/ +static void mob_readchatdb(void) +{ + char arc[]="mob_chat_db.txt"; + uint32 lines=0, count=0; + char line[1024], path[256]; + int i, tmp=0; + FILE *fp; + sprintf(path, "%s/%s", db_path, arc); + fp=fopen(path, "r"); + if(fp == NULL) + { + ShowWarning("mob_readchatdb: File not found \"%s\", skipping.\n", path); + return; + } + + while(fgets(line, sizeof(line), fp)) + { + char *str[3], *p, *np; + int j=0; + + lines++; + if(line[0] == '/' && line[1] == '/') + continue; + memset(str, 0, sizeof(str)); + + p=line; + while(ISSPACE(*p)) + ++p; + if(*p == '\0') + continue;// empty line + for(i = 0; i <= 2; i++) + { + str[i] = p; + if(i<2 && (np = strchr(p, ',')) != NULL) { + *np = '\0'; p = np + 1; j++; + } + } + + if( j < 2 || str[2]==NULL) + { + ShowError("mob_readchatdb: Insufficient number of fields for skill at %s, line %d\n", arc, lines); + continue; + } + + if( !mob_parse_row_chatdb(str, path, lines, &tmp) ) + continue; + + count++; + } + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", arc); +} + +/*========================================== * processes one mob_skill_db entry * @param last_mob_id ensures that only one error message per mob id is printed *------------------------------------------*/ @@ -4092,6 +4201,12 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i ms->emotion=atoi(str[17]); else ms->emotion=-1; + + if(str[18]!=NULL && mob_chat_db[atoi(str[18])]!=NULL) + ms->msg_id=atoi(str[18]); + else + ms->msg_id=0; + if (mob_id < 0) { //Set this skill to ALL mobs. [Skotlex] mob_id *= -1; @@ -4156,6 +4271,7 @@ static int mob_readskilldb(void) while(fgets(line, sizeof(line), fp)) { char *str[20], *p, *np; + int j=0; lines++; if(line[0] == '/' && line[1] == '/') @@ -4167,15 +4283,15 @@ static int mob_readskilldb(void) ++p; if( *p == '\0' ) continue;// empty line - for(i = 0; i < 18; i++) + for(i = 0; i < 19; i++) { str[i] = p; if((np = strchr(p, ',')) != NULL) { - *np = '\0'; p = np + 1; + *np = '\0'; p = np + 1; j++; } } - if( i < 18 ) + if ( j < 18 || str[18]==NULL ) { ShowError("mob_readskilldb: Insufficient number of fields for skill at %s, line %d\n", filename[fi], lines); continue; @@ -4262,6 +4378,7 @@ void mob_reload(void) memset(&mob_db_data[i]->skill,0,sizeof(mob_db_data[i]->skill)); mob_db_data[i]->maxskill=0; } + mob_readchatdb(); mob_readskilldb(); mob_readdb_race(); } @@ -4294,6 +4411,7 @@ int do_init_mob(void) mob_readdb_mobavail(); mob_read_randommonster(); + mob_readchatdb(); mob_readskilldb(); mob_readdb_race(); @@ -4329,6 +4447,14 @@ int do_final_mob(void) mob_db_data[i] = NULL; } } + for (i = 0; i <= MAX_MOB_CHAT; i++) + { + if (mob_chat_db[i] != NULL) + { + aFree(mob_chat_db[i]); + mob_chat_db[i] = NULL; + } + } ers_destroy(item_drop_ers); ers_destroy(item_drop_list_ers); return 0; diff --git a/src/map/mob.h b/src/map/mob.h index b5127310f..b7f193b5b 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -62,6 +62,13 @@ struct mob_skill { short target; int val[5]; short emotion; + unsigned short msg_id; +}; + +struct mob_chat { + unsigned short msg_id; + unsigned long color; + char msg[CHAT_SIZE_MAX]; }; struct spawn_info { diff --git a/src/map/skill.c b/src/map/skill.c index dde93adbf..3c3ea3802 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -5701,6 +5701,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in skill_castend_nodamage_id); } break; + case NPC_TALK: case ALL_WEWISH: clif_skill_nodamage(src,bl,skillid,skilllv,1); break; diff --git a/src/map/skill.h b/src/map/skill.h index 6c8ac178e..a74a0e644 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -965,9 +965,9 @@ enum e_skill { NPC_VAMPIRE_GIFT, NPC_WIDESOULDRAIN, - ALL_INCCARRY = 681, - //NPC_TALK = 682, - NPC_HELLPOWER = 683, + ALL_INCCARRY, + NPC_TALK, + NPC_HELLPOWER, NPC_WIDEHELLDIGNITY, NPC_INVINCIBLE, NPC_INVINCIBLEOFF, |