Unit formations

Downloads, info and technical help for Napoleonic Total War 3
User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Unit formations

Postby risorgimento59 » Tue Jul 21, 2015 4:05 pm

Hi Lordz.
I'm going to paste here a couple of posts of mine from TWC.
Let's see if there's some interest around it.
Sorry for my bad English.

Hi all.

Implementing formations on top of the ranks/files system should be doable.
I never looked (and I don't plan to) into placing individual soldiers like square, wedge, diamond, etc. do.

The UI/Lua side is almost ready (added a couple of scroll buttons too in case of > 20 cards).
The panel is shown above the card that received a right click event.
It's resized according to the number of formations available for the unit (BattleUI.GetLBUnitFormations() to create all the buttons and BattleUI.GetLBUnitFormationsAvailable to show/move a subset of them).

Image

I also made a little experiment by patching the speed rate of units (Unk1A4).
It worked like a charm.

Code: Select all

NTWLib::Battle::CLandUnit *pUnit = pLocomotionState->pUnit;

switch (pUnit->pDBLandUnitRecord->Category)
{
case NTWLib::DB::SDBLandUnitRecord::CATEGORY_INFANTRY:
    {
        bool bLightInfantryBehaviourEnabled = NTWLib::Battle::CLandUnitSpecialAbilityStateManager::Proxy_HasSpecialAbilityEnabled( // TODO
            &pUnit->SpecialAbilityStateMgr,
            NTWLib::Battle::UNIT_SPECIAL_ABILITY_LIGHT_INFANTRY_BEHAVIOUR);

        if (!bLightInfantryBehaviourEnabled && (
            !pUnit->pBattleEnv->pBattleModel->pBattleMgr->bUnk2704 || (
            pUnit->State.RoutingState != NTWLib::Battle::UNIT_ROUTING_STATE_BROKEN &&
            pUnit->State.RoutingState != NTWLib::Battle::UNIT_ROUTING_STATE_ROUTING)))
        {
            const float unitScaleFactor = *static_cast<const float *>(
                NTWLib::Game::CGame1A4::Proxy_GetGFXPreference(
                pUnit->pBattleEnv->pWSApp->pGame1A4,
                NTWLib::Game::GAME1A4_PREFERENCE_GFX_UNITSCALEFACTOR));

            const float *pUnitScaleFactorTable = NTWLib::Game::Proxy_GetUnitScaleFactorTable();
            unsigned int UnitScaleIndex = 0U;
            while (UnitScaleIndex != 4U) {
                if (unitScaleFactor <= pUnitScaleFactorTable[UnitScaleIndex])
                    break;
                ++UnitScaleIndex;
            }
           
            NTWPLUS_ASSERT(pUnit->UnkAE8 == 0);

            unsigned int numFiles = NTWLib::Battle::CLandUnitUnkADCUnk628::Proxy_WidthToSlots( // TODO
                pUnit->pUnkADC->pUnk628, pUnit->KinematicState.Width, pUnit->Soldiers.Size);

            // Logistic function
            static const float F = 1.25f; // flip
            static const float L = 0.75f; // y max value
            static const float K = 10.f; // steepness
            static const float N = 120.f; // normalize
            static const float M = 0.5f; // x midpoint

            pLocomotionState->Unk1A4 *= F - (L / (1 + exp(-K * (static_cast<float>(numFiles) / N - M))));

        //    TODO: consider unitScaleFactor
       
        //    NTWPLUS_TRACE(2U, "BATTLEMGR::LANDUNITLOCOMOTIONSTATE::UPDATEMOVEMENT", L"%d = { %d -> %.3f }\r\n", pUnit->Id, numFiles, pLocomotionState->Unk1A4);
        }
       
        break;
    }
default:
    {
        break;
    }
}


It has to be similar for morale and fatigue I guess.
Perhaps just a matter of following where the coefficents from KV tables are applied.

However I need help...
Icons, parameters but especially ideas (mixing gaming experience and historical knowledges).
Speed is easy as I said, but for example, we need to sort out and to weight all the factors coming into play when modifying the morale.
Connecting the number of ranks or files to it is clearly not enough.
We've to check at very least if troops are moving, if menaced, if underfire, etc.
It makes no sense to have an halted unit, maybe well behind the front, flying from battlefield only because of being in column of route instead of line. Am I right?

Hope you can share your points then.
Thanks in advance.


Forgot to say...
1) We shall penalize the unprescribed formations of course (by dragging, or clicking +files / +ranks);
2) No way AI is gonna use new formations at this stage.
Last edited by risorgimento59 on Tue Jul 21, 2015 6:09 pm, edited 1 time in total.

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Tue Jul 21, 2015 5:25 pm

Image

User avatar
Lord Fullin
Lord
Lord
Posts: 3793
Joined: Tue Apr 20, 2010 11:07 am
Location: Argentina

Re: Unit formations

Postby Lord Fullin » Tue Jul 21, 2015 10:28 pm

very very interesting
Sauve qui peut!' 'Nous sommes trahis!'

User avatar
Lord Avon Ulysses
Lord
Lord
Posts: 2080
Joined: Sun Apr 11, 2010 3:56 am

Re: Unit formations

Postby Lord Avon Ulysses » Wed Jul 22, 2015 1:51 am

risorgimento59,
if you can implement formation effects we will confer on you 'God status'.
As for suggestions on the effect of formations, you will find no shortage of ideas around here.
We are always looking of ways to improve our mod & the things you are proposing here would be fantastic enhancements.

Many of the morale effects you mention are already mod'able in the standard game tables.
Adjusting the effect based on formation/number of ranks (if possible) could give the results you are looking for.
To use your example: a march column (perhaps defiled as having more ranks than files) would have lower morale if attacked, so the morale effect of being under cannon or musket fire & taking losses, could be increased. Rather than just a blanket morale drop based on the formation.
Besides ideas, we have many talented modders who can help with things like icons & buttons.

Your knowledge of N:TW's coding may allow a fix for the biggest bugbear in the whole game.
Is it possible to set a timer on the square effect, or even better set it so the formation must be completely formed before it's effects activate?

I encourage you to post further. We would be honoured to have your knowledge available to improve our mod. Anyone who contributes, especially something as seismic as this, would be quickly included in the decision making side NTW3. In any case we would be happy to help you develop your earth shaking ideas for the general good of the total war community.
'Illegitimi non carborundum'

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Wed Jul 22, 2015 8:28 am

Lord Avon Ulysses wrote:Your knowledge of N:TW's coding may allow a fix for the biggest bugbear in the whole game.
Is it possible to set a timer on the square effect, or even better set it so the formation must be completely formed before it's effects activate?


In my plans, the FORMING state should act as a "barrier" (with timeout attached, of course) between UNDEFINED -> SPECIAL ABILITY, UNDEFINED -> UNIT FORMATION, UNIT FORMATION -> SPECIAL ABILITY, SPECIAL ABILITY -> UNIT FORMATION, UNIT FORMATION -> UNDEFINED, SPECIAL ABILITY -> UNDEFINED, etc...

Hope it'll work.

Thank you for the kind and encouraging words.

User avatar
Lord Lepic
Honourary Lord
Honourary Lord
Posts: 305
Joined: Mon May 20, 2013 8:20 pm

Re: Unit formations

Postby Lord Lepic » Wed Jul 22, 2015 12:39 pm

the biggest bugbear in the whole game

we all hope it works and thank you so much for your efforts
its great to see you have the determination to make improvements

not sure if can help and or how ?...............please advise as i am sure all are willing to do whatever they can here

i can only say from the entire community what this contribution would mean is unquantifiable !!!!!
Napoléonien Stratagème
Discord: https://discord.gg/7zB33xt
Follow the Eagle!

User avatar
turcoman
Villein
Villein
Posts: 46
Joined: Fri Jul 30, 2010 4:25 pm
Location: Istanbul

Re: Unit formations

Postby turcoman » Wed Jul 22, 2015 1:18 pm

If somebody can implement timer on square button and save us from this damn quicksquare after almost 5 years, I will be his humble servant, like Rustem for Napoleon !
Soldats! Faites votre devoir! Droit au cœur mais épargnez le visage. Feu!

User avatar
FireTight
Gentleman
Gentleman
Posts: 156
Joined: Sat Apr 26, 2014 3:03 pm
Location: Brno, CZE
Contact:

Re: Unit formations

Postby FireTight » Wed Jul 22, 2015 4:15 pm

turcoman wrote:If somebody can implement timer on square button and save us from this damn quicksquare after almost 5 years, I will be his humble servant, like Rustem for Napoleon !

Fun fact: squares in vanilla work much better than in NTW3.

Proof:
[youtube]http://www.youtube.com/watch?v=YERC8vJnl2A[/youtube]

User avatar
oOIYvYIOo
Baronet
Baronet
Posts: 2019
Joined: Tue Mar 08, 2011 6:42 pm
Location: Caldas da Rainha,Portugal

Re: Unit formations

Postby oOIYvYIOo » Wed Jul 22, 2015 5:19 pm

turcoman wrote:If somebody can implement timer on square button and save us from this damn quicksquare after almost 5 years, I will be his humble servant, like Rustem for Napoleon !


You alived ?
.☠. Lusitani Legio ,Fundator membrum
https://www.youtube.com/user/oOIYvYIOo

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Wed Jul 22, 2015 5:47 pm

Image

Looks much better expressed as HFSM (Hierarchical Finite State Machine). :smile:

User avatar
Lord Fullin
Lord
Lord
Posts: 3793
Joined: Tue Apr 20, 2010 11:07 am
Location: Argentina

Re: Unit formations

Postby Lord Fullin » Wed Jul 22, 2015 5:57 pm

This is the holy grail of NTW3, the filosopher stone, many have tried, yet none have ever got closer to achive it.

Dont toy with us resorgimento, you are dealing with our hopes and expectations,and my hart cannot take another blow.... :wink:
Sauve qui peut!' 'Nous sommes trahis!'

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Wed Jul 22, 2015 7:27 pm

Don't worry, hermano.
I've defrauded the poor Desaix once. And it was enough.
But I didn't have the needed knowledges on the internal structure of NTW at that time.
4 more years of (intermittent, though) reverse engineering changed the situation.
My only point of concern is MP. Our odds that it will work are 3 out of 4, at worst.
Unluckily I've to talk about odds and not certainty because it's impossible to perform any debugging under Steam (there're way too many protection tricks and if I forgot one, I risk ban).
I know how to inject my DLL on that context too, of course, but I cannot check it works (except logging and tracing).
Thus I'm testing on an unsteamead version at the moment. Which I'm not ever going to relase for obvious reasons.
If the BCQs (the command queue used to notify messages from the UI thread to the Battle Model updating thread, where the logics resides) is properly serialized across the network as I expect, there shouldn't be any problem (UI -> Network -> Battle Model).
Yet, your prayers are welcome.
Un abrazo.
Last edited by risorgimento59 on Thu Jul 23, 2015 10:56 am, edited 1 time in total.

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Thu Jul 23, 2015 10:04 am

Little code snippet and comments showing the hook to BCQ_MULTIPLE_SELECTION_CHANGE_SPECIAL_ABILITY, its "barrier" and interaction with the HFSM I've drawn above. :wink:

Code: Select all

void __cdecl CBattleManager::Hook_Battle_BCQCallback_MultipleSelectionOrder_ChangeSpecialAbility(NTWLib::CQ::SMessage *pMsg, void *pParam)
{
   NTWLib::Battle::CMultipleSelection MultipleSelection;
   NTWLib::Battle::CMultipleSelection::Proxy_FromCQMessage(&MultipleSelection, pMsg); // CtorFromCQMessage^
   
   if (pMsg->Unk04 == 0)
   {
      int type = -1;
      NTWLib::CQ::SMessage::Proxy_PopArg(pMsg, &type, 4, 7);
      
      bool bRally = false;
      NTWLib::CQ::SMessage::Proxy_PopArg(pMsg, &bRally, 1, 1);
      
      int state = -1;
      NTWLib::CQ::SMessage::Proxy_PopArg(pMsg, &state, 4, 7);
      
      if (pMsg->Unk04 == 0)
      {
         switch (type)
         {
         case NTWLib::Battle::UNIT_SPECIAL_ABILITY_PIKE_SQUARE_FORMATION:
         case NTWLib::Battle::UNIT_SPECIAL_ABILITY_SQUARE_FORMATION:
         case NTWLib::Battle::UNIT_SPECIAL_ABILITY_WEDGE_FORMATION:
         case NTWLib::Battle::UNIT_SPECIAL_ABILITY_DIAMOND_FORMATION:
         case NTWLib::Battle::UNIT_SPECIAL_ABILITY_LIGHT_INFANTRY_BEHAVIOUR:
         case NTWLib::Battle::UNIT_SPECIAL_ABILITY_PIKE_WALL_FORMATION:
            {
               NTWPlus::Battle::CBattleManager *pBattleManager = UtilityLib::CSingleton<NTWPlus::App::CNTWPlusApp>::Instance().GetBattleManager();
               
               std::for_each(MultipleSelection.LandUnitGroups.pData, MultipleSelection.LandUnitGroups.pData + MultipleSelection.LandUnitGroups.Size,
                  [pBattleManager, type, state](NTWLib::Battle::CLandUnitGroup *pUnitGroup) -> void
                  {
                     std::for_each(pUnitGroup->Units.pData, pUnitGroup->Units.pData + pUnitGroup->Units.Size,
                        [pBattleManager, type, state](NTWLib::Battle::CLandUnit *pUnit) -> void
                        {
                           pBattleManager->NotifyUnitSpecialAbilityOrder(pUnit, type, state);
                        }
                     );
                  }
               );
               
               std::for_each(MultipleSelection.LandUnits.pData, MultipleSelection.LandUnits.pData + MultipleSelection.LandUnits.Size,
                  [pBattleManager, type, state](NTWLib::Battle::CLandUnit *pUnit) -> void
                  {
                     pBattleManager->NotifyUnitSpecialAbilityOrder(pUnit, type, state);
                  }
               );
               
               break;
            }
         default: // original code
            {
               NTWLib::Battle::SBattleModel *pBattleModel = static_cast<NTWLib::Battle::SBattleModel *>(pParam);
               
               NTWLib::Battle::CLandUnit::Proxy_ChangeUnitSpecialAbilityFromMultipleSelection(type, bRally, state, &MultipleSelection);
               
               NTWLib::Battle::CUnitSpecialAbilityItem::Proxy_Update(&pBattleModel->pUnitSpecialAbilityMgr->Cache[89], type);
               
               break;
            }
         }
      }
   }
   
   NTWLib::Battle::CMultipleSelection::Proxy_Dtor(&MultipleSelection);
}

class NTWPlus::Battle::CUnitFormationFormingState
{
   Update
   {
      // don't go back to top-most hierarchy FSM (UNDEFINED, UNIT FORMATION, SPECIAL ABILITY) until all timeouts expire (pHFSM->m_SpecialAbilityOrders)
      // remove from m_SpecialAbilityOrders the expired ones
      
      // otherwise we can exit only if unit become routed meanwhile (jump to ROUTED state or, in alternative, to UNDEFINED and then let it jump to ROUTED on its own?)
   }
   
   OnEnter; // apply modifiers from now on
   OnExit; // stop applying modifiers from now on
};

class NTWPlus::Battle::CUnitFormationHFSM
{
   // These are set by active states
   float m_MovementModifier;
   float m_Fatigue???;
   float m_MoraleChange;
   
   struct SSpecialAbilityOrder
   {
      int Type;
      int State;
      unsigned long Completion/*(Battle)*/Time;
   };

   std::vector<CUnitFormationHFSM::SSpecialAbilityOrder> m_SpecialAbilityOrders;
};

void CBattleManager::NotifyUnitSpecialAbilityOrder(NTWLib::Battle::CLandUnit *pUnit, int type, int state)
{
   // m_UnitFormationHFSMCache[pUnit->Id];
   
   // add one SSpecialAbilityOrder to the HFSM
   // CompletionTime = CurrentBattleTime + Duration
   // Duration is choosen from any of these matrices: und->uf, und->sa, uf->uf, uf->sa, sa->uf (xxx->und is instantaneous, right?)
   // In this case it can be picked from und->sa or uf->sa if state==ENABLE, sa->uf or sa->und (instantaneous) if state==DISABLE
}

// hook to speed:
{
   *= m_UnitFormationHFSMCache[pUnit->Id].m_SpeedModifier;
   // apply...
}

// hook to fatigue:
{
   ?= m_UnitFormationHFSMCache[pUnit->Id].m_Fatigue???;
   // apply...
}

// hook to morale:
{
   += m_UnitFormationHFSMCache[pUnit->Id].m_MoraleChange;
   // apply...
}

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Thu Jul 23, 2015 4:13 pm

:eek: :eek: :eek: :eek:

Image
Image
Image
Image
Image
Image

Image
Image

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Fri Jul 24, 2015 9:51 am

Still a lot of work to do.
But at least I started coding the HFSM yesterday... :wink:

Code: Select all

//--------------------------------------------------------------------------------------
// File: NTWPlus\Battle\BattleUnitFormationFSM.h
//
// Copyright (c) Risorgimento59. All rights reserved.
//--------------------------------------------------------------------------------------

#ifndef __NTWPLUS_BATTLE_UNIT_FORMATION_FSM_H__
#define __NTWPLUS_BATTLE_UNIT_FORMATION_FSM_H__

namespace NTWPlus {

namespace Battle {

//--------------------------------------------------------------------------------------
// Enumeration: NTWPlus::Battle::UNIT_FORMATION_ORDER_XXX
//--------------------------------------------------------------------------------------
enum
{
//   UNIT_FORMATION_ORDER_NONE = -1,
   UNIT_FORMATION_ORDER_UNDEFINED = 0,
   UNIT_FORMATION_ORDER_SPECIAL_ABILITY = 1,
   UNIT_FORMATION_ORDER_FORMED = 2
};

//--------------------------------------------------------------------------------------
// Structure: NTWPlus::Battle::SUnitFormationFSMContext
//--------------------------------------------------------------------------------------
struct SUnitFormationFSMContext
{
   // Binding
   NTWLib::Battle::SBattleManager *pBattleMgr;
   NTWLib::Battle::CLandUnit *pUnit;

   // Tables
   const float **ppTimeoutTable; // [type] [ row * w + col ]

   // State
   int OrderType; // init to UNDEFINED or NONE?
   int OrderId;
   int OrderState;
   float OrderCompletionTime;
   int LastOrderType;
   int LastOrderId;
   bool bReform;
//   int LastEnabledSpecialAbilityType;
//   int LastFormationId;
};



//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::IUnitFormationState
//--------------------------------------------------------------------------------------
class IUnitFormationState : public UtilityLib::HFSM::IState
{
public:
   IUnitFormationState(NTWPlus::Battle::SUnitFormationFSMContext *);
   virtual ~IUnitFormationState(void) {}

public:
   virtual void ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *) = 0;

protected:
   NTWPlus::Battle::SUnitFormationFSMContext *m_pContext;
};

//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::IUnitFormationTransition
//--------------------------------------------------------------------------------------
class IUnitFormationTransition : public UtilityLib::HFSM::ITransition
{
public:
   IUnitFormationTransition(NTWPlus::Battle::SUnitFormationFSMContext *);
   virtual ~IUnitFormationTransition(void) {}

protected:
   NTWPlus::Battle::SUnitFormationFSMContext *m_pContext;
};


//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationUndefinedState
//--------------------------------------------------------------------------------------
class CUnitFormationUndefinedState : public NTWPlus::Battle::IUnitFormationState
{
public:
   CUnitFormationUndefinedState(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::IState */
   void Enter(void);
   void Exit(void);
//   void Update(void);

public: /* NTWPlus::Battle::IUnitFormationState */
   void ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *);

private:
   // ...
   NTWPlus::Battle::SDBUnitFormationUndefinedStateTable &m_DBTable;

   float m_MovementModifier;
};

//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationSpecialAbilityState
//--------------------------------------------------------------------------------------
class CUnitFormationSpecialAbilityState : public NTWPlus::Battle::IUnitFormationState
{
public:
   CUnitFormationSpecialAbilityState(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::IState */
   void Enter(void);
   void Exit(void);
//   void Update(void);

public: /* NTWPlus::Battle::IUnitFormationState */
   void ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *);

private:
   // ...
   NTWPlus::Battle::SDBUnitFormationSpecialAbilityStateTable &m_DBTable;

   float m_MovementModifier;
};

//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationFormedState
//--------------------------------------------------------------------------------------
class CUnitFormationFormedState : public NTWPlus::Battle::IUnitFormationState
{
public:
   CUnitFormationFormedState(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::IState */
   void Enter(void);
   void Exit(void);
//   void Update(void);

public: /* NTWPlus::Battle::IUnitFormationState */
   void ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *);

private:
   // ...
   NTWPlus::Battle::SDBUnitFormationFormedStateTable &m_DBTable;
   
   float m_MovementModifier;
};











//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationRoutedStateInTransition
//--------------------------------------------------------------------------------------
class CUnitFormationRoutedStateInTransition : public NTWPlus::Battle::IUnitFormationTransition // TODO
{
public:
   CUnitFormationRoutedStateInTransition(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::ITransition */
   int GetLevel(void) const;
   bool bIsValid(void) const; // unit routing state == BROKEN or == ROUTED
   UtilityLib::HFSM::IState *GetTargetState(void) const; // return rootHFSM->m_pRouted
   void Transition(void);
};

//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationRoutedStateOutTransition
//--------------------------------------------------------------------------------------
class CUnitFormationRoutedStateOutTransition : public NTWPlus::Battle::IUnitFormationTransition // TODO
{
public:
   CUnitFormationRoutedStateOutTransition(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::ITransition */
   int GetLevel(void) const;
   bool bIsValid(void) const; // unit routing state != BROKEN and != ROUTED
   UtilityLib::HFSM::IState *GetTargetState(void) const; // return rootHFSM->m_pCore
   void Transition(void);
};

//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationRoutedState
//--------------------------------------------------------------------------------------
class CUnitFormationRoutedState : public NTWPlus::Battle::IUnitFormationState
{
public:
   CUnitFormationRoutedState(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::IState */
   void Enter(void);
   void Exit(void);
//   void Update(void);

public: /* NTWPlus::Battle::IUnitFormationState */
   void ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *);

private:
   // Transitions
   NTWPlus::Battle::CUnitFormationRoutedStateOutTransition m_Transition;

   // ...
   NTWPlus::Battle::SDBUnitFormationRoutedStateTable &m_DBTable;

   float m_MovementModifier;
};







//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationFormingStateInTransition
//--------------------------------------------------------------------------------------
class CUnitFormationFormingStateInTransition : public NTWPlus::Battle::IUnitFormationTransition // TODO
{
public:
   CUnitFormationFormingStateInTransition(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::ITransition */
   int GetLevel(void) const;
   bool bIsValid(void) const; // m_pContext->bReform == true
   UtilityLib::HFSM::IState *GetTargetState(void) const; // return rootHFSM->m_pForming
   void Transition(void);
};

//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationFormingStateOutTransition
//--------------------------------------------------------------------------------------
class CUnitFormationFormingStateOutTransition : public NTWPlus::Battle::IUnitFormationTransition // TODO
{
public:
   CUnitFormationFormingStateOutTransition(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::ITransition */
   int GetLevel(void) const;
   bool bIsValid(void) const; // m_pContext->bReform == false
   UtilityLib::HFSM::IState *GetTargetState(void) const; // return rootHFSM->m_pCore
   void Transition(void);
};

//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationFormingState
//--------------------------------------------------------------------------------------
class CUnitFormationFormingState : public NTWPlus::Battle::IUnitFormationState
{
public:
   CUnitFormationFormingState(NTWPlus::Battle::SUnitFormationFSMContext *);

public: /* UtilityLib::HFSM::IState */
   void Enter(void);
   void Exit(void);
   void Update(void);

public: /* NTWPlus::Battle::IUnitFormationState */
   void ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *);

private:
   // Transitions
   NTWPlus::Battle::CUnitFormationFormingStateOutTransition m_Transition;

   // ...
   NTWPlus::Battle::SDBUnitFormationRoutedStateTable &m_DBTable;

   float m_Timeout;
   float m_MovementModifier;
};








//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationCoreHFSM
//--------------------------------------------------------------------------------------
class CUnitFormationCoreHFSM : public UtilityLib::HFSM::IHFSM
{
public:
   // UtilityLib::HFSM::IHFSM::AddState(&m_Undefined); ...
   // UtilityLib::HFSM::IState::AddTransition(&m_RoutedTransition); ...
   CUnitFormationCoreHFSM(NTWPlus::Battle::SUnitFormationFSMContext *);

   /*void Update(void);

   std::forward_list<UtilityLib::HFSM::IState *>::const_iterator GetStateBegIt(void) const;
   std::forward_list<UtilityLib::HFSM::IState *>::const_iterator GetStateEndIt(void) const;
   UtilityLib::HFSM::IState *GetInitialState(void) const;
   UtilityLib::HFSM::IState *GetActiveState(void) const;*/

private:
   NTWPlus::Battle::SUnitFormationFSMContext *m_pContext;

   // States
   NTWPlus::Battle::CUnitFormationUndefinedState m_Undefined;
   NTWPlus::Battle::CUnitFormationSpecialAbilityState m_SpecialAbility;
   NTWPlus::Battle::CUnitFormationFormedState m_Formed;
   
   // Transitions
   NTWPlus::Battle::CUnitFormationRoutedStateInTransition m_RoutedTransition;
   NTWPlus::Battle::CUnitFormationFormingStateInTransition m_FormingTransition;
};







//--------------------------------------------------------------------------------------
// Class: NTWPlus::Battle::CUnitFormationRootHFSM
//--------------------------------------------------------------------------------------
class CUnitFormationRootHFSM : public UtilityLib::HFSM::IHFSM
{
public:
   CUnitFormationRootHFSM(void);

   // UtilityLib::HFSM::IHFSM::AddState(m_pCore); ...
   void Init(NTWLib::Battle::CLandUnit *, const float *[]); // init m_Context and create child states

   // Called from the hooks of NTWPlus::Battle::CBattleManager
   void NotifyUndefined(void);
   void NotifySpecialAbility(int, int);
   void NotifyFormation(int);

//   void Update(void);

   /*std::forward_list<UtilityLib::HFSM::IState *>::const_iterator GetStateBegIt(void) const;
   std::forward_list<UtilityLib::HFSM::IState *>::const_iterator GetStateEndIt(void) const;
   UtilityLib::HFSM::IState *GetInitialState(void) const;
   UtilityLib::HFSM::IState *GetActiveState(void) const;*/

//   UtilityLib::HFSM::IState *GetActiveState(void) const; // CORE.UNDEFINED, CORE.SPECIAL_ABILITY, CORE.FORMED or ROUTED, FORMING

private:
   NTWPlus::Battle::SUnitFormationFSMContext m_Context;

   // States
   NTWPlus::Battle::CUnitFormationCoreHFSM *m_pCore;
   NTWPlus::Battle::CUnitFormationRoutedState *m_pRouted;
   NTWPlus::Battle::CUnitFormationFormingState *m_pForming;
};

} /* namespace Battle */

} /* namespace NTWPlus */

#endif /* __NTWPLUS_BATTLE_UNIT_FORMATION_FSM_H__ */


Code: Select all

//--------------------------------------------------------------------------------------
// File: NTWPlus\Battle\BattleUnitFormationFSM.cpp
//
// Copyright (c) Risorgimento59. All rights reserved.
//--------------------------------------------------------------------------------------

/* Precompiled headers. */
#include "NTWPlus\NTWPlus_PCH.h"
/* NTWPlus headers. */
#include "NTWPlus\Battle\BattleUnitFormationFSM.h"
/* Application headers. */
#include "NTWPlus\Application\NTWPlusApp.h"

namespace NTWPlus {

namespace Battle {

//--------------------------------------------------------------------------------------
IUnitFormationState::IUnitFormationState(NTWPlus::Battle::SUnitFormationFSMContext *pContext)
   : m_pContext(pContext)
{
}



//--------------------------------------------------------------------------------------
CUnitFormationUndefinedState::CUnitFormationUndefinedState(NTWPlus::Battle::SUnitFormationFSMContext *pContext)
   : IUnitFormationState(pContext)
   , m_DBTable(UtilityLib::CSingleton<NTWPlus::App::CNTWPlusApp>::Instance().GetBattleManager()->GetDBUnitFormationUndefinedStateTable())
   , m_MovementModifier(1.f)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationUndefinedState::Enter(void)
{
   NTWLib::Battle::CLandUnit *pUnit = IUnitFormationState::m_pContext->pUnit;

   // ...
   m_MovementModifier = 1.f;

   switch (pUnit->pDBLandUnitRecord->Category)
   {
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_CAVALRY:
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_INFANTRY:
      {
         if (NTWLib::Battle::CLandUnit::IsCavalryAndChevauxDeFriseNotEnabled(pUnit))
         {
            if (NTWLib::Battle::CLandUnit::IsCavalryAndIsMounted(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierMountedCavalry;
            }
         }
         else
         {
            if (NTWLib::Battle::CLandUnit::IsAtFoot(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierFoot;
            }
         }

         break;
      }
   default:
      {
         break;
      }
   }
}

//--------------------------------------------------------------------------------------
void CUnitFormationUndefinedState::Exit(void)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationUndefinedState::ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *pLocomotionState)
{
   pLocomotionState->MovementModifier *= m_MovementModifier;
}



//--------------------------------------------------------------------------------------
CUnitFormationSpecialAbilityState::CUnitFormationSpecialAbilityState(NTWPlus::Battle::SUnitFormationFSMContext *pContext)
   : IUnitFormationState(pContext)
   , m_DBTable(UtilityLib::CSingleton<NTWPlus::App::CNTWPlusApp>::Instance().GetBattleManager()->GetDBUnitFormationSpecialAbilityStateTable())
   , m_MovementModifier(1.f)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationSpecialAbilityState::Enter(void)
{
   NTWLib::Battle::CLandUnit *pUnit = IUnitFormationState::m_pContext->pUnit;

   // ...
   NTWLib::Battle::CLandUnit::Proxy_ChangeUnitSpecialAbility(pUnit, IUnitFormationState::m_pContext->OrderId, false, IUnitFormationState::m_pContext->OrderState);
               
   NTWLib::Battle::CUnitSpecialAbilityItem::Proxy_Update(&pUnit->pBattleEnv->pBattleModel->pUnitSpecialAbilityMgr->Cache[89], IUnitFormationState::m_pContext->OrderId);

   // ...
   m_MovementModifier = 1.f;

   switch (pUnit->pDBLandUnitRecord->Category)
   {
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_CAVALRY:
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_INFANTRY:
      {
         if (NTWLib::Battle::CLandUnit::IsCavalryAndChevauxDeFriseNotEnabled(pUnit))
         {
            if (NTWLib::Battle::CLandUnit::IsCavalryAndIsMounted(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierMountedCavalry[m_pContext->OrderId];
            }
         }
         else
         {
            if (NTWLib::Battle::CLandUnit::IsAtFoot(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierFoot[m_pContext->OrderId];
            }
         }

         break;
      }
   default:
      {
         break;
      }
   }
}

//--------------------------------------------------------------------------------------
void CUnitFormationSpecialAbilityState::Exit(void)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationSpecialAbilityState::ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *pLocomotionState)
{
   pLocomotionState->MovementModifier *= m_MovementModifier;
}



//--------------------------------------------------------------------------------------
CUnitFormationFormedState::CUnitFormationFormedState(NTWPlus::Battle::SUnitFormationFSMContext *pContext)
   : IUnitFormationState(pContext)
   , m_DBTable(UtilityLib::CSingleton<NTWPlus::App::CNTWPlusApp>::Instance().GetBattleManager()->GetDBUnitFormationFormedStateTable())
   , m_MovementModifier(1.f)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationFormedState::Enter(void)
{
   NTWLib::Battle::CLandUnit *pUnit = IUnitFormationState::m_pContext->pUnit;

   // ...
   const float unitScaleFactor = *static_cast<const float *>(
      NTWLib::Game::CGame1A4::Proxy_GetGFXPreference(
      pUnit->pBattleEnv->pWSApp->pGame1A4,
      NTWLib::Game::GAME1A4_PREFERENCE_GFX_UNITSCALEFACTOR));
   
   const float *pUnitScaleFactorTable = NTWLib::Game::Proxy_GetUnitScaleFactorTable();
   unsigned int UnitScaleIndex = 0U;
   while (UnitScaleIndex != 4U) {
      if (unitScaleFactor <= pUnitScaleFactorTable[UnitScaleIndex])
         break;
      ++UnitScaleIndex;
   }

   // ...
   /*void *pUnitUnkADC = pUnit->pUnkADC;
   
   if (pUnit->UnkAE8 != 0)
   {
      pUnitUnkADC = pUnit->pUnkADC[pUnit->UnkAE8];
      NTWLib::Battle::CLandUnitUnkADC::Proxy_UnkVTable10(pUnitUnkADC, 0, widthChange);
   }*/

   bool bUpdateUnitKinematicState = false;
   float unitWidth = pUnit->KinematicState.Width;

   NTWPlus::Battle::SDBUnitFormationInfo &DBFormationInfo = m_DBTable.FormationInfo[m_pContext->OrderId];

   switch (DBFormationInfo.FixedAxisType)
   {
   case NTWPlus::Battle::SDBUnitFormationInfo::AXIS_TYPE_FILES:
      {
         unitWidth = NTWLib::Battle::CLandUnitUnkADCUnk628::Proxy_SlotsToWidth(
            pUnit->pUnkADC->pUnk628,
            DBFormationInfo.AxisData.NumFiles[UnitScaleIndex],
            pUnit->Soldiers.Size);

         bUpdateUnitKinematicState = true;

         break;
      }
   case NTWPlus::Battle::SDBUnitFormationInfo::AXIS_TYPE_RANKS:
      {
         unsigned int numUnitFiles = pUnit->Soldiers.Size / DBFormationInfo.AxisData.NumRanks[UnitScaleIndex]; // ???

         unitWidth = NTWLib::Battle::CLandUnitUnkADCUnk628::Proxy_SlotsToWidth(
            pUnit->pUnkADC->pUnk628,
            numUnitFiles,
            pUnit->Soldiers.Size);

         bUpdateUnitKinematicState = true;

         break;
      }
   default:
      {
         break;
      }
   }

   if (bUpdateUnitKinematicState)
   {
      NTWLib::Battle::CLandUnit::Proxy_UpdateKinematicState(
         pUnit,
         pUnit->KinematicState.Position,
         pUnit->KinematicState.Orientation,
         unitWidth,
         pUnit->pUnkADC->pUnk628,
         true,
         true,
         false); // TODO
   }
   
   // ...
   m_MovementModifier = 1.f;

   switch (pUnit->pDBLandUnitRecord->Category)
   {
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_CAVALRY:
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_INFANTRY:
      {
         if (NTWLib::Battle::CLandUnit::IsCavalryAndChevauxDeFriseNotEnabled(pUnit))
         {
            if (NTWLib::Battle::CLandUnit::IsCavalryAndIsMounted(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierMountedCavalry[m_pContext->OrderId];
            }
         }
         else
         {
            if (NTWLib::Battle::CLandUnit::IsAtFoot(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierFoot[m_pContext->OrderId];
            }
         }

         break;
      }
   default:
      {
         break;
      }
   }
}

//--------------------------------------------------------------------------------------
void CUnitFormationFormedState::Exit(void)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationFormedState::ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *pLocomotionState)
{
   pLocomotionState->MovementModifier *= m_MovementModifier;
}













//--------------------------------------------------------------------------------------
CUnitFormationRoutedState::CUnitFormationRoutedState(NTWPlus::Battle::SUnitFormationFSMContext *pContext)
   : IUnitFormationState(pContext)
   , m_Transition(pContext)
   , m_DBTable(UtilityLib::CSingleton<NTWPlus::App::CNTWPlusApp>::Instance().GetBattleManager()->GetDBUnitFormationRoutedStateTable())
   , m_MovementModifier(1.f)
{
   UtilityLib::HFSM::IState::AddTransition(&m_Transition);
}

//--------------------------------------------------------------------------------------
void CUnitFormationRoutedState::Enter(void)
{
   NTWLib::Battle::CLandUnit *pUnit = IUnitFormationState::m_pContext->pUnit;
   
   // ...
   m_MovementModifier = 1.f;

   switch (pUnit->pDBLandUnitRecord->Category)
   {
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_CAVALRY:
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_INFANTRY:
      {
         if (NTWLib::Battle::CLandUnit::IsCavalryAndChevauxDeFriseNotEnabled(pUnit))
         {
            if (NTWLib::Battle::CLandUnit::IsCavalryAndIsMounted(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierMountedCavalry;
            }
         }
         else
         {
            if (NTWLib::Battle::CLandUnit::IsAtFoot(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierFoot;
            }
         }

         break;
      }
   default:
      {
         break;
      }
   }
}

//--------------------------------------------------------------------------------------
void CUnitFormationRoutedState::Exit(void)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationRoutedState::ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *pLocomotionState)
{
   pLocomotionState->MovementModifier *= m_MovementModifier;
}














//--------------------------------------------------------------------------------------
CUnitFormationFormingState::CUnitFormationFormingState(NTWPlus::Battle::SUnitFormationFSMContext *pContext)
   : IUnitFormationState(pContext)
   , m_Transition(pContext)
   , m_DBTable(UtilityLib::CSingleton<NTWPlus::App::CNTWPlusApp>::Instance().GetBattleManager()->GetDBUnitFormationFormingStateTable())
   , m_Timeout(0.f)
   , m_MovementModifier(1.f)
{
   UtilityLib::HFSM::IState::AddTransition(&m_Transition);
}

//--------------------------------------------------------------------------------------
void CUnitFormationFormingState::Enter(void)
{
   NTWLib::Battle::CLandUnit *pUnit = IUnitFormationState::m_pContext->pUnit;
   NTWLib::Battle::SBattleManager *pBattleMgr = IUnitFormationState::m_pContext->pBattleMgr;
   
   // Set timeout
   m_Timeout = pBattleMgr->ElapsedBattleTime;

   const int battlePhase = IUnitFormationState::m_pContext->pBattleMgr->BattlePhase;

   bool bIsConflictPhase =
      battlePhase != NTWLib::Battle::BATTLE_PHASE_DEPLOYMENT ||
      battlePhase == NTWLib::Battle::BATTLE_PHASE_CONFLICT_0 ||
      battlePhase == NTWLib::Battle::BATTLE_PHASE_CONFLICT_2 ||
      battlePhase == NTWLib::Battle::BATTLE_PHASE_CONFLICT_3 ||
      battlePhase == NTWLib::Battle::BATTLE_PHASE_CONFLICT_4 ||
      battlePhase == NTWLib::Battle::BATTLE_PHASE_CONFLICT_5;
   
   if (bIsConflictPhase)
   {
      static const int s_OrderComboToTimeout[3][3] =
      {
         { -1, NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_UNDEFINED_TO_SPECIAL_ABILITY, NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_UNDEFINED_TO_FORMED },
         { NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_SPECIAL_ABILITY_TO_UNDEFINED, -1, NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_SPECIAL_ABILITY_TO_FORMED },
         { NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_FORMED_TO_UNDEFINED, NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_FORMED_TO_SPECIAL_ABILITY, NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_FORMED_TO_FORMED }
      };
   
      const int timeoutTableType = s_OrderComboToTimeout[IUnitFormationState::m_pContext->LastOrderType][IUnitFormationState::m_pContext->OrderType];

      if (timeoutTableType != -1)
      {
         unsigned long timeoutTableOffset = 0UL;

         switch (timeoutTableType)
         {
         case NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_UNDEFINED_TO_SPECIAL_ABILITY:
            {
               timeoutTableOffset = IUnitFormationState::m_pContext->OrderId;
               break;
            }
         case NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_UNDEFINED_TO_FORMED:
            {
               timeoutTableOffset = IUnitFormationState::m_pContext->OrderId;
               break;
            }
         case NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_SPECIAL_ABILITY_TO_UNDEFINED:
            {
               timeoutTableOffset = IUnitFormationState::m_pContext->LastOrderId;
               break;
            }
         case NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_SPECIAL_ABILITY_TO_FORMED:
            {
               timeoutTableOffset = IUnitFormationState::m_pContext->LastOrderId * NTWPlus::Battle::MAX_UNIT_FORMATION_ID + IUnitFormationState::m_pContext->OrderId;
               break;
            }
         case NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_FORMED_TO_UNDEFINED:
            {
               timeoutTableOffset = IUnitFormationState::m_pContext->LastOrderId;
               break;
            }
         case NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_FORMED_TO_SPECIAL_ABILITY:
            {
               timeoutTableOffset = IUnitFormationState::m_pContext->LastOrderId * NTWLib::Battle::NUM_LAND_UNIT_SPECIAL_ABILITY_TYPES + IUnitFormationState::m_pContext->OrderId;

               break;
            }
         case NTWPlus::Battle::UNIT_FORMATION_TIMEOUT_FORMED_TO_FORMED:
            {
               timeoutTableOffset = IUnitFormationState::m_pContext->LastOrderId * NTWPlus::Battle::MAX_UNIT_FORMATION_ID + IUnitFormationState::m_pContext->OrderId;

               break;
            }
         default:
            {
               break;
            }
         }
   
         m_Timeout += IUnitFormationState::m_pContext->ppTimeoutTable[timeoutTableType][timeoutTableOffset];
      }
   }

   // Set modifiers
   m_MovementModifier = 1.f;

   switch (pUnit->pDBLandUnitRecord->Category)
   {
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_CAVALRY:
   case NTWLib::DB::SDBLandUnitRecord::CATEGORY_INFANTRY:
      {
         if (NTWLib::Battle::CLandUnit::IsCavalryAndChevauxDeFriseNotEnabled(pUnit))
         {
            if (NTWLib::Battle::CLandUnit::IsCavalryAndIsMounted(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierMountedCavalry;
            }
         }
         else
         {
            if (NTWLib::Battle::CLandUnit::IsAtFoot(pUnit))
            {
               m_MovementModifier = m_DBTable.MovementModifierFoot;
            }
         }

         break;
      }
   default:
      {
         break;
      }
   }
}

//--------------------------------------------------------------------------------------
void CUnitFormationFormingState::Exit(void)
{
}

//--------------------------------------------------------------------------------------
void CUnitFormationFormingState::Update(void)
{
//   NTWLib::Battle::CLandUnit *pUnit = IUnitFormationState::m_pContext->pUnit;
//   NTWLib::Battle::SBattleManager *pBattleMgr = IUnitFormationState::m_pContext->pBattleMgr;

   if (IUnitFormationState::m_pContext->OrderCompletionTime <= IUnitFormationState::m_pContext->pBattleMgr->ElapsedBattleTime)
   {
      IUnitFormationState::m_pContext->bReform = false;
   }
}

//--------------------------------------------------------------------------------------
void CUnitFormationFormingState::ApplyMovementModifier(NTWLib::Battle::ILandUnitLocomotionState *pLocomotionState)
{
   pLocomotionState->MovementModifier *= m_MovementModifier;
}

} /* namespace Battle */

} /* namespace NTWPlus */

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Sun Jul 26, 2015 9:17 am

Anybody remembering a non-campaign battlefield with field walls, please?
I need that to understand how to reject my BCQ_UNIT_ORDER_FORMATION_CHANGE in the case one unit is deployed behind them (but also fort wall, engine pickup, building, etc.).
Thanks.

Much has been done. What is left:
- Find a better hook point for HFSM::Update and UpdateAvailableUnitFormations(pUnit);
- BCQ detours to call HFSM::NotifyUndefined (everything involving a manual width change basically, plus building/walls/etc.);
- Add to the unit's tooltip of UI some kind of information bit about the HFSM state and, if in forming state, the timeout to completion.
- Read the formations/timeouts/modifiers DB from XML within the NTW filesystem;
- Add more modifiers patching (only speed atm, but fatigue and morale should be fairly easy... I've spotted also accuracy/range/reload routines, you never know);
- Finally add all the addresses for the Steamed version;
- A lot of testing.

:wink:

User avatar
turcoman
Villein
Villein
Posts: 46
Joined: Fri Jul 30, 2010 4:25 pm
Location: Istanbul

Re: Unit formations

Postby turcoman » Sun Jul 26, 2015 12:51 pm

FireTight wrote:
turcoman wrote:If somebody can implement timer on square button and save us from this damn quicksquare after almost 5 years, I will be his humble servant, like Rustem for Napoleon !

Fun fact: squares in vanilla work much better than in NTW3.

Proof:
[youtube]http://www.youtube.com/watch?v=YERC8vJnl2A[/youtube]


Yes but its very very rare occassion i met in such realistic way, usually 1/4 formed square crush charging cav.


Yoyo, yes, sorry, i had to delete the game, to prepare for couple of business interviews and as you know NTW3 is an addiction which sucks all of our times.
Soldats! Faites votre devoir! Droit au cœur mais épargnez le visage. Feu!

User avatar
Lord Uxbridge
Lord
Lord
Posts: 895
Joined: Fri Jun 10, 2011 10:09 pm
Location: London, England

Re: Unit formations

Postby Lord Uxbridge » Mon Jul 27, 2015 12:43 pm

Risorgimiento59, I am astounded already at what you have achieved and even though I'm not a religious man at all, I will, like the others, be on my knees in prayer for success in this endeavour.

User avatar
Lord Fullin
Lord
Lord
Posts: 3793
Joined: Tue Apr 20, 2010 11:07 am
Location: Argentina

Re: Unit formations

Postby Lord Fullin » Mon Jul 27, 2015 2:42 pm

risorgimento59 wrote:Anybody remembering a non-campaign battlefield with field walls, please?



If Iam correct Field Walls were only available in Empire.

As you may know this game has a lot of outdated and uncompleated stuff in it.
Sauve qui peut!' 'Nous sommes trahis!'

User avatar
risorgimento59
Villein
Villein
Posts: 23
Joined: Sat Feb 12, 2011 5:51 pm

Re: Unit formations

Postby risorgimento59 » Mon Jul 27, 2015 7:07 pm

Sorry for the poor video quality.
Had no time this night for a good recompression.
Maybe tomorrow. :wink:

https://youtu.be/x51kYSDt1xA

https://youtu.be/4NSs-SQcJLQ

User avatar
stilgar
Beta Tester
Beta Tester
Posts: 952
Joined: Wed Feb 23, 2011 2:29 pm
Location: 2000km from Borodino

Re: Unit formations

Postby stilgar » Mon Jul 27, 2015 8:04 pm

Hmm, that looked like a decent pause before square was formed. Pls keep up the good work and show us some more of those little miracles, preferably in HD :smile:
"Постой-ка, брат мусью ..."

User avatar
Lord Fullin
Lord
Lord
Posts: 3793
Joined: Tue Apr 20, 2010 11:07 am
Location: Argentina

Re: Unit formations

Postby Lord Fullin » Mon Jul 27, 2015 8:37 pm

Even in HD is gonna look blurry throu my crying eyes....
Sauve qui peut!' 'Nous sommes trahis!'

User avatar
Sloop
Beta Tester
Beta Tester
Posts: 401
Joined: Sun Apr 18, 2010 8:55 pm
Contact:

Re: Unit formations

Postby Sloop » Tue Jul 28, 2015 1:19 am

What's an old exploiter going to do? Hmm... was that 12 or 13 seconds?

New tactic; must keep some close units in square so unsquared infantry can run to them.
Larger units will gain some advantages as they can form a block column and fair better out of square.
Cavalry will be extremely effective.
It will be a huge cat and mouse game.

Of course if this new feature is added then the Lordz will have many more other changes as well, so no use theorizing about it now.

User avatar
Chromey
Baronet
Baronet
Posts: 640
Joined: Tue Nov 15, 2011 5:21 pm
Location: Florida Americas Wang

Re: Unit formations

Postby Chromey » Tue Jul 28, 2015 1:36 am

Heresy!
Death to Tyranny

User avatar
[N]Clinch
Knight
Knight
Posts: 458
Joined: Sun Apr 25, 2010 12:45 am

Re: Unit formations

Postby [N]Clinch » Tue Jul 28, 2015 2:16 am

@Sloop- yeah cav will have to be reworked but to have realistic square leads us to a more realistic game. Looks good. Keep up the good work.


Return to “NTW3 General Discussions”

Who is online

Users browsing this forum: No registered users and 6 guests