00001 
00016 
00017 
00018 #include "graffiti.h"
00019 
00020 #include "globals.h"
00021 #include "lev_data.h"
00022 #include "obj_column_def.h"
00023 #include "obj_things.h"
00024 #include "obj_slabs.h"
00025 #include "obj_column.h"
00026 
00032 short level_free_graffiti(struct LEVEL *lvl)
00033 {
00034     int i;
00035     for (i=lvl->graffiti_count-1; i>=0 ; i--)
00036     {
00037       free (lvl->graffiti[i]->text);
00038       free (lvl->graffiti[i]);
00039     }
00040     if (lvl->graffiti_count>0)
00041       free(lvl->graffiti);
00042     return ERR_NONE;
00043 }
00044 
00051 int graffiti_idx(struct LEVEL *lvl, int tx, int ty)
00052 {
00053     return graffiti_idx_next(lvl, tx, ty,-1);
00054 }
00055 
00066 int graffiti_idx_next(struct LEVEL *lvl, int tx, int ty, int prev_idx)
00067 {
00068     if (prev_idx < -1) return -1;
00069     int i;
00070     struct DK_GRAFFITI *graf;
00071     for (i=prev_idx+1; i < lvl->graffiti_count; i++)
00072     {
00073       graf = lvl->graffiti[i];
00074       if ((tx>=graf->tile.x) && (tx<=graf->fin_tile.x) && (ty>=graf->tile.y) && (ty<=graf->fin_tile.y))
00075           return i;
00076       
00077       if ((ty==graf->tile.y) && (tx==graf->tile.x))
00078           return i;
00079     }
00080     return -1;
00081 }
00082 
00090 char *get_graffiti_text(struct LEVEL *lvl,unsigned int num)
00091 {
00092     if ((num>=lvl->graffiti_count) || (num<0))
00093       return "";
00094     return lvl->graffiti[num]->text;
00095 }
00096 
00104 void graffiti_del(struct LEVEL *lvl,unsigned int num)
00105 {
00106     int i;
00107     if ((lvl==NULL)||(num>=lvl->graffiti_count))
00108       return;
00109     struct DK_GRAFFITI *graf;
00110     graf=lvl->graffiti[num];
00111     if (graf!=NULL)
00112     {
00113       free(graf->text);
00114       free(graf);
00115     }
00116     int graff_max_idx=lvl->graffiti_count-1;
00117     for (i=num; i < graff_max_idx; i++)
00118     {
00119       lvl->graffiti[i]=lvl->graffiti[i+1];
00120     }
00121     
00122     lvl->graffiti_count=graff_max_idx;
00123     
00124     lvl->graffiti = (struct DK_GRAFFITI **)realloc(lvl->graffiti,
00125              (graff_max_idx)*sizeof(struct DK_GRAFFITI *));
00126 }
00127 
00138 struct DK_GRAFFITI *create_graffiti(int tx, int ty, char *text, const struct LEVEL *lvl, int orient)
00139 {
00140     tx%=lvl->tlsize.x;
00141     ty%=lvl->tlsize.y;
00142     if (text==NULL) return NULL;
00143     struct DK_GRAFFITI *graf;
00144     
00145     graf = (struct DK_GRAFFITI *)malloc(sizeof(struct DK_GRAFFITI));
00146     if (graf==NULL)
00147     {
00148         message_error("Cannot alloc memory for graffiti item");
00149         return NULL;
00150     }
00151     graf->tile.x=tx;
00152     graf->tile.y=ty;
00153     graf->font=GRAFF_FONT_ADICLSSC;
00154     graf->cube=0x0184;
00155     graf->text = strdup(text);
00156     set_graffiti_orientation(graf,lvl,orient);
00157     return graf;
00158 }
00159 
00167 int graffiti_add_obj(struct LEVEL *lvl,struct DK_GRAFFITI *graf)
00168 {
00169     if ((lvl==NULL)||(graf==NULL)) return -1;
00170 
00171     int graf_idx=lvl->graffiti_count;
00172     lvl->graffiti = (struct DK_GRAFFITI **)realloc (lvl->graffiti,
00173                      (graf_idx+1)*sizeof(struct DK_GRAFFITI *));
00174     if (lvl->graffiti==NULL)
00175     {
00176         message_error("Cannot alloc memory for graffiti array");
00177         return -1;
00178     }
00179     lvl->graffiti[graf_idx]=graf;
00180     lvl->graffiti_count=graf_idx+1;
00181     return graf_idx;
00182 }
00183 
00193 short set_graffiti_orientation(struct DK_GRAFFITI *graf,const struct LEVEL *lvl,unsigned short orient)
00194 {
00195     if ((graf==NULL)||(graf->text==NULL)) return false;
00196     
00197     int arr_entries_x=lvl->tlsize.x*MAP_SUBNUM_X;
00198     int arr_entries_y=lvl->tlsize.y*MAP_SUBNUM_Y;
00199     unsigned short font=graf->font;
00200     int i;
00201     int l;
00202     l = strlen(graf->text);
00203     
00204     int subtl_len=0;
00205     for (i=0; i<l; i++)
00206     {
00207       
00208       
00209       
00210       subtl_len+=get_font_char(font,graf->text[i])[0]+1;
00211       int graf_end_subtl_x,graf_end_subtl_y;
00212       switch (orient)
00213       {
00214       case ORIENT_NS:
00215       case ORIENT_SN:
00216           graf_end_subtl_x=graf->tile.x*MAP_SUBNUM_X;
00217           graf_end_subtl_y=graf->tile.y*MAP_SUBNUM_Y+subtl_len;
00218           break;
00219       case ORIENT_WE:
00220       case ORIENT_EW:
00221           graf_end_subtl_x=graf->tile.x*MAP_SUBNUM_X+subtl_len;
00222           graf_end_subtl_y=graf->tile.y*MAP_SUBNUM_Y;
00223           break;
00224       case ORIENT_TNS:
00225       case ORIENT_TSN:
00226           graf_end_subtl_x=graf->tile.x*MAP_SUBNUM_X;
00227           graf_end_subtl_y=graf->tile.y*MAP_SUBNUM_Y+subtl_len;
00228           break;
00229       case ORIENT_TWE:
00230       case ORIENT_TEW:
00231           graf_end_subtl_x=graf->tile.x*MAP_SUBNUM_X+subtl_len;
00232           graf_end_subtl_y=graf->tile.y*MAP_SUBNUM_Y;
00233           break;
00234       default:
00235           graf_end_subtl_x=graf->tile.x*MAP_SUBNUM_X;
00236           graf_end_subtl_y=graf->tile.y*MAP_SUBNUM_Y;
00237           break;
00238       }
00239       
00240       
00241       if ((graf_end_subtl_x > arr_entries_x)||(graf_end_subtl_y > arr_entries_y))
00242       {
00243         l=i;
00244         break;
00245       }
00246     }
00247     
00248     subtl_len--;
00249     
00250     int tiles_len=(subtl_len/MAP_SUBNUM_X) + ((subtl_len%MAP_SUBNUM_X)>0);
00251     if (tiles_len<1) tiles_len=1;
00252     
00253     int txt_height=get_graffiti_cube_height(graf->font,graf->text);
00254     int txt_tile_height=(txt_height/MAP_SUBNUM_X)+((txt_height%MAP_SUBNUM_X)>0);
00255     
00256     graf->orient=orient;
00257     int graf_h=6-txt_height;
00258     if ((graf_h<0)||(graf_h>7))
00259       graf_h=0;
00260     switch (orient)
00261     {
00262       case ORIENT_NS:
00263       case ORIENT_SN:
00264            graf->fin_tile.x = graf->tile.x;
00265            graf->fin_tile.y = graf->tile.y+tiles_len-1;
00266            graf->height=graf_h;
00267            break;
00268       case ORIENT_WE:
00269       case ORIENT_EW:
00270            graf->fin_tile.x = graf->tile.x+tiles_len-1;
00271            graf->fin_tile.y = graf->tile.y;
00272            graf->height=graf_h;
00273            break;
00274       case ORIENT_TNS:
00275       case ORIENT_TSN:
00276            graf->fin_tile.x = graf->tile.x+txt_tile_height-1;
00277            graf->fin_tile.y = graf->tile.y+tiles_len-1;
00278            if (slab_is_tall(get_tile_slab(lvl,graf->tile.x,graf->tile.y)))
00279              graf->height=4;
00280            else
00281              graf->height=0;
00282            break;
00283       case ORIENT_TWE:
00284       case ORIENT_TEW:
00285            graf->fin_tile.x = graf->tile.x+tiles_len-1;
00286            graf->fin_tile.y = graf->tile.y+txt_tile_height-1;
00287            if (slab_is_tall(get_tile_slab(lvl,graf->tile.x,graf->tile.y)))
00288              graf->height=4;
00289            else
00290              graf->height=0;
00291            break;
00292       default:
00293            graf->fin_tile.x = graf->tile.x+tiles_len-1;
00294            graf->fin_tile.y = graf->tile.y+tiles_len-1;
00295            graf->height=graf_h;
00296            break;
00297     }
00298     return ERR_NONE;
00299 }
00300 
00308 int set_graffiti_height(struct DK_GRAFFITI *graf,int height)
00309 {
00310     if (graf==NULL) return 0;
00311     int height_max;
00312     switch (graf->orient)
00313     {
00314       case ORIENT_NS:
00315       case ORIENT_SN:
00316       case ORIENT_WE:
00317       case ORIENT_EW:
00318            height_max=7-get_graffiti_cube_height(graf->font,graf->text);
00319            break;
00320       case ORIENT_TNS:
00321       case ORIENT_TSN:
00322       case ORIENT_TWE:
00323       case ORIENT_TEW:
00324       default:
00325            height_max=7;
00326            break;
00327     }
00328     if (height<0) height=0;
00329     if (height>height_max) height=height_max;
00330     graf->height=height;
00331     return height;
00332 }
00333 
00346 int graffiti_add(struct LEVEL *lvl,int tx, int ty,int height, char *text,int font,
00347       unsigned short orient,unsigned short cube)
00348 {
00349     if ((lvl==NULL)||(text==NULL)||(strlen(text)<1)) return -1;
00350     struct DK_GRAFFITI *graf=create_graffiti(tx,ty,text,lvl,orient);
00351     if (graf==NULL) return false;
00352     graf->font=font;
00353     graf->height=height;
00354     graf->cube=cube;
00355     int graf_idx=graffiti_add_obj(lvl,graf);
00356     if (graf_idx<0)
00357     {
00358       free(graf->text);
00359       free(graf);
00360     }
00361     return graf_idx;
00362 }
00363 
00369 void graffiti_update_columns(struct LEVEL *lvl,int graf_idx)
00370 {
00371     if (graf_idx<0) return;
00372     struct DK_GRAFFITI *graf;
00373     graf=get_graffiti(lvl, graf_idx);
00374     if (graf==NULL) return;
00375     update_datclm_for_square(lvl,graf->tile.x,graf->fin_tile.x,graf->tile.y,graf->fin_tile.y);
00376 }
00377 
00384 void graffiti_clear_from_columns(struct LEVEL *lvl,int graf_idx)
00385 {
00386     if (graf_idx<0) return;
00387     struct DK_GRAFFITI *graf;
00388     graf=get_graffiti(lvl, graf_idx);
00389     if (graf==NULL) return;
00390     int tx,fin_tx,ty,fin_ty;
00391     
00392     tx=graf->tile.x;graf->tile.x=lvl->tlsize.x;
00393     fin_tx=graf->fin_tile.x;graf->fin_tile.x=lvl->tlsize.x;
00394     ty=graf->tile.y;graf->tile.y=lvl->tlsize.y;
00395     fin_ty=graf->fin_tile.y;graf->fin_tile.y=lvl->tlsize.y;
00396     
00397     update_datclm_for_square(lvl,tx,fin_tx,ty,fin_ty);
00398     
00399     graf->tile.x=tx;
00400     graf->fin_tile.x=fin_tx;
00401     graf->tile.y=ty;
00402     graf->fin_tile.y=fin_ty;
00403 }
00404 
00410 unsigned int get_graffiti_count(struct LEVEL *lvl)
00411 {
00412     if (lvl==NULL) return 0;
00413     return lvl->graffiti_count;
00414 }
00415 
00422 struct DK_GRAFFITI *get_graffiti(struct LEVEL *lvl, int graf_idx)
00423 {
00424     if ((graf_idx<0)||(graf_idx>=lvl->graffiti_count)) return NULL;
00425     return lvl->graffiti[graf_idx];
00426 }
00427 
00434 int compute_graffiti_subtl_length(unsigned short font,char *text)
00435 {
00436     if (text==NULL) return 0;
00437     int l = strlen(text);
00438     if (l<1) return 0;
00439     switch (font)
00440     {
00441     case GRAFF_FONT_ADICLSSC:
00442     case GRAFF_FONT_ADISIZE8:
00443          break;
00444     case GRAFF_FONT_NONE:
00445     default:
00446         return 0;
00447     }
00448     
00449     int i;
00450     int subtl_len=0;
00451     for (i=0; i < l; i++)
00452     {
00453         
00454         
00455         
00456         subtl_len+=get_font_char(font,text[i])[0]+1;
00457     }
00458     
00459     subtl_len--;
00460     return subtl_len;
00461 }
00462 
00469 int get_graffiti_cube_height(unsigned short font,char *text)
00470 {
00471     
00472     
00473   switch (font)
00474   {
00475   case GRAFF_FONT_ADICLSSC:
00476     return font_adiclssc_height;
00477   case GRAFF_FONT_ADISIZE8:
00478     return font_adisize8_height;
00479   default:
00480     return 0;
00481   }
00482 }
00483 
00490 const unsigned char *get_font_char(unsigned short font,char chr)
00491 {
00492   switch (font)
00493   {
00494   case GRAFF_FONT_ADICLSSC:
00495     return font_adiclssc_chars[(unsigned char)chr];
00496   case GRAFF_FONT_ADISIZE8:
00497     return font_adisize8_chars[(unsigned char)chr];
00498   default:
00499     return font_any_chnull;
00500   }
00501 }
00502 
00511 int place_graffiti_on_slab(struct COLUMN_REC *clm_recs[9],struct LEVEL *lvl, int tx, int ty)
00512 {
00513     static const int dy[4][3]={{0,1,2}, {2,2,2}, {2,1,0}, {0,0,0}};
00514     static const int dx[4][3]={{0,0,0}, {0,1,2}, {2,2,2}, {2,1,0}};
00515     int mod_clms=0;
00516     int graf_idx=-1;
00517     while ((graf_idx=graffiti_idx_next(lvl,tx,ty,graf_idx))>=0)
00518     {
00519       struct DK_GRAFFITI *graf;
00520       graf=get_graffiti(lvl,graf_idx);
00521       if (graf==NULL) continue;
00522       
00523       int i;
00524       int base_sx=graf->tile.x*MAP_SUBNUM_X;
00525       int base_sy=graf->tile.y*MAP_SUBNUM_Y;
00526       
00527       int subtl_len=compute_graffiti_subtl_length(graf->font,graf->text);
00528       
00529       int graf_subtl_start;
00530       
00531       
00532       short orient_top=false;
00533       switch (graf->orient)
00534       {
00535       case ORIENT_TNS: orient_top=true;
00536       case ORIENT_NS: graf_subtl_start=ty*MAP_SUBNUM_Y-base_sy; break;
00537       case ORIENT_TSN: orient_top=true;
00538       case ORIENT_SN: graf_subtl_start=(base_sy+subtl_len-1)-ty*MAP_SUBNUM_Y; break;
00539       case ORIENT_TWE: orient_top=true;
00540       case ORIENT_WE: graf_subtl_start=tx*MAP_SUBNUM_X-base_sx; break;
00541       case ORIENT_TEW: orient_top=true;
00542       case ORIENT_EW: graf_subtl_start=(base_sx+subtl_len-1)-tx*MAP_SUBNUM_X; break;
00543       default: graf_subtl_start=0; break;
00544       }
00545       if (orient_top)
00546       {
00547         int subtl_h=get_graffiti_cube_height(graf->font,graf->text);
00548         int graf_subtl_h_st;
00549         switch (graf->orient)
00550         {
00551         case ORIENT_TNS: graf_subtl_h_st=tx*MAP_SUBNUM_X-base_sx; break;
00552         case ORIENT_TSN: graf_subtl_h_st=(base_sx+subtl_h-1)-(tx+1)*MAP_SUBNUM_X; break;
00553         case ORIENT_TWE: graf_subtl_h_st=(base_sy+subtl_h-1)-(ty+1)*MAP_SUBNUM_Y; break;
00554         case ORIENT_TEW: graf_subtl_h_st=ty*MAP_SUBNUM_Y-base_sy; break;
00555         default: graf_subtl_h_st=0; break;
00556         }
00557         for (i=0; i<MAP_SUBNUM_X; i++)
00558         {
00559           int k;
00560           int graf_subtl=graf_subtl_start+i;
00561           for (k=0; k<MAP_SUBNUM_Y; k++)
00562           {
00563             int subtl;
00564             switch (graf->orient)
00565             {
00566             case ORIENT_TNS: subtl=i*MAP_SUBNUM_X + k; break;
00567             case ORIENT_TSN: subtl=(2-i)*MAP_SUBNUM_X + (2-k); break;
00568             case ORIENT_TWE: subtl=(2-k)*MAP_SUBNUM_X + i; break;
00569             case ORIENT_TEW: subtl=k*MAP_SUBNUM_X + (2-i); break;
00570             default: subtl=0; break;
00571             }
00572             int graf_subtl_h=graf_subtl_h_st+k;
00573             short modified=place_graffiti_on_clm_top(clm_recs[subtl],graf->font,
00574                   graf->height,graf->text,graf_subtl,graf_subtl_h,graf->cube);
00575             if (modified) mod_clms++;
00576           }
00577         }
00578       } else
00579       {
00580         unsigned short or=((graf->orient%4));
00581         for (i=0; i<MAP_SUBNUM_X; i++)
00582         {
00583           int subtl=dy[or][i]*MAP_SUBNUM_X + dx[or][i];
00584           int graf_subtl=graf_subtl_start+i;
00585           short modified=place_graffiti_on_column(clm_recs[subtl],graf->font,
00586                 graf->height,graf->text,graf_subtl,graf->cube);
00587           if (modified) mod_clms++;
00588         }
00589       }
00590     }
00591     return mod_clms;
00592 }
00593 
00605 short place_graffiti_on_clm_top(struct COLUMN_REC *clm_rec,unsigned short font,
00606         unsigned short height,char *text,int graf_subtl,int graf_subtl_h,
00607         unsigned short cube)
00608 {
00609     if ((clm_rec==NULL)||(text==NULL)||(strlen(text)<1)) return false;
00610     int i;
00611     int l = strlen(text);
00612     int text_pos=0; 
00613     int clm_pos=0; 
00614     i=0;
00615     for (text_pos=0; text_pos<l; text_pos++)
00616     {
00617         
00618         
00619         int chr_clms_count=get_font_char(font,text[text_pos])[0]+1;
00620         if ((i<=graf_subtl)&&(i+chr_clms_count>graf_subtl))
00621         {
00622             
00623             
00624             clm_pos=graf_subtl-i+1;
00625             break;
00626         }
00627         i+=chr_clms_count;
00628     }
00629     
00630     if (text_pos>=l) return false;
00631     const unsigned char *char_data=get_font_char(font,text[text_pos]);
00632     
00633     if ((clm_pos<=0)||(clm_pos>char_data[0])) return false;
00634     unsigned char clm_mask=char_data[clm_pos];
00635     if ((clm_mask>>graf_subtl_h)&0x01)
00636     {
00637         if (height<8) clm_rec->c[height]=cube;
00638     }
00639     clm_rec->solid=compute_clm_rec_solid(clm_rec);
00640     clm_rec->height=compute_clm_rec_height(clm_rec);
00641     return true;
00642 }
00643 
00654 short place_graffiti_on_column(struct COLUMN_REC *clm_rec,unsigned short font,
00655         unsigned short height,char *text,int graf_subtl,unsigned short cube)
00656 {
00657     if ((clm_rec==NULL)||(text==NULL)||(strlen(text)<1)) return false;
00658     int i;
00659     int l = strlen(text);
00660     int text_pos=0; 
00661     int clm_pos=0; 
00662     i=0;
00663     for (text_pos=0; text_pos<l; text_pos++)
00664     {
00665         
00666         
00667         int chr_clms_count=get_font_char(font,text[text_pos])[0]+1;
00668         if ((i<=graf_subtl)&&(i+chr_clms_count>graf_subtl))
00669         {
00670             
00671             
00672             clm_pos=graf_subtl-i+1;
00673             break;
00674         }
00675         i+=chr_clms_count;
00676     }
00677     
00678     if (text_pos>=l) return false;
00679     const unsigned char *char_data=get_font_char(font,text[text_pos]);
00680     
00681     if ((clm_pos<=0)||(clm_pos>char_data[0])) return false;
00682     unsigned char clm_mask=char_data[clm_pos];
00683     for (i=0;i<8;i++)
00684     {
00685         if ((clm_mask>>i)&0x01)
00686         {
00687             int idx=i+height;
00688             if ((idx>=0)&&(idx<8)) clm_rec->c[idx]=cube;
00689         }
00690     }
00691     clm_rec->solid=compute_clm_rec_solid(clm_rec);
00692     clm_rec->height=compute_clm_rec_height(clm_rec);
00693     return true;
00694 }