//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 <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#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;
}