Planeshift

buffable.h

Go to the documentation of this file.
00001 /*
00002  * buffable.h by Kenneth Graunke <[email protected]>
00003  *
00004  * Copyright (C) 2008 Atomic Blue ([email protected], http://www.atomicblue.org)
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation (version 2 of the License)
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00016  *
00017  */
00018 
00019 #ifndef BUFFABLE_HEADER
00020 #define BUFFABLE_HEADER
00021 
00022 //=============================================================================
00023 // Crystal Space Includes
00024 //=============================================================================
00025 #include <cstypes.h>
00026 #include <csutil/list.h>
00027 #include <csutil/tuple.h>
00028 
00029 class ActiveSpell;
00030 
00037 class iSpellModifier
00038 {
00039 public:
00040     virtual ~iSpellModifier() { }
00041     virtual void Cancel(const ActiveSpell* owner) = 0;
00042 };
00043 
00044 //-----------------------------------------------------------------------------
00045 
00069 template <typename T>
00070 class Overridable : public iSpellModifier
00071 {
00072 public:
00073 
00074     Overridable(T x)
00075     {
00076         values.PushBack(csTuple2<const ActiveSpell*,T>(NULL, x));
00077     }
00078 
00079     virtual ~Overridable() { }
00080 
00081     T Current() const
00082     {
00083         return values.Front().second;
00084     }
00085 
00086     T Base() const
00087     {
00088         CS_ASSERT(values.Last().first == NULL);
00089         return values.Last().second;
00090     }
00091 
00092     void SetBase(T x)
00093     {
00094         CS_ASSERT(values.Last().first == NULL);
00095 
00096         const T &old = Current();
00097 
00098         values.PopBack();
00099         values.PushBack(csTuple2<const ActiveSpell*,T>(NULL, x));
00100 
00101         if(Current() != old)
00102             OnChange();
00103     }
00104 
00105     void Override(const ActiveSpell* owner, T x)
00106     {
00107         const T &old = Current();
00108 
00109         values.PushFront(csTuple2<const ActiveSpell*,T>(owner, x));
00110 
00111         if(x != old)
00112             OnChange();
00113     }
00114 
00115     virtual void Cancel(const ActiveSpell* owner)
00116     {
00117         const T &old = Current();
00118 
00119         typename csList< csTuple2<const ActiveSpell*, T> >::Iterator it(values);
00120         while(it.HasNext())
00121         {
00122             csTuple2<const ActiveSpell*, T> &curr = it.Next();
00123             if(curr.first == owner)
00124             {
00125                 values.Delete(it);
00126             }
00127         }
00128 
00129         if(Current() != old)
00130             OnChange();
00131     }
00132 
00133 protected:
00135     virtual void OnChange()
00136     {
00137     }
00138 
00139     csList< csTuple2<const ActiveSpell*, T> > values;
00140 };
00141 
00142 //-----------------------------------------------------------------------------
00143 
00149 template <typename T>
00150 class Buffable : public iSpellModifier
00151 {
00152 public:
00153     Buffable()
00154     {
00155         base = cached = 0;
00156     }
00157     Buffable(T x)
00158     {
00159         base = cached = x;
00160     }
00161     virtual ~Buffable() { }
00162 
00163     T Current() const
00164     {
00165         return cached;
00166     }
00167     T Base() const
00168     {
00169         return base;
00170     }
00171 
00172     void SetBase(T x)
00173     {
00174         if(x == base)
00175             return;
00176 
00177         cached += x - base;
00178         base = x;
00179 
00180         OnChange();
00181     }
00182 
00183     void Buff(const ActiveSpell* owner, T x)
00184     {
00185         cached += x;
00186         buffs.Push(csTuple2<const ActiveSpell*,T>(owner, x));
00187 
00188         OnChange();
00189     }
00190 
00191     virtual void Cancel(const ActiveSpell* owner)
00192     {
00193         bool changed = false;
00194 
00195         // Count backwards since we're deleting and things may shift on the right
00196         for(size_t i = buffs.GetSize() - 1; i != (size_t) -1; i--)
00197         {
00198             if(buffs[i].first == owner)
00199             {
00200                 cached -= buffs[i].second;
00201                 buffs.DeleteIndexFast(i);
00202                 changed = true;
00203             }
00204         }
00205 
00206         if(changed)
00207             OnChange();
00208     }
00209 
00210 protected:
00212     virtual void OnChange()
00213     {
00214     }
00215 
00216     T base;
00217     T cached;
00218     csArray< csTuple2<const ActiveSpell*, T> > buffs;
00219 };
00220 
00221 //-----------------------------------------------------------------------------
00222 
00229 class Multiplier : public iSpellModifier
00230 {
00231 public:
00232     Multiplier()
00233     {
00234         cached = 1;
00235     }
00236     virtual ~Multiplier() { }
00237 
00238     float Value()
00239     {
00240         return cached;
00241     }
00242 
00243     void Buff(const ActiveSpell* owner, float x)
00244     {
00245         cached *= x;
00246         buffs.PushBack(csTuple2<const ActiveSpell*, float>(owner, x));
00247     }
00248 
00249     virtual void Cancel(const ActiveSpell* owner)
00250     {
00251         // Recompute the cache...avoid rounding errors.
00252         cached = 1;
00253 
00254         csList< csTuple2<const ActiveSpell*, float> >::Iterator it(buffs);
00255         while(it.HasNext())
00256         {
00257             csTuple2<const ActiveSpell*, float> &curr = it.Next();
00258             if(curr.first == owner)
00259             {
00260                 buffs.Delete(it);
00261             }
00262             else
00263             {
00264                 cached *= curr.second;
00265             }
00266         }
00267     }
00268 
00269 protected:
00270     float cached;
00271     csList< csTuple2<const ActiveSpell*, float> > buffs;
00272 };
00273 
00274 //-----------------------------------------------------------------------------
00275 
00277 template <typename T>
00278 class ClampedPositiveBuffable : public Buffable<T>
00279 {
00280 public:
00281     using Buffable<T>::cached;
00282     int Current()
00283     {
00284         // Clamp to avoid underflow problems with negative buffs.
00285         return cached > 0 ? cached : 0;
00286     }
00287 };
00288 
00289 #endif