MOTR logo
    • Категории
    • Последние
    • Популярные
    • Метки
    • Пользователи
    • Группы
    • Зарегистрироваться
    • Войти

    Вопрос по теории: расчёт дамага.

    Запланировано Прикреплена Закрыта Перенесена Справочник по Магии
    52 Сообщения 14 Posters 4.1k Просмотры
    Загружаем больше сообщений
    • Сначала старые
    • Сначала новые
    • По количеству голосов
    Ответить
    • Ответить, создав новую тему
    Авторизуйтесь, чтобы ответить
    Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
    • ProkuratorP Не в сети
      Prokurator
      отредактировано

      Если исходить из предположения, что МОТР всё-таки работает на jAthena, то можно просто открыть исходники и посмотреть все формулы досканально. Только, смотрите не офигейте от увиденного, к тому же комментарии все на японском 😃 Все формулы там в виде набора бесконечно вложенных друг в друга условных переходов. Вот взгляните на какой-то кусок:

      int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,int div_,int skill_num,int skill_lv,int flag)
      {
      struct map_session_data *sd=NULL;
      struct mob_data *md=NULL;
      struct homun_data *hd=NULL;
      struct status_change *sc_data,*sc;
      short *sc_count;
      int class;

      nullpo_retr(0, src);
      nullpo_retr(0, bl);
      
      BL_CAST( BL_PC,  bl, sd );
      BL_CAST( BL_MOB, bl, md );
      BL_CAST( BL_HOM, bl, hd );
      
      sc_data = status_get_sc_data(bl);
      sc_count= status_get_sc_count(bl);
      class = status_get_class(bl);
      
      //ѓXѓLѓ‹ѓ_ѓЃЃ[ѓW•вђі
      if(skill_num>0){
      	int damage_rate=100;
      	if(map[bl->m].flag.normal)
      		damage_rate = skill_get_damage_rate(skill_num,0);
      	else if(map[bl->m].flag.gvg)
      		damage_rate = skill_get_damage_rate(skill_num,2);
      	else if(map[bl->m].flag.pvp)
      		damage_rate = skill_get_damage_rate(skill_num,1);
      	else if(map[bl->m].flag.pk)
      		damage_rate = skill_get_damage_rate(skill_num,3);
      	if(damage>0 && damage_rate!=100)
      		damage = damage*damage_rate/100;
      }
      if(sc_count!=NULL && *sc_count>0){
      	if(sc_data[SC_ASSUMPTIO].timer != -1 && damage > 0 && skill_num!=PA_PRESSURE && skill_num!=HW_GRAVITATION) { //ѓAѓXѓЂѓvѓeѓBѓI
      		if(map[bl->m].flag.pvp || map[bl->m].flag.gvg)
      			damage=damage*2/3;
      		else
      			damage=damage/2;
      	}
      
      	if (sc_data[SC_BASILICA].timer!=-1 && !(status_get_mode(src)&0x20) && damage > 0)
      		damage = 0;
      
      	if (sc_data[SC_FOGWALL].timer!=-1 && damage>0 && flag&BF_WEAPON && flag&BF_LONG)
      	{
      		if(skill_num == 0)//’КЏнЌUЊ‚75%OFF
      		{
      			damage = damage*25/100;
      		}else{	//ѓXѓLѓ‹25%OFF
      			damage = damage*75/100;
      		}
      	}
      
      	if (sc_data[SC_SAFETYWALL].timer!=-1 && flag&BF_WEAPON &&
      				flag&BF_SHORT && skill_num != NPC_GUIDEDATTACK) {
      		// ѓZЃ[ѓtѓeѓBѓEѓHЃ[ѓ‹
      		struct skill_unit *unit;
      		unit = (struct skill_unit *)sc_data[SC_SAFETYWALL].val2;
      		if (unit && unit->group) {
      			if ((--unit->group->val2)<=0)
      				skill_delunit(unit);
      			damage=0;
      		} else {
      			status_change_end(bl,SC_SAFETYWALL,-1);
      		}
      	}
      
      	// ѓjѓ…Ѓ[ѓ}
      	if((sc_data[SC_PNEUMA].timer!=-1 || sc_data[SC_TATAMIGAESHI].timer != -1) && damage>0 && flag&(BF_WEAPON|BF_MISC) && flag&BF_LONG && skill_num != NPC_GUIDEDATTACK){
      		damage=0;
      	}
      	if(sc_data[SC_AETERNA].timer!=-1 && damage>0 && skill_num!=PA_PRESSURE && skill_num!=HW_GRAVITATION){	// ѓЊѓbѓNѓXѓGЃ[ѓeѓ‹ѓi
      		damage<<=1;
      		status_change_end( bl,SC_AETERNA,-1 );
      	}
      
      	//‘®ђ«Џк‚Мѓ_ѓЃЃ[ѓW‘ќ‰Б
      	if(sc_data[SC_VOLCANO].timer!=-1 && damage>0){	// ѓ{ѓ‹ѓPЃ[ѓm
      		if(flag&BF_SKILL && skill_get_pl(skill_num)==3)
      			damage += damage*sc_data[SC_VOLCANO].val4/100;
      		else if(!flag&BF_SKILL && status_get_attack_element(bl)==3)
      			damage += damage*sc_data[SC_VOLCANO].val4/100;
      	}
      
      	if(sc_data[SC_VIOLENTGALE].timer!=-1 && damage>0){	// ѓoѓCѓIѓЊѓ“ѓgѓQѓCѓ‹
      		if(flag&BF_SKILL && skill_get_pl(skill_num)==4)
      			damage += damage*sc_data[SC_VIOLENTGALE].val4/100;
      		else if(!flag&BF_SKILL && status_get_attack_element(bl)==4)
      			damage += damage*sc_data[SC_VIOLENTGALE].val4/100;
      	}
      
      	if(sc_data[SC_DELUGE].timer!=-1 && damage>0){	// ѓfѓЉѓ…Ѓ[ѓW
      		if(flag&BF_SKILL && skill_get_pl(skill_num)==1)
      			damage += damage*sc_data[SC_DELUGE].val4/100;
      		else if(!flag&BF_SKILL && status_get_attack_element(bl)==1)
      			damage += damage*sc_data[SC_DELUGE].val4/100;
      	}
      
      	if(sc_data[SC_ENERGYCOAT].timer!=-1 && damage>0  && flag&BF_WEAPON && skill_num != PA_PRESSURE){	// ѓGѓiѓWЃ[ѓRЃ[ѓg ѓvѓЊѓbѓVѓѓЃ[‚НЊyЊё‚µ‚И‚ў
      		if(sd){
      			if(sd->status.sp>0){
      				int per = sd->status.sp * 5 / (sd->status.max_sp + 1);
      				sd->status.sp -= sd->status.sp * (per * 5 + 10) / 1000;
      				if( sd->status.sp < 0 ) sd->status.sp = 0;
      				damage -= damage * ((per+1) * 6) / 100;
      				clif_updatestatus(sd,SP_SP);
      			}
      			if(sd->status.sp<=0)
      				status_change_end( bl,SC_ENERGYCOAT,-1 );
      		}
      		else
      			damage -= damage * (sc_data[SC_ENERGYCOAT].val1 * 6) / 100;
      	}
      
      	if(sc_data[SC_KYRIE].timer!=-1 && damage > 0){	// ѓLѓЉѓGѓGѓЊѓCѓ\ѓ“
      		sc=&sc_data[SC_KYRIE];
      		sc->val2-=damage;
      		if(flag&BF_WEAPON){
      			if(sc->val2>=0)	damage=0;
      			else damage=-sc->val2;
      		}
      		if((--sc->val3)<=0 || (sc->val2<=0) || skill_num == AL_HOLYLIGHT)
      			status_change_end(bl, SC_KYRIE, -1);
      	}
      	/* ѓCѓ“ѓfѓ…ѓA */
      	if(sc_data[SC_ENDURE].timer != -1 && damage > 0 && flag&BF_WEAPON && src->type != BL_PC){
      		if((--sc_data[SC_ENDURE].val2)<=0)
      			status_change_end(bl, SC_ENDURE, -1);
      	}
      	/* ѓIЃ[ѓgѓKЃ[ѓh */
      	if(sc_data[SC_AUTOGUARD].timer != -1 && damage > 0 && flag&BF_WEAPON) {
      		if(atn_rand()%100 < sc_data[SC_AUTOGUARD].val2) {
      			int delay;
      			damage = 0;
      			clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sc_data[SC_AUTOGUARD].val1,1);
      			if (sc_data[SC_AUTOGUARD].val1 <= 5)
      				delay = 300;
      			else if (sc_data[SC_AUTOGUARD].val1 > 5 && sc_data[SC_AUTOGUARD].val1 <= 9)
      				delay = 200;
      			else
      				delay = 100;
      			if(sd){
      				sd->ud.canmove_tick = gettick() + delay;
      				if(sc_data[SC_SHRINK].timer != -1 && atn_rand()%100<5*sc_data[SC_AUTOGUARD].val1)
      				{
      					skill_blown(bl,src,2);
      				}
      
      			}else if(md)
      				md->ud.canmove_tick = gettick() + delay;
      		}
      	}
      	/* ѓpѓЉѓCѓ“ѓO */
      	if(sc_data[SC_PARRYING].timer != -1 && damage > 0 && flag&BF_WEAPON) {
      		if(atn_rand()%100 < sc_data[SC_PARRYING].val2) {
      			damage = 0;
      			clif_skill_nodamage(bl,bl,LK_PARRYING,sc_data[SC_PARRYING].val1,1);
      		}
      	}
      	// ѓЉѓWѓFѓNѓgѓ\Ѓ[ѓh
      	if(sc_data[SC_REJECTSWORD].timer!=-1 && damage > 0 && flag&BF_WEAPON &&
      	   ((src->type==BL_PC && ((struct map_session_data *)src)->status.weapon == (1 || 2 || 3))
      	  || src->type==BL_MOB )){
      		if(atn_rand()%100 < (15*sc_data[SC_REJECTSWORD].val1)){ //”ЅЋЛЉm—¦‚Н15*Lv
      			damage = damage*50/100;
      			battle_damage(bl,src,damage,0);
      			//ѓ_ѓЃЃ[ѓW‚р—^‚¦‚Ѕ‚М‚Н—З‚ў‚с‚ѕ‚ЄЃA‚±‚±‚©‚з‚З‚¤‚µ‚Д•\Ћ¦‚·‚й‚с‚ѕ‚©‚н‚©‚с‚Л‚Ґ
      			//ѓGѓtѓFѓNѓg‚а‚±‚к‚Е‚ў‚ў‚М‚©‚н‚©‚с‚Л‚Ґ
      			clif_skill_nodamage(bl,bl,ST_REJECTSWORD,sc_data[SC_REJECTSWORD].val1,1);
      			if((--sc_data[SC_REJECTSWORD].val2)<=0)
      				status_change_end(bl, SC_REJECTSWORD, -1);
      		}
      	}
      	if(sc_data[SC_SPIDERWEB].timer!=-1 && damage > 0)	// [Celest]
      		if( (flag&BF_SKILL && skill_get_pl(skill_num)==3) ||
      		  (!(flag&BF_SKILL) && status_get_attack_element(src)==3) ) {
      			damage<<=1;
      			status_change_end(bl, SC_SPIDERWEB, -1);
      		}
      }
      
      if(damage > 0) { //GvG PK
      	struct guild_castle *gc=guild_mapname2gc(map[bl->m].name);
      	struct guild *g;
      
      	if(class == 1288) {	// 1288:ѓGѓ“ѓyѓЉѓEѓЂ
      		if(flag&BF_SKILL && skill_num!=PA_PRESSURE && skill_num!=HW_GRAVITATION)//ѓvѓЊѓbѓVѓѓЃ[
      			return 0;
      		if(src->type == BL_PC) {
      			g=guild_search(((struct map_session_data *)src)->status.guild_id);
      
      			if(g == NULL)
      				return 0;//ѓMѓ‹ѓh–ў‰Б“ь‚И‚зѓ_ѓЃЃ[ѓW–і‚µ
      			else if((gc != NULL) && g->guild_id == gc->guild_id)
      				return 0;//Ћ©ђи—МѓMѓ‹ѓh‚МѓGѓ“ѓy‚И‚зѓ_ѓЃЃ[ѓW–і‚µ
      			else if(guild_checkskill(g,GD_APPROVAL) <= 0)
      				return 0;//ђі‹KѓMѓ‹ѓhЏі”F‚Є‚И‚ў‚Жѓ_ѓЃЃ[ѓW–і‚µ
      			else if (g && gc && guild_check_alliance(gc->guild_id, g->guild_id, 0) == 1)
      				return 0;	// “Ї–ї‚И‚зѓ_ѓЃЃ[ѓW–і‚µ
      		}
      		else
      			return 0;
      	}
      	if(map[bl->m].flag.gvg && skill_num!=PA_PRESSURE && skill_num!=HW_GRAVITATION){
      		if(gc && bl->type == BL_MOB){	//defense‚Є‚ ‚к‚Оѓ_ѓЃЃ[ѓW‚ЄЊё‚й‚з‚µ‚ўЃH
      			damage -= damage*(gc->defense/100)*(battle_config.castle_defense_rate/100);
      		}
      		if(flag&BF_WEAPON) {
      			if(flag&BF_SHORT)
      				damage=damage*battle_config.gvg_short_damage_rate/100;
      			if(flag&BF_LONG)
      				damage=damage*battle_config.gvg_long_damage_rate/100;
      		}
      		if(flag&BF_MAGIC)
      			damage = damage*battle_config.gvg_magic_damage_rate/100;
      		if(flag&BF_MISC)
      			damage=damage*battle_config.gvg_misc_damage_rate/100;
      		if(damage < 1) damage = (!battle_config.skill_min_damage && flag&BF_MAGIC && src->type==BL_PC)? 0: 1;
      	}
      
      	//PK
      	if(map[bl->m].flag.pk && bl->type == BL_PC && skill_num!=PA_PRESSURE && skill_num!=HW_GRAVITATION){
      		if(flag&BF_WEAPON) {
      			if(flag&BF_SHORT)
      				damage=damage*battle_config.pk_short_damage_rate/100;
      			if(flag&BF_LONG)
      				damage=damage*battle_config.pk_long_damage_rate/100;
      		}
      		if(flag&BF_MAGIC)
      			damage = damage*battle_config.pk_magic_damage_rate/100;
      		if(flag&BF_MISC)
      			damage=damage*battle_config.pk_misc_damage_rate/100;
      		if(damage < 1) damage = (!battle_config.skill_min_damage && flag&BF_MAGIC && src->type==BL_PC)? 0: 1;
      	}
      }
      
      if((battle_config.skill_min_damage || flag&BF_MISC) && damage > 0) {
      	if(div_==255) {
      		if(damage<3)
      			damage = 3;
      	}
      	else {
      		if(damage<div_)
      			damage = div_;
      	}
      }
      
      if( md!=NULL && md->hp>0 && damage > 0 )	// ”ЅЊ‚‚И‚З‚МMOBѓXѓLѓ‹”»’и
      {
      	unsigned int mst = md->state.skillstate;
      	int mtg = md->target_id;
      
      	// ЌUЊ‚Џу‘Ф‚Ц€кЋћ•ПЌX
      	md->state.skillstate = MSS_ATTACK;
      	if (battle_config.mob_changetarget_byskill != 0 || mtg == 0)
      	{
      		md->target_id = src->id;
      	}
      
      	mobskill_event(md,flag);
      
      	// Џу‘Ф‚р–Я‚·
      	md->state.skillstate = mst;
      	md->target_id = mtg;
      }
      
      //PC‚М”ЅЊ‚ѓIЃ[ѓgѓXѓyѓ‹
      if(sd && sd->bl.type == BL_PC && src!=bl && sd->status.hp > 0 && damage > 0)
      {
      	struct map_session_data *target=(struct map_session_data *)src;
      	long asflag = EAS_REVENGE;
      
      	nullpo_retr(damage, target);
      
      	if(skill_num==AM_DEMONSTRATION)
      		flag=(flag&~BF_WEAPONMASK)|BF_MISC;
      
      	if(flag&BF_WEAPON) {
      		if(flag&BF_SKILL){
      			if(battle_config.weapon_attack_autospell)
      				asflag += EAS_NORMAL;
      			else
      				asflag += EAS_SKILL;
      		}else
      			asflag += EAS_NORMAL;
      		if(flag&BF_SHORT)
      			asflag += EAS_SHORT;
      		if(flag&BF_LONG)
      			asflag += EAS_LONG;
      	}
      	if(flag&BF_MAGIC){
      		if(battle_config.magic_attack_autospell)
      			asflag += EAS_SHORT|EAS_LONG;
      		else
      			asflag += EAS_MAGIC;
      	}
      	if(flag&BF_MISC){
      		if(battle_config.misc_attack_autospell)
      			asflag += EAS_SHORT|EAS_LONG;
      		else
      			asflag += EAS_MISC;
      	}
      
      	skill_bonus_autospell(&sd->bl,&target->bl,asflag,gettick(),0);
      }
      
      //PC‚М”ЅЊ‚
      if(sd && sd->bl.type == BL_PC && src!=bl &&
       			sd->status.hp > 0 && damage > 0 && flag&BF_WEAPON)
      {
      	struct map_session_data *target=(struct map_session_data *)src;
      	nullpo_retr(damage, target);
      	//”ЅЊ‚Џу‘Ф€ЩЏн
      	if(sd->addreveff_flag){
      		int i;
      		int rate;
      		int luk;
      		int sc_def_card=100;
      		int sc_def_mdef,sc_def_vit,sc_def_int,sc_def_luk;
      		//int race = status_get_race(target), ele = status_get_element(target);
      		const int sc2[]={
      			MG_STONECURSE,MG_FROSTDIVER,NPC_STUNATTACK,
      			NPC_SLEEPATTACK,TF_POISON,NPC_CURSEATTACK,
      			NPC_SILENCEATTACK,0,NPC_BLINDATTACK,LK_HEADCRUSH
      		};
      		//‘ОЏЫ‚М‘Пђ«
      		luk = status_get_luk(&target->bl);
      		sc_def_mdef=50 - (3 + status_get_mdef(&target->bl) + luk/3);
      		sc_def_vit=50 - (3 + status_get_vit(&target->bl) + luk/3);
      		sc_def_int=50 - (3 + status_get_int(&target->bl) + luk/3);
      		sc_def_luk=50 - (3 + luk);
      

      /* if(target->bl.type==BL_MOB){
      if(sc_def_mdef<50)
      sc_def_mdef=50;
      if(sc_def_vit<50)
      sc_def_vit=50;
      if(sc_def_int<50)
      sc_def_int=50;
      if(sc_def_luk<50)
      sc_def_luk=50;
      }
      */
      if(sc_def_mdef<0)
      sc_def_mdef=0;
      if(sc_def_vit<0)
      sc_def_vit=0;
      if(sc_def_int<0)
      sc_def_int=0;

      		for(i=SC_STONE;i<=SC_BLEED;i++){
      			//‘ОЏЫ‚ЙЏу‘Ф€ЩЏн
      			if(i==SC_STONE || i==SC_FREEZE)
      				sc_def_card=sc_def_mdef;
      			else if(i==SC_STAN || i==SC_POISON || i==SC_SILENCE || i==SC_BLEED)
      				sc_def_card=sc_def_vit;
      			else if(i==SC_SLEEP || i==SC_CONFUSION || i==SC_BLIND)
      				sc_def_card=sc_def_int;
      			else if(i==SC_CURSE)
      				sc_def_card=sc_def_luk;
      
      			if(battle_config.reveff_plus_addeff)
      				rate = (sd->addreveff[i-SC_STONE] + sd->addeff[i-SC_STONE] + sd->arrow_addeff[i-SC_STONE])*sc_def_card/100;
      			else
      				rate = (sd->addreveff[i-SC_STONE])*sc_def_card/100;
      
      			if(target->bl.type == BL_PC || target->bl.type == BL_MOB || target->bl.type == BL_HOM)
      			{
      				if(atn_rand()%10000 < rate ){
      					if(battle_config.battle_log)
      						printf("PC %d skill_addreveff: card‚Й‚ж‚й€ЩЏн”­“® %d %d\n",sd->bl.id,i,sd->addreveff[i-SC_STONE]);
      					status_change_start(&target->bl,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
      				}
      			}
      		}
      	}
      }
      
      return damage;
      

      }

      Это лишь одна из бесчисленных функций вызывающих друг друга.
      Если кто-то всерьез озаботится разбором полетов, то вперед 😃 Имхо, вы можете спорить друг с другом бесконечно, а реально оно все равно окажется не так.

      1 ответ Последний ответ Ответить Цитировать 0
      • zALzZ Не в сети
        zALz
        отредактировано

        Прокуратор, складывается впечатление, что главным для тебя было написать, неважно что.
        Спора тут нет, здесь высказываются предположения и проверяются. Уже найдена серьёзная ошибка в действующей механике, подозреваю, что действие ещё пары скиллов также неверно, что проверю сам чуть позже.

        1 ответ Последний ответ Ответить Цитировать 0
        • D Не в сети
          DivineDivinity
          отредактировано

          Прокуратор, умри.
          Смотри battle_calc_magic_attack()
          Советую открывать код еАфины рядом с кодом жАфины.
          Там комменты на англиЦЦком, очень часто код совпадает.
          ЗЫ Оборот "друг друга" насколько я знаю имеет другое значение
          Функций там немного
          battle_calc_weapon_attack()
          battle_calc_magic_attack()
          battle_calc_misc_attack()

          • Все остальные не несут информации, о которой тут говорят.
            Все они потом вызывают ту, что ты привел, правда не догадываюсь зачем.
          1 ответ Последний ответ Ответить Цитировать 0
          • ProkuratorP Не в сети
            Prokurator
            отредактировано

            Зачем сразу "умри"? Я же не сказал никому, что я пытался всерьез разобраться. Просто запостил кусок, который первым попался на глаза, как справедливо заметил zALz. Я хотел этим постом сказать в сущности, что строгих "формул" в плане четкой зависимости дамага от значений определенных параметров, я не увидел. Там слишком много запутанных вложенных if-ов.

            1 ответ Последний ответ Ответить Цитировать 0
            • D Не в сети
              DivineDivinity
              отредактировано

              Тогда зач6ем было постить этот огромный кусок кода, "который первый попался на глаза"?
              Ничего сложного там нет. Это писали люди. Значит, (при определенном упорстве) это можно понять. Исходники выкладывают не просто так, чтобы подписать себя в команду "OpenSource" или что-то подобное. Предполагалось (GPL) что ты можешь часть этих исходников использовать в своих целях, правда некомерческих )
              Если читать твой пост то ифов действительно много и все запутано, а если читать нормальный табулированый исходник, то все просто. Ну да, желательно иметь хотябы смутное представление о С )

              *До сих пор непонимаю, как бонус от рода входит в квадрате, не могу найти соотвествующего места в /src

              Кстати - серьезная ошибка это именно этот бонус?

              1 ответ Последний ответ Ответить Цитировать 0
              • zALzZ Не в сети
                zALz
                отредактировано

                Да, двойной учёт прибавки от стаффа - это серьёзная ошибка.

                Можешь заодно поглядеть модификацию повреждений от амп и брейкера. Что-то мне подсказывает, что работать это должно как:
                x+x0.15+x0.5+x=2.65x, где х - базовые повреждения. При таком раскладе прибавка к повреждениям идёт, исходя каждый раз из базового матка.
                У нас же, я подозреваю, так:
                x1.151.151.52=3.9675, что почти в два раза больше вышеприведённого результата.

                1 ответ Последний ответ Ответить Цитировать 0
                • ProkuratorP Не в сети
                  Prokurator
                  отредактировано

                  DevineDevinity, не понимаю, зачем мне это писать. Я по образованию математик-программист, т.е. специалист с дипломом, и о Си имею не смутное, а вполне приличное представление. Как ни табулируй, стиль тут мерзкий, как ни крути.

                  1 ответ Последний ответ Ответить Цитировать 0
                  • D Не в сети
                    DivineDivinity
                    отредактировано

                    Посмотрю завтра, сегодня уже спать пора )
                    Надеюсь я получу более качественное образование по той же специальности.
                    Стиль может и мерзкий, мне еАфина тоже больше нравится, но что поделать?
                    Я о твоем знаии Си не говорю, это оффтоп :))
                    Насчет того, зачем писать - это протест в знак огромного поста, не несущего см. нагрузки ). Пусть будет так )

                    Сложность в следующем, что есть база вещей, и там не очень ясно указаны свойства, которые они дают, по крайней мере мне так показалось.
                    Есть функция MATK_FIX(a,b) действует так:
                    matk1=matk1*(a/b); matk2=matk2*(a/b)
                    Есть ещё функция pc_bonus(), которая тоже производит некоторые изменения в характеристиках в зависимости от шмоток. По-моему там был бонус от рода, точнее скажу завтра, эта часть смотрелась мельком, мне тогда было лень читать этот топег )
                    Главное подозрение - что род учитывается и там и там, хотя по беглому взгляду функцию MATK_FIX() вызвают обычно только при подсчете урона спеллов. Например так
                    case WZ_STORMGUST:
                    MATK_FIX(40*skill_lvl+100,100);
                    //...
                    break;
                    Что касается рода - загадка. Если я найду это место в более новом емуле, будет надежда дать ответ на вопрос будет ли это пофиксено )

                    кстати ел. учитывается в самом конце и это явно фиксится не будет

                    1 ответ Последний ответ Ответить Цитировать 0
                    • TerramorpherT Не в сети
                      Terramorpher
                      отредактировано

                      Насчёт комментов - вот, примерный перевод.
                      (не судите строго - больно спать хочется...)
                      Ну по порядку представленному в вышепреведённом отрывке...

                      [code:3jaxocgl]//スキルダメージ補正 - skill damage
                      //アスムプティオ - assumptio
                      //通常攻撃75%OFF - ммм... вроде "урезка атаки"
                      //スキル25%OFF - урезка скилла.
                      // セーフティウォール - сефети
                      // ニューマ - пневма
                      // レックスエーテルナ - атерна
                      //属性場のダメージ増加 - усиление от ковриков сага
                      // バイオレントゲイル - воздушный коврик
                      // デリュージ - лужа
                      // エナジーコート プレッシャーは軽減しない - выключение энержи коата.
                      // キリエエレイソン - кирия
                      /* インデュア / - эндюра
                      /
                      オートガード / - гвард
                      /
                      パリイング / - парринг
                      // リジェクトソード режект сворд
                      //反射確率は15
                      Lv шанс режекта 15*лев
                      //ダメージを与えたのは良いんだが、ここからどうして表示するんだかわかんねぇ - что-то про отображение дамага... %)
                      //エフェクトもこれでいいのかわかんねぇ - теперь про эффекты
                      // 1288:エンペリウム - 1288- империум
                      //ギルド未加入ならダメージ無し - это к империуму
                      //自占領ギルドのエンペならダメージ無し - это тоже про империум
                      //正規ギルド承認がないとダメージ無し - и это
                      / 同盟ならダメージ無し - а это проверяет может ли член альянса бить имп.
                      //defenseが・ればダメージが減るらしい? - понижается ли дефенс гравитацией...
                      // 反撃などのMOBスキル判定 - скиллы мобов
                      // 攻撃状態へ一時変更 - опять мобы
                      // 状態を戻す тоже не про магию.
                      //PCの反撃オートスペル -
                      //PCの反撃 - ??
                      //反撃状態異常 -??
                      //対象の耐性 - формулы выживательности цели.
                      //対象に状態異常 -статусы[/code:3jaxocgl]
                      Вот и все комменты.
                      Если наложить на текст, видно, что перевода и не требовалось - всё указано в названиях переменных.

                      1 ответ Последний ответ Ответить Цитировать 0
                      • D Не в сети
                        DivineDivinity
                        отредактировано

                        Доброго времени суток )

                        Свершилось чудо и ошибка таки была найдена )

                        [code:s0dkl0ij]// jAthena-2060 [athena-2.1.1]

                        [../src/map/status.c]

                        int status_calc_pc(struct map_session_data* sd, ...)
                        {

                        // ...
                        
                        int b_matk1,b_matk2;
                        
                        // ...
                        
                        b_matk1 = sd->matk1;
                        b_matk2 = sd->matk2;
                        
                        // ...
                        
                        sd->matk1 =0;
                        sd->matk2 =0;
                        
                        // ...
                        
                        sd->matk1 += sd->paramc[3]+(sd->paramc[3]/5)*(sd->paramc[3]/5); /* char paramc[5]={str, agi, vit, int, dex, luk} [me] */
                        sd->matk2 += sd->paramc[3]+(sd->paramc[3]/7)*(sd->paramc[3]/7); /* помните, что в С отсчет начинается с 0 */
                        
                        // ...
                        
                        if(sd->matk1 < sd->matk2) {
                        	int temp = sd->matk2;
                        	sd->matk2 = sd->matk1;
                        	sd->matk1 = temp;
                        }
                        
                        if (sd->sc_data[SC_MINDBREAKER].timer!=-1) {
                        		sd->matk1 += (sd->matk1*20*sd->sc_data[SC_MINDBREAKER].val1)/100;
                        		sd->matk2 += (sd->matk2*20*sd->sc_data[SC_MINDBREAKER].val1)/100;
                        		sd->mdef -= (sd->mdef*12*sd->sc_data[SC_MINDBREAKER].val1)/100;
                        	}
                        
                        // ...
                        
                        if(sd->matk_rate!=100){
                        	sd->matk1 = sd->matk1*sd->matk_rate/100;
                        	sd->matk2 = sd->matk2*sd->matk_rate/100;
                        }
                        if(sd->matk1<1)
                         	sd->matk1 = 1;
                        if(sd->matk2<1)
                        	sd->matk2 = 1;
                        
                        // ...
                        
                        if(b_matk1 != sd->matk1)
                        	clif_updatestatus(sd,SP_MATK1); /* визуальное обновление [me] */
                        if(b_matk2 != sd->matk2)
                        	clif_updatestatus(sd,SP_MATK2); /* визуальное обновление [me] */
                        
                        // ...
                        
                        return 0;
                        

                        }

                        int status_get_matk1(struct block_list *bl)
                        {

                        int matk1,int_;
                        nullpo_retr(0, bl);
                        
                        if (bl->type==BL_PC)
                        	return ((struct map_session_data *)bl)->matk1;
                        
                        // ...
                        

                        }

                        int status_get_matk2(struct block_list *bl)
                        {

                        int matk1,int_;
                        nullpo_retr(0, bl);
                        
                        if (bl->type==BL_PC)
                        	return ((struct map_session_data *)bl)->matk1;
                        
                        // ...
                        

                        }

                        [../src/map/battle.c]

                        struct Damage battle_calc_magic_attack (struct block_list *bl, ...)
                        {

                        // ...
                        
                        int matk1,matk2;
                        
                        // ...
                        
                        matk1 = status_get_matk1(bl); /* вызывает status_get_matk1 из [status.c] см. выше [me] */
                        matk2 = status_get_matk2(bl); /* вызывает status_get_matk2 из [status.c] см. выше [me] */
                        
                        // ...
                        

                        #define MATK_FIX( a,b ) { matk1=matk1*(a)/(b); matk2=matk2*(a)/(b); }

                        /*  тут начинаются чудеса  */
                        if(sd) {
                        	sd->state.attack_type = BF_MAGIC;
                        	if(sd->matk_rate != 100)		
                        		MATK_FIX(sd->matk_rate,100);
                        }
                        
                        
                        
                        // ...
                        
                        if (sc_data && sc_data[SC_MAGICPOWER].timer != -1) {
                        	matk1 += (matk1 * sc_data[SC_MAGICPOWER].val1 * 5)/100; /* SC_MAGICPOWER = MYSTICAL AMPLIFICATION [me] */
                        	matk2 += (matk2 * sc_data[SC_MAGICPOWER].val1 * 5)/100; /* SC_MAGICPOWER = MYSTICAL AMPLIFICATION [me] */
                        }
                        
                        // ...
                        

                        }
                        [/code:s0dkl0ij]
                        Все вопросы, связаные с неправильным расчетом mAtk снимаются. На мой взгляд предполагалось что status_get_matk() возвратит "чистый" mAtk зависящий только от инты.
                        Это эмулятор за текущий месяц (впрочем jAthena-1735 не отличаетися кодом в этом месте), так что я думаю никаких исправлений пока не предвидится, хотя неизвестно, когда именно администрация решится на ввод очередной версии емулятора.

                        Конечно, с особым цинизмом надо удалять это место из емула, ибо нефих ^_~

                        К чести код eAthena'ы, отвечающий за расчет mAtk выглядит куда более елегантно и не содержит таких грубых оплошностей.

                        [code:s0dkl0ij]// eAthena-7028 [Jun 2006] athena-2.1.1

                        [../src/map/status.c]

                        int status_calc_matk(struct block_list *bl, int matk)
                        {
                        struct status_change *sc;
                        nullpo_retr(matk,bl);
                        sc = status_get_sc(bl);

                        if(sc && sc->count){
                        
                        // ...
                        
                        	if(sc->data[SC_MAGICPOWER].timer!=-1) /* SC_MAGICPOWER = MYSTICAL AMPLIFICATION [me] */
                        		matk += matk * 5*sc->data[SC_MAGICPOWER].val1/100;
                        	if(sc->data[SC_MINDBREAKER].timer!=-1)
                        		matk += matk * 20*sc->data[SC_MINDBREAKER].val1/100;
                        
                        // ...	
                        
                        }
                        return matk;
                        

                        }

                        /*
                        ...
                        */

                        int status_calc_pc(struct map_session_data* sd,int first)
                        {

                        // ...
                        
                        int b_matk1,b_matk2;
                        
                        // ...
                        
                        b_matk1 = sd->matk1;
                        b_matk2 = sd->matk2;
                        
                        // ...
                        
                        sd->matk1 += sd->paramc[3]+(sd->paramc[3]/5)*(sd->paramc[3]/5); /* char paramc[5]={str, agi, vit, int, dex, luk} [me] */
                        sd->matk2 += sd->paramc[3]+(sd->paramc[3]/7)*(sd->paramc[3]/7); /* помните, что в С отсчет начинается с 0 */
                        if(sd->matk1 < sd->matk2) {
                        	int temp = sd->matk2;
                        	sd->matk2 = sd->matk1;
                        	sd->matk1 = temp;
                        }
                        
                        sd->matk1 = status_calc_matk(&sd->bl,sd->matk1);
                        sd->matk2 = status_calc_matk(&sd->bl,sd->matk2);
                        
                        if(sd->matk_rate != 100){
                        	sd->matk1 = sd->matk1 * sd->matk_rate/100;
                        	sd->matk2 = sd->matk2 * sd->matk_rate/100;
                        }
                        
                        // ...
                        
                        if(b_matk1 != sd->matk1)
                        	clif_updatestatus(sd,SP_MATK1); /* визуальное обновление [me] */
                        if(b_matk2 != sd->matk2)
                        	clif_updatestatus(sd,SP_MATK2); / визуальное обновлениеt [me] */
                        return 0;
                        

                        }

                        [../src/map/battle.c]

                        struct Damage battle_calc_magic_attack(
                        struct block_list *src, ...)
                        {
                        // ...

                        struct Damage ad;
                        ad.damage = 1;
                        
                        // ...
                        

                        #define MATK_RATE( a ) { ad.damage= ad.damage*(a)/100; }
                        #define MATK_ADDRATE( a ) { ad.damage+= ad.damage*(a)/100; }
                        #define MATK_ADD( a ) { ad.damage+= a; }

                        // ...
                        
                        matkmin = status_get_matk2(src);
                        matkmax = status_get_matk1(src);
                        MATK_ADD(matkmin+(matkmax>matkmin?rand()%(matkmax-matkmin+1):0));
                        
                        // ...
                        

                        }
                        [/code:s0dkl0ij]

                        Зальз, полный код приводился именно для тебя чтобы дать ответ на твой вопрос про сочетание МБ, МА и пр.

                        1 ответ Последний ответ Ответить Цитировать 0
                        • zALzZ Не в сети
                          zALz
                          отредактировано

                          К сожалению, моя специальность не связана сильно с программированием, а имеющихся основ си мне хватает лишь на часть написанного, поэтому лучше поясни полностью.

                          1 ответ Последний ответ Ответить Цитировать 0
                          • D Не в сети
                            DivineDivinity
                            отредактировано

                            Попробую )
                            sd - скоращено от session data, для тебя будет проще воспринимать это как твоего чара. Дальше я это sd буду просто опускать.
                            Начнем с места matk1=0 это я думаю понятно )
                            Дальше идет обычный подсчет верхнего и нижнего матк, тоже думаю в комментариях не нуждается
                            sd->paramc[3] - это суммарная инт.
                            Если вдруг оказалось что тот матк, что должен быть больше (1) оказывается меньше, они просто меняются местами.
                            Проверяется наличие статус маиндбрейк, если он наложен, то
                            матк += (увеличить на) 20скил_мб(5)матк/100
                            то есть просто ещё + матк (ну соотвественно к нижнему нижний к верхнему верхний)
                            дальше идет бонус от палки, пускай 15%. То есть в итоге мы получили 2
                            матк
                            1.15, это что отображается у нас в окошечке.

                            Когда мы начинаем кого-то бить (собственно вызываются функции, описаны в battle.c), сервер запрашивает матк, получает его, а потом ещё раз добавляет бонус палки. то есть имеет 2матк1.151.15, то есть в итоге 2,45матк вместо 2.3матк
                            После этого идет проверка амплика. Заметь, что всюду переписывалось значение матк1, матк2 и на момент этой проверки матк уже составляет 2.45
                            матк изначального значения, то есть +50% к этому, получим
                            2.45матк1.5 = 3.675*матк.

                            Код еАфины отличается тем, что в battle.c уже нет повтороного учитывания бонуса bMatkRate, но бонусы от прочих статусов (маинд брейк, амплик) точно также перемножаются поэтому получим
                            матк21.151.5=3.45матк

                            1 ответ Последний ответ Ответить Цитировать 0
                            • Первое сообщение
                              Последнее сообщение