long creature_move_direct_line_backwards(struct Thing *thing, struct Coord3d *nextpos, MoveSpeed speed)
{
    if (creature_turn_to_face_backwards(thing, nextpos) > 0)
    {
        // Creature is turning - don't let it move
        creature_set_speed(thing, 0);
        return 2;
    }
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(thing);
    creature_set_speed(thing, -speed);
    cctrl->flgfield_2 |= TF2_Unkn01;
    if (get_2d_box_distance(&thing->mappos, nextpos) > -2*cctrl->move_speed)
    {
        ERRORDBG(3,"The %s index %d tried to reach (%d,%d) from (%d,%d) with excessive backward speed",
            thing_model_name(thing),(int)thing->index,(int)nextpos->x.stl.num,(int)nextpos->y.stl.num,
            (int)thing->mappos.x.stl.num,(int)thing->mappos.y.stl.num);
        cctrl->moveaccel.x.val = distance_with_angle_to_coord_x(cctrl->move_speed, thing->move_angle_xy);
        cctrl->moveaccel.y.val = distance_with_angle_to_coord_y(cctrl->move_speed, thing->move_angle_xy);
        cctrl->moveaccel.z.val = 0;
        return 1;
    } else
    {
        cctrl->moveaccel.x.val = nextpos->x.val - (MapCoordDelta)thing->mappos.x.val;
        cctrl->moveaccel.y.val = nextpos->y.val - (MapCoordDelta)thing->mappos.y.val;
        cctrl->moveaccel.z.val = 0;
        return 0;
    }
}
Exemple #2
0
TbBool set_door_buildable_and_add_to_amount(PlayerNumber plyr_idx, ThingModel tngmodel, long buildable, long amount)
{
    struct Dungeon *dungeon;
    if ( (tngmodel <= 0) || (tngmodel >= DOOR_TYPES_COUNT) ) {
        ERRORDBG(1,"Can't set door availability; invalid door kind %d.",(int)tngmodel);
        return false;
    }
    dungeon = get_dungeon(plyr_idx);
    if (dungeon_invalid(dungeon)) {
        ERRORDBG(11,"Can't set door availability; player %d has no dungeon.",(int)plyr_idx);
        return false;
    }
    if (buildable)
        dungeon->door_build_flags[tngmodel] |= MnfBldF_Manufacturable;
    dungeon->door_amount_offmap[tngmodel] += amount;
    dungeon->door_amount_placeable[tngmodel] += amount;
    if (amount > 0)
      dungeon->door_build_flags[tngmodel] |= MnfBldF_Built;
    return true;
}
Exemple #3
0
void delaunay_stack_point(long pt_x, long pt_y)
{
    long tri_idx,cor_idx;
    long dst_tri_idx,dst_cor_idx;
    long tri_id2, i;
    NAVIDBG(19,"Starting");
    //_DK_delaunay_stack_point(pt_x, pt_y); return;

    tri_idx = triangle_find8(pt_x << 8, pt_y << 8);
    if (tri_idx == -1) {
        NAVIDBG(19,"Tri not found");
        return;
    }
    delaunay_add_triangle(tri_idx);
    for (cor_idx=0; cor_idx < 3; cor_idx++)
    {
        tri_id2 = Triangles[tri_idx].tags[cor_idx];
        if (tri_id2 != -1) {
            delaunay_add_triangle(tri_id2);
        }
    }
    if (point_find(pt_x, pt_y, &dst_tri_idx, &dst_cor_idx))
    {
      tri_idx = dst_tri_idx;
      cor_idx = dst_cor_idx;
      unsigned long k;
      k = 0;
      do
      {
          tri_id2 = Triangles[tri_idx].tags[cor_idx];
          if (tri_id2 == -1) {
              NAVIDBG(19,"Tag not found");
              break;
          }
          i = link_find(tri_id2, tri_idx);
          if (i == -1) {
              NAVIDBG(19,"Link not found");
              break;
          }
          cor_idx = MOD3[i+1];
          tri_idx = tri_id2;
          delaunay_add_triangle(tri_idx);
          k++;
          if (k >= TRIANLGLES_COUNT) {
              ERRORDBG(9,"Infinite loop detected");
              break;
          }
      }
      while (tri_idx != dst_tri_idx);
    }
    NAVIDBG(19,"Done");
}
Exemple #4
0
struct Thing *create_cave_in(struct Coord3d *pos, unsigned short cimodel, unsigned short owner)
{
    struct MagicStats *magstat;
    struct Dungeon *dungeon;
    struct Thing *thing;
    if ( !i_can_allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots) )
    {
        ERRORDBG(3,"Cannot create cave in %d for player %d. There are too many things allocated.",(int)cimodel,(int)owner);
        erstat_inc(ESE_NoFreeThings);
        return INVALID_THING;
    }
    thing = allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots);
    if (thing->index == 0) {
        ERRORDBG(3,"Should be able to allocate cave in %d for player %d, but failed.",(int)cimodel,(int)owner);
        erstat_inc(ESE_NoFreeThings);
        return INVALID_THING;
    }
    thing->class_id = TCls_CaveIn;
    thing->model = 0;
    thing->parent_idx = thing->index;
    memcpy(&thing->mappos,pos,sizeof(struct Coord3d));
    thing->owner = owner;
    thing->creation_turn = game.play_gameturn;
    magstat = &game.keeper_power_stats[PwrK_CAVEIN];
    thing->word_15 = magstat->time;
    thing->byte_13 = pos->x.stl.num;
    thing->byte_14 = pos->y.stl.num;
    thing->byte_17 = cimodel;
    thing->health = magstat->time;
    if (owner != game.neutral_player_num)
    {
        dungeon = get_dungeon(owner);
        dungeon->camera_deviate_quake = thing->word_15;
    }
    add_thing_to_its_class_list(thing);
    place_thing_in_mapwho(thing);
    return thing;
}
Exemple #5
0
long tree_to_route(long tag_start_id, long tag_end_id, long *route_pts)
{
    long ipt;
    if (tag_current != Tags[tag_start_id])
        return -1;
    ipt = copy_tree_to_route(tag_start_id, tag_end_id, route_pts, 3000+1);
    if (ipt < 0)
    {
        erstat_inc(ESE_BadRouteTree);
        ERRORDBG(6,"route length overflow");
    }
    return ipt;

}
Exemple #6
0
struct Thing *create_ambient_sound(const struct Coord3d *pos, ThingModel model, PlayerNumber owner)
{
    struct Thing *thing;
    if ( !i_can_allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots) )
    {
        ERRORDBG(3,"Cannot create ambient sound %d for player %d. There are too many things allocated.",(int)model,(int)owner);
        erstat_inc(ESE_NoFreeThings);
        return INVALID_THING;
    }
    thing = allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots);
    if (thing->index == 0) {
        ERRORDBG(3,"Should be able to allocate ambient sound %d for player %d, but failed.",(int)model,(int)owner);
        erstat_inc(ESE_NoFreeThings);
        return INVALID_THING;
    }
    thing->class_id = TCls_AmbientSnd;
    thing->model = model;
    thing->parent_idx = thing->index;
    memcpy(&thing->mappos,pos,sizeof(struct Coord3d));
    thing->owner = owner;
    thing->field_4F |= TF4F_DoNotDraw;
    add_thing_to_its_class_list(thing);
    return thing;
}
long light_create_light(struct InitLight *ilght)
{
    struct Light *lgt;
    struct ShadowCache *shdc;
    unsigned long k;
    lgt = light_allocate_light();
    if (light_is_invalid(lgt)) {
        return 0;
    }
    if (ilght->is_dynamic)
    {
        shdc = light_allocate_shadow_cache();
        if (light_shadow_cache_invalid(shdc))
        {
            ERRORDBG(11,"Cannot allocate cache for dynamic light");
            light_free_light(lgt);
            return 0;
        }
        light_total_dynamic_lights++;
        lgt->shadow_index = light_shadow_cache_index(shdc);
        light_add_light_to_list(lgt, &game.thing_lists[TngList_DynamLights]);
    } else
    {
        light_total_stat_lights++;
        light_add_light_to_list(lgt, &game.thing_lists[TngList_StaticLights]);
        stat_light_needs_updating = 1;
    }
    lgt->flags |= LgtF_Unkn02;
    lgt->flags |= LgtF_Unkn08;
    lgt->mappos.x.val = ilght->mappos.x.val;
    lgt->mappos.y.val = ilght->mappos.y.val;
    lgt->mappos.z.val = ilght->mappos.z.val;
    lgt->field_16 = ilght->field_0;
    lgt->field_2 = ilght->field_2;
    k = 2 * ilght->field_3;
    lgt->field_1 = k ^ ((k ^ lgt->field_1) & 0x01);
    set_flag_byte(&lgt->flags,LgtF_Dynamic,ilght->is_dynamic);
    lgt->field_1A = ilght->field_8;
    lgt->field_18 = ilght->field_4;
    lgt->field_12 = ilght->field_12;
    return lgt->index;
}
Exemple #8
0
/**
 * Counts amount of rooms of specific type owned by specific player.
 * @param plyr_idx The player number. Only specific player number is accepted.
 * @param rkind Room kind to count. Only specific kind is accepted.
 */
long count_player_rooms_of_type(PlayerNumber plyr_idx, RoomKind rkind)
{
    struct Dungeon *dungeon;
    struct Room *room;
    long i;
    unsigned long k;
    // note that we can't get_players_num_dungeon() because players
    // may be uninitialized yet when this is called.
    dungeon = get_dungeon(plyr_idx);
    if (dungeon_invalid(dungeon))
        return 0;
    i = dungeon->room_kind[rkind];
    k = 0;
    while (i != 0)
    {
        room = room_get(i);
        if (room_is_invalid(room))
        {
            ERRORLOG("Jump to invalid room detected");
            break;
        }
        i = room->next_of_owner;
        // No Per-room code - we only want count
        SYNCDBG(19,"Player %d has %s at (%d,%d)",(int)plyr_idx, room_code_name(room->kind), (int)room->central_stl_x, (int)room->central_stl_y);
        if (room->owner != plyr_idx) {
            ERRORDBG(3,"Player %d has bad room in %s list; it's really %s index %d owned by player %d",(int)plyr_idx, room_code_name(rkind), room_code_name(room->kind), (int)room->index, (int)room->owner);
            break;
        }
        k++;
        if (k > ROOMS_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping rooms list");
            break;
        }
    }
    return k;
}
TbBool sibling_line_of_sight_ignoring_door(const struct Coord3d *prevpos,
    const struct Coord3d *nextpos, const struct Thing *doortng)
{
    // If we don't want to ignore any doors
    if (thing_is_invalid(doortng))
    {
        // Check for door at central subtile
        if (subtile_is_door(stl_slab_center_subtile(nextpos->x.stl.num),stl_slab_center_subtile(nextpos->y.stl.num))) {
            return false;
        }
    }
    // If only one dimensions changed, allow the pass
    // (in that case the outcome has been decided before this call)
    if ((nextpos->x.stl.num == prevpos->x.stl.num) ||
        (nextpos->y.stl.num == prevpos->y.stl.num)) {
        // change is (x,0) or (0,x)
        return true;
    }
    struct Coord3d posmvx;
    struct Coord3d posmvy;
    MapSubtlDelta subdelta_x, subdelta_y;
    subdelta_x = (nextpos->x.stl.num - (MapSubtlDelta)prevpos->x.stl.num);
    subdelta_y = (nextpos->y.stl.num - (MapSubtlDelta)prevpos->y.stl.num);
    switch (subdelta_x + 2 * subdelta_y)
    {
    case -3:
        posmvx.x.val = prevpos->x.val - COORD_PER_STL;
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val - COORD_PER_STL;
        posmvy.z.val = prevpos->z.val;
        if (point_in_map_is_solid_ignoring_door(&posmvx, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) X",(int)posmvx.x.stl.num,(int)posmvx.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        if (point_in_map_is_solid_ignoring_door(&posmvy, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) Y",(int)posmvy.x.stl.num,(int)posmvy.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        break;

    case -1:
        posmvx.x.val = prevpos->x.val + COORD_PER_STL;
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val - COORD_PER_STL;
        posmvy.z.val = prevpos->z.val;
        if (point_in_map_is_solid_ignoring_door(&posmvx, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) X",(int)posmvx.x.stl.num,(int)posmvx.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        if (point_in_map_is_solid_ignoring_door(&posmvy, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) Y",(int)posmvy.x.stl.num,(int)posmvy.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        break;

    case 1:
        posmvx.x.val = prevpos->x.val - COORD_PER_STL;
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val + COORD_PER_STL;
        posmvy.z.val = prevpos->z.val;
        if (point_in_map_is_solid_ignoring_door(&posmvx, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) X",(int)posmvx.x.stl.num,(int)posmvx.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        if (point_in_map_is_solid_ignoring_door(&posmvy, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) Y",(int)posmvy.x.stl.num,(int)posmvy.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        break;

    case 3:
        posmvx.x.val = prevpos->x.val + COORD_PER_STL;
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val + COORD_PER_STL;
        posmvy.z.val = prevpos->z.val;
        if (point_in_map_is_solid_ignoring_door(&posmvx, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) X",(int)posmvx.x.stl.num,(int)posmvx.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        if (point_in_map_is_solid_ignoring_door(&posmvy, doortng)) {
            SYNCDBG(17, "Cannot see through (%d,%d) with delta (%d,%d) Y",(int)posmvy.x.stl.num,(int)posmvy.y.stl.num,(int)subdelta_x,(int)subdelta_y);
            return false;
        }
        break;

    default:
        ERRORDBG(8,"Invalid use of sibling function, delta (%d,%d)",(int)subdelta_x,(int)subdelta_y);
        break;
    }
    return true;
}
Exemple #10
0
TbBool sibling_line_of_sight_3d_including_lava_check_ignoring_own_door(const struct Coord3d *prevpos,
    const struct Coord3d *nextpos, PlayerNumber plyr_idx)
{
    // Check for door at central subtile
    if (subtile_is_door(stl_slab_center_subtile(nextpos->x.stl.num), stl_slab_center_subtile(nextpos->y.stl.num))) {
        return false;
    }
    // If only one dimensions changed, allow the pass
    // (in that case the outcome has been decided before this call)
    if ((nextpos->x.stl.num == prevpos->x.stl.num)
     || (nextpos->y.stl.num == prevpos->y.stl.num)) {
        // change is (x,0) or (0,x)
        return true;
    }
    struct Coord3d posmvy;
    struct Coord3d posmvx;
    int subdelta_x, subdelta_y;
    subdelta_x = (nextpos->x.stl.num - (MapSubtlDelta)prevpos->x.stl.num);
    subdelta_y = (nextpos->y.stl.num - (MapSubtlDelta)prevpos->y.stl.num);
    switch (subdelta_x + 2 * subdelta_y)
    {
    case -3: // change is (-1,-1)
        posmvx.x.val = prevpos->x.val - subtile_coord(1,0);
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val - subtile_coord(1,0);
        posmvy.z.val = prevpos->z.val;
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvy, plyr_idx) & 0x01) {
            return false;
        }
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvx, plyr_idx) & 0x01) {
            return false;
        }
        break;

    case -1: // change is (1,-1) as (-1,0) was eliminated earlier
        posmvx.x.val = prevpos->x.val + subtile_coord(1,0);
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val - subtile_coord(1,0);
        posmvy.z.val = prevpos->z.val;
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvy, plyr_idx) & 0x01) {
            return false;
        }
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvx, plyr_idx) & 0x01) {
            return false;
        }
        break;

    case 1: // change is (-1,1) as (1,0) was eliminated earlier
        posmvx.x.val = prevpos->x.val - subtile_coord(1,0);
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val + subtile_coord(1,0);
        posmvy.z.val = prevpos->z.val;
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvy, plyr_idx) & 0x01) {
            return false;
        }
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvx, plyr_idx) & 0x01) {
            return false;
        }
        break;

    case 3: // change is (1,1)
        posmvx.x.val = prevpos->x.val + subtile_coord(1,0);
        posmvx.y.val = prevpos->y.val;
        posmvx.z.val = prevpos->z.val;
        posmvy.x.val = prevpos->x.val;
        posmvy.y.val = prevpos->y.val + subtile_coord(1,0);
        posmvy.z.val = prevpos->z.val;
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvy, plyr_idx) & 0x01) {
            return false;
        }
        if (get_point_in_map_solid_flags_ignoring_own_door(&posmvx, plyr_idx) & 0x01) {
            return false;
        }
        break;

    default:
        ERRORDBG(8,"Invalid use of sibling function, delta (%d,%d)",(int)subdelta_x,(int)subdelta_y);
        break;
    }
    return true;
}
long creature_move_to_using_gates(struct Thing *thing, struct Coord3d *pos, MoveSpeed speed, long a4, NaviRouteFlags flags, TbBool backward)
{
    struct Coord3d nextpos;
    AriadneReturn follow_result;
    long i;
    SYNCDBG(18,"Starting to move %s index %d from (%d,%d) to (%d,%d) with speed %d",thing_model_name(thing),
        (int)thing->index,(int)thing->mappos.x.stl.num,(int)thing->mappos.y.stl.num,(int)pos->x.stl.num,(int)pos->y.stl.num,(int)speed);
    TRACE_THING(thing);
    if ( backward )
    {
        // Rotate the creature 180 degrees to trace route with forward move
        i = (thing->move_angle_xy + LbFPMath_PI);
        thing->move_angle_xy = i & LbFPMath_AngleMask;
    }
    follow_result = creature_follow_route_to_using_gates(thing, pos, &nextpos, speed, flags);
    SYNCDBG(18,"The %s index %d route result: %d, next pos (%d,%d)",thing_model_name(thing),(int)thing->index,(int)follow_result,(int)nextpos.x.stl.num,(int)nextpos.y.stl.num);
    if ( backward )
    {
        // Rotate the creature back
        i = (thing->move_angle_xy + LbFPMath_PI);
        thing->move_angle_xy = i & LbFPMath_AngleMask;
    }
    if ((follow_result == AridRet_PartOK) || (follow_result == AridRet_Val2))
    {
        creature_set_speed(thing, 0);
        return -1;
    }
    if (follow_result == AridRet_FinalOK)
    {
        return  1;
    }
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(thing);
    if ( backward )
    {
        if (creature_turn_to_face_backwards(thing, &nextpos) > 0)
        {
            // Creature is turning - don't let it move
            creature_set_speed(thing, 0);
        } else
        {
            creature_set_speed(thing, -speed);
            cctrl->flgfield_2 |= TF2_Unkn01;
            if (get_2d_box_distance(&thing->mappos, &nextpos) > -2*cctrl->move_speed)
            {
                ERRORDBG(3,"The %s index %d tried to reach (%d,%d) from (%d,%d) with excessive backward speed",
                    thing_model_name(thing),(int)thing->index,(int)nextpos.x.stl.num,(int)nextpos.y.stl.num,
                    (int)thing->mappos.x.stl.num,(int)thing->mappos.y.stl.num);
                cctrl->moveaccel.x.val = distance_with_angle_to_coord_x(cctrl->move_speed, thing->move_angle_xy);
                cctrl->moveaccel.y.val = distance_with_angle_to_coord_y(cctrl->move_speed, thing->move_angle_xy);
                cctrl->moveaccel.z.val = 0;
            } else
            {
                cctrl->moveaccel.x.val = nextpos.x.val - (MapCoordDelta)thing->mappos.x.val;
                cctrl->moveaccel.y.val = nextpos.y.val - (MapCoordDelta)thing->mappos.y.val;
                cctrl->moveaccel.z.val = 0;
            }
        }
        SYNCDBG(18,"Backward target set, speed %d, accel (%d,%d)",(int)cctrl->move_speed,(int)cctrl->moveaccel.x.val,(int)cctrl->moveaccel.y.val);
    } else
    {
        if (creature_turn_to_face(thing, &nextpos) > 0)
        {
            // Creature is turning - don't let it move
            creature_set_speed(thing, 0);
        } else
        {
            creature_set_speed(thing, speed);
            cctrl->flgfield_2 |= TF2_Unkn01;
            if (get_2d_box_distance(&thing->mappos, &nextpos) > 2*cctrl->move_speed)
            {
                ERRORDBG(3,"The %s index %d tried to reach (%d,%d) from (%d,%d) with excessive forward speed",
                    thing_model_name(thing),(int)thing->index,(int)nextpos.x.stl.num,(int)nextpos.y.stl.num,
                    (int)thing->mappos.x.stl.num,(int)thing->mappos.y.stl.num);
                cctrl->moveaccel.x.val = distance_with_angle_to_coord_x(cctrl->move_speed, thing->move_angle_xy);
                cctrl->moveaccel.y.val = distance_with_angle_to_coord_y(cctrl->move_speed, thing->move_angle_xy);
                cctrl->moveaccel.z.val = 0;
            } else
            {
                cctrl->moveaccel.x.val = nextpos.x.val - (MapCoordDelta)thing->mappos.x.val;
                cctrl->moveaccel.y.val = nextpos.y.val - (MapCoordDelta)thing->mappos.y.val;
                cctrl->moveaccel.z.val = 0;
            }
        }
        SYNCDBG(18,"Forward target set, speed %d, accel (%d,%d)",(int)cctrl->move_speed,(int)cctrl->moveaccel.x.val,(int)cctrl->moveaccel.y.val);
    }
    return 0;
}
Exemple #12
0
struct Thing *create_trap(struct Coord3d *pos, ThingModel trpkind, PlayerNumber plyr_idx)
{
    SYNCDBG(7,"Starting");
    struct TrapStats *trapstat;
    trapstat = &trap_stats[trpkind];
    if (!i_can_allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots)) {
        ERRORDBG(3,"Cannot create trap %s for player %d. There are too many things allocated.",trap_code_name(trpkind),(int)plyr_idx);
        erstat_inc(ESE_NoFreeThings);
        return INVALID_THING;
    }
    struct InitLight ilght;
    LbMemorySet(&ilght, 0, sizeof(struct InitLight));
    struct Thing *thing;
    thing = allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots);
    if (thing->index == 0) {
        ERRORDBG(3,"Should be able to allocate trap %s for player %d, but failed.",trap_code_name(trpkind),(int)plyr_idx);
        erstat_inc(ESE_NoFreeThings);
        return INVALID_THING;
    }
    thing->class_id = TCls_Trap;
    thing->model = trpkind;
    thing->mappos.x.val = pos->x.val;
    thing->mappos.y.val = pos->y.val;
    thing->mappos.z.val = pos->z.val;
    thing->next_on_mapblk = 0;
    thing->parent_idx = thing->index;
    thing->owner = plyr_idx;
    char start_frame;
    if (trapstat->field_13) {
        start_frame = -1;
    } else {
        start_frame = 0;
    }
    set_thing_draw(thing, trapstat->field_4, trapstat->field_D, trapstat->field_8, trapstat->field_C, start_frame, 2);
    if (trapstat->field_11) {
        thing->field_4F |= 0x02;
    } else {
        thing->field_4F &= ~0x02;
    }
    if (trapstat->field_C) {
        thing->field_4F |= 0x40;
    } else {
        thing->field_4F &= ~0x40;
    }
    thing->clipbox_size_xy = trapstat->size_xy;
    thing->clipbox_size_yz = trapstat->field_16;
    thing->solid_size_xy = trapstat->size_xy;
    thing->field_5C = trapstat->field_16;
    thing->creation_turn = game.play_gameturn;
    thing->health = trapstat->field_0;
    thing->field_4F &= ~0x10;
    thing->field_4F |= 0x20;
    thing->byte_13 = 0;
    thing->long_14 = game.play_gameturn;
    if (trapstat->field_1C != 0)
    {
        ilght.mappos.x.val = thing->mappos.x.val;
        ilght.mappos.y.val = thing->mappos.y.val;
        ilght.mappos.z.val = thing->mappos.z.val;
        ilght.field_0 = trapstat->field_1C;
        ilght.field_2 = trapstat->field_1E;
        ilght.is_dynamic = 1;
        ilght.field_3 = trapstat->field_1F;
        thing->light_id = light_create_light(&ilght);
        if (thing->light_id <= 0) {
            SYNCDBG(8,"Cannot allocate dynamic light to %s.",thing_model_name(thing));
        }
    }
    add_thing_to_its_class_list(thing);
    place_thing_in_mapwho(thing);
    return thing;
}