notice.c

Go to the documentation of this file.
00001 
00025 #include "notice.h"
00026 #include "color.h"
00027 #include "player.h"
00028 #include <assert.h>
00029 
00034 #define MAX_NOTICES  4
00035 
00041 #define SPACING  2
00042 
00047 struct Notice_t {
00051     RenderItem text;
00055     Uint32 expiryTime;
00059     Uint8 type;
00060 };
00061 
00062 typedef struct Notice_t  Notice;
00063 
00068 static Notice notices[MAX_NOTICES] = { 0 };
00069 
00075 static Notice *order[MAX_NOTICES] = { 
00076     &notices[0], &notices[1], &notices[2], &notices[3]
00077 };
00078 
00083 static int timeouts = 0;
00084 
00089 static int notimeouts = 0;
00090 
00098 static void RemoveOneNotice(int index) {
00099     Notice *n = order[index];
00100     assert(index < MAX_NOTICES);
00101     // clear it from view
00102     ClearRenderItem(&(n->text));
00103     // take it out of the renderer
00104     RemoveRenderItem(&(n->text));
00105     // destroy the surface with rendered text
00106     SDL_FreeSurface(n->text.data);
00107     n->text.data = NULL;
00108     // update notice counts
00109     if (n->expiryTime == NOTICE_NOEXPIRATION) {
00110         notimeouts--;
00111     }
00112     else {
00113         timeouts--;
00114     }
00115     // move remaining notices forward in order
00116     for (; index < MAX_NOTICES - 1; index++) {
00117         // also, tag for later placement
00118         (order[index] = order[index + 1])->text.loc.y = -1;
00119     }
00120     // put the pointer to the removed notice at the end
00121     order[MAX_NOTICES - 1] = n;
00122 }
00123 
00124 void AddNotice(Uint32 expiryTime, Uint8 type, rtsa_char *format, ...) {
00125     Notice *n;
00126     va_list args;
00127     int ind;
00128     Bool add = TRUE;
00129     assert(type < NOTICE_MAXTYPE);
00130     // find an available notice
00131     // first, see if there are greater than the maximum notices
00132     if ((ind = timeouts + notimeouts) >= MAX_NOTICES) {
00133         // won't be adding this one's render item
00134         add = FALSE;
00135         // find the oldest notice
00136         if (notimeouts == MAX_NOTICES) {
00137             // no room -- exit now
00138             return;
00139         }
00140         // the oldest is the last -- clear it from view
00141         ClearRenderItem(&((n = order[ind = MAX_NOTICES - 1])->text));
00142     }
00143     else {
00144         // add the notice at the end
00145         n = order[ind];
00146     }
00147     // adding a notice w/o a timeout?
00148     if (expiryTime == NOTICE_NOEXPIRATION) {
00149         // the notice will be inserted after the last non-timeout notice
00150         for (; ind > notimeouts; ind--) {
00151             // move notices down to make room, and tag it for placement
00152             (order[ind] = order[ind - 1])->text.loc.y = -1;
00153         }
00154         // insert the new notice
00155         order[ind] = n;
00156         // update count
00157         if (add) {
00158             notimeouts++;
00159         }
00160     }
00161     else if (add) {
00162         timeouts++;
00163     }
00164     assert(timeouts + notimeouts <= MAX_NOTICES);
00165     // get the variable argument list
00166     va_start(args, format);
00167     // render the text
00168     TextRenderStringV(&(n->text), FONT_SCORE, dInfo.pw >> 1,
00169     colorFmtInd[COLOR_BLACK], format, args);
00170     // done with the variable args
00171     va_end(args);
00172     // mark notice as not yet placed
00173     n->text.loc.y = -1;
00174     // fill out the notice
00175     n->expiryTime = expiryTime;
00176     n->type = type;
00177     // render it
00178     if (add) {
00179         AddRenderItem(&(n->text), LAYER_TEXT);
00180     }
00181 }
00182 
00183 extern Uint32 frameTime;
00184 
00185 void AddScoreNotice(int killerId, int killedId, int score) {
00186     Player *s = &players[killerId];  // scorer
00187     Player *l = &players[killedId];  // loser
00188     // assure good IDs
00189     assert((killerId < MAX_PLAYERS) && (killedId < MAX_PLAYERS));
00190     // check for killing of the same team
00191     if (s->team == l->team) {
00192         // killer is local player?
00193         if (s->pid == localPlayer) {
00194             AddNotice(frameTime + 3000, NOTICE_LOCALTEAMKILL,
00195             strings[STRING_LOCALTEAMKILLER], l->name);
00196         }
00197         // killed is local player?
00198         else if (l->pid == localPlayer) {
00199             AddNotice(frameTime + 3000, NOTICE_LOCALTEAMKILL,
00200             strings[STRING_LOCALTEAMKILLED], s->name);
00201         }
00202         else {
00203             AddNotice(frameTime + 3000, NOTICE_TEAMKILL,
00204             strings[STRING_TEAMKILL], s->name, l->name);
00205         }
00206     }
00207     else {
00208         // is scorer local player?
00209         if (s->pid == localPlayer) {
00210             AddNotice(frameTime + 3000, NOTICE_LOCALKILL,
00211             strings[STRING_LOCALKILL], l->name, score);
00212         }
00213         else {
00214             AddNotice(frameTime + 3000, NOTICE_KILL,
00215             strings[STRING_KILL], s->name, l->name, score);
00216         }
00217     }
00218 }
00219 
00220 void RemoveNotice(Uint8 type) {
00221     int loop;
00222     for (loop = timeouts + notimeouts - 1; loop >= 0; loop--) {
00223         // is this notice one that needs to be removed?
00224         if (order[loop]->type == type) {
00225             RemoveOneNotice(loop);
00226             // done
00227             break;
00228         }
00229     }
00230 }
00231 
00232 void RemoveAllNotices() {
00233     int loop;
00234     for (loop = timeouts + notimeouts - 1; loop >= 0; loop--) {
00235         // clear it from view
00236         ClearRenderItem(&(order[loop]->text));
00237         // take it out of the renderer
00238         RemoveRenderItem(&(order[loop]->text));
00239         // destroy the surface with rendered text
00240         SDL_FreeSurface(order[loop]->text.data);
00241         order[loop]->text.data = NULL;
00242     }
00243     // clear out the counts
00244     timeouts = notimeouts = 0;
00245 }
00246 
00247 void UpdateNotices(Uint32 time) {
00248     Bool placeRemaining = FALSE;
00249     int loop, top = TOP_MARGIN;
00250     Notice *n;
00251     for (loop = 0; loop < timeouts + notimeouts; ) {
00252         // time to remove?
00253         if ((n = order[loop])->expiryTime <= time) {
00254             // remove this one
00255             RemoveOneNotice(loop);
00256             // place all remaining notices
00257             placeRemaining = TRUE;
00258             // start the loop over -- stay on same index
00259             continue;
00260         }
00261         // need to place the notice?
00262         if (placeRemaining || (n->text.loc.y == -1)) {
00263             // place all remaining notices
00264             placeRemaining = TRUE;
00265             // compute new spot for this notice
00266             // center it horizontally
00267             n->text.loc.x = (dInfo.pw >> 1) - (n->text.loc.w >> 1);
00268             // place it vertically
00269             n->text.loc.y = top;
00270             // render in this spot
00271             PlaceRenderItem(&(n->text));
00272         }
00273         // grab the bottom of this notice for later placements
00274         top = SPACING + n->text.loc.y + n->text.loc.h;
00275         // move to the next notice
00276         loop++;
00277     }
00278 }
00279 

Generated on Mon May 28 04:41:39 2007 for Retro Tank Super Attack by  doxygen 1.5.2