void transfer_creature(struct Thing *boxtng, struct Thing *transftng, unsigned char plyr_idx) { SYNCDBG(7,"Starting"); struct CreatureControl *cctrl; if (!thing_exists(boxtng) || (box_thing_to_special(boxtng) != SpcKind_TrnsfrCrtr) ) { ERRORMSG("Invalid transfer box object!"); return; } // Check if 'things' are correct if (!thing_exists(transftng) || !thing_is_creature(transftng) || (transftng->owner != plyr_idx)) { ERRORMSG("Invalid transfer creature thing!"); return; } cctrl = creature_control_get_from_thing(transftng); set_transfered_creature(plyr_idx, transftng->model, cctrl->explevel); remove_thing_from_power_hand_list(transftng, plyr_idx); kill_creature(transftng, INVALID_THING, -1, CrDed_NoEffects|CrDed_NotReallyDying); create_special_used_effect(&boxtng->mappos, plyr_idx); remove_events_thing_is_attached_to(boxtng); force_any_creature_dragging_owned_thing_to_drop_it(boxtng); delete_thing_structure(boxtng, 0); if (is_my_player_number(plyr_idx)) output_message(SMsg_CommonAcknowledge, 0, true); }
TbBool attempt_anger_job_join_enemy(struct Thing *creatng) { struct Thing *heartng; int i, n; n = ACTION_RANDOM(PLAYERS_COUNT); for (i=0; i < PLAYERS_COUNT; i++, n=(n+1)%PLAYERS_COUNT) { if ((n == game.neutral_player_num) || (n == creatng->owner)) continue; struct PlayerInfo *player; player = get_player(n); if (!player_exists(player) || (player->field_2C != 1)) continue; heartng = get_player_soul_container(n); if (thing_exists(heartng) && (heartng->active_state != 3)) { TRACE_THING(heartng); if (creature_can_navigate_to(creatng, &heartng->mappos, NavRtF_Default)) { change_creature_owner(creatng, n); anger_set_creature_anger_all_types(creatng, 0); } } } return false; }
void set_sprite_view_isometric(void) { //_DK_set_sprite_view_isometric(); long i; for (i=1; i < THINGS_COUNT; i++) { struct Thing *thing; thing = thing_get(i); if (thing_exists(thing)) { if (thing_is_creature(thing) || ((thing->field_4F & 0x01) == 0)) { int n; n = straight_td_iso(thing->field_44); if (n >= 0) { thing->field_44 = n; long nframes; nframes = keepersprite_frames(thing->field_44); if (nframes != thing->field_49) { ERRORLOG("No frames different between views C%d, M%d, A%d, B%d",thing->class_id,thing->model,thing->field_49,nframes); thing->field_49 = nframes; n = thing->field_49 - 1; if (n > thing->field_48) { n = thing->field_48; } thing->field_48 = n; thing->field_40 = n << 8; } } } } } }
short creature_drop_body_in_prison(struct Thing *thing) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); struct Thing *dragtng; dragtng = thing_get(cctrl->dragtng_idx); if (!thing_exists(dragtng) || !creature_is_being_unconscious(dragtng)) { set_start_state(thing); return 0; } if (!subtile_is_room(thing->mappos.x.stl.num, thing->mappos.y.stl.num)) { set_start_state(thing); return 0; } struct Room *room; room = get_room_thing_is_on(thing); if ((room->owner != thing->owner) || (room->kind != RoK_PRISON)) { set_start_state(thing); return 0; } make_creature_conscious(dragtng); initialise_thing_state(dragtng, CrSt_CreatureArrivedAtPrison); struct CreatureControl *dragctrl; dragctrl = creature_control_get_from_thing(dragtng); dragctrl->flgfield_1 |= CCFlg_NoCompControl; set_start_state(thing); return 1; }
void set_sprite_view_3d(void) { long i; for (i=1; i < THINGS_COUNT; i++) { struct Thing *thing; thing = thing_get(i); if (thing_exists(thing)) { if (thing_is_creature(thing) || ((thing->field_4F & TF4F_DoNotDraw) == 0)) { int n; n = straight_iso_td(thing->anim_sprite); if (n >= 0) { thing->anim_sprite = n; long nframes; nframes = keepersprite_frames(thing->anim_sprite); if (nframes != thing->field_49) { ERRORLOG("No frames different between views C%d, M%d, A%d, B%d",thing->class_id,thing->model,thing->field_49,nframes); thing->field_49 = nframes; n = thing->field_49 - 1; if (n > thing->field_48) { n = thing->field_48; } thing->field_48 = n; thing->field_40 = n << 8; } } } } } }
void process_armageddon(void) { struct PlayerInfo *player; struct Dungeon *dungeon; struct Thing *heartng; long i; SYNCDBG(6,"Starting"); //_DK_process_armageddon(); return; if (game.armageddon_cast_turn == 0) return; if (game.armageddon.count_down+game.armageddon_cast_turn > game.play_gameturn) { if (player_cannot_win(game.armageddon_caster_idx)) { // Stop the armageddon if its originator is just losing game.armageddon_cast_turn = 0; } } else if (game.armageddon.count_down+game.armageddon_cast_turn == game.play_gameturn) { for (i=0; i < PLAYERS_COUNT; i++) { player = get_player(i); if (player_exists(player)) { if (player->field_2C == 1) reveal_whole_map(player); } } } else if (game.armageddon.count_down+game.armageddon_cast_turn < game.play_gameturn) { for (i=0; i < PLAYERS_COUNT; i++) { player = get_player(i); if ( (player_exists(player)) && (player->field_2C == 1) ) { dungeon = get_dungeon(player->id_number); if ((player->victory_state == VicS_Undecided) && (dungeon->num_active_creatrs == 0)) { event_kill_all_players_events(i); set_player_as_lost_level(player); if (is_my_player_number(i)) LbPaletteSet(engine_palette); heartng = get_player_soul_container(player->id_number); if (thing_exists(heartng)) { heartng->health = -1; } } } } } }
const struct Coord3d *dungeon_get_essential_pos(PlayerNumber plyr_idx) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); if (dungeon->dnheart_idx > 0) { struct Thing *heartng; heartng = thing_get(dungeon->dnheart_idx); if (thing_exists(heartng)) { return &heartng->mappos; } } return &dungeon->essential_pos; }
struct Thing *allocate_free_thing_structure_f(unsigned char allocflags, const char *func_name) { struct Thing *thing; long i; // Get a thing from "free things list" i = game.free_things_start_index; // If there is no free thing, try to free an effect if (i >= THINGS_COUNT-1) { if ((allocflags & FTAF_FreeEffectIfNoSlots) != 0) { thing = thing_get(game.thing_lists[TngList_EffectElems].index); if (!thing_is_invalid(thing)) { delete_thing_structure(thing, 0); } else { #if (BFDEBUG_LEVEL > 0) ERRORMSG("%s: Cannot free up effect element to allocate new thing!",func_name); #endif } } i = game.free_things_start_index; } // Now, if there is still no free thing (we couldn't free any) if (i >= THINGS_COUNT-1) { #if (BFDEBUG_LEVEL > 0) ERRORMSG("%s: Cannot allocate new thing, no free slots!",func_name); #endif return INVALID_THING; } // And if there is free one, allocate it thing = thing_get(game.free_things[i]); #if (BFDEBUG_LEVEL > 0) if (thing_exists(thing)) { ERRORMSG("%s: Found existing thing %d in free things list at pos %d!",func_name,(int)game.free_things[i],(int)i); } #endif LbMemorySet(thing, 0, sizeof(struct Thing)); if (thing_is_invalid(thing)) { ERRORMSG("%s: Got invalid thing slot instead of free one!",func_name); return INVALID_THING; } thing->alloc_flags |= TAlF_Exists; thing->index = game.free_things[i]; game.free_things[game.free_things_start_index] = 0; game.free_things_start_index++; TRACE_THING(thing); return thing; }
long get_explore_sight_distance_in_slabs(const struct Thing *thing) { struct PlayerInfo *player; if (!thing_exists(thing)) { return 0; } if (is_neutral_thing(thing)) { return 7; } player = get_player(thing->owner); long dist; if (player->controlled_thing_idx != thing->index) { dist = 7; } else { dist = get_creature_can_see_subtiles() / STL_PER_SLB; if (dist <= 7) dist = 7; } return dist; }
void select_transfer_creature(struct GuiButton *gbtn) { struct Dungeon *dungeon; dungeon = get_my_dungeon(); struct Thing *thing; thing = INVALID_THING; int listitm_idx; listitm_idx = selected_transfer_creature(dungeon, gbtn); if (listitm_idx != -1) { thing = get_player_list_nth_creature_of_model(dungeon->creatr_list_start, 0, listitm_idx); } if (thing_exists(thing)) { struct Packet *pckt; pckt = get_packet(my_player_number); set_packet_action(pckt, PckA_TransferCreatr, dungeon_special_selected, thing->index); turn_off_menu(GMnu_TRANSFER_CREATURE); } }
void resurrect_creature(struct Thing *boxtng, PlayerNumber owner, ThingModel crmodel, unsigned char crlevel) { struct Thing *creatng; if (!thing_exists(boxtng) || (box_thing_to_special(boxtng) != SpcKind_Resurrect) ) { ERRORMSG("Invalid resurrect box object!"); return; } creatng = create_creature(&boxtng->mappos, crmodel, owner); if (!thing_is_invalid(creatng)) { init_creature_level(creatng, crlevel); if (is_my_player_number(owner)) output_message(SMsg_CommonAcknowledge, 0, true); } create_special_used_effect(&boxtng->mappos, owner); remove_events_thing_is_attached_to(boxtng); force_any_creature_dragging_owned_thing_to_drop_it(boxtng); if ((gameadd.classic_bugs_flags & ClscBug_ResurrectForever) == 0) { remove_item_from_dead_creature_list(get_players_num_dungeon(owner), crmodel, crlevel); } delete_thing_structure(boxtng, 0); }
TbBool player_has_heart(PlayerNumber plyr_idx) { return thing_exists(get_player_soul_container(plyr_idx)); }
TbBool lights_stats_debug_dump(void) { long lights[LIGHTS_COUNT]; long lgh_things[THING_CLASSES_COUNT]; long shadowcs[SHADOW_CACHE_COUNT]; long shdc_used,shdc_linked,shdc_free; long lgh_used,lgh_free; long lgh_sttc,lgh_dynm; struct Thing * thing; struct Light *lgt; struct ShadowCache *shdc; long i,n; for (i=0; i < SHADOW_CACHE_COUNT; i++) { shdc = &game.lish.shadow_cache[i]; if ((shdc->flags & ShCF_Allocated) != 0) shadowcs[i] = -1; else shadowcs[i] = 0; } lgh_sttc = 0; lgh_dynm = 0; for (i=0; i < LIGHTS_COUNT; i++) { lgt = &game.lish.lights[i]; if ((lgt->flags & LgtF_Allocated) != 0) { lights[i] = -1; if ((lgt->flags & LgtF_Dynamic) != 0) lgh_dynm++; else lgh_sttc++; if ( (lgt->shadow_index > 0) && (lgt->shadow_index < SHADOW_CACHE_COUNT) ) { if (shadowcs[lgt->shadow_index] == -1) { shadowcs[lgt->shadow_index] = i; } else if (shadowcs[lgt->shadow_index] == 0) { WARNLOG("Shadow Cache %d is not allocated, but used by light %d!",(int)lgt->shadow_index,(int)i); } else { WARNLOG("Shadow Cache %d is double-allocated, for lights %d and %d!",(int)lgt->shadow_index,(int)shadowcs[lgt->shadow_index],(int)i); } } else if ((lgt->flags & LgtF_Dynamic) != 0) { WARNLOG("Dynamic light %d has bad Shadow Cache %d!",(int)i,(int)lgt->shadow_index); } } else { lights[i] = 0; } } for (i=1; i < THINGS_COUNT; i++) { thing = thing_get(i); if (thing_exists(thing)) { if ((thing->light_id > 0) && (thing->light_id < LIGHTS_COUNT)) { n = 1000+(long)thing->class_id; if (lights[thing->light_id] == -1) { lights[thing->light_id] = n; } else if (lights[thing->light_id] == 0) { WARNLOG("Light %d is not allocated, but used by %s!",(int)thing->light_id, thing_model_name(thing)); } else { WARNLOG("Light %d is double-allocated, for %d and %d!",(int)thing->light_id, (int)lights[thing->light_id], (int)n); } } } } lgh_used = 0; lgh_free = 0; for (i=0; i < THING_CLASSES_COUNT; i++) lgh_things[i] = 0; for (i=0; i < LIGHTS_COUNT; i++) { if (lights[i] != 0) { lgh_used++; if ((lights[i] > 1000) && (lights[i] < 1000+THING_CLASSES_COUNT)) lgh_things[lights[i]-1000]++; } else { lgh_free++; } } shdc_free = 0; shdc_used = 0; shdc_linked = 0; for (i=0; i < SHADOW_CACHE_COUNT; i++) { if (shadowcs[i] != 0) { shdc_used++; if (shadowcs[i] > 0) shdc_linked++; } else { shdc_free++; } } SYNCLOG("Lights: %ld free, %ld used; %ld static, %ld dynamic; for things:%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld",lgh_free,lgh_used,lgh_sttc,lgh_dynm,lgh_things[1],lgh_things[2],lgh_things[3],lgh_things[4],lgh_things[5],lgh_things[6],lgh_things[7],lgh_things[8],lgh_things[9],lgh_things[10],lgh_things[11],lgh_things[12],lgh_things[13]); if ((shdc_used != shdc_linked) || (shdc_used != lgh_dynm)) { WARNLOG("Amount of shadow cache mismatches: %ld free, %ld used, %ld linked to lights, %d dyn. lights.",shdc_free,shdc_used,shdc_linked,light_total_dynamic_lights); } if (lgh_sttc != light_total_stat_lights) { WARNLOG("Wrong global lights counter: %ld static lights and counter says %ld.",lgh_sttc,light_total_stat_lights); } if (lgh_dynm != light_total_dynamic_lights) { WARNLOG("Wrong global lights counter: %ld dynamic lights and counter says %ld.",lgh_dynm,light_total_dynamic_lights); } return false; }
void process_creature_in_training_room(struct Thing *thing, struct Room *room) { static const struct Around corners[] = { {1, 2}, {0, 1}, {1, 0}, {2, 1}, }; struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Thing *traintng; struct Thing *crtng; struct CreatureControl *cctrl2; struct Coord3d pos; long speed,dist; long i; cctrl = creature_control_get_from_thing(thing); SYNCDBG(8,"Starting %s mode %d",thing_model_name(thing),(int)cctrl->training.mode); //_DK_process_creature_in_training_room(thing, room); return; cctrl->field_4A = 0; switch (cctrl->training.mode) { case CrTrMd_SearchForTrainPost: // While we're in an instance, just wait if (cctrl->instance_id != CrInst_NULL) break; // On timeout, search for nearby training posts to start training ASAP if (cctrl->training.search_timeout < 1) { SYNCDBG(6,"Search timeout - selecting post nearest to (%d,%d)",(int)thing->mappos.x.stl.num, (int)thing->mappos.y.stl.num); setup_training_search_for_post(thing); cctrl->training.search_timeout = 100; break; } // Do a moving step cctrl->training.search_timeout--; speed = get_creature_speed(thing); i = creature_move_to(thing, &cctrl->moveto_pos, speed, 0, 0); if (i == 1) { // Move target is reached - find a training post which is supposed to be around here traintng = find_training_post_just_next_to_creature(thing); if (thing_is_invalid(traintng)) { SYNCDBG(6,"Reached (%d,%d) but there's no training post there",(int)thing->mappos.x.stl.num, (int)thing->mappos.y.stl.num); setup_move_to_new_training_position(thing, room, false); break; } // Found - go to next mode cctrl->training.mode = CrTrMd_SelectPositionNearTrainPost; cctrl->training.search_timeout = 50; } else if (i == -1) { ERRORLOG("Cannot get to (%d,%d) in the training room",(int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.y.stl.num); set_start_state(thing); } break; case CrTrMd_SelectPositionNearTrainPost: for (i=0; i < 4; i++) { long slb_x,slb_y; long stl_x,stl_y; struct SlabMap *slb; slb_x = subtile_slab_fast(thing->mappos.x.stl.num) + (long)small_around[i].delta_x; slb_y = subtile_slab_fast(thing->mappos.y.stl.num) + (long)small_around[i].delta_y; slb = get_slabmap_block(slb_x,slb_y); if ((slb->kind != SlbT_TRAINING) || (slabmap_owner(slb) != thing->owner)) continue; stl_x = slab_subtile(slb_x,corners[i].delta_x); stl_y = slab_subtile(slb_y,corners[i].delta_y); traintng = INVALID_THING; // Check if any other creature is using that post; allow only unused posts crtng = get_creature_of_model_training_at_subtile_and_owned_by(stl_x, stl_y, -1, thing->owner, thing->index); if (thing_is_invalid(crtng)) { traintng = get_object_at_subtile_of_model_and_owned_by(slab_subtile_center(slb_x), slab_subtile_center(slb_y), 31, thing->owner); } if (!thing_is_invalid(traintng)) { cctrl->training.pole_stl_x = slab_subtile_center(subtile_slab_fast(thing->mappos.x.stl.num)); cctrl->training.pole_stl_y = slab_subtile_center(subtile_slab_fast(thing->mappos.y.stl.num)); cctrl->moveto_pos.x.stl.num = stl_x; cctrl->moveto_pos.y.stl.num = stl_y; cctrl->moveto_pos.x.stl.pos = 128; cctrl->moveto_pos.y.stl.pos = 128; cctrl->moveto_pos.z.val = get_thing_height_at(thing, &cctrl->moveto_pos); if (thing_in_wall_at(thing, &cctrl->moveto_pos)) { ERRORLOG("Illegal setup to (%d,%d)", (int)cctrl->moveto_pos.x.stl.num, (int)cctrl->moveto_pos.y.stl.num); break; } cctrl->training.mode = CrTrMd_MoveToTrainPost; break; } } if (cctrl->training.mode == CrTrMd_SelectPositionNearTrainPost) setup_move_to_new_training_position(thing, room, 1); break; case CrTrMd_MoveToTrainPost: speed = get_creature_speed(thing); i = creature_move_to(thing, &cctrl->moveto_pos, speed, 0, 0); if (i == 1) { // If there's already someone training at that position, go somewhere else crtng = get_creature_of_model_training_at_subtile_and_owned_by(thing->mappos.x.stl.num, thing->mappos.y.stl.num, -1, thing->owner, thing->index); if (!thing_is_invalid(crtng)) { setup_move_to_new_training_position(thing, room, 1); break; } // Otherwise, train at this position cctrl->training.mode = CrTrMd_TurnToTrainPost; } else if (i == -1) { ERRORLOG("Cannot get where we're going in the training room."); set_start_state(thing); } break; case CrTrMd_TurnToTrainPost: pos.x.val = subtile_coord_center(cctrl->training.pole_stl_x); pos.y.val = subtile_coord_center(cctrl->training.pole_stl_y); if (creature_turn_to_face(thing, &pos) < 56) { cctrl->training.mode = CrTrMd_DoTrainWithTrainPost; cctrl->training.train_timeout = 75; } break; case CrTrMd_PartnerTraining: if (cctrl->training.partner_idx == 0) { setup_move_to_new_training_position(thing, room, false); return; } crtng = thing_get(cctrl->training.partner_idx); TRACE_THING(crtng); if (!thing_exists(crtng) || (get_creature_state_besides_move(crtng) != CrSt_Training) || (crtng->creation_turn != cctrl->training.partner_creation)) { SYNCDBG(8,"The %s cannot start partner training - creature to train with is gone.",thing_model_name(thing)); setup_move_to_new_training_position(thing, room, false); return; } cctrl2 = creature_control_get_from_thing(crtng); if (cctrl2->training.partner_idx != thing->index) { SYNCDBG(6,"The %s cannot start partner training - %s changed the partner.",thing_model_name(thing),thing_model_name(crtng)); cctrl->training.partner_idx = 0; setup_move_to_new_training_position(thing, room, false); break; } if (get_room_thing_is_on(crtng) != room) { SYNCDBG(8,"The %s cannot start partner training - partner has left the room.",thing_model_name(thing)); cctrl->training.partner_idx = 0; cctrl2->training.partner_idx = 0; setup_move_to_new_training_position(thing, room, false); break; } crstat = creature_stats_get_from_thing(thing); dist = get_combat_distance(thing, crtng); if (dist > 284) { if (creature_move_to(thing, &crtng->mappos, get_creature_speed(thing), 0, 0) == -1) { WARNLOG("The %s cannot navigate to training partner",thing_model_name(thing)); setup_move_to_new_training_position(thing, room, false); cctrl->training.partner_idx = 0; } } else if (dist >= 156) { if (creature_turn_to_face(thing, &crtng->mappos) < 56) { cctrl->training.train_timeout--; if (cctrl->training.train_timeout > 0) { if ((cctrl->instance_id == CrInst_NULL) && ((cctrl->training.train_timeout % 8) == 0)) { set_creature_instance(thing, CrInst_SWING_WEAPON_SWORD, 1, 0, 0); } } else { if (cctrl->instance_id == CrInst_NULL) { setup_move_to_new_training_position(thing, room, false); cctrl->training.partner_idx = 0; } else { cctrl->training.train_timeout = 1; } cctrl->exp_points += (room->efficiency * crstat->training_value); } } } else { creature_retreat_from_combat(thing, crtng, 33, 0); } break; case CrTrMd_DoTrainWithTrainPost: if (cctrl->training.train_timeout > 0) { // While training timeout is positive, continue initiating the train instances cctrl->training.train_timeout--; if ((cctrl->instance_id == CrInst_NULL) && ((cctrl->training.train_timeout % 8) == 0)) { set_creature_instance(thing, CrInst_SWING_WEAPON_SWORD, 1, 0, 0); } } else { // Wait for the instance to end, then select new move position if (cctrl->instance_id != CrInst_NULL) { cctrl->training.train_timeout = 0; } else { cctrl->training.train_timeout = 0; setup_move_to_new_training_position(thing, room, true); } } break; default: WARNLOG("Invalid %s training mode %d; reset",thing_model_name(thing),(int)cctrl->training.mode); cctrl->training.mode = CrTrMd_SearchForTrainPost; cctrl->training.search_timeout = 0; break; } SYNCDBG(18,"End"); }
void activate_dungeon_special(struct Thing *cratetng, struct PlayerInfo *player) { SYNCDBG(6,"Starting"); short used; struct Coord3d pos; int spkindidx; // Gathering data which we'll need if the special is used and disposed. memcpy(&pos,&cratetng->mappos,sizeof(struct Coord3d)); spkindidx = cratetng->model - 86; used = 0; if (thing_exists(cratetng) && is_dungeon_special(cratetng)) { switch (cratetng->model) { case 86: reveal_whole_map(player); remove_events_thing_is_attached_to(cratetng); used = 1; delete_thing_structure(cratetng, 0); break; case 87: start_resurrect_creature(player, cratetng); break; case 88: start_transfer_creature(player, cratetng); break; case 89: if (steal_hero(player, &cratetng->mappos)) { remove_events_thing_is_attached_to(cratetng); used = 1; delete_thing_structure(cratetng, 0); } break; case 90: multiply_creatures(player); remove_events_thing_is_attached_to(cratetng); used = 1; delete_thing_structure(cratetng, 0); break; case 91: increase_level(player); remove_events_thing_is_attached_to(cratetng); used = 1; delete_thing_structure(cratetng, 0); break; case 92: make_safe(player); remove_events_thing_is_attached_to(cratetng); used = 1; delete_thing_structure(cratetng, 0); break; case 93: activate_bonus_level(player); remove_events_thing_is_attached_to(cratetng); used = 1; delete_thing_structure(cratetng, 0); break; default: ERRORLOG("Invalid dungeon special (Model %d)", (int)cratetng->model); break; } if ( used ) { if (is_my_player(player)) output_message(special_desc[spkindidx].speech_msg, 0, true); create_special_used_effect(&pos, player->id_number); } } }
TbBool thing_exists_idx(long tng_idx) { return thing_exists(thing_get(tng_idx)); }