Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / sabrina / magic_action_attack.cpp
blob53c19c15538a4d1074f1eb7ad1bba94460f72325
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "stdpch.h"
20 #include "magic_action.h"
21 #include "magic_phrase.h"
22 #include "creature.h"
23 #include "character.h"
24 #include "phrase_utilities_functions.h"
25 #include "game_share/entity_structure/statistic.h"
26 #include "game_share/magic_fx.h"
27 #include "s_effect.h"
28 #include "phrase_manager.h"
30 using namespace NLNET;
31 using namespace NLMISC;
32 using namespace RY_GAME_SHARE;
33 using namespace std;
35 std::vector< std::pair< std::string , IMagicActionFactory* > >* IMagicActionFactory::Factories = NULL;
38 class CMagicActionBasicDamage : public IMagicAction
40 public:
41 CMagicActionBasicDamage()
42 :_DmgHp(0),_DmgSap(0),_DmgSta(0),_DmgType(DMGTYPE::UNDEFINED){}
43 protected:
44 virtual bool addBrick( const CStaticBrick & brick, CMagicPhrase * phrase, bool &effectEnd )
46 for ( uint i=0 ; i<brick.Params.size() ; ++i)
48 switch(brick.Params[i]->id())
50 case TBrickParam::MA_END:
51 INFOLOG("MA_END Found: end of effect");
52 effectEnd = true;
53 return true;
55 case TBrickParam::MA_DMG_TYPE:
56 INFOLOG("MA_DMG_TYPE: %s",((CSBrickParamMagicDmgType *)brick.Params[i])->DmgType.c_str());
57 _DmgType = DMGTYPE::stringToDamageType( ((CSBrickParamMagicDmgType *)brick.Params[i])->DmgType );
58 if ( _DmgType == DMGTYPE::UNDEFINED )
60 nlwarning("<CMagicActionBasicDamage addBrick> invalid dmg type %s", ((CSBrickParamMagicDmgType *)brick.Params[i])->DmgType.c_str());
61 return false;
63 break;
65 case TBrickParam::MA_DMG:
66 INFOLOG("MA_DMG: %u %u %u",((CSBrickParamMagicDmg *)brick.Params[i])->Hp,((CSBrickParamMagicDmg *)brick.Params[i])->Sap,((CSBrickParamMagicDmg *)brick.Params[i])->Sta);
67 _DmgHp = ((CSBrickParamMagicDmg *)brick.Params[i])->Hp;
68 _DmgSap = ((CSBrickParamMagicDmg *)brick.Params[i])->Sap;
69 _DmgSta = ((CSBrickParamMagicDmg *)brick.Params[i])->Sta;
70 break;
72 default:
73 // unused param, can be useful in the phrase
74 phrase->applyBrickParam( brick.Params[i] );
75 break;
78 ///\todo nico: check if everything is set
79 return true;
81 virtual bool validate(CMagicPhrase * phrase)
83 return PHRASE_UTILITIES::validateSpellTarget(phrase->getActor(),phrase->getTargets()[0],ACTNATURE::OFFENSIVE);
85 virtual void apply( CMagicPhrase * phrase, float successFactor,MBEHAV::CBehaviour & behav , bool isMad )
87 ///\todo nico:
88 // - location
89 // - armor + shield
90 // - player damages + on armor
91 // - behaviour + chat messages
92 // - aggro
94 CEntityBase* actor = CEntityBaseManager::getEntityBasePtr( phrase->getActor() );
95 if (!actor)
96 return;
98 /// test resistance
99 if ( successFactor <= 0.0f )
101 if ( actor->getId().getType() == RYZOMID::player )
102 CCharacter::sendMessageToClient( actor->getId(),"MAGIC_TOTAL_MISS" );
103 return;
106 const std::vector< TDataSetRow > & targets = phrase->getTargets();
108 SSkill * skillAtt = actor->getSkills().getSkillStruct( _Skill );
109 if ( ! skillAtt )
111 nlwarning("<CMagicActionBasicDamage apply> %s is not a valid skill",SKILLS::toString(_Skill).c_str());
112 return;
115 const CSEffect * debuff = actor->lookForSEffect( EFFECT_FAMILIES::DebuffSkillMagic );
116 sint skillValue = skillAtt->Current;
117 if ( debuff )
118 skillValue -= debuff->getParamValue();
120 for ( uint i = 0; i < targets.size(); i++ )
122 // check target
123 CEntityBase* target = CEntityBaseManager::getEntityBasePtr( targets[i] );
124 if ( !target)
125 continue;
126 if ( isMad || PHRASE_UTILITIES::validateSpellTarget(actor->getEntityRowId(),target->getEntityRowId(),ACTNATURE::OFFENSIVE) )
128 ///\NOT USED NOW
129 //behav.Magic.SpellPower = PHRASE_UTILITIES::getAttackIntensity( phrase->getSabrinaCost() );
132 // test resistance
133 /* SSkill * skillResist = target->getSkills().getSkillStruct( SKILLS::MagicDefense ); //TODO skill missing
134 if ( ! skillResist )
136 nlwarning("<CMagicActionBasicDamage apply> MagicDefense is not a valid skill");
137 return;
139 */ // get the chances ( delta level is divided by 10 because a level is 10
140 const uint8 chances = PHRASE_UTILITIES::getSuccessChance( ( skillValue /*- skillResist->Current*/ )/10 ); //TODO skillResist
141 const uint8 roll = (uint8)RandomGenerator.rand( 99 );
142 float resistFactor = PHRASE_UTILITIES::getSucessFactor(chances, roll);
144 if ( resistFactor > 0.0f )
146 if ( resistFactor > 1.0f )
147 resistFactor = 1.0f;
148 //behav.Spell.Resist = 0;
149 behav.Spell.SpellId = MAGICFX::toMagicFx( _DmgType ,false);
151 float mult = resistFactor;
152 const CSEffect * effect = target->lookForSEffect( EFFECT_FAMILIES::MagicDmgAmpli );
153 if ( effect )
154 mult *= ( effect->getParamValue() / 100.0f );
156 sint32 realDmgHp = sint32 ( _DmgHp * mult );
157 realDmgHp = sint32( target->applyDamageOnArmor( _DmgType, realDmgHp ) );
158 if ( target->changeCurrentHp( - realDmgHp ) )
160 // send mission event
161 if ( actor->getId().getType()== RYZOMID::player )
163 CMissionEventKill event ( target->getEntityRowId() );
164 ((CCharacter*) actor)->processMissionEvent( event );
167 if ( target->getScores()._PhysicalScores[SCORES::hit_points].Current <= 0)
169 target->getScores()._PhysicalScores[SCORES::hit_points].Current = 0;
170 //behav.Spell.KillingBlow = 1;
172 PHRASE_UTILITIES::sendScoreModifierSpellMessage( actor, target, realDmgHp ,SCORES::hit_points , ACTNATURE::OFFENSIVE);
174 sint32 realDmgSap;
176 RY_GAME_SHARE::SCharacteristicsAndScores &score = target->getScores()._PhysicalScores[SCORES::sap];
177 realDmgSap = sint32( _DmgSap * mult );
178 realDmgSap = target->applyDamageOnArmor( _DmgType, realDmgSap );
179 score.Current = score.Current - realDmgSap;
180 if ( score.Current < 0)
181 score.Current = 0;
182 PHRASE_UTILITIES::sendScoreModifierSpellMessage( actor, target, realDmgSap ,SCORES::sap , ACTNATURE::OFFENSIVE);
185 sint32 realDmgSta;
187 RY_GAME_SHARE::SCharacteristicsAndScores &score = target->getScores()._PhysicalScores[SCORES::stamina];
188 realDmgSta = sint32( _DmgSta * mult );
189 realDmgSta = target->applyDamageOnArmor( _DmgType, realDmgSta );
190 score.Current = score.Current - realDmgSta;
191 if ( score.Current < 0)
192 score.Current = 0;
193 PHRASE_UTILITIES::sendScoreModifierSpellMessage( actor, target, realDmgSta ,SCORES::stamina , ACTNATURE::OFFENSIVE);
196 ///\todo nico: real value
197 behav.Spell.SpellIntensity = 5;
199 // compute aggro
200 sint32 max = target->getPhysScores()._PhysicalScores[SCORES::hit_points].Max;
201 if (max)
203 const sint32 aggro = (-1) * sint32((100.0 * float(realDmgHp))/float(max) );
204 // update the report
205 CAiEventReport report;
206 report.AggroMul = 1.0f;
207 report.AggroAdd = aggro;
208 report.addDelta(AI_EVENT_REPORT::HitPoints, (-1)*realDmgHp);
209 CPhraseManager::getInstance()->addAiEventReport(report);
212 max = target->getPhysScores()._PhysicalScores[SCORES::sap].Max;
213 if (max)
215 const sint32 aggro = (-1) * sint32((100.0 * float(realDmgSap))/float(max) );
216 // update the report
217 CAiEventReport report;
218 report.AggroMul = 1.0f;
219 report.AggroAdd = aggro;
220 report.addDelta(AI_EVENT_REPORT::Sap, (-1)*realDmgSap);
221 CPhraseManager::getInstance()->addAiEventReport(report);
224 max = target->getPhysScores()._PhysicalScores[SCORES::stamina].Max;
225 if (max)
227 const sint32 aggro = (-1) * sint32((100.0 * float(realDmgSta))/float(max) );
228 // update the report
229 CAiEventReport report;
230 report.AggroMul = 1.0f;
231 report.AggroAdd = aggro;
232 report.addDelta(AI_EVENT_REPORT::Stamina, (-1)*realDmgSta);
233 CPhraseManager::getInstance()->addAiEventReport(report);
236 else
238 if ( actor->getId().getType() == RYZOMID::player )
239 CCharacter::sendMessageToClient( actor->getId(),"MAGIC_TOTAL_RESIST" );
240 if ( target->getId().getType() == RYZOMID::player )
241 CCharacter::sendMessageToClient( target->getId(),"MAGIC_U_TOTAL_RESIST" );
242 ///\todo nico msgs
243 //behav.Spell.Resist = 1;
245 /// compute resist XP gain
246 /* if ( target->getId().getType() == RYZOMID::player && resistFactor < 1.0f)
248 ///\todo nico resistFactor is the quality factor of the action for xp
249 ((CCharacter*) target)->actionReport( actor, (skillResist->Current - skillValue)/10, ACTNATURE::DEFENSIVE, SKILLS::toString( SKILLS::MagicDefense ) );
251 */ }
254 DMGTYPE::EDamageType _DmgType;
255 sint32 _DmgHp;
256 sint32 _DmgSap;
257 sint32 _DmgSta;
259 BEGIN_MAGIC_ACTION_FACTORY(CMagicActionBasicDamage)
260 ADD_MAGIC_ACTION_TYPE( "mto" )
261 END_MAGIC_ACTION_FACTORY(CMagicActionBasicDamage)