From 92249d9f8e219916670589ba6c5f9fce47808ed8 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Fri, 20 Apr 2012 18:05:14 +0000 Subject: Initial support for Genetic, Sorcerer and Elemental Summons. Special Thanks to 3CeAM for the base. Notice this revision onwards requires you to update your char sql table and add the elemental sql table (check sql-files/upgrade_svn15885_log.sql) If you step by any bugs, let us know at http://rathena.org/board/tracker/ Thank you very much. ARRIBA ARRIBA. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15885 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/Makefile.in | 4 +- src/map/atcommand.c | 3 + src/map/battle.c | 252 +++++- src/map/chrif.c | 3 + src/map/clif.c | 305 +++++-- src/map/clif.h | 39 +- src/map/elemental.c | 825 +++++++++++++++++++ src/map/elemental.h | 95 +++ src/map/intif.c | 97 ++- src/map/intif.h | 6 + src/map/itemdb.h | 1 + src/map/map.c | 11 +- src/map/map.h | 6 +- src/map/mob.c | 10 + src/map/npc_chat.c | 2 +- src/map/pc.c | 11 +- src/map/pc.h | 3 +- src/map/script.c | 2 +- src/map/skill.c | 2287 ++++++++++++++++++++++++++++++++++++--------------- src/map/skill.h | 91 +- src/map/status.c | 477 +++++++---- src/map/status.h | 22 +- src/map/unit.c | 287 ++++--- 23 files changed, 3646 insertions(+), 1193 deletions(-) create mode 100644 src/map/elemental.c create mode 100644 src/map/elemental.h (limited to 'src/map') diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 0b5ba023d..beeab32dd 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -31,7 +31,7 @@ MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \ storage.o skill.o atcommand.o battle.o battleground.o \ intif.o trade.o party.o vending.o guild.o pet.o \ log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \ - buyingstore.o searchstore.o duel.o pc_groups.o + buyingstore.o searchstore.o duel.o pc_groups.o elemental.o MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \ obj_sql/mapreg_sql.o MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ @@ -41,7 +41,7 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \ buyingstore.h searchstore.h duel.h pc_groups.h \ config/core.h config/renewal.h config/secure.h config/const.h \ - config/classes/general.h config/classes/swordsman.h + config/classes/general.h config/classes/swordsman.h elemental.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 8a918633a..c19164d1a 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -34,6 +34,7 @@ #include "homunculus.h" #include "mail.h" #include "mercenary.h" +#include "elemental.h" #include "party.h" #include "guild.h" #include "script.h" @@ -3764,6 +3765,7 @@ ACMD_FUNC(reloadmobdb) read_petdb(); merc_reload(); read_mercenarydb(); + reload_elementaldb(); clif_displaymessage(fd, msg_txt(98)); // Monster database has been reloaded. return 0; @@ -3777,6 +3779,7 @@ ACMD_FUNC(reloadskilldb) nullpo_retr(-1, sd); skill_reload(); merc_skill_reload(); + reload_elemental_skilldb(); read_mercenary_skilldb(); clif_displaymessage(fd, msg_txt(99)); // Skill database has been reloaded. diff --git a/src/map/battle.c b/src/map/battle.c index 48f8e1cab..cea562661 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -18,6 +18,7 @@ #include "skill.h" #include "homunculus.h" #include "mercenary.h" +#include "elemental.h" #include "mob.h" #include "itemdb.h" #include "clif.h" @@ -103,6 +104,7 @@ int battle_gettarget(struct block_list* bl) case BL_PET: return ((struct pet_data*)bl)->target_id; case BL_HOM: return ((struct homun_data*)bl)->ud.target; case BL_MER: return ((struct mercenary_data*)bl)->ud.target; + case BL_ELEM: return ((struct elemental_data*)bl)->ud.target; } return 0; } @@ -299,8 +301,7 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag } ratio = attr_fix_table[def_lv-1][atk_elem][def_type]; - if (sc && sc->count) - { + if (sc && sc->count) { if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE) ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1]; if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND) @@ -308,8 +309,27 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER) ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1]; } - if( atk_elem == ELE_FIRE && tsc && tsc->count && tsc->data[SC_SPIDERWEB] ) - { + if( target && target->type == BL_SKILL ) { + if( atk_elem == ELE_FIRE && battle_getcurrentskill(target) == GN_WALLOFTHORN ) { + struct skill_unit *su = (struct skill_unit*)target; + struct skill_unit_group *sg; + struct block_list *src; + int x,y; + + if( !su || !su->alive || (sg = su->group) == NULL || !sg || sg->val3 == -1 || + (src = map_id2bl(su->val2)) == NULL || status_isdead(src) ) + return 0; + + if( sg->unit_id != UNT_FIREWALL ) { + x = sg->val3 >> 16; + y = sg->val3 & 0xffff; + skill_unitsetting(src,su->group->skill_id,su->group->skill_lv,x,y,1); + sg->val3 = -1; + sg->limit = DIFF_TICK(gettick(),sg->tick)+300; + } + } + } + if( atk_elem == ELE_FIRE && tsc && tsc->count && tsc->data[SC_SPIDERWEB] ){ tsc->data[SC_SPIDERWEB]->val1 = 0; // free to move now if( tsc->data[SC_SPIDERWEB]->val2-- > 0 ) damage <<= 1; // double damage @@ -932,6 +952,8 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int case W_DAGGER: if((skill = pc_checkskill(sd,SM_SWORD)) > 0) damage += (skill * 4); + if((skill = pc_checkskill(sd,GN_TRAINING_SWORD)) > 0) + damage += skill * 10; break; case W_2HSWORD: #ifdef RENEWAL @@ -1486,15 +1508,27 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if(sd && pc_checkskill(sd,AS_SONICACCEL)>0) hitrate += hitrate * 50 / 100; break; + case MC_CARTREVOLUTION: + case GN_CART_TORNADO: + case GN_CARTCANNON: + if( sd && pc_checkskill(sd, GN_REMODELING_CART) ) + hitrate += pc_checkskill(sd, GN_REMODELING_CART) * 4; + break; case GC_VENOMPRESSURE: hitrate += 10 + 4 * skill_lv; break; } - // Weaponry Research hidden bonus - if (sd && (skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0) - hitrate += hitrate * ( 2 * skill ) / 100; - + if( sd ) { + // Weaponry Research hidden bonus + if ((skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0) + hitrate += hitrate * ( 2 * skill ) / 100; + + if( (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) && + (skill = pc_checkskill(sd, GN_TRAINING_SWORD))>0 ) + hitrate += 3 * skill; + } + hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate); if(rnd()%100 >= hitrate) @@ -2238,6 +2272,76 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case WM_SOUND_OF_DESTRUCTION: skillratio += 400; break; + case GN_CART_TORNADO: + if( sd ) + skillratio += 50 * skill_lv + pc_checkskill(sd, GN_REMODELING_CART) * 100 - 100; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_GN_CARTBOOST] ) + skillratio += 10 * sc->data[SC_GN_CARTBOOST]->val1; + break; + case GN_CARTCANNON: + if( sd ) skillratio += 250 + 50 * skill_lv + pc_checkskill(sd, GN_REMODELING_CART) * (sstatus->int_ / 2); + if( sc && sc->data[SC_GN_CARTBOOST] ) + skillratio += 10 * sc->data[SC_GN_CARTBOOST]->val1; + break; + case GN_SPORE_EXPLOSION: + skillratio += 200 + 100 * skill_lv; + break; + case GN_CRAZYWEED_ATK: + skillratio += 400 + 100 * skill_lv; + break; + case GN_SLINGITEM_RANGEMELEEATK: + if( sd ) { + switch( sd->itemid ) { + case 13260: // Apple Bomob + case 13261: // Coconut Bomb + case 13262: // Melon Bomb + case 13263: // Pinapple Bomb + skillratio += 400; // Unconfirded + break; + case 13264: // Banana Bomb 2000% + skillratio += 1900; + break; + case 13265: skillratio -= 75; break; // Black Lump 25% + case 13266: skillratio -= 25; break; // Hard Black Lump 75% + case 13267: skillratio += 100; break; // Extremely Hard Black Lump 200% + } + } else + skillratio += 300; // Bombs + break; + case SO_VARETYR_SPEAR: //Assumed Formula. + skillratio += -100 + 200 * ( sd ? pc_checkskill(sd, SA_LIGHTNINGLOADER) : 1 ); + if( sc && sc->data[SC_BLAST_OPTION] ) + skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100; + break; + // Physical Elemantal Spirits Attack Skills + case EL_CIRCLE_OF_FIRE: + case EL_FIRE_BOMB_ATK: + case EL_STONE_RAIN: + skillratio += 200; + break; + case EL_FIRE_WAVE_ATK: + skillratio += 500; + break; + case EL_TIDAL_WEAPON: + skillratio += 1400; + break; + case EL_WIND_SLASH: + skillratio += 100; + break; + case EL_HURRICANE: + skillratio += 600; + break; + case EL_TYPOON_MIS: + case EL_WATER_SCREW_ATK: + skillratio += 900; + break; + case EL_STONE_HAMMER: + skillratio += 400; + break; + case EL_ROCK_CRUSHER: + skillratio += 700; + break; } ATK_RATE(skillratio); @@ -2920,7 +3024,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int mflag) { int i, nk; - short s_ele; + short s_ele = 0; unsigned int skillratio = 100; //Skill dmg modifiers. struct map_session_data *sd, *tsd; @@ -2954,16 +3058,38 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, target); - //Initialize variables that will be used afterwards - s_ele = skill_get_ele(skill_num, skill_lv); - - if (s_ele == -1) // pl=-1 : the skill takes the weapon's element - s_ele = sstatus->rhw.ele; - else if (s_ele == -2) //Use status element - s_ele = status_get_attack_sc_element(src,status_get_sc(src)); - else if( s_ele == -3 ) //Use random element - s_ele = rnd()%ELE_MAX; - + if( skill_num == SO_PSYCHIC_WAVE ) { + struct status_change *sc = status_get_sc(src); + if( sc && sc->count && ( sc->data[SC_HEATER_OPTION] || sc->data[SC_COOLER_OPTION] || + sc->data[SC_BLAST_OPTION] || sc->data[SC_CURSED_SOIL_OPTION] ) ) { + if( sc->data[SC_HEATER_OPTION] ) s_ele = sc->data[SC_HEATER_OPTION]->val4; + else if( sc->data[SC_COOLER_OPTION] ) s_ele = sc->data[SC_COOLER_OPTION]->val4; + else if( sc->data[SC_BLAST_OPTION] ) s_ele = sc->data[SC_BLAST_OPTION]->val3; + else if( sc->data[SC_CURSED_SOIL_OPTION] ) s_ele = sc->data[SC_CURSED_SOIL_OPTION]->val4; + } else { + //#HALP# I didn't get a clue on how to do this without unnecessary adding a overhead of status_change on every call while this is a per-skill case. + //, - so i duplicated this code. make yourself comfortable to fix if you have any better ideas. + //Initialize variables that will be used afterwards + s_ele = skill_get_ele(skill_num, skill_lv); + + if (s_ele == -1) // pl=-1 : the skill takes the weapon's element + s_ele = sstatus->rhw.ele; + else if (s_ele == -2) //Use status element + s_ele = status_get_attack_sc_element(src,status_get_sc(src)); + else if( s_ele == -3 ) //Use random element + s_ele = rnd()%ELE_MAX; + } + } else { + //Initialize variables that will be used afterwards + s_ele = skill_get_ele(skill_num, skill_lv); + + if (s_ele == -1) // pl=-1 : the skill takes the weapon's element + s_ele = sstatus->rhw.ele; + else if (s_ele == -2) //Use status element + s_ele = status_get_attack_sc_element(src,status_get_sc(src)); + else if( s_ele == -3 ) //Use random element + s_ele = rnd()%ELE_MAX; + } //Set miscellaneous data that needs be filled if(sd) { sd->state.arrow_atk = 0; @@ -3334,6 +3460,24 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list else skillratio += 110 + 20 * skill_lv; break; + // Magical Elemental Spirits Attack Skills + case EL_FIRE_MANTLE: + case EL_WATER_SCREW: + skillratio += 900; + break; + case EL_FIRE_ARROW: + case EL_ROCK_CRUSHER_ATK: + skillratio += 200; + break; + case EL_FIRE_BOMB: + case EL_ICE_NEEDLE: + case EL_HURRICANE_ATK: + skillratio += 400; + break; + case EL_FIRE_WAVE: + case EL_TYPOON_MIS_ATK: + skillratio += 1100; + break; } @@ -3493,6 +3637,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage=battle_calc_gvg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag); else if( map[target->m].flag.battleground ) ad.damage=battle_calc_bg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag); + + + if( skill_num == SO_VARETYR_SPEAR ) { // Physical damage. + struct Damage wd = battle_calc_weapon_attack(src,target,skill_num,skill_lv,mflag); + ad.damage += wd.damage; + } + return ad; } @@ -3675,7 +3826,15 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * if (sd) md.damage = md.damage + status_get_hp(src); status_set_sp(src, 0, 0); break; - + case GN_THORNS_TRAP: + md.damage = 100 + 200 * skill_lv + sstatus->int_; + break; + case GN_BLOOD_SUCKER: + md.damage = 200 + 100 * skill_lv + sstatus->int_; + break; + case GN_HELLS_PLANT_ATK: + md.damage = sstatus->int_ * 4 * skill_lv * (10 / (10 - pc_checkskill(sd,AM_CANNIBALIZE)));//Need accurate official formula. [Rytech] + break; } if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets @@ -4168,24 +4327,38 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t map_freeblock_lock(); battle_delay_damage(tick, wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion); - - if( tsc && tsc->data[SC_DEVOTION] ) - { - struct status_change_entry *sce = tsc->data[SC_DEVOTION]; - struct block_list *d_bl = map_id2bl(sce->val1); - - if( d_bl && ( - (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) || - (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id) - ) && check_distance_bl(target, d_bl, sce->val3) ) - { - clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, 0, 0); - status_fix_damage(NULL, d_bl, damage, 0); - } - else - status_change_end(target, SC_DEVOTION, INVALID_TIMER); + if( tsc ) { + if( tsc->data[SC_DEVOTION] ) { + struct status_change_entry *sce = tsc->data[SC_DEVOTION]; + struct block_list *d_bl = map_id2bl(sce->val1); + + if( d_bl && ( + (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) || + (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id) + ) && check_distance_bl(target, d_bl, sce->val3) ) + { + clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, 0, 0); + status_fix_damage(NULL, d_bl, damage, 0); + } + else + status_change_end(target, SC_DEVOTION, INVALID_TIMER); + } else if( tsc->data[SC_CIRCLE_OF_FIRE_OPTION] && (wd.flag&BF_SHORT) && target->type == BL_PC ) { + struct elemental_data *ed = ((TBL_PC*)target)->ed; + if( ed ) { + clif_skill_damage(&ed->bl, target, tick, status_get_amotion(src), 0, -30000, 1, EL_CIRCLE_OF_FIRE, tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1, 6); + skill_attack(BF_MAGIC,&ed->bl,&ed->bl,src,EL_CIRCLE_OF_FIRE,tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1,tick,wd.flag); + } + } else if( tsc->data[SC_WATER_SCREEN_OPTION] && tsc->data[SC_WATER_SCREEN_OPTION]->val1 ) { + struct block_list *e_bl = map_id2bl(tsc->data[SC_WATER_SCREEN_OPTION]->val1); + if( e_bl && !status_isdead(e_bl) ) { + clif_damage(e_bl,e_bl,tick,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2); + status_damage(target,e_bl,damage,0,0,0); + // Just show damage in target. + clif_damage(src, target, tick, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 ); + return ATK_NONE; + } + } } - if (sc && sc->data[SC_AUTOSPELL] && rnd()%100 < sc->data[SC_AUTOSPELL]->val4) { int sp = 0; int skillid = sc->data[SC_AUTOSPELL]->val2; @@ -4314,6 +4487,10 @@ struct block_list* battle_get_master(struct block_list *src) if (((TBL_MER*)src)->master) src = (struct block_list*)((TBL_MER*)src)->master; break; + case BL_ELEM: + if (((TBL_ELEM*)src)->master) + src = (struct block_list*)((TBL_ELEM*)src)->master; + break; case BL_SKILL: if (((TBL_SKILL*)src)->group && ((TBL_SKILL*)src)->group->src_id) src = map_id2bl(((TBL_SKILL*)src)->group->src_id); @@ -4409,6 +4586,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f //Valid targets with no special checks here. case BL_MER: case BL_HOM: + case BL_ELEM: break; //All else not specified is an invalid target. default: diff --git a/src/map/chrif.c b/src/map/chrif.c index c4ff4b662..095129e80 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -22,6 +22,7 @@ #include "homunculus.h" #include "instance.h" #include "mercenary.h" +#include "elemental.h" #include "chrif.h" #include "quest.h" #include "storage.h" @@ -307,6 +308,8 @@ int chrif_save(struct map_session_data *sd, int flag) merc_save(sd->hd); if( sd->md && mercenary_get_lifetime(sd->md) > 0 ) mercenary_save(sd->md); + if( sd->ed && elemental_get_lifetime(sd->ed) > 0 ) + elemental_save(sd->ed); if( sd->save_quest ) intif_quest_save(sd); diff --git a/src/map/clif.c b/src/map/clif.c index 3533c7eff..bfe78a58d 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -36,6 +36,7 @@ #include "homunculus.h" #include "instance.h" #include "mercenary.h" +#include "elemental.h" #include "log.h" #include "clif.h" #include "mail.h" @@ -273,7 +274,7 @@ static inline unsigned char clif_bl_type(struct block_list *bl) { case BL_PET: return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE case BL_HOM: return 0x8; //NPC_HOM_TYPE case BL_MER: return 0x9; //NPC_MERSOL_TYPE -// case BL_ELEM: return 0xA; //NPC_ELEMENTAL_TYPE + case BL_ELEM: return 0xa; //NPC_ELEMENTAL_TYPE default: return 0x1; //NPC_TYPE } } @@ -5193,44 +5194,60 @@ void clif_skill_produce_mix_list(struct map_session_data *sd, int skillid , int /// 4 = GN_MIX_COOKING /// 5 = GN_MAKEBOMB /// 6 = GN_S_PHARMACY -void clif_cooking_list(struct map_session_data *sd, int trigger) +void clif_cooking_list(struct map_session_data *sd, int trigger, int skill_id, int qty, int list_type) { int fd; int i, c; int view; - + nullpo_retv(sd); fd = sd->fd; - - WFIFOHEAD(fd, 6 + 2*MAX_SKILL_PRODUCE_DB); + + WFIFOHEAD(fd, 6 + 2 * MAX_SKILL_PRODUCE_DB); WFIFOW(fd,0) = 0x25a; - WFIFOW(fd,4) = 1; // list type - + WFIFOW(fd,4) = list_type; // list type + c = 0; - for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) - { - if( !skill_can_produce_mix(sd,skill_produce_db[i].nameid,trigger, 1) ) + for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) { + if( !skill_can_produce_mix(sd,skill_produce_db[i].nameid,trigger, qty) ) continue; - + if( (view = itemdb_viewid(skill_produce_db[i].nameid)) > 0 ) - WFIFOW(fd, 6+2*c)= view; + WFIFOW(fd, 6 + 2 * c) = view; else - WFIFOW(fd, 6+2*c)= skill_produce_db[i].nameid; - + WFIFOW(fd, 6 + 2 * c) = skill_produce_db[i].nameid; + c++; } - - WFIFOW(fd,2) = 6 + 2*c; - WFIFOSET(fd,WFIFOW(fd,2)); - - //TODO: replace with proper solution - if( c > 0 ) - { - sd->menuskill_id = AM_PHARMACY; + + if( skill_id == AM_PHARMACY ) { // Only send it while Cooking else check for c. + WFIFOW(fd,2) = 6 + 2 * c; + WFIFOSET(fd,WFIFOW(fd,2)); + } + + if( c > 0 ) { + sd->menuskill_id = skill_id; sd->menuskill_val = trigger; + if( skill_id != AM_PHARMACY ) { + sd->menuskill_val2 = qty; // amount. + WFIFOW(fd,2) = 6 + 2 * c; + WFIFOSET(fd,WFIFOW(fd,2)); + } + } else { + clif_menuskill_clear(sd); + if( skill_id != AM_PHARMACY ) { // AM_PHARMACY is used to Cooking. + // It fails. +#if PACKETVER >= 20090922 + clif_msg_skill(sd,skill_id,0x625); +#else + WFIFOW(fd,2) = 6 + 2 * c; + WFIFOSET(fd,WFIFOW(fd,2)); +#endif + } } } + /// Notifies clients of a status change. /// 0196 .W .L .B (ZC_MSG_STATE_CHANGE) [used for ending status changes and starting them on non-pc units (when needed)] /// 043f .W .L .B .L { .L }*3 (ZC_MSG_STATE_CHANGE2) [used exclusively for starting statuses on pcs] @@ -8107,11 +8124,12 @@ void clif_refresh(struct map_session_data *sd) clif_refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF); if(merc_is_hom_active(sd->hd)) clif_send_homdata(sd,SP_ACK,0); - if( sd->md ) - { + if( sd->md ) { clif_mercenary_info(sd); clif_mercenary_skillblock(sd); } + if( sd->ed ) + clif_elemental_info(sd); map_foreachinrange(clif_getareachar,&sd->bl,AREA_SIZE,BL_ALL,sd); clif_weather_check(sd); if( sd->chatID ) @@ -8255,6 +8273,9 @@ void clif_charnameack (int fd, struct block_list *bl) // memcpy(WBUFP(buf,6), (struct chat*)->title, NAME_LENGTH); // break; return; + case BL_ELEM: + memcpy(WBUFP(buf,6), ((TBL_ELEM*)bl)->db->name, NAME_LENGTH); + break; default: ShowError("clif_charnameack: bad type %d(%d)\n", bl->type, bl->id); return; @@ -9082,14 +9103,22 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) skill_unit_move(&sd->hd->bl,gettick(),1); // apply land skills immediately } - if( sd->md ) - { + if( sd->md ) { map_addblock(&sd->md->bl); clif_spawn(&sd->md->bl); clif_mercenary_info(sd); clif_mercenary_skillblock(sd); } + if( sd->ed ) { + map_addblock(&sd->ed->bl); + clif_spawn(&sd->ed->bl); + clif_elemental_info(sd); + clif_elemental_updatestatus(sd,SP_HP); + clif_hpmeter_single(sd->fd,sd->ed->bl.id,sd->ed->battle_status.hp,sd->ed->battle_status.matk_max); + clif_elemental_updatestatus(sd,SP_SP); + } + if(sd->state.connect_new) { int lv; sd->state.connect_new = 0; @@ -10587,15 +10616,13 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) if( sd->sc.data[SC_BASILICA] && (skillnum != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) return; // On basilica only caster can use Basilica again to stop it. - if( sd->menuskill_id ) - { - if( sd->menuskill_id == SA_TAMINGMONSTER ) - sd->menuskill_id = sd->menuskill_val = 0; //Cancel pet capture. - else if( sd->menuskill_id != SA_AUTOSPELL ) + if( sd->menuskill_id ) { + if( sd->menuskill_id == SA_TAMINGMONSTER ) { + clif_menuskill_clear(sd); //Cancel pet capture. + } else if( sd->menuskill_id != SA_AUTOSPELL ) return; //Can't use skills while a menu is open. } - if( sd->skillitem == skillnum ) - { + if( sd->skillitem == skillnum ) { if( skilllv != sd->skillitemlv ) skilllv = sd->skillitemlv; if( !(tmp&INF_SELF_SKILL) ) @@ -10606,15 +10633,12 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) sd->skillitem = sd->skillitemlv = 0; - if( skillnum >= GD_SKILLBASE ) - { + if( skillnum >= GD_SKILLBASE ) { if( sd->state.gmaster_flag ) skilllv = guild_checkskill(sd->state.gmaster_flag, skillnum); else skilllv = 0; - } - else - { + } else { tmp = pc_checkskill(sd, skillnum); if( skilllv > tmp ) skilllv = tmp; @@ -10661,10 +10685,8 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, sho if( sd->ud.skilltimer != INVALID_TIMER ) return; - if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) - { - if( sd->skillitem != skillnum ) - { + if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) { + if( sd->skillitem != skillnum ) { clif_skill_fail(sd, skillnum, USESKILL_FAIL_SKILLINTERVAL, 0); return; } @@ -10676,28 +10698,23 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, sho if( sd->sc.data[SC_BASILICA] && (skillnum != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) return; // On basilica only caster can use Basilica again to stop it. - if( sd->menuskill_id ) - { - if( sd->menuskill_id == SA_TAMINGMONSTER ) - sd->menuskill_id = sd->menuskill_val = 0; //Cancel pet capture. - else if( sd->menuskill_id != SA_AUTOSPELL ) + if( sd->menuskill_id ) { + if( sd->menuskill_id == SA_TAMINGMONSTER ) { + clif_menuskill_clear(sd); //Cancel pet capture. + } else if( sd->menuskill_id != SA_AUTOSPELL ) return; //Can't use skills while a menu is open. } pc_delinvincibletimer(sd); - if( sd->skillitem == skillnum ) - { + if( sd->skillitem == skillnum ) { if( skilllv != sd->skillitemlv ) skilllv = sd->skillitemlv; unit_skilluse_pos(&sd->bl, x, y, skillnum, skilllv); - } - else - { + } else { int lv; sd->skillitem = sd->skillitemlv = 0; - if( (lv = pc_checkskill(sd, skillnum)) > 0 ) - { + if( (lv = pc_checkskill(sd, skillnum)) > 0 ) { if( skilllv > lv ) skilllv = lv; unit_skilluse_pos(&sd->bl, x, y, skillnum,skilllv); @@ -10759,9 +10776,8 @@ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd) if(skill_num != sd->menuskill_id) return; - if( pc_cant_act(sd) ) - { - sd->menuskill_id = sd->menuskill_val = 0; + if( pc_cant_act(sd) ) { + clif_menuskill_clear(sd); return; } @@ -10795,12 +10811,12 @@ void clif_parse_ProduceMix(int fd,struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } if( skill_can_produce_mix(sd,RFIFOW(fd,2),sd->menuskill_val, 1) ) skill_produce_mix(sd,0,RFIFOW(fd,2),RFIFOW(fd,4),RFIFOW(fd,6),RFIFOW(fd,8), 1); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10813,24 +10829,22 @@ void clif_parse_ProduceMix(int fd,struct map_session_data *sd) /// 4 = GN_MIX_COOKING /// 5 = GN_MAKEBOMB /// 6 = GN_S_PHARMACY -void clif_parse_Cooking(int fd,struct map_session_data *sd) -{ - //int type = RFIFOW(fd,2); +void clif_parse_Cooking(int fd,struct map_session_data *sd) { + int type = RFIFOW(fd,2); int nameid = RFIFOW(fd,4); - - if( sd->menuskill_id != AM_PHARMACY ) { + int amount = sd->menuskill_val2?sd->menuskill_val2:1; + if( type == 6 && sd->menuskill_id != GN_MIX_COOKING && sd->menuskill_id != GN_S_PHARMACY ) return; - } - + if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } - if( skill_can_produce_mix(sd,nameid,sd->menuskill_val, 1) ) - skill_produce_mix(sd,0,nameid,0,0,0,1); - sd->menuskill_val = sd->menuskill_id = 0; + if( skill_can_produce_mix(sd,nameid,sd->menuskill_val, amount) ) + skill_produce_mix(sd,sd->menuskill_id,nameid,0,0,0,amount); + clif_menuskill_clear(sd); } @@ -10843,11 +10857,11 @@ void clif_parse_RepairItem(int fd, struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } skill_repairweapon(sd,RFIFOW(fd,2)); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10862,12 +10876,12 @@ void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } idx = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]); skill_weaponrefine(sd, idx-2); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10952,13 +10966,12 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) if (sd->menuskill_id != MC_IDENTIFY) return; - if( idx == -1 ) - {// cancel pressed - sd->menuskill_val = sd->menuskill_id = 0; + if( idx == -1 ) {// cancel pressed + clif_menuskill_clear(sd); return; } skill_identify(sd,idx-2); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10969,7 +10982,7 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } switch( sd->menuskill_id ) { @@ -10990,7 +11003,7 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd) break; } - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -11001,7 +11014,7 @@ void clif_parse_AutoSpell(int fd,struct map_session_data *sd) if (sd->menuskill_id != SA_AUTOSPELL) return; skill_autospell(sd,RFIFOL(fd,2)); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -12074,7 +12087,7 @@ void clif_parse_SelectEgg(int fd, struct map_session_data *sd) return; } pet_select_egg(sd,RFIFOW(fd,2)-2); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -13038,7 +13051,7 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd) // clif_misceffect2(&sd->bl, 0x1b0); // clif_misceffect2(&sd->bl, 0x21f); clif_feel_info(sd, i, 0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -15051,6 +15064,94 @@ void clif_parse_LessEffect(int fd, struct map_session_data* sd) sd->state.lesseffect = ( isLess != 0 ); } +/// S 07e4 .w