//Stats - Plugin //by Normynator //Beta Version //Ignore ShowWarning since its used for debugging //Ignore comments in beta version //Ignore coding styl during beta //Triggers by using script bonus3 99,X,X,X; #include "common/hercules.h" #include #include #include #include #include "common/HPMi.h" #include "common/mmo.h" #include "common/socket.h" #include "common/memmgr.h" #include "common/strlib.h" #include "common/nullpo.h" #include "common/timer.h" #include "map/battle.h" #include "map/script.h" #include "map/pc.h" #include "map/clif.h" #include "map/status.h" #include "map/npc.h" #include "map/mob.h" #include "map/map.h" #include "plugins/HPMHooking.h" #include "common/HPMDataCheck.h" HPExport struct hplugin_info pinfo = { "Stats", SERVER_TYPE_MAP, "0.1", HPM_VERSION, }; #define MAX_DATA 3 #define MAX_ARGS 10 //#define OUTPUT_LENGTH 8+1+1 #define BONUS_FOREACH_RCARRAY_FROMMASK(loop_counter, mask) \ for ((loop_counter) = RC_FORMLESS; (loop_counter) < RC_MAX; ++(loop_counter)) \ if (((mask) & 1<<(loop_counter)) == RCMASK_NONE) { \ continue; \ } else struct sample_data_struct { int stat[MAX_ARGS]; int rate[MAX_ARGS]; int increase[MAX_ARGS]; int size; }; int pc_bonus_addele_sub(struct map_session_data* sd, unsigned char ele, short rate, short flag) { int i; struct weapon_data* wd; nullpo_ret(sd); wd = (sd->state.lr_flag ? &sd->left_weapon : &sd->right_weapon); ARR_FIND(0, MAX_PC_BONUS, i, wd->addele2[i].rate == 0); if (i == MAX_PC_BONUS) { ShowWarning("pc_addele: Reached max (%d) possible bonuses for this player.\n", MAX_PC_BONUS); return 0; } if (!(flag&BF_RANGEMASK)) flag |= BF_SHORT|BF_LONG; if (!(flag&BF_WEAPONMASK)) flag |= BF_WEAPON; if (!(flag&BF_SKILLMASK)) { if (flag&(BF_MAGIC|BF_MISC)) flag |= BF_SKILL; if (flag&BF_WEAPON) flag |= BF_NORMAL|BF_SKILL; } wd->addele2[i].ele = ele; wd->addele2[i].rate = rate; wd->addele2[i].flag = flag; return 0; } int pc_bonus_subele_sub(struct map_session_data* sd, unsigned char ele, short rate, short flag) { int i; nullpo_ret(sd); ARR_FIND(0, MAX_PC_BONUS, i, sd->subele2[i].rate == 0); if (i == MAX_PC_BONUS) { ShowWarning("pc_subele: Reached max (%d) possible bonuses for this player.\n", MAX_PC_BONUS); return 0; } if (!(flag&BF_RANGEMASK)) flag |= BF_SHORT|BF_LONG; if (!(flag&BF_WEAPONMASK)) flag |= BF_WEAPON; if (!(flag&BF_SKILLMASK)) { if (flag&(BF_MAGIC|BF_MISC)) flag |= BF_SKILL; if (flag&BF_WEAPON) flag |= BF_NORMAL|BF_SKILL; } sd->subele2[i].ele = ele; sd->subele2[i].rate = rate; sd->subele2[i].flag = flag; return 0; } int pc_bonus3_pre(struct map_session_data *sd,int type,int type2,int type3,int val){ ShowWarning("Here"); struct sample_data_struct *data; int i; nullpo_ret(sd); switch(type){ case SP_ADD_MONSTER_DROP_ITEM: { uint32 race_mask = map->race_id2mask(type3); if (race_mask == RCMASK_NONE) { ShowWarning("pc_bonus2: SP_ADD_MONSTER_DROP_ITEM: Invalid Race (%d)\n", type3); break; } if (sd->state.lr_flag != 2) pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, race_mask, val); } break; case SP_ADD_CLASS_DROP_ITEM: if(sd->state.lr_flag != 2) pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, -type3, val); break; case SP_AUTOSPELL: if(sd->state.lr_flag != 2) { int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), target?-type2:type2, type3, val, 0, status->current_equip_card_id); } break; case SP_AUTOSPELL_WHENHIT: if(sd->state.lr_flag != 2) { int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), target?-type2:type2, type3, val, BF_NORMAL|BF_SKILL, status->current_equip_card_id); } break; case SP_SP_DRAIN_RATE: if (sd->state.lr_flag == 0) { // Decomposed RC_ALL: sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; sd->right_weapon.sp_drain[RC_NONBOSS].per += type3; sd->right_weapon.sp_drain[RC_NONBOSS].type = val; sd->right_weapon.sp_drain[RC_BOSS].rate += type2; sd->right_weapon.sp_drain[RC_BOSS].per += type3; sd->right_weapon.sp_drain[RC_BOSS].type = val; } else if (sd->state.lr_flag == 1) { // Decomposed RC_ALL: sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; sd->left_weapon.sp_drain[RC_NONBOSS].per += type3; sd->left_weapon.sp_drain[RC_NONBOSS].type = val; sd->left_weapon.sp_drain[RC_BOSS].rate += type2; sd->left_weapon.sp_drain[RC_BOSS].per += type3; sd->left_weapon.sp_drain[RC_BOSS].type = val; } break; case SP_HP_DRAIN_RATE_RACE: { uint32 race_mask = map->race_id2mask(type2); if (race_mask == RCMASK_NONE) { ShowWarning("pc_bonus3: SP_HP_DRAIN_RATE_RACE: Invalid Race (%d)\n", type2); break; } BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) { if (sd->state.lr_flag == 0) { sd->right_weapon.hp_drain[i].rate += type3; sd->right_weapon.hp_drain[i].per += val; } else if(sd->state.lr_flag == 1) { sd->left_weapon.hp_drain[i].rate += type3; sd->left_weapon.hp_drain[i].per += val; } } } break; case SP_SP_DRAIN_RATE_RACE: { uint32 race_mask = map->race_id2mask(type2); if (race_mask == RCMASK_NONE) { ShowWarning("pc_bonus3: SP_SP_DRAIN_RATE_RACE: Invalid Race (%d)\n", type2); break; } BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) { if (sd->state.lr_flag == 0) { sd->right_weapon.sp_drain[i].rate += type3; sd->right_weapon.sp_drain[i].per += val; } else if(sd->state.lr_flag == 1) { sd->left_weapon.sp_drain[i].rate += type3; sd->left_weapon.sp_drain[i].per += val; } } } break; case SP_ADDEFF: if (type2 > SC_MAX) { ShowWarning("pc_bonus3 (Add Effect): %d is not supported.\n", type2); break; } pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, sd->state.lr_flag!=2?type3:0, sd->state.lr_flag==2?type3:0, val, 0); break; case SP_ADDEFF_WHENHIT: if (type2 > SC_MAX) { ShowWarning("pc_bonus3 (Add Effect when hit): %d is not supported.\n", type2); break; } if(sd->state.lr_flag != 2) pc->bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, type3, 0, val, 0); break; case SP_ADDEFF_ONSKILL: if( type3 > SC_MAX ) { ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type3); break; } if( sd->state.lr_flag != 2 ) pc->bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, val, type2, ATF_TARGET); break; case SP_ADDELE: if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) { ShowError("pc_bonus3: SP_ADDELE: Invalid element %d\n", type2); break; } if ( sd->state.lr_flag != 2 ) { if ( type2 == ELE_ALL ) { for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) pc_bonus_addele_sub(sd, (unsigned char)i, type3, val); } else { pc_bonus_addele_sub(sd, (unsigned char)type2, type3, val); } } break; case SP_SUBELE: if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) { ShowError("pc_bonus3: SP_SUBELE: Invalid element %d\n", type2); break; } if ( sd->state.lr_flag != 2 ) { if ( type2 == ELE_ALL ) { for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) pc_bonus_subele_sub(sd, (unsigned char)i, type3, val); } else { pc_bonus_subele_sub(sd, (unsigned char)type2, type3, val); } } break; case SP_HP_VANISH_RATE: if (sd->state.lr_flag != 2) { sd->bonus.hp_vanish_rate += type2; sd->bonus.hp_vanish_per = max(sd->bonus.hp_vanish_per, type3); sd->bonus.hp_vanish_trigger = val; } break; case SP_SP_VANISH_RATE: if (sd->state.lr_flag != 2) { sd->bonus.sp_vanish_rate += type2; sd->bonus.sp_vanish_per = max(sd->bonus.sp_vanish_per, type3); sd->bonus.sp_vanish_trigger = val; } break; case 99: ShowWarning("Wichtig: %d\n",val); //type ist 99 //type2 ist str,agi,dex oder oder //type3 ist wann es triggert (bsp wenn der gegner mehr als 50 int hat) //val wie viel mehr dmg man dann macht if(!(data = getFromMSD(sd,0))){ CREATE(data,struct sample_data_struct,1); data->stat[0] = type2; data->rate[0] = type3; data->increase[0] = val; data->size = 1; addToMSD(sd,data,0,true); }else{ int i = data->size; if(i > MAX_ARGS){ break; } data->stat[i] = type2; data->rate[i] = type3; data->increase[i] = val; data->size = data->size + 1; } break; default: ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val); Assert_report(0); break; } return 0; } void status_calc_pc_additional_post(struct map_session_data* sd, enum e_status_calc_opt opt) { removeFromMSD(sd,0); return; } int64 battle_calc_cardfix_post(int64 retVal, int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int64 damage, int cflag, int wflag){ if(retVal < 0){ return retVal; } struct map_session_data *sd; struct sample_data_struct *data; int value; nullpo_ret(src); sd = BL_CAST(BL_PC, src); //tsd = BL_CAST(BL_PC, target); struct status_data *tstatus; tstatus = status->get_status_data(target); //ShowWarning("%d",src->type); if(src->type != 1) return retVal; if((data = getFromMSD(sd,0))){ for(int i = 0; i < data->size; i++){ //ShowWarning("%d. Entry of Array: %d\n",i,data->stat[i]); switch(data->stat[i]){ case 1: value = tstatus->str; break; case 2: value = tstatus->agi; break; case 3: value = tstatus->vit; break; case 4: value = tstatus->int_; break; case 5: value = tstatus->dex; break; case 6: value = tstatus->luk; break; default: value = 0; break; } ShowWarning("%d\n",data->rate[i]); if(value < data->rate[i]) retVal += retVal * data->increase[i] / 100; } } return retVal; } HPExport void plugin_init(void) { addHookPost(status, calc_pc_additional, status_calc_pc_additional_post); addHookPost(battle, calc_cardfix, battle_calc_cardfix_post); } HPExport void server_online (void) { ShowInfo ("'%s' Plugin by Normynator/Hercules. Version '%s'\n",pinfo.name,pinfo.version); } HPExport void server_preinit(void){ pc->bonus3 = pc_bonus3_pre; }