// ZZZ: If not already in predictive mode, save off partial game-state for later restoration. static void enter_predictive_mode() { if(sPredictedTicks == 0) { for(short i = 0; i < dynamic_world->player_count; i++) { sSavedPlayerData[i] = *get_player_data(i); if(sSavedPlayerData[i].monster_index != NONE) { sSavedPlayerMonsterData[i] = *get_monster_data(sSavedPlayerData[i].monster_index); if(sSavedPlayerMonsterData[i].object_index != NONE) { sSavedPlayerObjectData[i] = *get_object_data(sSavedPlayerMonsterData[i].object_index); sSavedPlayerObjectNextObject[i] = sSavedPlayerObjectData[i].next_object; if(sSavedPlayerObjectData[i].parasitic_object != NONE) sSavedPlayerParasiticObjectData[i] = *get_object_data(sSavedPlayerObjectData[i].parasitic_object); } } } // Sanity checking sSavedTickCount = dynamic_world->tick_count; sSavedRandomSeed = get_random_seed(); } }
static void m2_swipe_nearby_items(short player_index) { object_data *object; object_data *player_object; player_data *player= get_player_data(player_index); short next_object; polygon_data *polygon; short *neighbor_indexes; short i; player_object= get_object_data(get_monster_data(player->monster_index)->object_index); polygon= get_polygon_data(player_object->polygon); neighbor_indexes= get_map_indexes(polygon->first_neighbor_index, polygon->neighbor_count); // Skip this step if neighbor indexes were not found if (!neighbor_indexes) return; for (i=0;i<polygon->neighbor_count;++i) { polygon_data *neighboring_polygon= get_polygon_data(*neighbor_indexes++); if (POLYGON_IS_DETACHED(neighboring_polygon)) continue; next_object= neighboring_polygon->first_object; while(next_object != NONE) { object= get_object_data(next_object); if (GET_OBJECT_OWNER(object)==_object_is_item && !OBJECT_IS_INVISIBLE(object)) { if (guess_distance2d((world_point2d *) &player->location, (world_point2d *) &object->location)<=MAXIMUM_ARM_REACH) { world_distance radius, height; get_monster_dimensions(player->monster_index, &radius, &height); if (object->location.z >= player->location.z - MAXIMUM_ARM_REACH && object->location.z <= player->location.z + height && test_item_retrieval(player_object->polygon, &player_object->location, &object->location)) { if(get_item(player_index, next_object)) { /* Start the search again.. */ next_object= neighboring_polygon->first_object; continue; } } } } next_object= object->next_object; } } }
static int Lua_Monster_Get_Polygon(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); object_data *object = get_object_data(monster->object_index); Lua_Polygon::Push(L, object->polygon); return 1; }
static int Lua_Monster_Get_Facing(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); object_data *object = get_object_data(monster->object_index); lua_pushnumber(L, (double) object->facing * AngleConvert); return 1; }
static int Lua_Effect_Get_Facing(lua_State* L) { effect_data* effect = get_effect_data(Lua_Effect::Index(L, 1)); object_data* object = get_object_data(effect->object_index); lua_pushnumber(L, (double) object->facing * AngleConvert); return 1; }
static int Lua_Effect_Get_Polygon(lua_State* L) { effect_data* effect = get_effect_data(Lua_Effect::Index(L, 1)); object_data* object = get_object_data(effect->object_index); Lua_Polygon::Push(L, object->polygon); return 1; }
static int Lua_Effect_Get_Z(lua_State* L) { effect_data* effect = get_effect_data(Lua_Effect::Index(L, 1)); object_data* object = get_object_data(effect->object_index); lua_pushnumber(L, (double) object->location.z / WORLD_ONE); return 1; }
int Lua_Effect_Position(lua_State* L) { if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4)) return luaL_error(L, "position: incorrect argument type"); short polygon_index = 0; if (lua_isnumber(L, 5)) { polygon_index = static_cast<int>(lua_tonumber(L, 5)); if (!Lua_Polygon::Valid(polygon_index)) return luaL_error(L, "position: invalid polygon index"); } else if (Lua_Polygon::Is(L, 5)) { polygon_index = Lua_Polygon::Index(L, 5); } else return luaL_error(L, "position: incorrect argument type"); effect_data* effect = get_effect_data(Lua_Effect::Index(L, 1)); object_data *object = get_object_data(effect->object_index); object->location.x = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE); object->location.y = static_cast<int>(lua_tonumber(L, 3) * WORLD_ONE); object->location.z = static_cast<int>(lua_tonumber(L, 4) * WORLD_ONE); if (polygon_index != object->polygon) { remove_object_from_polygon_object_list(effect->object_index); add_object_to_polygon_object_list(effect->object_index, polygon_index); } return 0; }
static bool Lua_Scenery_Valid(int32 index) { if (index < 0 || index >= MAXIMUM_OBJECTS_PER_MAP) return false; object_data *object = GetMemberWithBounds(objects, index, MAXIMUM_OBJECTS_PER_MAP); if (SLOT_IS_USED(object)) { if (GET_OBJECT_OWNER(object) == _object_is_scenery) return true; else if (GET_OBJECT_OWNER(object) == _object_is_normal) { // check to make sure it's not a player's legs or torso for (int player_index = 0; player_index < dynamic_world->player_count; player_index++) { player_data *player = get_player_data(player_index); monster_data *monster = get_monster_data(player->monster_index); if (monster->object_index == index) return false; else { object_data *object = get_object_data(monster->object_index); if (object->parasitic_object == index) return false; } } return true; } } return false; }
static int Lua_Monster_Get_Z(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); object_data *object = get_object_data(monster->object_index); lua_pushnumber(L, (double) object->location.z / WORLD_ONE); return 1; }
static int Lua_Monster_Get_Visible(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); object_data *object = get_object_data(monster->object_index); lua_pushboolean(L, OBJECT_IS_VISIBLE(object)); return 1; }
/** Create an object \verbatim gl('create', class, property, value, ...) \endverbatim **/ void cmex_create(int nlhs, mxArray *plhs[], /**< {properties} */ int nrhs, const mxArray *prhs[]) /**< (class, property1, value1, property2, value2, ..., propertyN, valueN) */ { CLASS *oclass; OBJECT *obj; CLASSNAME classname; unsigned int num_properties = (nrhs-1)/2; /* check return value */ if (nlhs>1) output_error("create only returns one struct"); /* check class name */ else if (!mxIsChar(prhs[0])) output_error("class name (arg 1) must be a string"); /* get class name */ else if (mxGetString(prhs[0],classname,sizeof(classname))) output_error("unable to read class name (arg 1)"); /* check the number of properties */ else if (num_properties!=(nrhs/2)) output_error("an object property value is missing"); /* create object */ else if ((oclass=class_get_class_from_classname(classname))==NULL) output_error("class '%s' is not registered", classname); /* create the object */ else if (oclass->create(&obj,NULL)==FAILED) output_error("unable to create object of class %s", classname); /* copy properties */ else { unsigned int i; for (i=0; i<num_properties; i++) { char name[256]; char value[1024]; unsigned int n=i*2+1; const mxArray *p[] = {prhs[n],prhs[n+1]}; if (!mxIsChar(p[0])) output_error("property name (arg %d) must be a string", n); else if (mxGetString(p[0],name,sizeof(name))) output_error("property name (arg %d) couldn't be read", n); else if (mxIsChar(p[1]) && mxGetString(p[1],value,sizeof(value))) output_error("property %s (arg %d) value couldn't be read", name, n); else if (mxIsDouble(p[1]) && sprintf(value,"%lg",*(double*)mxGetPr(p[1]))<1) output_error("property %s (arg %d) value couldn't be converted from double", name, n); else if (mxIsComplex(p[1]) && sprintf(value,"%lg%+lgi",*(double*)mxGetPr(p[1]),*(double*)mxGetPi(p[1]))<1) output_error("property %s (arg %d) value couldn't be converted from complex", name, n); else if (object_set_value_by_name(obj,name,value)==0) output_error("property %s (arg %d) couldn't be set to '%s'", name, n, value); else if (nlhs>0 && (plhs[0]=get_object_data(obj))==NULL) output_error("couldn't get object data for %s", name); } } }
static int set_object_facing(lua_State *L) { if (!lua_isnumber(L, 2)) return luaL_error(L, "facing: incorrect argument type"); object_data *object = get_object_data(T::Index(L, 1)); object->facing = static_cast<int>(lua_tonumber(L, 2) / AngleConvert); return 0; }
static int Lua_Scenery_Set_Solid(lua_State *L) { if (!lua_isboolean(L, 2)) return luaL_error(L, "solid: incorrect argument type"); object_data *object = get_object_data(Lua_Scenery::Index(L, 1)); SET_OBJECT_SOLIDITY(object, lua_toboolean(L, 2)); return 0; }
static int Lua_Scenery_Get_Damaged(lua_State *L) { object_data *object = get_object_data(Lua_Scenery::Index(L, 1)); // if it made it this far (past valid() check), // it's either scenery or normal lua_pushboolean(L, GET_OBJECT_OWNER(object) == _object_is_normal); return 1; }
int Lua_Monster_Move_By_Path(lua_State *L) { int monster_index = Lua_Monster::Index(L, 1); int polygon_index = 0; if (lua_isnumber(L, 2)) { polygon_index = static_cast<int>(lua_tonumber(L, 2)); if (!Lua_Polygon::Valid(polygon_index)) return luaL_error(L, "move_by_path: invalid polygon index"); } else if (Lua_Polygon::Is(L, 2)) { polygon_index = Lua_Polygon::Index(L, 2); } else return luaL_error(L, "move_by_path: incorrect argument type"); monster_data *monster = get_monster_data(monster_index); if (MONSTER_IS_PLAYER(monster)) return luaL_error(L, "move_by_path: monster is player"); monster_definition *definition = get_monster_definition_external(monster->type); object_data *object = get_object_data(monster->object_index); monster_pathfinding_data path; world_point2d destination; if (!MONSTER_IS_ACTIVE(monster)) activate_monster(monster_index); if (monster->path != NONE) { delete_path(monster->path); monster->path = NONE; } SET_MONSTER_NEEDS_PATH_STATUS(monster, false); path.definition = definition; path.monster = monster; path.cross_zone_boundaries = true; destination = get_polygon_data(polygon_index)->center; monster->path = new_path((world_point2d *) &object->location, object->polygon, &destination, polygon_index, 3 * definition->radius, monster_pathfinding_cost_function, &path); if (monster->path == NONE) { if (monster->action != _monster_is_being_hit || MONSTER_IS_DYING(monster)) { set_monster_action(monster_index, _monster_is_stationary); } set_monster_mode(monster_index, _monster_unlocked, NONE); return 0; } advance_monster_path(monster_index); return 0; }
static int Lua_Effect_Set_Facing(lua_State* L) { if (!lua_isnumber(L, 2)) return luaL_error(L, "facing: incorrect argument type"); effect_data* effect = get_effect_data(Lua_Effect::Index(L, 1)); object_data* object = get_object_data(effect->object_index); object->facing = static_cast<int>(lua_tonumber(L, 2) / AngleConvert); return 0; }
int Lua_Item_Delete(lua_State* L) { object_data* object = get_object_data(Lua_Item::Index(L, 1)); int16 item_type = object->permutation; remove_map_object(Lua_Item::Index(L, 1)); if (L_Get_Proper_Item_Accounting(L)) { object_was_just_destroyed(_object_is_item, item_type); } return 0; }
/* every other field in the player structure should be valid when this call is made */ void initialize_player_physics_variables( short player_index) { struct player_data *player= get_player_data(player_index); struct monster_data *monster= get_monster_data(player->monster_index); struct object_data *object= get_object_data(monster->object_index); struct physics_variables *variables= &player->variables; struct physics_constants *constants= get_physics_constants_for_model(static_world->physics_model, 0); //#ifdef DEBUG obj_set(*variables, 0x80); //#endif variables->head_direction= 0; variables->adjusted_yaw= variables->direction= INTEGER_TO_FIXED(object->facing); variables->adjusted_pitch= variables->elevation= 0; variables->angular_velocity= variables->vertical_angular_velocity= 0; variables->velocity= 0, variables->perpendicular_velocity= 0; variables->position.x= WORLD_TO_FIXED(object->location.x); variables->position.y= WORLD_TO_FIXED(object->location.y); variables->position.z= WORLD_TO_FIXED(object->location.z); variables->last_position= variables->position; variables->last_direction= variables->direction; /* .floor_height, .ceiling_height and .media_height will be calculated by instantiate, below */ variables->external_angular_velocity= 0; variables->external_velocity.i= variables->external_velocity.j= variables->external_velocity.k= 0; variables->actual_height= constants->height; variables->step_phase= 0; variables->step_amplitude= 0; variables->action= _player_stationary; variables->old_flags= variables->flags= 0; /* not recentering, not above ground, not below ground (i.e., on floor) */ /* setup shadow variables in player_data structure */ instantiate_physics_variables(get_physics_constants_for_model(static_world->physics_model, 0), &player->variables, player_index, true, true); #ifdef DIVERGENCE_CHECK if (!saved_point_iterations) { saved_points= new world_point3d[SAVED_POINT_COUNT]; saved_thetas= new angle[SAVED_POINT_COUNT]; } saved_point_count= 0; saved_point_iterations+= 1; saved_divergence_warning= false; #endif }
static bool get_item(short player_index, short object_index) { object_data *object = get_object_data(object_index); bool success; assert(GET_OBJECT_OWNER(object)==_object_is_item); success = try_and_add_player_item(player_index, object->permutation); if (success) { /* remove it */ remove_map_object(object_index); } return success; }
std::shared_ptr<MeshFormatObject> MeshFormat::spawn_object(const StringIntern& s){ MeshFormatObjectData* d = &get_object_data(s); if(!d){ std::cout<<s<<" was not found\n"; return nullptr; } std::shared_ptr<MeshFormatObject> o(new MeshFormatObject(d,&file)); if(d->materials.size()) o->material=get_material(d->materials[0]); o->parent = &*spawned_nodes[d->parent]; if(!o->parent)o->parent=this; return o; }
/* false means donÕt fire this (itÕs in a floor or ceiling or outside of the map), otherwise the monster that was intersected first (or NONE) is returned in target_index */ bool preflight_projectile( world_point3d *origin, short origin_polygon_index, world_point3d *destination, angle delta_theta, short type, short owner, short owner_type, short *obstruction_index) { bool legal_projectile= false; struct projectile_definition *definition= get_projectile_definition(type); (void) (delta_theta); /* will be used when we truly preflight projectiles */ (void) (owner_type); if (origin_polygon_index!=NONE) { world_distance dx= destination->x-origin->x, dy= destination->y-origin->y; angle elevation= arctangent(isqrt(dx*dx + dy*dy), destination->z-origin->z); if (elevation<MAXIMUM_PROJECTILE_ELEVATION || elevation>FULL_CIRCLE-MAXIMUM_PROJECTILE_ELEVATION) { struct polygon_data *origin_polygon= get_polygon_data(origin_polygon_index); // LP note: "penetrates media boundary" means "hit media surface and continue"; // it will act like "penetrates_media" here // Added idiot-proofing to media data media_data *media = get_media_data(origin_polygon->media_index); if (origin->z>origin_polygon->floor_height && origin->z<origin_polygon->ceiling_height && (origin_polygon->media_index==NONE || definition->flags&(_penetrates_media) || (media ? origin->z>media->height : true))) { /* make sure it hits something */ uint16 flags= translate_projectile(type, origin, origin_polygon_index, destination, (short *) NULL, owner, obstruction_index, 0, true, NONE); *obstruction_index= (flags&_projectile_hit_monster) ? get_object_data(*obstruction_index)->permutation : NONE; legal_projectile= true; } } } return legal_projectile; }
static boolean line_is_within_range( short monster_index, short line_index, world_distance range) { world_point3d monster_origin= get_object_data(get_monster_data(monster_index)->object_index)->location; world_point3d line_origin; world_distance radius, height; world_distance dx, dy, dz; calculate_line_midpoint(line_index, &line_origin); get_monster_dimensions(monster_index, &radius, &height); monster_origin.z+= height>>1; dx= monster_origin.x-line_origin.x; dy= monster_origin.y-line_origin.y; dz= 2*(monster_origin.z-line_origin.z); /* dz is weighted */ return isqrt(dx*dx + dy*dy + dz*dz)<range ? TRUE : FALSE; }
void cause_polygon_damage( short polygon_index, short monster_index) { struct polygon_data *polygon= get_polygon_data(polygon_index); struct monster_data *monster= get_monster_data(monster_index); struct object_data *object= get_object_data(monster->object_index); short polygon_type = polygon->type; // apply damage from flooded platforms if (polygon->type == _polygon_is_platform) { struct platform_data *platform= get_platform_data(polygon->permutation); if (platform && PLATFORM_IS_FLOODED(platform)) { short adj_index = find_flooding_polygon(polygon_index); if (adj_index != NONE) { struct polygon_data *adj_polygon = get_polygon_data(adj_index); polygon_type = adj_polygon->type; } } } // #if 0 if ((polygon_type==_polygon_is_minor_ouch && !(dynamic_world->tick_count&MINOR_OUCH_FREQUENCY) && object->location.z==polygon->floor_height) || (polygon_type==_polygon_is_major_ouch && !(dynamic_world->tick_count&MAJOR_OUCH_FREQUENCY))) { struct damage_definition damage; damage.flags= _alien_damage; damage.type= polygon_type==_polygon_is_minor_ouch ? _damage_polygon : _damage_major_polygon; damage.base= polygon_type==_polygon_is_minor_ouch ? MINOR_OUCH_DAMAGE : MAJOR_OUCH_DAMAGE; damage.random= 0; damage.scale= FIXED_ONE; damage_monster(monster_index, NONE, NONE, (world_point3d *) NULL, &damage, NONE); } // #endif }
void update_player_physics_variables( short player_index, uint32 action_flags, bool predictive) { struct player_data *player= get_player_data(player_index); struct physics_variables *variables= &player->variables; struct physics_constants *constants= get_physics_constants_for_model(static_world->physics_model, action_flags); physics_update(constants, variables, player, action_flags); instantiate_physics_variables(constants, variables, player_index, false, !predictive); #ifdef DIVERGENCE_CHECK if (saved_point_count<SAVED_POINT_COUNT) { struct object_data *object= get_object_data(get_monster_data(player->monster_index)->object_index); world_point3d p= object->location; world_point3d *q= saved_points+saved_point_count; angle *facing= saved_thetas+saved_point_count; if (saved_point_iterations==1) { saved_points[saved_point_count]= p; *facing= object->facing; } else { if (p.x!=q->x||p.y!=q->y||p.z!=q->z||*facing!=object->facing&&!saved_divergence_warning) { dprintf("divergence @ tick %d: (%d,%d,%d,%d)!=(%d,%d,%d,%d)", saved_point_count, q->x, q->y, q->z, *facing, p.x, p.y, p.z, object->facing); saved_divergence_warning= true; } } saved_point_count+= 1; } #endif }
static int Lua_Monster_Set_Visible(lua_State *L) { int monster_index = Lua_Monster::Index(L, 1); monster_data *monster = get_monster_data(monster_index); object_data *object = get_object_data(monster->object_index); int invisible = !lua_toboolean(L, 2); if(monster->action == _monster_is_teleporting_out) return 0; if(MONSTER_IS_ACTIVE(monster) || monster->vitality >= 0) { // Cool stuff happens if you just set an active // monster to invisible. What we should do instead of // the below is expose teleports_out_when_deactivated /*if(invisible) { monster->flags |= (uint16)_monster_teleports_out_when_deactivated; deactivate_monster(monster_index); }*/ return luaL_error(L, "visible: monster already activated"); } else { // No real possibility of messing stuff up here. SET_OBJECT_INVISIBILITY(object, invisible); } return 0; }
void trigger_nearby_items(short polygon_index) { polygon_index = flood_map(polygon_index, INT32_MAX, item_trigger_cost_function, _breadth_first, nullptr); while(polygon_index != NONE) { object_data *object; for(auto object_index = get_polygon_data(polygon_index)->first_object; object_index != NONE; object_index = object->next_object) { object = get_object_data(object_index); switch (GET_OBJECT_OWNER(object)) { case _object_is_item: if (OBJECT_IS_INVISIBLE(object) && object->permutation!=NONE) { teleport_object_in(object_index); } break; } } polygon_index= flood_map(NONE, INT32_MAX, item_trigger_cost_function, _breadth_first, nullptr); } }
static int get_object_y(lua_State *L) { object_data *object = get_object_data(T::Index(L, 1)); lua_pushnumber(L, (double) object->location.y / WORLD_ONE); return 1; }
static int get_object_type(lua_State *L) { object_data *object = get_object_data(T::Index(L, 1)); TT::Push(L, object->permutation); return 1; }
static int get_object_polygon(lua_State *L) { object_data *object = get_object_data(T::Index(L, 1)); Lua_Polygon::Push(L, object->polygon); return 1; }