void PerformUpgradeLink(OneObject* OBJ) {
    word OI=OBJ->LocalOrder->info.PUpgrade.NewUpgrade;
    Nation* NT=OBJ->Nat;
    byte NI=NT->NNUM;
    SimpleUTP* SU=NT->UPG.utp[OI];
    if(!CheckCost(NI,1,SU->Cost))return;
    OBJ->LocalOrder->info.PUpgrade.Stage++;
    OBJ->Ustage=OBJ->LocalOrder->info.PUpgrade.Stage;
    if(OBJ->LocalOrder->info.PUpgrade.Stage>=OBJ->LocalOrder->info.PUpgrade.NStages) {
        OBJ->Ready=true;
        for(int i=0; i<SU->NLinks; i++)
            NT->UPG.utp[SU->Links[i]]->Enabled=true;
        if(SU->NLinks)SU->Enabled=false;
        for(i=0; i<SU->NAuto; i++)
            NT->UPG.utp[SU->AutoPerf[i]]->DoUpgrade(NI,OBJ);
        RESRC[NT->NNUM][1]-=SU->Cost;
        SU->DoUpgrade(NT->NNUM,OBJ);
        SU->Finished=true;
        if(int(OBJ->LocalOrder)) {
            Order1* Or1=OBJ->LocalOrder->NextOrder;
            OBJ->FreeOrdBlock(OBJ->LocalOrder);
            OBJ->LocalOrder=Or1;
            OBJ->Important=false;
            return;
        };
    };
};
void OneObject::PerformUpgrade(word NewU) {
    if(Nat->UPG.NUpgrades<=NewU||!Ready)return;
    word NUP=Ref.General->NUpgrades;
    word* UPL=Ref.General->Upg;
    bool canU=false;
    for(int pp=0; pp<NUP; pp++)if(UPL[pp]==NewU)canU=true;
    if(!canU)return;
    if(!Nat->UPG.utp[NewU]->Enabled)return;
    if(!CheckCost(NNUM,1,Nat->UPG.utp[NewU]->Cost))return;
    Order1* Or1=GetOrdBlock();
    Or1->PrioryLevel=0;
    Or1->NextOrder=LocalOrder;
    Or1->OrderType=75;//Upgrade
    Or1->OrderTime=0;
    Or1->DoLink=&PerformUpgradeLink;
    Or1->info.PUpgrade.NewUpgrade=NewU;
    Or1->info.PUpgrade.Stage=1;
    Or1->info.PUpgrade.NStages=Nat->UPG.utp[NewU]->Time;
    //Nat->UPG.utp[NewU]->Stage=1;
    Order1* LOR=LocalOrder;
    if(int(InLineCom))FreeAsmLink();
    LocalOrder=Or1;
    //OrderReport=NULL;
    //MessageKind=0;
    //Sender=0xFFFF;
    SimpleUTP* SU=Nat->UPG.utp[NewU];
    //if(SU->OneTime)
    if(SU->OneTime) {
        SU->Done=true;
        SU->Enabled=false;
    };
    Ustage=0;
    NUstages=SU->Time;
    Ready=false;
};
bool UGameplayAbility::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo) const
{
	SetCurrentActorInfo(Handle, ActorInfo);

	if (ActorInfo->AbilitySystemComponent->GetUserAbilityActivationInhibited())
	{
		/**
		 *	Input is inhibited (UI is pulled up, another ability may be blocking all other input, etc).
		 *	When we get into triggered abilities, we may need to better differentiate between CanActviate and CanUserActivate or something.
		 *	E.g., we would want LMB/RMB to be inhibited while the user is in the menu UI, but we wouldn't want to prevent a 'buff when I am low health'
		 *	ability to not trigger.
		 *	
		 *	Basically: CanActivateAbility is only used by user activated abilities now. If triggered abilities need to check costs/cooldowns, then we may
		 *	want to split this function up and change the calling API to distinguish between 'can I initiate an ability activation' and 'can this ability be activated'.
		 */ 
		return false;
	}
	
	if (!CheckCooldown(ActorInfo))
	{
		return false;
	}

	if (!CheckCost(ActorInfo))
	{
		return false;
	}

	// If we're instance per actor and we already have an instance, don't let us activate again as this breaks the graph
	if (GetInstancingPolicy() == EGameplayAbilityInstancingPolicy::InstancedPerActor)
	{
		if (bIsActive)
		{
			return false;
		}
	}

	if (HasBlueprintCanUse)
	{
		if (K2_CanActivateAbility(*ActorInfo) == false)
		{
			ABILITY_LOG(Log, TEXT("CanActivateAbility %s failed, blueprint refused"), *GetName());
			return false;
		}
	}

	return true;
}
bool UGameplayAbility::CommitCheck(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo)
{
	/**
	 *	Checks if we can (still) commit this ability. There are some subtleties here.
	 *		-An ability can start activating, play an animation, wait for a user confirmation/target data, and then actually commit
	 *		-Commit = spend resources/cooldowns. Its possible the source has changed state since he started activation, so a commit may fail.
	 *		-We don't want to just call CanActivateAbility() since right now that also checks things like input inhibition.
	 *			-E.g., its possible the act of starting your ability makes it no longer activatable (CanaCtivateAbility() may be false if called here).
	 */

	if (!CheckCooldown(ActorInfo))
	{
		return false;
	}

	if (!CheckCost(ActorInfo))
	{
		return false;
	}

	return true;
}