/************************************************************************** * # # # ## # # ### ## ## ### http://www.lyonesse.it * * # # # # # ## # # # # # * * # # # # # ## ## # # ## ## ## # # ## * * # # # # # ## # # # # # # # # # # # * * ### # ## # # ### ## ## ### # # #### ## Ver. 1.0 * * * * -Based on CircleMud & Smaug- Copyright (c) 2001-2002 by Mithrandir * * * * ********************************************************************** * * * * File: wild.info.c * * * * Code for survey, track, scan, and all wild information related funcs * * Code for portal stones * * Code for camping * * * **************************************************************************/ #include "conf.h" #include "sysdep.h" #include <math.h> #include "structs.h" #include "utils.h" #include "comm.h" #include "db.h" #include "interpreter.h" #include "handler.h" #include "constants.h" extern TIME_INFO_DATA time_info; /* external funcs */ ROOM_DATA *create_wild_room(COORD_DATA *coord, bool Static); WEATHER_DATA *get_coord_weather(COORD_DATA *coord); int list_scanned_chars_to_char(CHAR_DATA *list, CHAR_DATA *ch, int dir, int dist); void show_ship_on_map(CHAR_DATA *ch); /* locals */ ACMD(do_camp); EVENTFUNC(camp_event); /* globals */ PSTONE_DATA *first_pstone = NULL; PSTONE_DATA *last_pstone = NULL; /* *************************************************************** */ /* M A T H */ /* *************************************************************** */ double distance(int chX, int chY, int lmX, int lmY) { double xchange, ychange, distance; xchange = (chX - lmX); xchange *= xchange; ychange = (chY - lmY); ychange *= ychange; distance = sqrt((xchange + ychange)); return (distance); } int calc_angle(int chX, int chY, int lmX, int lmY, int *ipDist) { double dDist1, dDist2, dTandeg, dDeg; int iNx1 = 0, iNy1 = 0, iNx2, iNy2, iNx3, iNy3, iFinal; iNx2 = lmX - chX; iNy2 = lmY - chY; iNx3 = 0; iNy3 = iNy2; *ipDist = (int) distance( iNx1, iNy1, iNx2, iNy2 ); if ( iNx2 == 0 && iNy2 == 0 ) return ( -1 ); if ( iNx2 == 0 && iNy2 > 0 ) return ( 180 ); if ( iNx2 == 0 && iNy2 < 0 ) return ( 0 ); if ( iNy2 == 0 && iNx2 > 0 ) return ( 90 ); if ( iNy2 == 0 && iNx2 < 0 ) return ( 270 ); /* ADJACENT */ dDist1 = distance( iNx1, iNy1, iNx3, iNy3 ); /* OPPOSITE */ dDist2 = distance( iNx3, iNy3, iNx2, iNy2 ); dTandeg = dDist2 / dDist1; dDeg = atan(dTandeg); iFinal = ( dDeg * 180 ) / 3.14159265358979323846; if ( iNx2 > 0 && iNy2 > 0 ) return ( ( 90 + ( 90 - iFinal ) ) ); if ( iNx2 > 0 && iNy2 < 0 ) return ( iFinal ); if ( iNx2 < 0 && iNy2 > 0 ) return ( ( 180 + iFinal ) ); if ( iNx2 < 0 && iNy2 < 0 ) return ( ( 270 + ( 90 - iFinal ) ) ); return ( -1 ); } int clock_to_dir( int oclock ) { if ( oclock == 12 ) return (NORTH); if ( oclock == 6 ) return (SOUTH); if ( oclock == 3 ) return (EAST); if ( oclock == 9 ) return (WEST); if ( oclock == 10 || oclock == 11 ) return (NORTHWEST); if ( oclock == 2 || oclock == 1 ) return (NORTHEAST); if ( oclock == 4 || oclock == 5 ) return (SOUTHEAST); if ( oclock == 7 || oclock == 8 ) return (SOUTHWEST); return (NOWHERE); } int angle_to_dir( int iAngle ) { int cDir; if (iAngle == -1) cDir = 13; else if (iAngle >= 360) cDir = 12; else if (iAngle >= 330) cDir = 11; else if (iAngle >= 300) cDir = 10; else if (iAngle >= 270) cDir = 9; else if (iAngle >= 240) cDir = 8; else if (iAngle >= 210) cDir = 7; else if (iAngle >= 180) cDir = 6; else if (iAngle >= 150) cDir = 5; else if (iAngle >= 120) cDir = 4; else if (iAngle >= 90) cDir = 3; else if (iAngle >= 60) cDir = 2; else if (iAngle >= 30) cDir = 1; else cDir = 12; return (cDir); } int distance_to_index( int iDist ) { int iMes; if (iDist > 200) iMes = 0; else if (iDist > 150) iMes = 1; else if (iDist > 100) iMes = 2; else if (iDist > 75) iMes = 3; else if (iDist > 50) iMes = 4; else if (iDist > 25) iMes = 5; else if (iDist > 15) iMes = 6; else if (iDist > 10) iMes = 7; else if (iDist > 5) iMes = 8; else if (iDist > 1) iMes = 9; else iMes = 10; return (iMes); } /* =================================================== */ /* S U R V E Y */ /* =================================================== */ ACMD(do_survey) { SURVEY_DATA *sd; bool count = FALSE; int ry, rx, iDist, iAngle, dmes, ames; if (!IN_WILD(ch) && !ON_DECK(ch) && !IN_FERRY(ch)) { send_to_char("You can use survey only in the wilderness.\r\n", ch); return; } if (AFF_FLAGGED(ch, AFF_BLIND)) { send_to_char("You can't see a damn thing, you're blind!\r\n", ch); return; } /* * survey called from a ship deck shows only * ships around */ if (ON_DECK(ch)) { show_ship_on_map(ch); return; } else if (IN_FERRY(ch)) { FERRY_DATA *pFerry = get_ferry(ch->in_room->extra_data->vnum); ry = GET_RY(pFerry->in_room); rx = GET_RX(pFerry->in_room); } else { ry = GET_RY(ch->in_room); rx = GET_RX(ch->in_room); } for ( sd = survey_table; sd; sd = sd->next ) { iDist = (int) distance(rx, ry, sd->coord->x, sd->coord->y); if ( iDist > MAX_SURVEY_DIST ) continue; count = TRUE; iAngle = calc_angle( rx, ry, sd->coord->x, sd->coord->y, &iDist ); ames = angle_to_dir( iAngle ); dmes = distance_to_index( iDist ); if ( dmes == 13) sprintf(buf,"In the immediate area, %s\r\n", sd->descriz ? sd->descriz : "<NULL PLEASE REPORT>"); else sprintf(buf,"At %d o'clock, %s %s\r\n", ames, dist_descr[(int) dmes], sd->descriz ? sd->descriz : "<NULL PLEASE REPORT>"); send_to_char(buf,ch); } if ( !count ) send_to_char("You don't see anything nearby.\r\n", ch); } /* =================================================== */ /* T R A C K */ /* =================================================== */ int wild_track( CHAR_DATA *ch, CHAR_DATA *vict, bool silent ) { int dist, angle, dir; /* safeguard */ if ( !ch || !vict ) return (NOWHERE); angle = calc_angle( GET_X(ch), GET_Y(ch), GET_X(vict), GET_Y(vict), &dist ); if ( dist > MAX_TRACK_DIST ) { if ( !silent ) send_to_char("You sense no trail.\r\n", ch); return (NOWHERE); } dir = clock_to_dir(angle_to_dir(angle)); if ( dir == 13 ) dir = NOWHERE; if ( !silent ) ch_printf(ch, "You sense a trail %s%s&0 from here!\r\n", exits_color[dir], dirs[dir]); return (dir); } int get_sail_dir( SHIP_DATA *ship, COORD_DATA *cto, bool silent ) { int iDist, iAngle, iDir; iDist = (int) distance( GET_X(ship), GET_Y(ship), cto->x, cto->y ); /* if (iDist > MAX_SAIL_DIST) { if ( SHIP_FLAGGED(ship, SHIP_IN_COURSE ) ) log("SYSERR: get_sail_dir() - next step (%d %d) is too far [%d].", cto->y, cto->x, iDist); if ( !silent && ship->helmperson ) send_to_char("You fail to follow the course.\r\n", ship->helmperson ); return (NOWHERE); } */ iAngle = calc_angle( GET_X(ship), GET_Y(ship), cto->x, cto->y, &iDist ); iDir = clock_to_dir(angle_to_dir(iAngle)); if ( iDir < 0 || iDir > NUM_OF_DIRS ) iDir = NOWHERE; return (iDir); } /* =================================================== */ /* S C A N */ /* =================================================== */ void wild_scan(CHAR_DATA *ch) { COORD_DATA curr, real; ROOM_DATA *pRoom; int chy, chx; int x, y, xmax, ymax, xmin, ymin; int iDist, radius, modx, mody, dir; int count = 0; x = y = xmax = ymax = xmin = ymin = 0; chy = GET_Y(ch); chx = GET_X(ch); mody = MOD_SMALL_Y + 1; modx = MOD_SMALL_X + 1; if (PRF_FLAGGED(ch, PRF_WILDSMALL)) radius = MAX_SCAN_DIST - 2; else { WEATHER_DATA *sky = get_coord_weather(ch->in_room->coord); radius = MAX_SCAN_DIST; if (IS_MORTAL(ch)) { /* modifica raggio visivo in base all'ora... */ if (time_info.hours < 6 || time_info.hours > 21) { radius -= 2; if (Sunlight == MOON_LIGHT) { if (MoonPhase < 2 || MoonPhase > 6) radius -= 1; else if (MoonPhase == MOON_FULL) radius += 1; } } /* ... e al tempo atmosferico */ if (sky->precip_rate > 50) radius -= 2; else if (sky->precip_rate > 20) radius -= 1; radius = URANGE(1, radius, MAX_SCAN_DIST); } } y = abs(chy - (chy / MAP_SIZE * MAP_SIZE)) + MAP_SIZE; x = abs(chx - (chx / MAP_SIZE * MAP_SIZE)) + MAP_SIZE; ymin = y - mody; ymax = y + mody; xmin = x - modx; xmax = x + modx; real.y = chy - mody; for (curr.y = ymin; curr.y < ymax + 1; curr.y++, real.y++) { real.x = chx - modx; for (curr.x = xmin; curr.x < xmax + 1; curr.x++, real.x++) { if ((iDist = distance(x, y, curr.x, curr.y)) > radius) continue; if (!(pRoom = get_wild_room(&real))) continue; if (!pRoom->people) continue; if ((dir = wild_track(ch, pRoom->people, TRUE)) == NOWHERE) continue; count += list_scanned_chars_to_char(pRoom->people, ch, dir, iDist); } } if (count == 0) send_to_char("You don't see anyone nearby.\r\n", ch); } /* =================================================== */ /* Portal Stone Code */ /* =================================================== */ PSTONE_DATA *get_pstone( int vnum ) { PSTONE_DATA *pstone; for ( pstone = first_pstone; pstone; pstone = pstone->next ) { if ( vnum == pstone->vnum ) break; } return (pstone); } PSTONE_DATA *get_pstone_by_name( char *pname ) { PSTONE_DATA *pstone; for ( pstone = first_pstone; pstone; pstone = pstone->next ) { if ( isname( pname, pstone->name ) ) break; } return (pstone); } PSTONE_DATA *get_pstone_by_coord( COORD_DATA *coord ) { PSTONE_DATA *pstone; for ( pstone = first_pstone; pstone; pstone = pstone->next ) { if ( coord->y == pstone->coord.y && coord->x == pstone->coord.x ) break; } return (pstone); } void show_travel( CHAR_DATA *ch ) { int pn; if ( !ch->in_room->portal_stone ) { send_to_char("You can't Travel if in room there isn't a portal stone.\r\n", ch); return; } ch_printf(ch, "From the portal stone '&b&1%s&0' you can Travel to:\r\n", ch->in_room->portal_stone->name); for ( pn = 0; pn < MAX_LNK_STONE; pn++ ) { if ( ch->in_room->portal_stone->link_to[pn] ) { PSTONE_DATA *pstone = get_pstone(ch->in_room->portal_stone->link_to[pn]); if ( pstone ) ch_printf(ch, "[%d] &b&1%-25s&0\t Keyword: %-15s\t Coord: %d %d\r\n", pstone->vnum, pstone->short_descr, pstone->name, pstone->coord.y, pstone->coord.x); } } } void stone_travel( CHAR_DATA *ch, char *argument ) { PSTONE_DATA *pstone; ROOM_DATA *pRoom; char arg[MAX_STRING_LENGTH]; int pn; one_argument( argument, arg ); if ( !*arg ) { show_travel(ch); return; } if ( !ch->in_room->portal_stone ) { send_to_char("You can't Travel if in room there isn't a portal stone.\r\n", ch); return; } if ( !(pstone = get_pstone_by_name(arg)) ) { ch_printf(ch, "In this world there isn't a portal stone called '%s'.\r\n", arg); return; } for ( pn = 0; pn < MAX_LNK_STONE; pn++ ) { if ( ch->in_room->portal_stone->link_to[pn] == pstone->vnum ) break; } if ( pn >= MAX_LNK_STONE ) { ch_printf(ch, "You can't Travel to '%s' from here.\r\n", arg); return; } if ( !( pRoom = get_wild_room( &pstone->coord ) ) ) pRoom = create_wild_room( &pstone->coord, FALSE ); if ( !pRoom->portal_stone ) pRoom->portal_stone = pstone; act("As you touch the portal stone, a flash of pure white light surrounds you, and you Travel...", FALSE, ch, NULL, NULL, TO_CHAR); act("As $n touch the portal stone, a flash of pure white light surrounds $m, and $s Travel...", FALSE, ch, NULL, NULL, TO_ROOM); char_from_room(ch); char_to_room(ch, pRoom); // transport mount too if ( RIDING(ch) ) { char_from_room(RIDING(ch)); char_to_room(RIDING(ch), pRoom); } // transport vehicle too else if (WAGONER(ch)) { vehicle_from_room(WAGONER(ch)); vehicle_to_room(WAGONER(ch), ch->in_room); } act("You arrive at your destination, and suddenly loose your grip to realty...", FALSE, ch, NULL, NULL, TO_CHAR); act("$n suddenly appears from nowhere, lying here unconscious...", FALSE, ch, NULL, NULL, TO_ROOM); if ( IS_MORTAL(ch) ) GET_POS(ch) = POS_STUNNED; else look_at_room(ch, TRUE); } ACMD(do_travel) { stone_travel(ch, argument); } /* ************************************************************ */ PSTONE_DATA *new_pstone( void ) { PSTONE_DATA *pstone; int pn; CREATE(pstone, PSTONE_DATA, 1); pstone->next = NULL; pstone->prev = NULL; pstone->name = NULL; pstone->short_descr = NULL; pstone->description = NULL; pstone->vnum = NOTHING; for ( pn = 0; pn < MAX_LNK_STONE; pn++ ) pstone->link_to[pn] = 0; LINK(pstone, first_pstone, last_pstone, next, prev); return (pstone); } #if defined(KEY) #undef KEY #endif #define KEY( literal, field, value ) \ if ( !strcmp( word, literal ) ) \ { \ field = value; \ fMatch = TRUE; \ break; \ } void fread_pstone( FILE *fp ) { PSTONE_DATA *pstone = new_pstone(); char *word; bool fMatch; int pn = 0; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'C': if ( !strcmp(word, "Coord") ) { pstone->coord.y = fread_number(fp); pstone->coord.x = fread_number(fp); fMatch = TRUE; break; } break; case 'D': KEY("Description", pstone->description, fread_string_nospace(fp)); break; case 'E': if ( !strcmp(word, "End") ) return; case 'L': if ( !strcmp(word, "LinkStone") ) { fMatch = TRUE; if ( pn >= MAX_LNK_STONE ) { log("SYSERR: fread_pstone() - too many linked stone for stone %d.", pstone->vnum); break; } pstone->link_to[pn++] = fread_number(fp); break; } break; case 'N': KEY("Name", pstone->name, str_dup(fread_word(fp))); break; case 'S': KEY("Shortdescr", pstone->short_descr, fread_string_nospace(fp)); break; case 'V': KEY("Vnum", pstone->vnum, fread_number(fp)); break; default: log("SYSERR: Unknown word %s in pstone file", word); break; } if ( !fMatch ) log( "fread_pstone(): no match: %s", word ); } } void LoadPortalStones( void ) { FILE *fp; char fname[128]; char letter; char *word; sprintf(fname, "%spstone.txt", WLS_PREFIX); if ( !( fp = fopen(fname, "r") ) ) { log(" No Portal Stones defined."); return; } for ( ; ; ) { letter = fread_letter( fp ); if ( letter == '*' ) { fread_to_eol( fp ); continue; } if ( feof( fp ) ) break; if ( letter != '#' ) { log( "SYSERR: LoadPortalStones() - # not found." ); break; } word = fread_word( fp ); if ( !strcmp( word, "PSTONE" ) ) fread_pstone(fp); else if ( !strcmp( word, "END" ) ) // Done break; else { log("SYSERR: LoadPortalStones() - bad section %s", word ); continue; } } fclose(fp); } /* ************************************************************ */ void fwrite_pstone( FILE *fp, PSTONE_DATA *pstone ) { int pn; fprintf(fp, "#PSTONE\n"); fprintf(fp, "Vnum %d\n", pstone->vnum); fprintf(fp, "Coord %hd %hd\n", pstone->coord.y, pstone->coord.x); if ( pstone->name ) fprintf(fp, "Name %s\n", pstone->name); if ( pstone->short_descr ) fprintf(fp, "Shortdescr %s~\n", pstone->short_descr); if ( pstone->description ) fprintf(fp, "Description %s~\n", pstone->description); for ( pn = 0; pn < MAX_LNK_STONE; pn++ ) { if ( pstone->link_to[pn] ) fprintf(fp, "LinkStone %hd\n", pstone->link_to[pn]); } fprintf(fp, "End\n\n"); } void SavePortalStones( void ) { FILE *fp; PSTONE_DATA *pstone; char fname[128]; if ( !first_pstone ) return; sprintf(fname, "%spstone.txt", WLS_PREFIX); if ( !( fp = fopen(fname, "w") ) ) return; for ( pstone = first_pstone; pstone; pstone = pstone->next ) fwrite_pstone(fp, pstone); fprintf(fp, "#END\n"); fclose(fp); } /* ================================================================ */ ACMD(do_camp) { ROOM_AFFECT *raff; int move_needed = 100; if (!IN_WILD(ch)) { send_to_char("You can make a campsite only in the wilderness.\r\n", ch); return; } if ( RIDING(ch) ) { send_to_char("You cannot prepare a camp while mounted.\r\n", ch); return; } if ( WAGONER(ch) ) { send_to_char("You cannot prepare a camp while driving a vehicle.\r\n", ch); return; } if (ch->action) { send_to_char("You are too busy to do this!\r\n", ch); return; } if ((raff = get_room_aff_bitv(ch->in_room, RAFF_CAMP))) { ROOM_DATA *tRoom = ch->in_room; /* refresh the current campsite */ raff->timer = 60; send_to_char( "You throw more wood on the fire and get the campsite ready.\r\n", ch ); if (!GET_INVIS_LEV(ch)) act( "$n throws more wood on the fire.", TRUE, ch, 0, 0, TO_ROOM ); GET_MOVE(ch) /= 2; if (!GET_INVIS_LEV(ch)) act("$n camps, preparing to leave this world.", TRUE, ch, 0, 0, TO_ROOM); } else { /* make a new campsite */ CAMP_EVENT *ce; /* create and initialize the camp event */ CREATE(ce, CAMP_EVENT, 1); ce->ch = ch; ce->pRoom = ch->in_room; ch->action = event_create( camp_event, ce, 100 ); send_to_char("You begin to prepare a campsite...\r\n", ch); act("$n begins to prepare a campsite...", FALSE, ch, NULL, NULL, TO_ROOM); } } EVENTFUNC(camp_event) { CAMP_EVENT *ce = (CAMP_EVENT *) event_obj; CHAR_DATA *ch = NULL; ROOM_DATA *tRoom; ROOM_AFFECT *raff; /* extract all the info from ce */ ch = ce->ch; tRoom = ce->pRoom; /* make sure we're supposed to be here */ if (!ch || !ch->desc || !tRoom) return (0); if (!ch->action) return (0); ch->action = NULL; if (!IN_WILD(ch) || !IS_WILD(tRoom)) { send_to_char("You can prepare campsites only in the wilderness.\r\n", ch); return (0); } if ( RIDING(ch) ) { send_to_char("You cannot prepare a camp while mounted.\r\n", ch); return (0); } if ( WAGONER(ch) ) { send_to_char("You cannot prepare a camp while driving a vehicle.\r\n", ch); return (0); } if ( tRoom != ch->in_room ) { send_to_char("You are no longer near where you began the campsite.\r\n", ch); return (0); } send_to_char("You complete your campsite, now you can leave this world for awhile.\r\n", ch); if (!GET_INVIS_LEV(ch)) act("$n camps, preparing to leave this world.", TRUE, ch, 0, 0, TO_ROOM); free(event_obj); if ((raff = get_room_aff_bitv(tRoom, RAFF_CAMP))) raff->timer = 60; else { /* create, initialize, and link a room-affection node */ CREATE(raff, ROOM_AFFECT, 1); raff->coord = NULL; raff->vroom = NOWHERE; raff->timer = 60; raff->bitvector = RAFF_CAMP; raff->spell = 0; raff->level = GET_LEVEL(ch); raff->value = 0; raff->text = "The fire slowly fades and sputters out...\r\n"; CREATE( raff->coord, COORD_DATA, 1 ); raff->coord->y = GET_RY(tRoom); raff->coord->x = GET_RX(tRoom); /* add to the room list */ raff->next_in_room = tRoom->affections; tRoom->affections = raff; /* add to the global list */ raff->next = raff_list; raff_list = raff; } return (0); }