Planeshift
|
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