void setup_training_move_near(struct Thing *creatng, SubtlCodedCoords stl_num) { SubtlCodedCoords near_stl_num; MapSubtlDelta dist_x,dist_y; long stl_x,stl_y; stl_x = stl_num_decode_x(stl_num); stl_y = stl_num_decode_y(stl_num); // Select a subtile closer to current position dist_x = stl_x - (MapSubtlDelta)creatng->mappos.x.stl.num; dist_y = stl_y - (MapSubtlDelta)creatng->mappos.y.stl.num; if (abs(dist_x) > abs(dist_y)) { if (dist_x > 0) { stl_x -= 1; } else { stl_x += 1; } } else { if (dist_y > 0) { stl_y -= 1; } else { stl_y += 1; } } near_stl_num = get_subtile_number(stl_x,stl_y); setup_training_move(creatng, near_stl_num); }
/** * Finds a safe and unused, adjacent position in room for a creature. * * @param pos Position of the creature to be moved. * @param owner Room owner to keep. * @return Coded subtiles of the new position, or 0 on failure. * @see person_get_somewhere_adjacent_in_room() */ SubtlCodedCoords find_unused_adjacent_position_in_workshop(const struct Coord3d *pos, long owner) { static const struct Around corners[] = { {1,2}, {0,1}, {1,0}, {2,1} }; long i; for (i=0; i < SMALL_AROUND_LENGTH; i++) { MapSlabCoord slb_x, slb_y; slb_x = subtile_slab_fast(pos->x.stl.num) + (long)small_around[i].delta_x; slb_y = subtile_slab_fast(pos->y.stl.num) + (long)small_around[i].delta_y; struct SlabMap *slb; slb = get_slabmap_block(slb_x, slb_y); if ((slb->kind == SlbT_WORKSHOP) && (slabmap_owner(slb) == owner)) { struct Thing *mnfc_creatng; MapSubtlCoord stl_x, stl_y; stl_x = slab_subtile(slb_x, corners[i].delta_x); stl_y = slab_subtile(slb_y, corners[i].delta_y); mnfc_creatng = get_other_creature_manufacturing_on_subtile(owner, stl_x, stl_y, INVALID_THING); if (!thing_is_invalid(mnfc_creatng)) { // Position used by another manufacturer continue; } struct Thing *objtng; objtng = get_workshop_equipment_to_work_with_on_subtile(owner, slab_subtile_center(slb_x), slab_subtile_center(slb_y)); if (thing_is_invalid(objtng)) { // Position has no work equipment nearby continue; } // Found an acceptable position return get_subtile_number(stl_x, stl_y); } } return 0; }
void process_disease(struct Thing *creatng) { SYNCDBG(18,"Starting"); //_DK_process_disease(thing); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); if (!creature_affected_by_spell(creatng, SplK_Disease)) { return; } if (ACTION_RANDOM(100) < game.disease_transfer_percentage) { SubtlCodedCoords stl_num; long n; stl_num = get_subtile_number(creatng->mappos.x.stl.num,creatng->mappos.y.stl.num); for (n=0; n < AROUND_MAP_LENGTH; n++) { struct Thing *thing; struct Map *mapblk; unsigned long k; long i; mapblk = get_map_block_at_pos(stl_num+around_map[n]); k = 0; i = get_mapwho_thing_index(mapblk); while (i != 0) { thing = thing_get(i); if (thing_is_invalid(thing)) { WARNLOG("Jump out of things array"); break; } i = thing->next_on_mapblk; // Per thing code if (thing_is_creature(thing) && ((get_creature_model_flags(thing) & CMF_IsSpecDigger) == 0) && (thing->owner != cctrl->disease_caster_plyridx) && !creature_affected_by_spell(thing, SplK_Disease)) { struct CreatureControl *tngcctrl; tngcctrl = creature_control_get_from_thing(thing); apply_spell_effect_to_thing(thing, SplK_Disease, cctrl->explevel); tngcctrl->disease_caster_plyridx = cctrl->disease_caster_plyridx; } // Per thing code ends k++; if (k > THINGS_COUNT) { ERRORLOG("Infinite loop detected when sweeping things list"); erstat_inc(ESE_InfChainTngPerMapWho); break_mapwho_infinite_chain(mapblk); break; } } } } if (((game.play_gameturn - cctrl->disease_start_turn) % game.disease_lose_health_time) == 0) { apply_damage_to_thing_and_display_health(creatng, game.disease_lose_percentage_health * cctrl->max_health / 100, DmgT_Biological, cctrl->disease_caster_plyridx); } }
short creature_scavenged_disappear(struct Thing *thing) { struct CreatureControl *cctrl; struct Dungeon *dungeon; struct Room *room; struct Coord3d pos; long stl_x, stl_y; long i; //return _DK_creature_scavenged_disappear(thing); cctrl = creature_control_get_from_thing(thing); cctrl->byte_9A--; if (cctrl->byte_9A > 0) { if ((cctrl->byte_9A == 7) && (cctrl->byte_9B < PLAYERS_COUNT)) { create_effect(&thing->mappos, get_scavenge_effect_element(cctrl->byte_9B), thing->owner); } return 0; } // We don't really have to convert coordinates into numbers and back to XY. i = get_subtile_number(cctrl->scavenge.stl_9D_x, cctrl->scavenge.stl_9D_y); stl_x = stl_num_decode_x(i); stl_y = stl_num_decode_y(i); room = subtile_room_get(stl_x, stl_y); if (room_is_invalid(room) || (room->kind != RoK_SCAVENGER)) { ERRORLOG("Room %s at (%d,%d) disappeared.",room_code_name(RoK_SCAVENGER),(int)stl_x,(int)stl_y); kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects); return -1; } if (find_random_valid_position_for_thing_in_room(thing, room, &pos)) { move_thing_in_map(thing, &pos); anger_set_creature_anger_all_types(thing, 0); dungeon = get_dungeon(cctrl->byte_9B); dungeon->creatures_scavenge_gain++; if (is_my_player_number(thing->owner)) output_message(SMsg_MinionScanvenged, 0, true); cctrl->byte_9C = thing->owner; change_creature_owner(thing, cctrl->byte_9B); internal_set_thing_state(thing, CrSt_CreatureScavengedReappear); return 0; } else { ERRORLOG("No valid position inside %s room for %s.",room_code_name(room->kind),thing_model_name(thing)); kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects); return -1; } }
void clear_stat_light_map(void) { unsigned long x,y,i; game.lish.field_46149 = 32; game.lish.field_4614D = 0; game.lish.field_4614F = 0; for (y=0; y < (map_subtiles_y+1); y++) { for (x=0; x < (map_subtiles_x+1); x++) { i = get_subtile_number(x,y); game.lish.stat_light_map[i] = 0; } } }
void setup_move_to_new_training_position(struct Thing *thing, struct Room *room, unsigned long restart) { struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Thing *prtng; struct CreatureControl *prctrl; struct Coord3d pos; long i; SYNCDBG(8,"Starting for %s",thing_model_name(thing)); //_DK_setup_move_to_new_training_position(thing, room, a3); cctrl = creature_control_get_from_thing(thing); crstat = creature_stats_get_from_thing(thing); if ( restart ) cctrl->training.search_timeout = 50; // Try partner training if ((crstat->partner_training > 0) && (ACTION_RANDOM(100) < crstat->partner_training)) { prtng = get_creature_in_training_room_which_could_accept_partner(room, thing); if (!thing_is_invalid(prtng)) { SYNCDBG(7,"The %s found %s as training partner.",thing_model_name(thing),thing_model_name(prtng)); prctrl = creature_control_get_from_thing(prtng); prctrl->training.mode = CrTrMd_PartnerTraining; prctrl->training.train_timeout = 75; prctrl->training.partner_idx = thing->index; prctrl->training.partner_creation = thing->creation_turn; cctrl->training.mode = CrTrMd_PartnerTraining; cctrl->training.train_timeout = 75; cctrl->training.partner_idx = prtng->index; cctrl->training.partner_creation = prtng->creation_turn; return; } } // No partner - train at some random position cctrl->training.mode = CrTrMd_SearchForTrainPost; if (find_random_valid_position_for_thing_in_room(thing, room, &pos)) { SYNCDBG(8,"Going to train at (%d,%d)",(int)pos.x.stl.num,(int)pos.y.stl.num); i = get_subtile_number(pos.x.stl.num,pos.y.stl.num); setup_training_move(thing, i); } else { SYNCDBG(8,"No new position found, staying at (%d,%d)",(int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.x.stl.num); } if (cctrl->instance_id == CrInst_NULL) { set_creature_instance(thing, CrInst_SWING_WEAPON_SWORD, 1, 0, 0); } }
void setup_workshop_search_for_post(struct Thing *creatng) { struct Room *room; struct Thing *postng; postng = INVALID_THING; room = get_room_thing_is_on(creatng); // Find a random slab in the room to be used as our starting point long i; unsigned long n; i = ACTION_RANDOM(room->slabs_count); n = room->slabs_list; while (i > 0) { n = get_next_slab_number_in_room(n); i--; } i = room->slabs_count; while (i > 0) { // Loop the slabs list if (n <= 0) { n = room->slabs_list; } MapSlabCoord slb_x, slb_y; slb_x = subtile_slab_fast(stl_num_decode_x(n)); slb_y = subtile_slab_fast(stl_num_decode_y(n)); struct Thing *objtng; objtng = get_workshop_equipment_to_work_with_on_subtile(creatng->owner, slab_subtile_center(slb_x), slab_subtile_center(slb_y)); if (!thing_is_invalid(objtng)) { postng = objtng; } n = get_next_slab_number_in_room(n); i--; } if (thing_is_invalid(postng)) { SYNCDBG(9,"Work in %s, the %s moves to new pos",room_code_name(room->kind),thing_model_name(creatng)); setup_move_to_new_workshop_position(creatng, room, 1); } else { SYNCDBG(9,"Work in %s, the %s found a post",room_code_name(room->kind),thing_model_name(creatng)); setup_workshop_move(creatng, get_subtile_number(postng->mappos.x.stl.num, postng->mappos.y.stl.num)); } }
TbBool load_map_data_file(LevelNumber lv_num) { struct Map *mapblk; unsigned long x,y; unsigned char *buf; unsigned long i; unsigned long n; unsigned short *wptr; long fsize; clear_map(); fsize = 2*(map_subtiles_y+1)*(map_subtiles_x+1); buf = load_single_map_file_to_buffer(lv_num,"dat",&fsize,LMFF_None); if (buf == NULL) return false; i = 0; for (y=0; y < (map_subtiles_y+1); y++) { for (x=0; x < (map_subtiles_x+1); x++) { mapblk = get_map_block_at(x,y); n = -lword(&buf[i]); mapblk->data ^= (mapblk->data ^ n) & 0x7FF; i += 2; } } LbMemoryFree(buf); // Clear some bits and do some other setup for (y=0; y < (map_subtiles_y+1); y++) { for (x=0; x < (map_subtiles_x+1); x++) { mapblk = get_map_block_at(x,y); wptr = &game.lish.subtile_lightness[get_subtile_number(x,y)]; *wptr = 32; mapblk->data &= 0xFFC007FFu; mapblk->data &= ~0x0F000000; mapblk->data &= ~0xF0000000; } } return true; }
short good_back_at_start(struct Thing *thing) { // Debug code to find incorrect states if (!is_hero_thing(thing)) { ERRORLOG("Non hero thing %ld, %s, owner %ld - reset",(long)thing->index,thing_model_name(thing),(long)thing->owner); set_start_state(thing); return false; } //return _DK_good_back_at_start(thing); if (thing->creature.gold_carried <= 0) { set_start_state(thing); return 1; } SubtlCodedCoords stl_num; long m,n; stl_num = get_subtile_number(thing->mappos.x.stl.num,thing->mappos.y.stl.num); m = ACTION_RANDOM(AROUND_MAP_LENGTH); for (n=0; n < AROUND_MAP_LENGTH; n++) { struct Map *mapblk; mapblk = get_map_block_at_pos(stl_num+around_map[m]); // Per-block code if ((mapblk->flags & MapFlg_IsTall) == 0) { MapSubtlCoord stl_x, stl_y; stl_x = stl_num_decode_x(stl_num+around_map[m]); stl_y = stl_num_decode_y(stl_num+around_map[m]); if (setup_person_move_to_position(thing, stl_x, stl_y, NavRtF_Default)) { thing->continue_state = CrSt_GoodDropsGold; return 1; } } // Per-block code ends m = (m + 1) % AROUND_MAP_LENGTH; } set_start_state(thing); return 1; }
/** * Finds a random training post near to the current position of given creature. * Used when finding a training post seems to be taking too long; in that case, creature should start training with a nearest post. * Note that this routine does not always select the nearest post - it is enough if it's 3 subtiles away. * * @param creatng The creature who wish to train with training post. */ void setup_training_search_for_post(struct Thing *creatng) { struct Room *room; struct Thing *traintng; struct Thing *thing; long start_slab; long min_distance,dist; long slb_x,slb_y; long i,k; room = get_room_thing_is_on(creatng); // Let's start from a random slab slb_x = -1; slb_y = -1; min_distance = LONG_MAX; traintng = INVALID_THING; start_slab = ACTION_RANDOM(room->slabs_count); k = start_slab; i = room->slabs_list; while (i != 0) { slb_x = slb_num_decode_x(i); slb_y = slb_num_decode_y(i); i = get_next_slab_number_in_room(i); if (k <= 0) break; k--; } // Got random starting slab, now sweep room slabs from it thing = INVALID_THING; k = room->slabs_count; i = get_slab_number(slb_x,slb_y); while (k > 0) { slb_x = slb_num_decode_x(i); slb_y = slb_num_decode_y(i); i = get_next_slab_number_in_room(i); if (i == 0) i = room->slabs_list; // Per room tile code - find a nearest training post thing = get_object_at_subtile_of_model_and_owned_by(slab_subtile_center(slb_x), slab_subtile_center(slb_y), 31, creatng->owner); if (!thing_is_invalid(thing)) { dist = get_2d_distance(&creatng->mappos, &thing->mappos); if (dist < min_distance) { traintng = thing; min_distance = dist; if (min_distance < (3<<8)) break; } } // Per room tile code ends k--; } // Got trainer (or not...), now do the correct action if (thing_is_invalid(traintng)) { SYNCDBG(6,"Room no longer have training post, moving somewhere else."); setup_move_to_new_training_position(creatng, room, true); } else { i = get_subtile_number(traintng->mappos.x.stl.num,traintng->mappos.y.stl.num); setup_training_move_near(creatng, i); } }