1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
   2: /* hack.pri.c - version 1.0.3 */
   3: 
   4: #include "hack.h"
   5: #include <stdio.h>
   6: xchar scrlx, scrhx, scrly, scrhy;   /* corners of new area on screen */
   7: 
   8: extern char *hu_stat[]; /* in eat.c */
   9: extern char *CD;
  10: 
  11: swallowed()
  12: {
  13:     char *ulook = "|@|";
  14:     ulook[1] = u.usym;
  15: 
  16:     cls();
  17:     curs(u.ux-1, u.uy+1);
  18:     fputs("/-\\", stdout);
  19:     curx = u.ux+2;
  20:     curs(u.ux-1, u.uy+2);
  21:     fputs(ulook, stdout);
  22:     curx = u.ux+2;
  23:     curs(u.ux-1, u.uy+3);
  24:     fputs("\\-/", stdout);
  25:     curx = u.ux+2;
  26:     u.udispl = 1;
  27:     u.udisx = u.ux;
  28:     u.udisy = u.uy;
  29: }
  30: 
  31: 
  32: /*VARARGS1*/
  33: boolean panicking;
  34: 
  35: panic(str,a1,a2,a3,a4,a5,a6)
  36: char *str;
  37: {
  38:     if(panicking++) exit(1);    /* avoid loops - this should never happen*/
  39:     home();
  40:     puts(" Suddenly, the dungeon collapses.");
  41:     fputs(" ERROR:  ", stdout);
  42:     printf(str,a1,a2,a3,a4,a5,a6);
  43: #ifdef DEBUG
  44: #ifdef UNIX
  45:     if(!fork())
  46:         abort();    /* generate core dump */
  47: #endif UNIX
  48: #endif DEBUG
  49:     more();         /* contains a fflush() */
  50:     done("panicked");
  51: }
  52: 
  53: atl(x,y,ch)
  54: register x,y;
  55: {
  56:     register struct rm *crm = &levl[x][y];
  57: 
  58:     if(x<0 || x>COLNO-1 || y<0 || y>ROWNO-1){
  59:         impossible("atl(%d,%d,%c)",x,y,ch);
  60:         return;
  61:     }
  62:     if(crm->seen && crm->scrsym == ch) return;
  63:     crm->scrsym = ch;
  64:     crm->new = 1;
  65:     on_scr(x,y);
  66: }
  67: 
  68: on_scr(x,y)
  69: register x,y;
  70: {
  71:     if(x < scrlx) scrlx = x;
  72:     if(x > scrhx) scrhx = x;
  73:     if(y < scrly) scrly = y;
  74:     if(y > scrhy) scrhy = y;
  75: }
  76: 
  77: /* call: (x,y) - display
  78: 	(-1,0) - close (leave last symbol)
  79: 	(-1,-1)- close (undo last symbol)
  80: 	(-1,let)-open: initialize symbol
  81: 	(-2,let)-change let
  82: */
  83: 
  84: tmp_at(x,y) schar x,y; {
  85: static schar prevx, prevy;
  86: static char let;
  87:     if((int)x == -2){   /* change let call */
  88:         let = y;
  89:         return;
  90:     }
  91:     if((int)x == -1 && (int)y >= 0){    /* open or close call */
  92:         let = y;
  93:         prevx = -1;
  94:         return;
  95:     }
  96:     if(prevx >= 0 && cansee(prevx,prevy)) {
  97:         delay_output();
  98:         prl(prevx, prevy);  /* in case there was a monster */
  99:         at(prevx, prevy, levl[prevx][prevy].scrsym);
 100:     }
 101:     if(x >= 0){ /* normal call */
 102:         if(cansee(x,y)) at(x,y,let);
 103:         prevx = x;
 104:         prevy = y;
 105:     } else {    /* close call */
 106:         let = 0;
 107:         prevx = -1;
 108:     }
 109: }
 110: 
 111: /* like the previous, but the symbols are first erased on completion */
 112: Tmp_at(x,y) schar x,y; {
 113: static char let;
 114: static xchar cnt;
 115: static coord tc[COLNO];     /* but watch reflecting beams! */
 116: register xx,yy;
 117:     if((int)x == -1) {
 118:         if(y > 0) { /* open call */
 119:             let = y;
 120:             cnt = 0;
 121:             return;
 122:         }
 123:         /* close call (do not distinguish y==0 and y==-1) */
 124:         while(cnt--) {
 125:             xx = tc[cnt].x;
 126:             yy = tc[cnt].y;
 127:             prl(xx, yy);
 128:             at(xx, yy, levl[xx][yy].scrsym);
 129:         }
 130:         cnt = let = 0;  /* superfluous */
 131:         return;
 132:     }
 133:     if((int)x == -2) {  /* change let call */
 134:         let = y;
 135:         return;
 136:     }
 137:     /* normal call */
 138:     if(cansee(x,y)) {
 139:         if(cnt) delay_output();
 140:         at(x,y,let);
 141:         tc[cnt].x = x;
 142:         tc[cnt].y = y;
 143:         if(++cnt >= COLNO) panic("Tmp_at overflow?");
 144:         levl[x][y].new = 0; /* prevent pline-nscr erasing --- */
 145:     }
 146: }
 147: 
 148: setclipped(){
 149:     error("Hack needs a screen of size at least %d by %d.\n",
 150:         ROWNO+2, COLNO);
 151: }
 152: 
 153: at(x,y,ch)
 154: register xchar x,y;
 155: char ch;
 156: {
 157: #ifndef lint
 158:     /* if xchar is unsigned, lint will complain about  if(x < 0)  */
 159:     if(x < 0 || x > COLNO-1 || y < 0 || y > ROWNO-1) {
 160:         impossible("At gets 0%o at %d %d.", ch, x, y);
 161:         return;
 162:     }
 163: #endif lint
 164:     if(!ch) {
 165:         impossible("At gets null at %d %d.", x, y);
 166:         return;
 167:     }
 168:     y += 2;
 169:     curs(x,y);
 170:     (void) putchar(ch);
 171:     curx++;
 172: }
 173: 
 174: prme(){
 175:     if(!Invisible) at(u.ux,u.uy,u.usym);
 176: }
 177: 
 178: doredraw()
 179: {
 180:     docrt();
 181:     return(0);
 182: }
 183: 
 184: docrt()
 185: {
 186:     register x,y;
 187:     register struct rm *room;
 188:     register struct monst *mtmp;
 189: 
 190:     if(u.uswallow) {
 191:         swallowed();
 192:         return;
 193:     }
 194:     cls();
 195: 
 196: /* Some ridiculous code to get display of @ and monsters (almost) right */
 197:     if(!Invisible) {
 198:         levl[(u.udisx = u.ux)][(u.udisy = u.uy)].scrsym = u.usym;
 199:         levl[u.udisx][u.udisy].seen = 1;
 200:         u.udispl = 1;
 201:     } else  u.udispl = 0;
 202: 
 203:     seemons();  /* reset old positions */
 204:     for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
 205:         mtmp->mdispl = 0;
 206:     seemons();  /* force new positions to be shown */
 207: /* This nonsense should disappear soon --------------------------------- */
 208: 
 209:     for(y = 0; y < ROWNO; y++)
 210:         for(x = 0; x < COLNO; x++)
 211:             if((room = &levl[x][y])->new) {
 212:                 room->new = 0;
 213:                 at(x,y,room->scrsym);
 214:             } else if(room->seen)
 215:                 at(x,y,room->scrsym);
 216:     scrlx = COLNO;
 217:     scrly = ROWNO;
 218:     scrhx = scrhy = 0;
 219:     flags.botlx = 1;
 220:     bot();
 221: }
 222: 
 223: docorner(xmin,ymax) register xmin,ymax; {
 224:     register x,y;
 225:     register struct rm *room;
 226:     register struct monst *mtmp;
 227: 
 228:     if(u.uswallow) {    /* Can be done more efficiently */
 229:         swallowed();
 230:         return;
 231:     }
 232: 
 233:     seemons();  /* reset old positions */
 234:     for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
 235:         if(mtmp->mx >= xmin && mtmp->my < ymax)
 236:         mtmp->mdispl = 0;
 237:     seemons();  /* force new positions to be shown */
 238: 
 239:     for(y = 0; y < ymax; y++) {
 240:         if(y > ROWNO && CD) break;
 241:         curs(xmin,y+2);
 242:         cl_end();
 243:         if(y < ROWNO) {
 244:             for(x = xmin; x < COLNO; x++) {
 245:             if((room = &levl[x][y])->new) {
 246:                 room->new = 0;
 247:                 at(x,y,room->scrsym);
 248:             } else
 249:                 if(room->seen)
 250:                     at(x,y,room->scrsym);
 251:             }
 252:         }
 253:     }
 254:     if(ymax > ROWNO) {
 255:         cornbot(xmin-1);
 256:         if(ymax > ROWNO+1 && CD) {
 257:             curs(1,ROWNO+3);
 258:             cl_eos();
 259:         }
 260:     }
 261: }
 262: 
 263: curs_on_u(){
 264:     curs(u.ux, u.uy+2);
 265: }
 266: 
 267: pru()
 268: {
 269:     if(u.udispl && (Invisible || u.udisx != u.ux || u.udisy != u.uy))
 270:         /* if(! levl[u.udisx][u.udisy].new) */
 271:             if(!vism_at(u.udisx, u.udisy))
 272:                 newsym(u.udisx, u.udisy);
 273:     if(Invisible) {
 274:         u.udispl = 0;
 275:         prl(u.ux,u.uy);
 276:     } else
 277:     if(!u.udispl || u.udisx != u.ux || u.udisy != u.uy) {
 278:         atl(u.ux, u.uy, u.usym);
 279:         u.udispl = 1;
 280:         u.udisx = u.ux;
 281:         u.udisy = u.uy;
 282:     }
 283:     levl[u.ux][u.uy].seen = 1;
 284: }
 285: 
 286: #ifndef NOWORM
 287: #include    "def.wseg.h"
 288: extern struct wseg *m_atseg;
 289: #endif NOWORM
 290: 
 291: /* print a position that is visible for @ */
 292: prl(x,y)
 293: {
 294:     register struct rm *room;
 295:     register struct monst *mtmp;
 296:     register struct obj *otmp;
 297: 
 298:     if(x == u.ux && y == u.uy && (!Invisible)) {
 299:         pru();
 300:         return;
 301:     }
 302:     if(!isok(x,y)) return;
 303:     room = &levl[x][y];
 304:     if((!room->typ) ||
 305:        (IS_ROCK(room->typ) && levl[u.ux][u.uy].typ == CORR))
 306:         return;
 307:     if((mtmp = m_at(x,y)) && !mtmp->mhide &&
 308:         (!mtmp->minvis || See_invisible)) {
 309: #ifndef NOWORM
 310:         if(m_atseg)
 311:             pwseg(m_atseg);
 312:         else
 313: #endif NOWORM
 314:         pmon(mtmp);
 315:     }
 316:     else if((otmp = o_at(x,y)) && room->typ != POOL)
 317:         atl(x,y,otmp->olet);
 318:     else if(mtmp && (!mtmp->minvis || See_invisible)) {
 319:         /* must be a hiding monster, but not hiding right now */
 320:         /* assume for the moment that long worms do not hide */
 321:         pmon(mtmp);
 322:     }
 323:     else if(g_at(x,y) && room->typ != POOL)
 324:         atl(x,y,'$');
 325:     else if(!room->seen || room->scrsym == ' ') {
 326:         room->new = room->seen = 1;
 327:         newsym(x,y);
 328:         on_scr(x,y);
 329:     }
 330:     room->seen = 1;
 331: }
 332: 
 333: char
 334: news0(x,y)
 335: register xchar x,y;
 336: {
 337:     register struct obj *otmp;
 338:     register struct trap *ttmp;
 339:     struct rm *room;
 340:     register char tmp;
 341: 
 342:     room = &levl[x][y];
 343:     if(!room->seen) tmp = ' ';
 344:     else if(room->typ == POOL) tmp = POOL_SYM;
 345:     else if(!Blind && (otmp = o_at(x,y))) tmp = otmp->olet;
 346:     else if(!Blind && g_at(x,y)) tmp = '$';
 347:     else if(x == xupstair && y == yupstair) tmp = '<';
 348:     else if(x == xdnstair && y == ydnstair) tmp = '>';
 349:     else if((ttmp = t_at(x,y)) && ttmp->tseen) tmp = '^';
 350:     else switch(room->typ) {
 351:     case SCORR:
 352:     case SDOOR:
 353:         tmp = room->scrsym; /* %% wrong after killing mimic ! */
 354:         break;
 355:     case HWALL:
 356:         tmp = '-';
 357:         break;
 358:     case VWALL:
 359:         tmp = '|';
 360:         break;
 361:     case LDOOR:
 362:     case DOOR:
 363:         tmp = '+';
 364:         break;
 365:     case CORR:
 366:         tmp = CORR_SYM;
 367:         break;
 368:     case ROOM:
 369:         if(room->lit || cansee(x,y) || Blind) tmp = '.';
 370:         else tmp = ' ';
 371:         break;
 372: /*
 373: 	case POOL:
 374: 		tmp = POOL_SYM;
 375: 		break;
 376: */
 377:     default:
 378:         tmp = ERRCHAR;
 379:     }
 380:     return(tmp);
 381: }
 382: 
 383: newsym(x,y)
 384: register x,y;
 385: {
 386:     atl(x,y,news0(x,y));
 387: }
 388: 
 389: /* used with wand of digging (or pick-axe): fill scrsym and force display */
 390: /* also when a POOL evaporates */
 391: mnewsym(x,y)
 392: register x,y;
 393: {
 394:     register struct rm *room;
 395:     char newscrsym;
 396: 
 397:     if(!vism_at(x,y)) {
 398:         room = &levl[x][y];
 399:         newscrsym = news0(x,y);
 400:         if(room->scrsym != newscrsym) {
 401:             room->scrsym = newscrsym;
 402:             room->seen = 0;
 403:         }
 404:     }
 405: }
 406: 
 407: nosee(x,y)
 408: register x,y;
 409: {
 410:     register struct rm *room;
 411: 
 412:     if(!isok(x,y)) return;
 413:     room = &levl[x][y];
 414:     if(room->scrsym == '.' && !room->lit && !Blind) {
 415:         room->scrsym = ' ';
 416:         room->new = 1;
 417:         on_scr(x,y);
 418:     }
 419: }
 420: 
 421: #ifndef QUEST
 422: prl1(x,y)
 423: register x,y;
 424: {
 425:     if(u.dx) {
 426:         if(u.dy) {
 427:             prl(x-(2*u.dx),y);
 428:             prl(x-u.dx,y);
 429:             prl(x,y);
 430:             prl(x,y-u.dy);
 431:             prl(x,y-(2*u.dy));
 432:         } else {
 433:             prl(x,y-1);
 434:             prl(x,y);
 435:             prl(x,y+1);
 436:         }
 437:     } else {
 438:         prl(x-1,y);
 439:         prl(x,y);
 440:         prl(x+1,y);
 441:     }
 442: }
 443: 
 444: nose1(x,y)
 445: register x,y;
 446: {
 447:     if(u.dx) {
 448:         if(u.dy) {
 449:             nosee(x,u.uy);
 450:             nosee(x,u.uy-u.dy);
 451:             nosee(x,y);
 452:             nosee(u.ux-u.dx,y);
 453:             nosee(u.ux,y);
 454:         } else {
 455:             nosee(x,y-1);
 456:             nosee(x,y);
 457:             nosee(x,y+1);
 458:         }
 459:     } else {
 460:         nosee(x-1,y);
 461:         nosee(x,y);
 462:         nosee(x+1,y);
 463:     }
 464: }
 465: #endif QUEST
 466: 
 467: vism_at(x,y)
 468: register x,y;
 469: {
 470:     register struct monst *mtmp;
 471: 
 472:     return((x == u.ux && y == u.uy && !Invisible)
 473:             ? 1 :
 474:            (mtmp = m_at(x,y))
 475:             ? ((Blind && Telepat) || canseemon(mtmp)) :
 476:         0);
 477: }
 478: 
 479: #ifdef NEWSCR
 480: pobj(obj) register struct obj *obj; {
 481: register int show = (!obj->oinvis || See_invisible) &&
 482:         cansee(obj->ox,obj->oy);
 483:     if(obj->odispl){
 484:         if(obj->odx != obj->ox || obj->ody != obj->oy || !show)
 485:         if(!vism_at(obj->odx,obj->ody)){
 486:             newsym(obj->odx, obj->ody);
 487:             obj->odispl = 0;
 488:         }
 489:     }
 490:     if(show && !vism_at(obj->ox,obj->oy)){
 491:         atl(obj->ox,obj->oy,obj->olet);
 492:         obj->odispl = 1;
 493:         obj->odx = obj->ox;
 494:         obj->ody = obj->oy;
 495:     }
 496: }
 497: #endif NEWSCR
 498: 
 499: unpobj(obj) register struct obj *obj; {
 500: /* 	if(obj->odispl){
 501: 		if(!vism_at(obj->odx, obj->ody))
 502: 			newsym(obj->odx, obj->ody);
 503: 		obj->odispl = 0;
 504: 	}
 505: */
 506:     if(!vism_at(obj->ox,obj->oy))
 507:         newsym(obj->ox,obj->oy);
 508: }
 509: 
 510: seeobjs(){
 511: register struct obj *obj, *obj2;
 512:     for(obj = fobj; obj; obj = obj2) {
 513:         obj2 = obj->nobj;
 514:         if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
 515:             && obj->age + 250 < moves)
 516:                 delobj(obj);
 517:     }
 518:     for(obj = invent; obj; obj = obj2) {
 519:         obj2 = obj->nobj;
 520:         if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
 521:             && obj->age + 250 < moves)
 522:                 useup(obj);
 523:     }
 524: }
 525: 
 526: seemons(){
 527: register struct monst *mtmp;
 528:     for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
 529:         if(mtmp->data->mlet == ';')
 530:             mtmp->minvis = (u.ustuck != mtmp &&
 531:                     levl[mtmp->mx][mtmp->my].typ == POOL);
 532:         pmon(mtmp);
 533: #ifndef NOWORM
 534:         if(mtmp->wormno) wormsee(mtmp->wormno);
 535: #endif NOWORM
 536:     }
 537: }
 538: 
 539: pmon(mon) register struct monst *mon; {
 540: register int show = (Blind && Telepat) || canseemon(mon);
 541:     if(mon->mdispl){
 542:         if(mon->mdx != mon->mx || mon->mdy != mon->my || !show)
 543:             unpmon(mon);
 544:     }
 545:     if(show && !mon->mdispl){
 546:         atl(mon->mx,mon->my,
 547:          (!mon->mappearance
 548:           || u.uprops[PROP(RIN_PROTECTION_FROM_SHAPE_CHANGERS)].p_flgs
 549:          ) ? mon->data->mlet : mon->mappearance);
 550:         mon->mdispl = 1;
 551:         mon->mdx = mon->mx;
 552:         mon->mdy = mon->my;
 553:     }
 554: }
 555: 
 556: unpmon(mon) register struct monst *mon; {
 557:     if(mon->mdispl){
 558:         newsym(mon->mdx, mon->mdy);
 559:         mon->mdispl = 0;
 560:     }
 561: }
 562: 
 563: nscr()
 564: {
 565:     register x,y;
 566:     register struct rm *room;
 567: 
 568:     if(u.uswallow || u.ux == FAR || flags.nscrinh) return;
 569:     pru();
 570:     for(y = scrly; y <= scrhy; y++)
 571:         for(x = scrlx; x <= scrhx; x++)
 572:             if((room = &levl[x][y])->new) {
 573:                 room->new = 0;
 574:                 at(x,y,room->scrsym);
 575:             }
 576:     scrhx = scrhy = 0;
 577:     scrlx = COLNO;
 578:     scrly = ROWNO;
 579: }
 580: 
 581: /* 100 suffices for bot(); no relation with COLNO */
 582: char oldbot[100], newbot[100];
 583: cornbot(lth)
 584: register int lth;
 585: {
 586:     if(lth < sizeof(oldbot)) {
 587:         oldbot[lth] = 0;
 588:         flags.botl = 1;
 589:     }
 590: }
 591: 
 592: bot()
 593: {
 594: register char *ob = oldbot, *nb = newbot;
 595: register int i;
 596: extern char *eos();
 597:     if(flags.botlx) *ob = 0;
 598:     flags.botl = flags.botlx = 0;
 599: #ifdef GOLD_ON_BOTL
 600:     (void) sprintf(newbot,
 601:         "Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Str ",
 602:         dlevel, u.ugold, u.uhp, u.uhpmax, u.uac);
 603: #else
 604:     (void) sprintf(newbot,
 605:         "Level %-2d   Hp %3d(%d)   Ac %-2d   Str ",
 606:         dlevel,  u.uhp, u.uhpmax, u.uac);
 607: #endif GOLD_ON_BOTL
 608:     if(u.ustr>18) {
 609:         if(u.ustr>117)
 610:         (void) strcat(newbot,"18/**");
 611:         else
 612:         (void) sprintf(eos(newbot), "18/%02d",u.ustr-18);
 613:     } else
 614:         (void) sprintf(eos(newbot), "%-2d   ",u.ustr);
 615: #ifdef EXP_ON_BOTL
 616:     (void) sprintf(eos(newbot), "  Exp %2d/%-5lu ", u.ulevel,u.uexp);
 617: #else
 618:     (void) sprintf(eos(newbot), "   Exp %2u  ", u.ulevel);
 619: #endif EXP_ON_BOTL
 620:     (void) strcat(newbot, hu_stat[u.uhs]);
 621:     if(flags.time)
 622:         (void) sprintf(eos(newbot), "  %ld", moves);
 623:     if(strlen(newbot) >= COLNO) {
 624:         register char *bp0, *bp1;
 625:         bp0 = bp1 = newbot;
 626:         do {
 627:             if(*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
 628:                 *bp1++ = *bp0;
 629:         } while(*bp0++);
 630:     }
 631:     for(i = 1; i<COLNO; i++) {
 632:         if(*ob != *nb){
 633:             curs(i,ROWNO+2);
 634:             (void) putchar(*nb ? *nb : ' ');
 635:             curx++;
 636:         }
 637:         if(*ob) ob++;
 638:         if(*nb) nb++;
 639:     }
 640:     (void) strcpy(oldbot, newbot);
 641: }
 642: 
 643: #ifdef WAN_PROBING
 644: mstatusline(mtmp) register struct monst *mtmp; {
 645:     pline("Status of %s: ", monnam(mtmp));
 646:     pline("Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Dam %d",
 647:         mtmp->data->mlevel, mtmp->mgold, mtmp->mhp, mtmp->mhpmax,
 648:         mtmp->data->ac, (mtmp->data->damn + 1) * (mtmp->data->damd + 1));
 649: }
 650: #endif WAN_PROBING
 651: 
 652: cls(){
 653:     if(flags.toplin == 1)
 654:         more();
 655:     flags.toplin = 0;
 656: 
 657:     clear_screen();
 658: 
 659:     flags.botlx = 1;
 660: }

Defined functions

Tmp_at defined in line 112; used 11 times
at defined in line 153; used 15 times
bot defined in line 592; used 3 times
cornbot defined in line 583; used 1 times
curs_on_u defined in line 263; used 1 times
doredraw defined in line 178; used 2 times
mstatusline defined in line 644; used 1 times
news0 defined in line 333; used 4 times
nose1 defined in line 444; used 2 times
nosee defined in line 407; used 12 times
nscr defined in line 563; used 2 times
pobj defined in line 480; never used
prl1 defined in line 422; used 3 times
pru defined in line 267; used 6 times
seemons defined in line 526; used 6 times
seeobjs defined in line 510; used 2 times
setclipped defined in line 148; used 1 times
swallowed defined in line 11; used 3 times
tmp_at defined in line 84; used 13 times
vism_at defined in line 467; used 7 times

Defined variables

newbot defined in line 582; used 13 times
oldbot defined in line 582; used 4 times
panicking defined in line 33; used 1 times
  • in line 38
scrhx defined in line 6; used 5 times
scrhy defined in line 6; used 5 times
scrlx defined in line 6; used 5 times
scrly defined in line 6; used 5 times
Last modified: 1985-10-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4635
Valid CSS Valid XHTML 1.0 Strict