diff --git a/Crawler/Ability.h b/Crawler/Ability.h index e7735b45..0206a172 100644 --- a/Crawler/Ability.h +++ b/Crawler/Ability.h @@ -66,6 +66,8 @@ struct Ability{ bool canCancelCast=false; InputGroup*input; std::string icon; + //If set to true, this ability instead activates immediately when a cast occurs. When the cast finishes, nothing happens instead. + bool actionPerformedDuringCast=false; bool waitForRelease=false; //Ability action function, returns true if the ability can be casted, otherwise returns false. // Argument 1: Player* - player pointer diff --git a/Crawler/Buff.h b/Crawler/Buff.h index 914183cc..c930ccbb 100644 --- a/Crawler/Buff.h +++ b/Crawler/Buff.h @@ -43,6 +43,7 @@ enum BuffType{ SLOWDOWN, BLOCK_SLOWDOWN, RESTORATION, + RESTORATION_DURING_CAST, }; class Crawler; diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index 27bbcb0a..37315036 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -2236,6 +2236,7 @@ void Crawler::SetLoadoutItem(int slot,std::string itemName){ }break; } Ability itemAbility{itemName,"","","Item.Item Cooldown Time"_F,0,inputGroup,"items/"+itemName+".png",VERY_DARK_RED,DARK_RED,PrecastData{GetLoadoutItem(slot).lock()->CastTime(),0,0},true}; + itemAbility.actionPerformedDuringCast=GetLoadoutItem(slot).lock()->UseDuringCast(); switch(slot){ case 0:{ diff --git a/Crawler/Item.cpp b/Crawler/Item.cpp index ebed674c..0a59f7b9 100644 --- a/Crawler/Item.cpp +++ b/Crawler/Item.cpp @@ -105,6 +105,7 @@ void ItemInfo::InitializeItems(){ std::vectorstatValueList; uint32_t sellValue=0; uint32_t buyValue=0; + bool useDuringCast=false; for(auto&[itemKey,itemValue]:data[key].GetKeys()){ std::string keyName=itemKey; if(keyName=="Description"){ @@ -159,6 +160,9 @@ void ItemInfo::InitializeItems(){ it.enhancement=enhancementStats; } if(scriptName!=""){ + if(scriptName=="RestoreDuringCast"){ + useDuringCast=true; + } if(!ITEM_SCRIPTS.count(scriptName)){ ERR("Could not load script "<0){ for(std::string&s:slot){ if(!nameToEquipSlot.count(s))ERR("WARNING! Tried to add item "<action,BuffType type){ + auto ParseItemScriptData=[&](const std::string&propName,std::functionaction){ int restoreAmt=props.GetIntProp(propName); action(game,restoreAmt); if(restoreAmt>0&&props.PropCount(propName)==3){ - game->GetPlayer()->AddBuff(type,props.GetFloatProp(propName,2),restoreAmt,props.GetFloatProp(propName,1),action); + game->GetPlayer()->AddBuff(RESTORATION,props.GetFloatProp(propName,2),restoreAmt,props.GetFloatProp(propName,1),action); } }; ParseItemScriptData("HP Restore",[&](Crawler*game,int restoreAmt){ game->GetPlayer()->Heal(restoreAmt); - },RESTORATION); + }); ParseItemScriptData("HP % Restore",[&](Crawler*game,int restoreAmt){ game->GetPlayer()->Heal(int(game->GetPlayer()->GetMaxHealth()*restoreAmt/100.0f)); - },RESTORATION); + }); ParseItemScriptData("MP Restore",[&](Crawler*game,int restoreAmt){ game->GetPlayer()->RestoreMana(restoreAmt); - },RESTORATION); + }); ParseItemScriptData("MP % Restore",[&](Crawler*game,int restoreAmt){ game->GetPlayer()->RestoreMana(int(game->GetPlayer()->GetMaxMana()*props.GetIntProp("MP % Restore")/100.f)); - },RESTORATION); + }); return true; }; ITEM_SCRIPTS["Buff"]=[](Crawler*game,ItemProps props){ game->GetPlayer()->AddBuff(BuffType::ATTACK_PCT_UP,props.GetFloatProp("Attack %",1),props.GetFloatProp("Attack %",0)/100); return true; }; + ITEM_SCRIPTS["RestoreDuringCast"]=[&](Crawler*game,ItemProps props){ + auto ParseItemScriptData=[&](const std::string&propName,std::functionaction){ + int restoreAmt=props.GetIntProp(propName); + action(game,restoreAmt); + if(restoreAmt>0&&props.PropCount(propName)==3){ + game->GetPlayer()->AddBuff(RESTORATION_DURING_CAST,props.GetFloatProp(propName,2),restoreAmt,props.GetFloatProp(propName,1),action); + } + }; + ParseItemScriptData("HP Restore",[&](Crawler*game,int restoreAmt){ + game->GetPlayer()->Heal(restoreAmt); + }); + ParseItemScriptData("HP % Restore",[&](Crawler*game,int restoreAmt){ + game->GetPlayer()->Heal(int(game->GetPlayer()->GetMaxHealth()*restoreAmt/100.0f)); + }); + ParseItemScriptData("MP Restore",[&](Crawler*game,int restoreAmt){ + game->GetPlayer()->RestoreMana(restoreAmt); + }); + ParseItemScriptData("MP % Restore",[&](Crawler*game,int restoreAmt){ + game->GetPlayer()->RestoreMana(int(game->GetPlayer()->GetMaxMana()*props.GetIntProp("MP % Restore")/100.f)); + }); + return true; + }; ITEM_SCRIPTS.SetInitialized(); std::cout<item){ const bool Item::_IsBlank()const{ Item::IsBlankStaticCallCounter++; return IsBlank(); -}; \ No newline at end of file +}; + +const bool Item::UseDuringCast()const{ + return it->UseDuringCast(); +} + +const bool ItemInfo::UseDuringCast()const{ + return useDuringCast; +} \ No newline at end of file diff --git a/Crawler/Item.h b/Crawler/Item.h index b5f3a8f7..c58c8483 100644 --- a/Crawler/Item.h +++ b/Crawler/Item.h @@ -155,6 +155,7 @@ public: const Stats GetStats()const; const ItemScript&OnUseAction()const; const float CastTime()const; + const bool UseDuringCast()const; //When true, the item is activated during the cast instead of after the cast. const float CooldownTime()const; //Use ISBLANK macro instead!! This should not be called directly!! const bool IsBlank()const; @@ -247,6 +248,8 @@ class ItemInfo{ ItemProps customProps; uint32_t buyValue=0; uint32_t sellValue=0; + //If true, this item's action is activated at the beginning of the cast instead of after the cast completes. + bool useDuringCast=false; private: static void InitializeScripts(); static void InitializeSets(); @@ -272,6 +275,7 @@ public: const uint32_t GetSellValue()const; const bool CanBeSold()const; const bool CanBePurchased()const; + const bool UseDuringCast()const; }; class ItemOverlay{ diff --git a/Crawler/Player.cpp b/Crawler/Player.cpp index c5b13cc6..262ae714 100644 --- a/Crawler/Player.cpp +++ b/Crawler/Player.cpp @@ -438,9 +438,13 @@ void Player::Update(float fElapsedTime){ if(CanAct(ability)){ if(ability.cooldown==0&&GetMana()>=ability.manaCost){ if(key.Held()||key.Released()&&&ability==castPrepAbility&&GetState()==State::PREP_CAST){ - if(AllowedToCast(ability)&&ability.action(this,{})){ - ability.cooldown=ability.COOLDOWN_TIME; - ConsumeMana(ability.manaCost); + if(AllowedToCast(ability)){ + bool allowed=ability.actionPerformedDuringCast; + if(!allowed&&ability.action(this,{}))allowed=true; + if(allowed){ + ability.cooldown=ability.COOLDOWN_TIME; + ConsumeMana(ability.manaCost); + } }else if(ability.precastInfo.precastTargetingRequired&&GetState()==State::NORMAL){ PrepareCast(ability); @@ -655,6 +659,7 @@ void Player::Moved(){ state=State::NORMAL; castPrepAbility->waitForRelease=true; castInfo={"",0}; + std::erase_if(buffList,[](Buff&b){return b.type==RESTORATION_DURING_CAST;}); //Remove all buffs that would be applied during a cast, as we got interrupted. DAMAGENUMBER_LIST.push_back(std::make_shared(GetPos(),0,true,INTERRUPT)); } for(MonsterSpawner&spawner:SPAWNER_LIST){ @@ -748,6 +753,7 @@ void Player::CastSpell(Ability&ability){ castPosition=GetPos()+pointToCursor; } castInfo={ability.name,ability.precastInfo.castTime,ability.precastInfo.castTime,castPosition}; + if(ability.actionPerformedDuringCast){ability.action(this,castPosition);} SetState(State::CASTING); } diff --git a/Crawler/Version.h b/Crawler/Version.h index 0a8b2cf7..753e56ea 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 4530 +#define VERSION_BUILD 4534 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/assets/config/items/ItemDatabase.txt b/Crawler/assets/config/items/ItemDatabase.txt index 2a0c2423..f24e152d 100644 --- a/Crawler/assets/config/items/ItemDatabase.txt +++ b/Crawler/assets/config/items/ItemDatabase.txt @@ -53,9 +53,9 @@ ItemDatabase } Bandages { - ItemScript = Restore + ItemScript = RestoreDuringCast Description = Restores 30% health points over 6 seconds. The effect can be interrupted. - HP % Restore = 30% + HP % Restore = 5%,1,6 Cast Time = 6.0 Cooldown Time = 5.0 ItemCategory = Consumables diff --git a/Crawler/assets/config/items/ItemScript.txt b/Crawler/assets/config/items/ItemScript.txt index a53c2229..2fb1af30 100644 --- a/Crawler/assets/config/items/ItemScript.txt +++ b/Crawler/assets/config/items/ItemScript.txt @@ -22,4 +22,13 @@ ItemScript { Attack % = 0,0.0 } + + # Unlike an item or ability that requires a cast to perform, this applies a buff immediately and then moving cancels the buff mid-application. + RestoreDuringCast + { + HP Restore = 0,0.0,0.0 + HP % Restore = 0,0.0,0.0 + MP Restore = 0,0.0,0.0 + MP % Restore = 0,0.0,0.0 + } } \ No newline at end of file