00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00022
00023 #include "crogue.h"
00024
00025
00030 void catprintf(char *target, const char *format, ...)
00031 {
00032 va_list varargs;
00033
00034 while(*target) target++;
00035
00036 va_start(varargs, format);
00037 vsprintf(target, format, varargs);
00038 va_end(varargs);
00039 }
00040
00041
00047 const char *retprintf(const char *format, ...)
00048 {
00049 va_list varargs;
00050 const char *ret;
00051 va_start(varargs, format);
00052 ret = vretprintf(format, varargs);
00053 va_end(varargs);
00054 return ret;
00055 }
00056
00057
00060 const char *vretprintf(const char *format, va_list args)
00061 {
00062 static char buf[128];
00063 vsprintf(buf, format, args);
00064 return buf;
00065 }
00066
00067
00068
00075 coord trace_path(int x, int y, direction dir, int distance)
00076 {
00077 while(distance)
00078 {
00079 x += dir.x;
00080 y += dir.y;
00081 if( w->t[y][x].flags & TFLAG_OCCUPIED ||
00082 !w->tiledescs[w->t[y][x].type].passable )
00083 break;
00084 distance--;
00085 }
00086 return COORD(x, y);
00087 }
00088
00089
00090
00098 const char *pluralize(int num, const char *str)
00099 {
00100 #if TARGET_LANGUAGE==ENGLISH
00101 int i=0, ii=0, xofyform=0;
00102 static char ret[64];
00103 char *lasttoken = ret;
00104
00105 if(num==1) return str;
00106
00107 while(str[i] != '\0') {
00108 if( str[i]==' ' && str[i+1]=='o' && str[i+2]=='f' ) {
00109 ret[ii++]='s';
00110 xofyform = 1;
00111 }
00112 if(str[i] == ' ')
00113 lasttoken = ret+i+1;
00114 ret[ii] = str[i];
00115 i++;
00116 ii++;
00117 }
00118 ret[ii]='\0';
00119 if( xofyform )
00120 {
00121 return ret;
00122 }
00123
00124 if(!strcmp(lasttoken, "tooth"))
00125 {
00126 lasttoken[1] = lasttoken[2] = 'e';
00127 return ret;
00128 }
00129
00130 ret[ii++]='s';
00131 ret[ii]='\0';
00132
00133 return ret;
00134 #elif TARGET_LANGUAGE==CZECH
00135 static char ret[64];
00136
00137 if(num==1)
00138 {
00139 return str;
00140 }
00141 else if(num <= 4)
00142 {
00143 strcpy(ret, str);
00144 strcat(ret, "e");
00145 }
00146 else
00147 {
00148 strcpy(ret, str);
00149 strcat(ret, "u");
00150 }
00151
00152 return ret;
00153 #else
00154
00155 return str;
00156 #endif
00157 }
00158
00159
00166 const char *indefinite_article(const char *noun)
00167 {
00168 #if TARGET_LANGUAGE==ENGLISH
00169 switch(noun[0])
00170 {
00171 case 'a': case 'A':
00172 case 'e': case 'E':
00173 case 'i': case 'I':
00174 case 'o': case 'O':
00175 case 'u': case 'U':
00176 return "an";
00177 default:
00178 return "a";
00179 }
00180 #elif TARGET_LANGUAGE==CZECH
00181 return "";
00182 #else
00183
00184 return "";
00185 #endif
00186 }
00187
00188
00190 monstdesc *find_monster_description(int m)
00191 {
00192 return (monstdesc*)deref_file_ptr(w->m[m].type);
00193 }
00194
00195
00196
00199 void init_shuffle_tab(void)
00200 {
00201 int i, j, k, pos;
00202 uint temp;
00203 uint *sizes;
00204
00205 w->shuffletranslation = (uint*)debug_malloc( sizeof(uint) * w->desc.shuffletabsize );
00206
00207
00208 for(i=0; i<w->desc.shuffletabsize; i++)
00209 w->shuffletranslation[i] = i;
00210
00211
00212 sizes = (uint*)deref_file_ptr(w->desc.stsizes);
00213 pos = 0;
00214 for(i=0; i<w->desc.numshuffletabs; i++)
00215 {
00216 for(j=0; j<sizes[i]; j++)
00217 {
00218 k = pos+RANGE(sizes[i]-1, 0);
00219
00220 temp = w->shuffletranslation[k];
00221 w->shuffletranslation[k] = w->shuffletranslation[pos+j];
00222 w->shuffletranslation[pos+j] = temp;
00223 }
00224 pos += sizes[i];
00225 }
00226 }
00227
00228
00229
00230 typedef struct jumptabentry
00231 {
00232 filelink target;
00233 uint freq;
00234 range condition;
00235 } jumptabentry;
00236
00237
00238 typedef struct jumptable
00239 {
00240 uint numEntries;
00241 uint condition;
00242 jumptabentry entries[1];
00243 } jumptable;
00244
00245 static filelink deref_jump_table(jumptable *table);
00246
00247 const filelink filelink_null = { 0, 0, 0 };
00248
00249
00257 const void *deref_file_ptr(filelink p)
00258 {
00259 if(isNull(p))
00260 return NULL;
00261 else
00262 {
00263 p = deref_file_ptr_partial(p);
00264
00265 switch(p.type)
00266 {
00267 default:
00268 return (char*)(p.offset + (char*)w->constfileoffset);
00269 }
00270 }
00271 }
00272
00273
00275 filelink deref_file_ptr_partial(filelink p)
00276 {
00277 char *target;
00278
00279 while(p.type == PTR_JUMPTABLE || p.type == PTR_SHUFFLETAB)
00280 {
00281 target = (char*)((char*)w->constfileoffset + p.offset);
00282
00283 if(p.type == PTR_JUMPTABLE)
00284 p = deref_jump_table((jumptable*)target);
00285 else
00286 p = w->shuffledata[w->shuffletranslation[p.offset]];
00287 }
00288
00289 return p;
00290 }
00291
00292
00293 static filelink deref_jump_table(jumptable *table)
00294 {
00295 const jumptabentry *body = table->entries;
00296 uint low, high, mid, target, conditionresult;
00297
00298 while(1)
00299 {
00300
00301 low = 1;
00302 high = table->numEntries-1;
00303 target = (lrand() % body[high].freq)+1;
00304
00305 while(1) {
00306 mid = (low+high)/2;
00307
00308 if(low>=high)
00309 break;
00310
00311 if(body[mid].freq >= target) {
00312 if(body[mid-1].freq < target)
00313 break;
00314 else
00315 high = mid-1;
00316 } else {
00317 low = mid+1;
00318 }
00319 }
00320
00321
00322 switch(table->condition)
00323 {
00324 default:
00325 case jt_unconditional:
00326 conditionresult = 1;
00327 break;
00328 case jt_playerlevel:
00329 conditionresult = w->plr.level;
00330 break;
00331 case jt_dungeonlevel:
00332 conditionresult = MAPDESC_CURRENT.difficulty;
00333 break;
00334 case jt_avglevel:
00335 conditionresult = (MAPDESC_CURRENT.difficulty + w->plr.level)/2;
00336 break;
00337 case jt_class:
00338 conditionresult = w->plr.class;
00339 break;
00340 }
00341 if(conditionresult >= body[mid].condition.min && conditionresult <= body[mid].condition.max)
00342 break;
00343 }
00344 return body[mid].target;
00345 }
00346
00347
00348 #ifdef DEBUG_ALLOCATOR
00349
00350
00351
00352
00353
00354
00355 #define GUARD_NUM 16
00356 #define GUARD_VAL 0xDEADBEEF
00357 #define GUARD_FREED 0xFEEBDAED
00358 static long *alloced_blocks[32];
00359 static int num_alloced_blocks=0;
00360
00361
00362 int debug_verify_mem(void)
00363 {
00364 int ii, tmp, ret=0;
00365 for(ii=0; ii<num_alloced_blocks; ii++)
00366 {
00367 if((tmp=debug_verify_block(alloced_blocks[ii])))
00368 ret = tmp;
00369 }
00370 return ret;
00371 }
00372
00373
00374 int debug_verify_block(long *block)
00375 {
00376 long size = *block;
00377 int ii;
00378
00379 for(ii=1; ii<GUARD_NUM; ii++)
00380 if(block[ii] != GUARD_VAL)
00381 {
00382 panic("Clobbered negative-write guard. Block size %i, write at"
00383 " offset -%i with value %li.",
00384 (int)size, (int)((GUARD_NUM-ii)*sizeof(long)), block[ii]
00385 );
00386 return size;
00387 }
00388
00389 block += (size>>2) + GUARD_NUM;
00390 for(ii=0; ii<GUARD_NUM; ii++)
00391 if(block[ii] != GUARD_VAL)
00392 {
00393 panic("Clobbered positive write guard. Block size %i, write at"
00394 "%i past the end.", (int)size, (int)(ii*sizeof(long))
00395 );
00396 return size;
00397 }
00398 return 0;
00399 }
00400
00401
00402 void *debug_malloc(size_t S)
00403 {
00404 long *ret, *pos;
00405 size_t size;
00406 int ii;
00407
00408
00409 if(num_alloced_blocks >= 31) {
00410 panic("Runaway allocator!");
00411 return NULL;
00412 }
00413
00414
00415 size = S+3;
00416 size &= ~0x3;
00417
00418
00419 ret = malloc_throw(size + 2*GUARD_NUM*sizeof(long));
00420 if(ret==NULL)
00421 panic("Out of space!");
00422
00423
00424 *ret = size;
00425
00426
00427 for(ii=1; ii<GUARD_NUM; ii++)
00428 ret[ii] = GUARD_VAL;
00429 pos = ret+GUARD_NUM+(size>>2);
00430 for(ii=0; ii<GUARD_NUM; ii++)
00431 pos[ii] = GUARD_VAL;
00432
00433 alloced_blocks[num_alloced_blocks++] = ret;
00434
00435 return ret+GUARD_NUM;
00436 }
00437
00438
00439 void debug_free(void *ptr)
00440 {
00441 long *block = ((long*)ptr) - GUARD_NUM;
00442 long size = *block;
00443 int ii;
00444 if(size == GUARD_FREED) {
00445 panic( "Multiply freed block (size %i)", (int)size );
00446 return;
00447 }
00448
00449
00450 for(ii=0; ii<num_alloced_blocks; ii++)
00451 {
00452 if(alloced_blocks[ii] == block) {
00453 alloced_blocks[ii] = alloced_blocks[--num_alloced_blocks];
00454 break;
00455 }
00456 }
00457
00458 debug_verify_block(block);
00459 *block = GUARD_FREED;
00460 free(block);
00461 }
00462
00463
00464 void *debug_calloc(size_t N, size_t S)
00465 {
00466 size_t size = N*S;
00467 void *ret = debug_malloc(size);
00468 memset(ret, 0, size);
00469 return ret;
00470 }
00471
00472
00473 void *debug_realloc(void *ptr, size_t S)
00474 {
00475 void *ret;
00476 long *blockstart, *pos;
00477 size_t size;
00478 int ii;
00479 if(S==0) {
00480 if(ptr!=NULL)
00481 debug_free(ptr);
00482 return NULL;
00483 }
00484 if(ptr==NULL)
00485 return debug_malloc(S);
00486
00487 blockstart = ((long*)ptr) - GUARD_NUM;
00488 ret = debug_malloc(S);
00489 memcpy(ret, ptr, *blockstart);
00490 debug_free(ptr);
00491 return ret;
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 }
00507
00508 #endif
00509