/************************************************************************** * # # # ## # # ### ## ## ### http://www.lyonesse.it * * # # # # # ## # # # # # * * # # # # # ## ## # # ## ## ## # # ## * * # # # # # ## # # # # # # # # # # # * * ### # ## # # ### ## ## ### # # #### ## Ver. 1.0 * * * * -Based on CircleMud & Smaug- Copyright (c) 2001-2002 by Mithrandir * * * * ********************************************************************** * * * * File: vehicles.c * * * * Vehicles code * * * **************************************************************************/ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "db.h" #include "handler.h" #include "interpreter.h" #include "constants.h" /* external functions */ char *make_bar(long val, long max, long len, int color); void free_room(ROOM_DATA *room); void rent_vehicle( CHAR_DATA *ch, VEHICLE_DATA *vehicle ); void check_wild_move(CHAR_DATA *ch, VEHICLE_DATA *vehicle, SHIP_DATA *ship, FERRY_DATA *ferry, ROOM_DATA *pRoomFrom, ROOM_DATA *pRoomTo); void wild_check_for_remove( ROOM_DATA *wRoom ); void wild_remove_dequeue( ROOM_DATA *wRoom ); void list_obj_to_char(OBJ_DATA *list, CHAR_DATA *ch, int mode, int show, bool RDR); void list_char_to_char(CHAR_DATA *list, CHAR_DATA *ch); /* globals */ VEHICLE_DATA *first_vehicle = NULL; VEHICLE_DATA *last_vehicle = NULL; VEHICLE_INDEX *vehicle_types[MAX_VEH_TYPE]; /* locals */ bool can_see_vehicle( CHAR_DATA *ch, VEHICLE_DATA *vehicle ); void mob_from_yoke( CHAR_DATA *mob, VEHICLE_DATA *vehicle ); /* *************************************************************************** */ /* Create / Destroy Vehicles Routines */ /* *************************************************************************** */ void clear_vehicle( VEHICLE_DATA *pVeh ) { if ( pVeh->name ) STRFREE(pVeh->name); if ( pVeh->short_description ) STRFREE(pVeh->short_description); if ( pVeh->description ) STRFREE(pVeh->description); if (pVeh->veh_room) { free_room(pVeh->veh_room); DISPOSE(pVeh->veh_room); } pVeh->next = NULL; pVeh->prev = NULL; pVeh->in_room = NULL; pVeh->last_room = NULL; pVeh->first_content = NULL; pVeh->last_content = NULL; pVeh->people = NULL; pVeh->wagoner = NULL; pVeh->next_in_room = NULL; pVeh->veh_room = NULL; pVeh->first_yoke = NULL; pVeh->last_yoke = NULL; pVeh->type = NULL; pVeh->flags = 0; } void new_vehicle_room( VEHICLE_DATA *pVeh ) { pVeh->veh_room = new_room(); pVeh->veh_room->sector_type = SECT_INSIDE; pVeh->veh_room->zone = NOWHERE; switch (pVeh->type->vnum) { case VEH_CART: /* set up vehicle's room descriptions */ pVeh->veh_room->name = str_dup("Inside a cart"); pVeh->veh_room->description = str_dup("You are inside a cart.\r\n"); break; case VEH_WAGON: /* set up vehicle's room descriptions */ pVeh->veh_room->name = str_dup("Inside a wagon"); pVeh->veh_room->description = str_dup("You are inside a four-wheeled wagon.\r\n"); break; default: log("SYSERR: new_vehicle_room() - unknown vehicle type %d.", pVeh->type->vnum); DISPOSE(pVeh->veh_room); } } VEHICLE_DATA *new_vehicle(void) { VEHICLE_DATA *pVeh; CREATE(pVeh, VEHICLE_DATA, 1); clear_vehicle(pVeh); return (pVeh); } /* create a new vehicle of the given type */ VEHICLE_DATA *init_vehicle( VEHICLE_INDEX *vType ) { VEHICLE_DATA *pVeh; if (!vType) { log("SYSERR: init_vehicle() - unused vehicle proto."); return (NULL); } if ( vType->vnum < 0 || vType->vnum >= MAX_VEH_TYPE ) { log("SYSERR: init_vehicle() - wrong vehicle type %d.", vType->vnum); return (NULL); } pVeh = new_vehicle(); pVeh->type = vType; // copy strings pVeh->name = str_dup(vType->name); pVeh->short_description = str_dup(vType->short_description); pVeh->description = str_dup(vType->description); // copy value pVeh->max_val = vType->value; // init some current values, others must be 0 pVeh->curr_val.health = pVeh->max_val.health; pVeh->curr_val.speed = pVeh->max_val.speed; // if needed, setup inside rooms if ( pVeh->max_val.passengers > 0 ) new_vehicle_room( pVeh ); /* add to the list */ LINK(pVeh, first_vehicle, last_vehicle, next, prev); return (pVeh); } /* * extract a vehicle from world * mode = 0 - leave mobs and objs in the room it was * mode = 1 - extract mobs and objs too * mode = 2 - from destroy_vehicle() */ void extract_vehicle( VEHICLE_DATA *vehicle, int mode ) { // destroyed vehicles don't loose theirs freights if (mode != 2) { if ( vehicle->first_content ) { OBJ_DATA *obj, *next_obj = NULL; for ( obj = vehicle->first_content; obj; obj = next_obj ) { next_obj = obj->next_content; if (mode == 1) extract_obj(obj); else { obj_from_vehicle(obj); obj_to_room(obj, vehicle->in_room); } } } } if ( vehicle->people ) { CHAR_DATA *ppl, *next_ppl = NULL; for ( ppl = vehicle->people; ppl; ppl = next_ppl ) { next_ppl = ppl->next_in_vehicle; char_from_vehicle(ppl); char_from_room(ppl); char_to_room(ppl, vehicle->in_room); } } if ( vehicle->first_yoke ) { YOKE_DATA *yoke, *next_yoke = NULL; for ( yoke = vehicle->first_yoke; yoke; yoke = next_yoke ) { next_yoke = yoke->next; if (mode == 1) extract_char_final(yoke->mob); else mob_from_yoke(yoke->mob, vehicle); } } if ( vehicle->veh_room ) { free_room( vehicle->veh_room ); DISPOSE(vehicle->veh_room); } if ( vehicle->wagoner ) stop_be_wagoner( vehicle->wagoner ); // destroyed vehicles must remain in place.... if (mode == 2) return; if ( vehicle->in_room ) vehicle_from_room(vehicle); UNLINK(vehicle, first_vehicle, last_vehicle, next, prev); clear_vehicle(vehicle); DISPOSE(vehicle); } /* *************************************************************** */ /* Finding Vehicles Routines */ /* *************************************************************** */ /* find the vehicle searching the entire world */ VEHICLE_DATA *find_vehicle(char *name) { VEHICLE_DATA *pVeh; int fnum; if (!name) return (NULL); if (!(fnum = get_number(&name))) return (NULL); for (pVeh = first_vehicle; pVeh; pVeh = pVeh->next) { if (isname(name, pVeh->name) || !str_cmp(name, "vehicle")) if (--fnum == 0) break; } return (pVeh); } /* find the vehicle in room */ VEHICLE_DATA *find_vehicle_in_room_by_name( CHAR_DATA *ch, char *name ) { VEHICLE_DATA *pVeh; int fnum; if ( !ch->in_room->vehicles ) return (NULL); if ( !name ) return (NULL); if ( !( fnum = get_number(&name) ) ) return (NULL); for ( pVeh = ch->in_room->vehicles; pVeh; pVeh = pVeh->next_in_room ) { if ( isname( name, pVeh->name ) || !str_cmp( name, "vehicle" ) ) if ( can_see_vehicle(ch, pVeh) ) if ( --fnum == 0 ) break; } return (pVeh); } bool empty_vehicle( VEHICLE_DATA *vehicle, bool bQuick ) { if ( vehicle->wagoner ) return (FALSE); if ( vehicle->people ) return (FALSE); if ( bQuick ) return (TRUE); if ( vehicle->first_yoke ) return (FALSE); if ( vehicle->first_content ) return (FALSE); return (TRUE); } /* *************************************************************** */ /* Enter/Exit Vehicle Routines */ /* *************************************************************** */ void char_to_vehicle( CHAR_DATA *ch, VEHICLE_DATA *vehicle ) { if ( !ch || !vehicle ) { log("SYSERR: char_to_vehicle() - NULL pointer."); return; } ch->in_vehicle = vehicle; char_to_room(ch, vehicle->veh_room); /* add to the ppl list */ ch->next_in_vehicle = vehicle->people; vehicle->people = ch; vehicle->curr_val.passengers++; } void char_from_vehicle( CHAR_DATA *ch ) { CHAR_DATA *temp; if ( !ch ) { log("SYSERR: char_from_vehicle() - NULL pointer."); return; } if ( !ch->in_vehicle ) return; ch->in_vehicle->curr_val.passengers--; REMOVE_FROM_LIST(ch, ch->in_vehicle->people, next_in_vehicle); ch->in_vehicle = NULL; ch->next_in_vehicle = NULL; } void char_enter_vehicle( CHAR_DATA *ch, VEHICLE_DATA *vehicle ) { if ( !ch || !vehicle ) { log("SYSERR: char_to_vehicle() - NULL pointer."); return; } if ( RIDING(ch) ) { send_to_char("You cannot enter a vehicle while mounted.\r\n", ch); return; } if ( WAGONER(ch) ) { send_to_char("You cannot enter a vehicle while driving a vehicle.\r\n", ch); return; } if ( ch->in_vehicle ) { send_to_char("You are already inside a vehicle.\r\n", ch); return; } if (IS_SET(vehicle->flags, VEH_DESTROYED)) { send_to_char("You cannot enter a destroyed vehicle.\r\n", ch); return; } if ( vehicle->owner_id != GET_IDNUM(ch) && !IS_IMMORTAL(ch) ) { ch_printf(ch, "%s is not yours that you can use it.\r\n", vehicle->short_description); return; } if ( !vehicle->max_val.passengers ) { ch_printf(ch, "%s cannot have passengers.\r\n", vehicle->short_description); return; } if ( vehicle->curr_val.passengers >= vehicle->max_val.passengers ) { send_to_char("It's full.\r\n", ch); return; } // sanity check if ( !vehicle->veh_room ) { ch_printf(ch, "Sorry, right now you cannot go inside %s.\r\n", vehicle->short_description); return; } act("You enter $v.", FALSE, ch, NULL, vehicle, TO_CHAR); act("$n enters $v.", FALSE, ch, NULL, vehicle, TO_ROOM); char_from_room(ch); char_to_vehicle(ch, vehicle); look_at_room(ch, 0); } void char_exit_vehicle( CHAR_DATA *ch ) { ROOM_DATA *pRoom; if ( !ch ) { log("SYSERR: char_exit_vehicle() - NULL pointer."); return; } if ( !ch->in_vehicle ) return; pRoom = ch->in_vehicle->in_room; // TODO - check if char can move in to the room.. act("You exit from $v.", FALSE, ch, NULL, ch->in_vehicle, TO_CHAR); act("$n exits from $v.", FALSE, ch, NULL, ch->in_vehicle, TO_ROOM); char_from_vehicle(ch); char_from_room(ch); char_to_room(ch, pRoom); look_at_room(ch, 0); } /* *************************************************************** */ /* Wagoner Routines */ /* *************************************************************** */ void start_be_wagoner( CHAR_DATA *ch, VEHICLE_DATA *vehicle ) { if ( !ch || !vehicle ) { log("SYSERR: start_be_wagoner() - NULL pointer."); return; } if ( WAGONER(ch) ) { ch_printf(ch, "You're already driving %s.\r\n", WAGONER(ch)->short_description); return; } if ( RIDING(ch) ) { send_to_char("You cannot drive a vehicle while mounted.\r\n", ch); return; } if (IS_SET(vehicle->flags, VEH_DESTROYED)) { send_to_char("You cannot drive a destroyed vehicle.\r\n", ch); return; } if ( vehicle->wagoner ) { ch_printf(ch, "%s is already drived by %s.\r\n", vehicle->short_description, PERS(vehicle->wagoner, ch)); return; } if ( vehicle->owner_id != GET_IDNUM(ch) && !IS_IMMORTAL(ch) ) { ch_printf(ch, "%s is not yours that you can use it.\r\n", vehicle->short_description); return; } WAGONER(ch) = vehicle; WAGONER(ch)->wagoner = ch; act("You climb up and start driving $v.", FALSE, ch, NULL, vehicle, TO_CHAR); act("$n climbs up and start driving $v.", FALSE, ch, NULL, vehicle, TO_ROOM); } /* * messages to char are not inside here because * this function is called also by extract_char() * and from check inside do_simple_move() */ void stop_be_wagoner( CHAR_DATA *ch ) { if ( !ch ) { log("SYSERR: stop_be_wagoner() - NULL pointer."); return; } if ( !WAGONER(ch) ) { log("SYSERR: ch is not driving any vehicle."); return; } WAGONER(ch)->wagoner = NULL; WAGONER(ch) = NULL; } /* *************************************************************** */ /* Yokeing Mobs Routines */ /* *************************************************************** */ bool hitched_mob( CHAR_DATA *mob ) { if ( !IS_NPC(mob) ) return (FALSE); if ( !mob->mob_specials.hitched_to ) return (FALSE); /* this should never happen!! */ if ( mob->in_room != mob->mob_specials.hitched_to->in_room ) return (FALSE); return (TRUE); } void mob_to_yoke( CHAR_DATA *mob, VEHICLE_DATA *vehicle ) { YOKE_DATA *yoke; if (!mob || !vehicle) return; if (IS_SET(vehicle->flags, VEH_DESTROYED)) return; CREATE(yoke, YOKE_DATA, 1); yoke->mob = mob; LINK(yoke, vehicle->first_yoke, vehicle->last_yoke, next, prev); mob->mob_specials.hitched_to = vehicle; mob->mob_specials.yoke = yoke; vehicle->curr_val.draft_mobs++; } void mob_from_yoke( CHAR_DATA *mob, VEHICLE_DATA *vehicle ) { YOKE_DATA *yoke; if ( !mob->mob_specials.hitched_to ) return; if ( !(yoke = mob->mob_specials.yoke) ) return; vehicle->curr_val.draft_mobs--; UNLINK(yoke, vehicle->first_yoke, vehicle->last_yoke, next, prev); yoke->next = NULL; yoke->prev = NULL; yoke->mob = NULL; DISPOSE(yoke); mob->mob_specials.hitched_to = NULL; mob->mob_specials.yoke = NULL; } /* *************************************************************** */ /* Vehicle Movement Routines */ /* *************************************************************** */ void vehicle_to_room( VEHICLE_DATA *pVeh, ROOM_DATA *pRoom ) { if ( !pVeh || !pRoom ) { log("SYSERR: vehicle_to_room() - invalid pointer."); return; } /* add to the room list */ pVeh->next_in_room = pRoom->vehicles; pRoom->vehicles = pVeh; pVeh->in_room = pRoom; /* Handle Wild Sectors */ if ( IS_WILD(pRoom) ) { check_wild_move(NULL, pVeh, NULL, NULL, pVeh->last_room, pRoom); if (ROOM_FLAGGED(pRoom, ROOM_WILD_REMOVE)) wild_remove_dequeue(pRoom); } } void vehicle_from_room( VEHICLE_DATA *pVeh ) { VEHICLE_DATA *temp; if ( !pVeh ) { log("SYSERR: NULL vehicle pointer in vehicle_from_room"); exit(1); } pVeh->last_room = pVeh->in_room; REMOVE_FROM_LIST(pVeh, pVeh->in_room->vehicles, next_in_room); pVeh->in_room = NULL; pVeh->next_in_room = NULL; wild_check_for_remove(pVeh->last_room); } bool vehicle_can_move( VEHICLE_DATA *vehicle ) { if (!vehicle) return (FALSE); if (!vehicle->first_yoke) return (FALSE); if (!vehicle->wagoner) return (FALSE); if (IS_SET(vehicle->flags, VEH_DESTROYED)) return (FALSE); return (TRUE); } bool vehicle_can_go( VEHICLE_DATA *pVeh, ROOM_DATA *to_room ) { /* * that's an hack.. in future must be handled * in do_simple_move() */ if ( ROOM_FLAGGED(to_room, ROOM_DEATH) ) return (FALSE); if ( IS_SET(pVeh->flags, VEH_FLY) ) return (TRUE); if ( to_room->sector_type == SECT_ROAD || to_room->sector_type == SECT_FIELD || to_room->sector_type == SECT_PLAIN || to_room->sector_type == SECT_CITY || to_room->sector_type == SECT_LAND || to_room->sector_type == SECT_BRIDGE || to_room->sector_type == SECT_FORD || to_room->sector_type == SECT_PORT) return (TRUE); return (FALSE); } /* *************************************************************** */ /* Goods Storing in Vehicle Routines */ /* *************************************************************** */ OBJ_DATA *obj_to_vehicle( OBJ_DATA *obj, VEHICLE_DATA *vehicle ) { OBJ_DATA *oret, *tmp_obj; if (!obj || !vehicle) { log("SYSERR: obj_to_vehicle() - NULL pointer"); return (NULL); } vehicle->curr_val.capacity += get_real_obj_weight(obj); for ( tmp_obj = vehicle->first_content; tmp_obj; tmp_obj = tmp_obj->next_content ) { if ( (oret = group_object(tmp_obj, obj)) == tmp_obj ) return (oret); } LINK(obj, vehicle->first_content, vehicle->last_content, next_content, prev_content); obj->in_vehicle = vehicle; obj->in_room = NULL; obj->in_obj = NULL; obj->carried_by = NULL; return (obj); } /* Take a goods object from a vehicle */ void obj_from_vehicle( OBJ_DATA *obj ) { if (!obj || !obj->in_vehicle) { log("SYSERR: obj_from_vehicle() - NULL pointer"); return; } obj->in_vehicle->curr_val.capacity -= get_real_obj_weight(obj); UNLINK(obj, obj->in_vehicle->first_content, obj->in_vehicle->last_content, next_content, prev_content); obj->in_obj = NULL; obj->in_room = NULL; obj->carried_by = NULL; obj->in_vehicle = NULL; obj->next_content = NULL; obj->prev_content = NULL; } void vehicle_load_goods( CHAR_DATA *ch, OBJ_DATA *goods, VEHICLE_DATA *vehicle ) { if ( !ch || !goods || !vehicle ) { log("SYSERR: vehicle_load_goods() - NULL pointer."); return; } if (IS_SET(vehicle->flags, VEH_DESTROYED)) { send_to_char("You cannot put items in a destroyed vehicle.\r\n", ch); return; } if ( vehicle->curr_val.capacity + get_real_obj_weight(goods) > vehicle->max_val.capacity ) { ch_printf(ch, "%s cannot contain that much.\r\n", vehicle->short_description); return; } obj_from_room(goods); obj_to_vehicle(goods, vehicle); ch_printf(ch, "You charge %s into %s.\r\n", goods->short_description, vehicle->short_description); } void vehicle_unload_goods( CHAR_DATA *ch, OBJ_DATA *goods, VEHICLE_DATA *vehicle ) { if ( !ch || !goods || !vehicle ) { log("SYSERR: vehicle_unload_goods() - NULL pointer."); return; } obj_from_vehicle(goods); obj_to_room(goods, ch->in_room); ch_printf(ch, "You discharge %s from %s.\r\n", goods->short_description, vehicle->short_description); } /* *************************************************************** */ /* Vehicle Display Routines */ /* *************************************************************** */ /* True if char can see vehicle */ bool can_see_vehicle( CHAR_DATA *ch, VEHICLE_DATA *vehicle ) { if ( !IS_NPC(ch) && PRF_FLAGGED(ch, PRF_HOLYLIGHT) ) return (TRUE); if ( AFF_FLAGGED( ch, AFF_BLIND ) ) return (FALSE); if ( IS_DARK(vehicle->in_room) && !AFF_FLAGGED(ch, AFF_INFRAVISION) ) return (FALSE); if ( IS_SET(vehicle->flags, VEH_INVISIBLE) && !AFF_FLAGGED(ch, AFF_DETECT_INVIS) ) return (FALSE); return (TRUE); } void list_vehicle_to_char( VEHICLE_DATA *vlist, CHAR_DATA *ch ) { VEHICLE_DATA *pVeh; char sbaf[MAX_STRING_LENGTH]; for ( pVeh = vlist; pVeh; pVeh = pVeh->next_in_room ) { if ( WAGONER(ch) && WAGONER(ch) == pVeh ) continue; // needed because of "look out" command.. if ( ch->in_vehicle && ch->in_vehicle == pVeh ) continue; if ( can_see_vehicle(ch, pVeh) ) { if (IS_SET(pVeh->flags, VEH_DESTROYED)) sprintf(sbaf, "&b&5You see a destroyed %s", pVeh->name); else sprintf(sbaf, "&b&5You see %s", pVeh->short_description); if (pVeh->wagoner) sprintf(sbaf+strlen(sbaf), ", drived by %s", PERS(pVeh->wagoner, ch)); if (pVeh->first_yoke) { YOKE_DATA *yoke; strcat(sbaf, ", dragged by "); for ( yoke = pVeh->first_yoke; yoke; yoke = yoke->next ) sprintf(sbaf+strlen(sbaf), "%s%s", GET_NAME(yoke->mob), (yoke->next ? ", " : " ") ); } strcat(sbaf, ".&0\r\n"); send_to_char(sbaf, ch); } } } int look_at_vehicle(CHAR_DATA *ch, VEHICLE_DATA *vehicle) { char sbaf[MAX_STRING_LENGTH]; if (!can_see_vehicle(ch, vehicle)) return (0); sprintf(sbaf, "%s%s\r\n" "Capacity : %s (%5d/%5d)\r\n" "Health : %s (%5d/%5d)\r\n" , vehicle->description, (IS_SET(vehicle->flags, VEH_DESTROYED) ? " [destroyed]" : ""), make_bar(vehicle->curr_val.capacity, vehicle->max_val.capacity, 40, 6), vehicle->curr_val.capacity, vehicle->max_val.capacity, make_bar(vehicle->curr_val.health, vehicle->max_val.health, 40, 6), vehicle->curr_val.health, vehicle->max_val.health ); send_to_char(sbaf, ch); if (vehicle->people) list_char_to_char(vehicle->people, ch); if (vehicle->first_content) { send_to_char("When you look inside you see:\r\n", ch); list_obj_to_char(vehicle->first_content, ch, 7, 1, FALSE); } return (1); } const char *veh_flags_descr[] = { "FLYING", "INVISIBLE", "DESTROYED", "\n" }; void stat_vehicle(CHAR_DATA *ch, VEHICLE_DATA *vehicle) { char sbaf[MAX_STRING_LENGTH], dflags[128]; if (!can_see_vehicle(ch, vehicle)) return; sprintbit(vehicle->flags, veh_flags_descr, dflags); sprintf(sbaf, "%s%s\r\n" "Flags : %s\r\n" "Capacity : %s (%5d/%5d)\r\n" "Health : %s (%5d/%5d)\r\n" , vehicle->description, (IS_SET(vehicle->flags, VEH_DESTROYED) ? " [destroyed]" : ""), dflags, make_bar(vehicle->curr_val.capacity, vehicle->max_val.capacity, 40, 6), vehicle->curr_val.capacity, vehicle->max_val.capacity, make_bar(vehicle->curr_val.health, vehicle->max_val.health, 40, 6), vehicle->curr_val.health, vehicle->max_val.health ); send_to_char(sbaf, ch); if (vehicle->people) list_char_to_char(vehicle->people, ch); if (vehicle->first_content) { send_to_char("When you look inside you see:\r\n", ch); list_obj_to_char(vehicle->first_content, ch, 7, 1, FALSE); } } /* *************************************************************** */ /* Vehicle Proto */ /* *************************************************************** */ #if defined(KEY) #undef KEY #endif #define KEY( literal, field, value ) \ if ( !strcmp( word, literal ) ) \ { \ field = value; \ fMatch = TRUE; \ break; \ } VEHICLE_INDEX *new_veh_proto(void) { VEHICLE_INDEX *vType = NULL; CREATE( vType, VEHICLE_INDEX, 1 ); vType->name = NULL; vType->short_description = NULL; vType->description = NULL; vType->vnum = NOTHING; return (vType); } VEHICLE_INDEX *fread_one_veh_proto( FILE *fp ) { VEHICLE_INDEX *vType = new_veh_proto(); char *word; bool fMatch; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch (UPPER(word[0])) { case '*': fMatch = TRUE; fread_to_eol(fp); break; case 'C': KEY("Capacity", vType->value.capacity, fread_number(fp)); break; case 'D': KEY("Descr", vType->description, fread_string_nospace(fp)); KEY("Draft_mobs", vType->value.draft_mobs, fread_number(fp)); break; case 'E': if (!str_cmp(word, "End")) { return (vType); } break; case 'H': KEY("Health", vType->value.health, fread_number(fp)); break; case 'N': KEY("Name", vType->name, str_dup(fread_word(fp))); break; case 'P': KEY("Passengers", vType->value.passengers, fread_number(fp)); break; case 'S': KEY("Short_descr", vType->short_description, fread_string_nospace(fp)); KEY("Speed", vType->value.speed, fread_number(fp)); break; case 'V': KEY("Vnum", vType->vnum, fread_number(fp)); break; } } } void LoadVehiclesTable(void) { FILE *fp; char fname[128]; char letter; char *word; int num_of_veh_proto; sprintf(fname, "%svehicles.data", LIB_DATA); if (!(fp = fopen(fname, "r"))) return; for (num_of_veh_proto = 0; num_of_veh_proto < MAX_VEH_TYPE; num_of_veh_proto++) vehicle_types[num_of_veh_proto] = NULL; num_of_veh_proto = 0; for ( ; ; ) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (letter != '#') { log("SYSERR: LoadVehiclesTable() - # not found."); break; } word = fread_word(fp); if (!str_cmp(word, "VEHICLE")) { if (num_of_veh_proto >= MAX_VEH_TYPE) { log("SYSERR: LoadVehiclesTable() - more prototypes than MAX_VEH_TYPE %d", MAX_VEH_TYPE); fclose(fp); return; } vehicle_types[num_of_veh_proto] = fread_one_veh_proto(fp); num_of_veh_proto++; } else if (!str_cmp(word, "END")) break; else { log("SYSERR: LoadVehiclesTable() - bad section %s.", word); continue; } } fclose(fp); } /* *************************************************************** */ /* Commands */ /* *************************************************************** */ /* wiz only */ ACMD(do_newvehicle) { VEHICLE_DATA *pVeh; char arg[MAX_INPUT_LENGTH]; int vnum; argument = one_argument(argument, arg); if ( !*arg ) { send_to_char("Possible vehicles are:\r\n", ch); for (vnum = 0; vnum < MAX_VEH_TYPE; vnum++) { if (!vehicle_types[vnum]) continue; ch_printf(ch, " (%d) %s\r\n", vnum, vehicle_types[vnum]->name); } send_to_char("Which type of vehicle?\r\n", ch); return; } if ( is_number(arg) ) vnum = atoi(arg); else { for (vnum = 0; vnum < MAX_VEH_TYPE; vnum++) { if (!vehicle_types[vnum]) continue; if (is_abbrev(arg, vehicle_types[vnum]->name)) break; } } if (vnum < 0 || vnum >= MAX_VEH_TYPE || !vehicle_types[vnum]) { ch_printf(ch, "Invalid vehicle type '%s'.\r\n", arg); return; } if ( ( pVeh = init_vehicle( vehicle_types[vnum] ) ) ) { pVeh->owner_id = GET_IDNUM(ch); vehicle_to_room(pVeh, ch->in_room); ch_printf(ch, "You create %s out of the blue.\r\n", vehicle_types[vnum]->short_description); } } /* * quick exit from a vehicle */ ACMD(do_out) { one_argument(argument, arg); if ( !ch->in_vehicle ) { send_to_char("You are not inside a vehicle.\r\n", ch); return; } if ( !str_cmp(arg, "save") ) { rent_vehicle(ch, ch->in_vehicle); return; } char_exit_vehicle(ch); } /* * so she wanna be a wagoner, eh? */ ACMD(do_drive) { VEHICLE_DATA *vehicle; char arg1[MAX_INPUT_LENGTH]; argument = one_argument(argument, arg1); if ( !*arg1 ) { send_to_char( "Usage:\r\n" "drive <vehicle> - you start drive a vehicle.\r\n" "drive stop - you stop drive a vehicle.\r\n", ch); return; } if ( !str_cmp(arg1, "stop") ) { if ( !( vehicle = WAGONER(ch) ) ) { send_to_char("You are not driving any vehicle.\r\n", ch); return; } act("You stop driving $v.", FALSE, ch, NULL, vehicle, TO_CHAR); act("$n stops driving $v.", FALSE, ch, NULL, vehicle, TO_ROOM); stop_be_wagoner(ch); } else { if ( !( vehicle = find_vehicle_in_room_by_name(ch, arg1) ) ) { ch_printf(ch, "You don't see %s %s here..\r\n", AN(arg1), arg1); return; } if (IS_SET(vehicle->flags, VEH_DESTROYED)) { send_to_char("You cannot drive a destroyed vehicle.\r\n", ch); return; } start_be_wagoner(ch, vehicle); } } /* attach a mob to the vehicle */ ACMD(do_yoke) { CHAR_DATA *mob; VEHICLE_DATA *vehicle; char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; if ( RIDING(ch) ) { send_to_char("You cannot yoke draft animal to a vehicle while mounted.\r\n", ch); return; } if ( WAGONER(ch) ) { send_to_char("You cannot yoke draft animal to a vehicle while driving the vehicle.\r\n", ch); return; } argument = two_arguments(argument, arg1, arg2); if ( !*arg1 || !*arg2 ) { send_to_char("Usage: yoke <mob> <vehicle>\r\n", ch); return; } if ( !( mob = get_char_room_vis(ch, arg1, NULL) ) ) { ch_printf(ch, "You don't see %s %s here.\r\n", AN(arg1), arg1); return; } if ( !IS_NPC(mob) || !MOB_FLAGGED(mob, MOB_DRAFT_ANIMAL)) { send_to_char("You can yoke only draft animal to a vehicle.\r\n", ch); return; } if ( !( vehicle = find_vehicle_in_room_by_name(ch, arg2) ) ) { ch_printf(ch, "You don't see %s %s here.\r\n", AN(arg2), arg2); return; } if (IS_SET(vehicle->flags, VEH_DESTROYED)) { send_to_char("You cannot yoke animals to a destroyed vehicle.\r\n", ch); return; } if ( vehicle->owner_id != GET_IDNUM(ch) && !IS_IMMORTAL(ch) ) { ch_printf(ch, "%s is not yours that you can yoke animals.\r\n", vehicle->short_description); return; } if ( !vehicle->max_val.draft_mobs ) { ch_printf(ch, "You cannot yoke draft animal to %s.\r\n", vehicle->short_description); return; } if ( vehicle->curr_val.draft_mobs >= vehicle->max_val.draft_mobs ) { ch_printf(ch, "You cannot yoke any more draft animal to %s.\r\n", vehicle->short_description); return; } mob_to_yoke(mob, vehicle); ch_printf(ch, "You yoke %s to %s.\r\n", GET_NAME(mob), vehicle->short_description); sprintf(buf, "$n yoke $N to %s.", vehicle->short_description); act(buf, FALSE, ch, NULL, mob, TO_ROOM); } ACMD(do_unyoke) { CHAR_DATA *mob; VEHICLE_DATA *vehicle; char arg1[MAX_INPUT_LENGTH]; if ( RIDING(ch) ) { send_to_char("You cannot unyoke draft animal from a vehicle while mounted.\r\n", ch); return; } if ( WAGONER(ch) ) { send_to_char("You cannot unyoke draft animal from a vehicle while driving the vehicle.\r\n", ch); return; } argument = one_argument(argument, arg1); if ( !*arg1 ) { send_to_char("Usage: unyoke <mob>\r\n", ch); return; } if ( !( mob = get_char_room_vis(ch, arg1, NULL) ) ) { ch_printf(ch, "You don't see %s %s here.\r\n", AN(arg1), arg1); return; } if ( !IS_NPC(mob) || !MOB_FLAGGED(mob, MOB_DRAFT_ANIMAL)) { send_to_char("You can unyoke only draft animal from a vehicle.\r\n", ch); return; } if ( !( vehicle = mob->mob_specials.hitched_to ) ) { ch_printf(ch, "%s isn't yoked to any vehicle.\r\n", GET_NAME(mob)); return; } if ( !mob->mob_specials.yoke ) { log("SYSERR: do_unyoke() - yoked mob does not have yoke data."); send_to_char("There is a problem, call an Immortal.\r\n", ch); return; } if (IS_SET(vehicle->flags, VEH_DESTROYED)) { send_to_char("You cannot unyoke animals from a destroyed vehicle.\r\n", ch); return; } if ( vehicle->owner_id != GET_IDNUM(ch) && !IS_IMMORTAL(ch) ) { ch_printf(ch, "%s is not yours that you can unyoke animals.\r\n", vehicle->short_description); return; } ch_printf(ch, "You unyoke %s from %s.\r\n", GET_NAME(mob), vehicle->short_description); sprintf(buf, "$n unyoke $N from %s.", vehicle->short_description); act(buf, FALSE, ch, NULL, mob, TO_ROOM); mob_from_yoke(mob, vehicle); } /* ******************************************************* */ /* Code for repairing and damaging vehicles */ /* ******************************************************* */ /* make some reparations */ void repair_vehicle(CHAR_DATA *ch, VEHICLE_DATA *pVeh) { if (IS_SET(pVeh->flags, VEH_DESTROYED)) { act("$v: you cannot repair destroyed vehicles.", FALSE, ch, NULL, pVeh, TO_CHAR); return; } if (pVeh->max_val.health == pVeh->curr_val.health) { act("$v does not need reparations.", FALSE, ch, NULL, pVeh, TO_CHAR); return; } if (!roll(GET_DEX(ch))) { send_to_char("You fail.\r\n", ch); return; } pVeh->curr_val.health++; act("You make sone reparations to $v.", FALSE, ch, NULL, pVeh, TO_CHAR); act("$n makes sone reparations to $v.", FALSE, ch, NULL, pVeh, TO_ROOM); } void destroy_vehicle(VEHICLE_DATA *pVeh) { SET_BIT(pVeh->flags, VEH_DESTROYED); extract_vehicle(pVeh, 2); } /* * return 0 if vehicle is destroyed, >0 otherwise */ int damage_vehicle(VEHICLE_DATA *pVeh, int dam) { if (dam < 0) dam = 0; pVeh->curr_val.health -= dam; if (pVeh->curr_val.health <= 0) { pVeh->curr_val.health = 0; destroy_vehicle(pVeh); return (0); } return (1); } void hit_vehicle(CHAR_DATA *ch, VEHICLE_DATA *pVeh) { OBJ_DATA *weapon; char dbuf[MAX_STRING_LENGTH]; int dam; if (!ch || !pVeh) return; if (!(weapon = GET_EQ(ch, WEAR_WIELD))) { send_to_char("You cannot damage a building with your bare hands.\r\n", ch); return; } if (GET_OBJ_TYPE(weapon) != ITEM_WEAPON) { send_to_char("Using a weapon would surely help.\r\n", ch); return; } // calc damage dam = GET_REAL_DAMROLL(ch); dam += dice(GET_OBJ_VAL(weapon, 1), GET_OBJ_VAL(weapon, 2)); // vehicle absorb damage.. dam -= pVeh->max_val.health; // damage goes from 0 to 100 dam = URANGE(0, dam, 100); // check for damaging the weapon used check_damage_obj(ch, weapon, 8); // no damage done if (!dam) { // message to attacker act("You strike $v, but make no damages.", FALSE, ch, NULL, pVeh, TO_CHAR); // message to room act("$n strikes $v but nothing happens.", FALSE, ch, NULL, pVeh, TO_ROOM); return; } // vehicle has been destroyed.. if (!damage_vehicle(pVeh, dam)) { // message to attacker act("Your attack DESTROY $v.", FALSE, ch, NULL, pVeh, TO_CHAR); // message to room act("$n DESTROYS $v with $s attack.", FALSE, ch, NULL, NULL, TO_ROOM); return; } // message to attacker sprintf(dbuf, "You strike $v, causing %d damages.", dam); act(dbuf, FALSE, ch, NULL, pVeh, TO_CHAR); // message to room act("$n strike $v, causing some damage.", FALSE, ch, NULL, pVeh, TO_ROOM); } bool attack_vehicle(CHAR_DATA *ch, char *arg) { VEHICLE_DATA *pVeh; if (!ch || !*arg) return (FALSE); if (!(pVeh = find_vehicle_in_room_by_name(ch, arg))) return (FALSE); if (IS_SET(pVeh->flags, VEH_DESTROYED)) { ch_printf(ch, "%s has already been destroyed.\r\n", pVeh->short_description); return (TRUE); } hit_vehicle(ch, pVeh); return (TRUE); }