1 
2 #include "floattext.h"
3 
4 #include "graphics/Renderer.h"
5 #include "nx.h"
6 #include "object.h"
7 using namespace NXE::Graphics;
8 #include "map.h"
9 
10 FloatText *FloatText::first = NULL;
11 FloatText *FloatText::last  = NULL;
12 
13 /*
14 void c------------------------------() {}
15 */
16 
FloatText(int sprite)17 FloatText::FloatText(int sprite)
18 {
19   prev = NULL;
20   next = first;
21 
22   if (first)
23     first->prev = this;
24   else
25     last = this;
26 
27   first        = this;
28   this->sprite = sprite;
29 
30   Reset();
31   ObjectDestroyed = false;
32 }
33 
~FloatText()34 FloatText::~FloatText()
35 {
36   if (this->next)
37     this->next->prev = this->prev;
38   if (this->prev)
39     this->prev->next = this->next;
40 
41   if (this == first)
42     first = first->next;
43   if (this == last)
44     last = last->prev;
45 }
46 
Reset()47 void FloatText::Reset()
48 {
49   this->state       = FT_IDLE;
50   this->shownAmount = 0;
51 }
52 
53 /*
54 void c------------------------------() {}
55 */
56 
57 // adds the spec'd amount of damage/energy to the object's point display
AddQty(int amt)58 void FloatText::AddQty(int amt)
59 {
60   // stat("FloatText::AddQty(%d)", amt);
61   if (amt == 0)
62     return;
63 
64   // first add the damage to the total
65   if (this->state == FT_IDLE)
66   {
67     this->state = FT_RISE;
68 
69     this->shownAmount = amt;
70     this->yoff        = FT_Y_START;
71     this->timer       = 0;
72   }
73   else
74   {
75     this->shownAmount += amt;
76 
77     // if we're scrolling away jerk back down
78     if (this->state == FT_SCROLL_AWAY)
79     {
80       this->state = FT_HOLD;
81       this->yoff  = FT_Y_HOLD;
82     }
83 
84     // reset the timer which counts how long we stay in hold state
85     if (this->state != FT_RISE)
86       this->timer = 0;
87   }
88 
89   if (this->shownAmount > 9999)
90     this->shownAmount = 9999; // overrun protection for buffer
91 }
92 
93 // updates the position of a floattext in respect to it's object
UpdatePos(Object * assoc_object)94 void FloatText::UpdatePos(Object *assoc_object)
95 {
96   // get the center pixel of the object we're associated with
97   this->objX = (assoc_object->x / CSFI) + (Renderer::getInstance()->sprites.sprites[assoc_object->sprite].w / 2);
98   this->objY = (assoc_object->y / CSFI) + (Renderer::getInstance()->sprites.sprites[assoc_object->sprite].h / 2);
99 
100   // adjust for possible draw point
101   SIFDir *dir = &Renderer::getInstance()->sprites.sprites[assoc_object->sprite].frame[assoc_object->frame].dir[assoc_object->dir];
102   this->objX -= dir->drawpoint.x;
103   this->objY -= dir->drawpoint.y;
104 }
105 
106 // moves and draws the given float text if need be
Draw()107 void FloatText::Draw()
108 {
109   FloatText *ft = this;
110   int x, y, i;
111 
112   // set the SDL clipping region to just above the hold point
113   // so it looks like it "rolls" away.
114   if (ft->state == FT_SCROLL_AWAY)
115   {
116     // this formula is confusing until you realize that FT_Y_HOLD is a negative number
117     int y = ((ft->objY - (map.displayed_yscroll / CSFI)) + FT_Y_HOLD);
118     int h = (Renderer::getInstance()->screenHeight - y);
119 
120     Renderer::getInstance()->setClip(0, y, Renderer::getInstance()->screenWidth, h);
121   }
122 
123   // render the damage amount into a string
124   char text[6] = {10};
125   sprintf(&text[1], "%d", ft->shownAmount);
126   for (i = 1; text[i]; i++)
127     text[i] -= '0';
128   int textlen = i;
129 
130   x = ft->objX - (textlen * (8 / 2)); // center the string on the object
131   y = ft->objY + ft->yoff;
132   // adjust to object's onscreen position
133   x -= (map.displayed_xscroll / CSFI);
134   y -= (map.displayed_yscroll / CSFI);
135 
136   // draw the text char by char
137   for (i = 0; i < textlen; i++)
138   {
139     Renderer::getInstance()->sprites.drawSprite(x, y, ft->sprite, text[i], 0);
140     x += 8;
141   }
142 
143   if (ft->state == FT_SCROLL_AWAY)
144     Renderer::getInstance()->clearClip();
145 }
146 
Update()147 void FloatText::Update()
148 {
149   FloatText *ft = this;
150 
151   switch (ft->state)
152   {
153     // rise to top point, moving once every other frame
154     case FT_RISE:
155     {
156       ft->timer ^= 1;
157       if (ft->timer)
158       {
159         if (--ft->yoff <= FT_Y_HOLD)
160         {
161           ft->state = FT_HOLD;
162           ft->timer = 0;
163         }
164       }
165     }
166     break;
167 
168     // hold at top for a moment
169     case FT_HOLD:
170     {
171       if (++ft->timer >= 42)
172         ft->state = FT_SCROLL_AWAY;
173     }
174     break;
175 
176     // scroll away quickly and disappear
177     case FT_SCROLL_AWAY:
178     {
179       if (--ft->yoff <= FT_Y_RISEAWAY)
180       {
181         ft->state       = FT_IDLE;
182         ft->shownAmount = 0;
183         ft->timer       = 0;
184         return;
185       }
186     }
187     break;
188   }
189 }
190 
IsScrollingAway()191 bool FloatText::IsScrollingAway()
192 {
193   return (this->state == FT_SCROLL_AWAY);
194 }
195 
196 /*
197 void c------------------------------() {}
198 */
199 
DrawAll(void)200 void FloatText::DrawAll(void)
201 {
202   FloatText *ft = first;
203   FloatText *nextft;
204   int count = 0;
205 
206   while (ft)
207   {
208     nextft = ft->next;
209 
210     if (ft->state != FT_IDLE)
211     {
212       ft->Draw();
213     }
214     else
215     {
216       if (ft->ObjectDestroyed)
217         delete ft;
218     }
219 
220     ft = nextft;
221     count++;
222   }
223 }
224 
UpdateAll(void)225 void FloatText::UpdateAll(void)
226 {
227   FloatText *ft = first;
228   FloatText *nextft;
229   int count = 0;
230 
231   while (ft)
232   {
233     nextft = ft->next;
234 
235     if (ft->state != FT_IDLE)
236     {
237       ft->Update();
238     }
239     else
240     {
241       if (ft->ObjectDestroyed)
242         delete ft;
243     }
244 
245     ft = nextft;
246     count++;
247   }
248 }
249 
250 // do NOT call this to remove all enemy's floattext from the map.
251 // for one thing, it could leave dangling invalid pointers.
252 // for another, it deletes the player->XPText, etc.
253 // instead, call ResetAll and let them clean themselves up.
DeleteAll(void)254 void FloatText::DeleteAll(void)
255 {
256   while (first)
257     delete first;
258 }
259 
ResetAll(void)260 void FloatText::ResetAll(void)
261 {
262   FloatText *ft = first;
263   while (ft)
264   {
265     ft->Reset();
266     ft = ft->next;
267   }
268 }
269