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 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; }
int Lua_Monster_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"); monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); object_data *object = get_object_data(monster->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(monster->object_index); add_object_to_polygon_object_list(monster->object_index, polygon_index); } return 0; }
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; }
int Lua_Monster_Damage(lua_State *L) { if (!lua_isnumber(L, 2)) return luaL_error(L, "damage: incorrect argument type"); int damage_amount = static_cast<int>(lua_tonumber(L, 2)); int damage_type = NONE; if (lua_gettop(L) == 3) { damage_type = Lua_DamageType::ToIndex(L, 3); } damage_definition damage; if (damage_type != NONE) damage.type = damage_type; else damage.type = _damage_fist; damage.base = damage_amount; damage.random = 0; damage.flags = 0; damage.scale = FIXED_ONE; int monster_index = Lua_Monster::Index(L, 1); monster_data *monster = get_monster_data(monster_index); damage_monster(monster_index, NONE, NONE, &(monster->sound_location), &damage, NONE); return 0; }
int Lua_Monster_Play_Sound(lua_State *L) { short sound_index = Lua_Sound::ToIndex(L, 2); monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); play_object_sound(monster->object_index, sound_index); return 0; }
// 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 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; }
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_Set_Vertical_Velocity(lua_State *L) { if (!lua_isnumber(L, 2)) return luaL_error(L, "vertical_velocity: incorrect argument type"); monster_data* monster = get_monster_data(Lua_Monster::Index(L, 1)); monster->vertical_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE); return 0; }
static int Lua_Monster_Get_Active(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); if (MONSTER_IS_PLAYER(monster)) return luaL_error(L, "active: monster is a player"); lua_pushboolean(L, MONSTER_IS_ACTIVE(monster)); return 1; }
static int Lua_Monster_Set_Vitality(lua_State *L) { if (!lua_isnumber(L, 2)) return luaL_error(L, "vitality: incorrect argument type"); monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); monster->vitality = static_cast<int>(lua_tonumber(L, 2)); return 0; }
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_Monster_Set_Facing(lua_State *L) { if (!lua_isnumber(L, 2)) return luaL_error(L, "facing: incorrect argument type"); monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); object_data *object = get_object_data(monster->object_index); object->facing = static_cast<int>(lua_tonumber(L, 2) / AngleConvert); return 0; }
static int Lua_Monster_Get_Player(lua_State *L) { int monster_index = Lua_Monster::Index(L, 1); monster_data *monster = get_monster_data(monster_index); if (MONSTER_IS_PLAYER(monster)) Lua_Player::Push(L, monster_index_to_player_index(monster_index)); else lua_pushnil(L); return 1; }
/* 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 }
int Lua_Monster_Accelerate(lua_State *L) { if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4)) return luaL_error(L, "accelerate: incorrect argument type"); short monster_index = Lua_Monster::Index(L, 1); monster_data *monster = get_monster_data(monster_index); (void)monster; double direction = static_cast<double>(lua_tonumber(L, 2)); double velocity = static_cast<double>(lua_tonumber(L, 3)); double vertical_velocity = static_cast<double>(lua_tonumber(L, 4)); accelerate_monster(monster_index, static_cast<int>(vertical_velocity * WORLD_ONE), static_cast<int>(direction/AngleConvert), static_cast<int>(velocity * WORLD_ONE)); return 0; }
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 }
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 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_Active(lua_State *L) { if (!lua_isboolean(L, 2)) return luaL_error(L, "active: incorrect argument type"); bool activate = lua_toboolean(L, 2); int monster_index = Lua_Monster::Index(L, 1); monster_data *monster = get_monster_data(monster_index); if (MONSTER_IS_PLAYER(monster)) return luaL_error(L, "active: monster is a player"); if (activate) { if (!MONSTER_IS_ACTIVE(monster)) activate_monster(monster_index); } else { if (MONSTER_IS_ACTIVE(monster)) deactivate_monster(monster_index); } return 0; }
static int Lua_Monster_Get_Type(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); Lua_MonsterType::Push(L, monster->type); return 1; }
// ZZZ: if in predictive mode, restore the saved partial game-state (it'd better take us back // to _exactly_ the same full game-state we saved earlier, else problems.) static void exit_predictive_mode() { if(sPredictedTicks > 0) { for(short i = 0; i < dynamic_world->player_count; i++) { player_data* player = get_player_data(i); assert(player->monster_index == sSavedPlayerData[i].monster_index); { // We *don't* restore this tiny part of the game-state back because // otherwise the player can't use [] to scroll the inventory panel. // [] scrolling happens outside the normal input/update system, so that's // enough to persuade me that not restoring this won't OOS any more often // than []-scrolling did before prediction. :) int16 saved_interface_flags = player->interface_flags; int16 saved_interface_decay = player->interface_decay; *player = sSavedPlayerData[i]; player->interface_flags = saved_interface_flags; player->interface_decay = saved_interface_decay; } if(sSavedPlayerData[i].monster_index != NONE) { assert(get_monster_data(sSavedPlayerData[i].monster_index)->object_index == sSavedPlayerMonsterData[i].object_index); *get_monster_data(sSavedPlayerData[i].monster_index) = sSavedPlayerMonsterData[i]; if(sSavedPlayerMonsterData[i].object_index != NONE) { assert(get_object_data(sSavedPlayerMonsterData[i].object_index)->parasitic_object == sSavedPlayerObjectData[i].parasitic_object); remove_object_from_polygon_object_list(sSavedPlayerMonsterData[i].object_index); *get_object_data(sSavedPlayerMonsterData[i].object_index) = sSavedPlayerObjectData[i]; // We have to defer this insertion since the object lists could still have other players // in their predictive locations etc. - we need to reconstruct everything exactly as it // was when we entered predictive mode. deferred_add_object_to_polygon_object_list(sSavedPlayerMonsterData[i].object_index, sSavedPlayerObjectNextObject[i]); if(sSavedPlayerObjectData[i].parasitic_object != NONE) *get_object_data(sSavedPlayerObjectData[i].parasitic_object) = sSavedPlayerParasiticObjectData[i]; } } } perform_deferred_polygon_object_list_manipulations(); sPredictedTicks = 0; // Sanity checking if(sSavedTickCount != dynamic_world->tick_count) logWarning2("saved tick count %d != dynamic_world->tick_count %d", sSavedTickCount, dynamic_world->tick_count); if(sSavedRandomSeed != get_random_seed()) logWarning2("saved random seed %d != get_random_seed() %d", sSavedRandomSeed, get_random_seed()); } }
/* assumes ¶t==1 tick */ void move_projectiles( void) { struct projectile_data *projectile; short projectile_index; for (projectile_index=0,projectile=projectiles;projectile_index<MAXIMUM_PROJECTILES_PER_MAP;++projectile_index,++projectile) { if (SLOT_IS_USED(projectile)) { struct object_data *object= get_object_data(projectile->object_index); // if (!OBJECT_IS_INVISIBLE(object)) { struct projectile_definition *definition= get_projectile_definition(projectile->type); short old_polygon_index= object->polygon; world_point3d new_location, old_location; short obstruction_index, new_polygon_index; new_location= old_location= object->location; /* update our objectÕs animation */ animate_object(projectile->object_index); /* if weÕre supposed to end when our animation loops, check this condition */ if ((definition->flags&_stop_when_animation_loops) && (GET_OBJECT_ANIMATION_FLAGS(object)&_obj_last_frame_animated)) { remove_projectile(projectile_index); } else { world_distance speed= definition->speed; uint32 adjusted_definition_flags = 0; uint16 flags; /* base alien projectile speed on difficulty level */ if (definition->flags&_alien_projectile) { switch (dynamic_world->game_information.difficulty_level) { case _wuss_level: speed-= speed>>3; break; case _easy_level: speed-= speed>>4; break; case _major_damage_level: speed+= speed>>3; break; case _total_carnage_level: speed+= speed>>2; break; } } /* if this is a guided projectile with a valid target, update guidance system */ if ((definition->flags&_guided) && projectile->target_index!=NONE && (dynamic_world->tick_count&1)) update_guided_projectile(projectile_index); if (PROJECTILE_HAS_CROSSED_MEDIA_BOUNDARY(projectile)) adjusted_definition_flags= _penetrates_media; /* move the projectile and check for collisions; if we didnÕt detonate move the projectile and check to see if we need to leave a contrail */ if ((definition->flags&_affected_by_half_gravity) && (dynamic_world->tick_count&1)) projectile->gravity-= GRAVITATIONAL_ACCELERATION; if (definition->flags&_affected_by_gravity) projectile->gravity-= GRAVITATIONAL_ACCELERATION; if (definition->flags&_doubly_affected_by_gravity) projectile->gravity-= 2*GRAVITATIONAL_ACCELERATION; if (film_profile.m1_low_gravity_projectiles && static_world->environment_flags&_environment_low_gravity && static_world->environment_flags&_environment_m1_weapons) { projectile->gravity /= 2; } new_location.z+= projectile->gravity; translate_point3d(&new_location, speed, object->facing, projectile->elevation); if (definition->flags&_vertical_wander) new_location.z+= (global_random()&1) ? WANDER_MAGNITUDE : -WANDER_MAGNITUDE; if (definition->flags&_horizontal_wander) translate_point3d(&new_location, (global_random()&1) ? WANDER_MAGNITUDE : -WANDER_MAGNITUDE, NORMALIZE_ANGLE(object->facing+QUARTER_CIRCLE), 0); if (film_profile.infinity_smg) { definition->flags ^= adjusted_definition_flags; } flags= translate_projectile(projectile->type, &old_location, object->polygon, &new_location, &new_polygon_index, projectile->owner_index, &obstruction_index, 0, false, projectile_index); if (film_profile.infinity_smg) { definition->flags ^= adjusted_definition_flags; } // LP change: set up for penetrating media boundary bool will_go_through = false; if (flags&_projectile_hit) { if ((flags&_projectile_hit_floor) && (definition->flags&_rebounds_from_floor) && projectile->gravity<-MINIMUM_REBOUND_VELOCITY) { play_object_sound(projectile->object_index, definition->rebound_sound); projectile->gravity= - projectile->gravity + (projectile->gravity>>2); /* 0.75 */ } else { short monster_obstruction_index= (flags&_projectile_hit_monster) ? get_object_data(obstruction_index)->permutation : NONE; bool destroy_persistent_projectile= false; if (flags&_projectile_hit_scenery) damage_scenery(obstruction_index); /* cause damage, if we can */ if (!PROJECTILE_HAS_CAUSED_DAMAGE(projectile)) { struct damage_definition *damage= &definition->damage; damage->scale= projectile->damage_scale; if (definition->flags&_becomes_item_on_detonation) { if (monster_obstruction_index==NONE) { struct object_location location; location.p= object->location, location.p.z= 0; location.polygon_index= object->polygon; location.yaw= location.pitch= 0; location.flags= 0; // START Benad // Found it! // With new_item(), current_item_count[item] increases, but not // with try_and_add_player_item(). So reverse the effect of new_item in advance. dynamic_world->current_item_count[projectile->permutation]--; // END Benad new_item(&location, projectile->permutation); destroy_persistent_projectile= true; } else { if(MONSTER_IS_PLAYER(get_monster_data(monster_obstruction_index))) { short player_obstruction_index= monster_index_to_player_index(monster_obstruction_index); destroy_persistent_projectile= try_and_add_player_item(player_obstruction_index, projectile->permutation); } } } else { if (definition->area_of_effect) { damage_monsters_in_radius(monster_obstruction_index, projectile->owner_index, projectile->owner_type, &old_location, object->polygon, definition->area_of_effect, damage, projectile_index); } else { if (monster_obstruction_index!=NONE) damage_monster(monster_obstruction_index, projectile->owner_index, projectile->owner_type, &old_location, damage, projectile_index); } } } if ((definition->flags&_persistent) && !destroy_persistent_projectile) { SET_PROJECTILE_DAMAGE_STATUS(projectile, true); } else { short detonation_effect= definition->detonation_effect; if (monster_obstruction_index!=NONE) { if (definition->flags&_bleeding_projectile) { detonation_effect= get_monster_impact_effect(monster_obstruction_index); } if (definition->flags&_melee_projectile) { short new_detonation_effect= get_monster_melee_impact_effect(monster_obstruction_index); if (new_detonation_effect!=NONE) detonation_effect= new_detonation_effect; } } if (flags&_projectile_hit_media) { get_media_detonation_effect(get_polygon_data(obstruction_index)->media_index, definition->media_detonation_effect, &detonation_effect); // LP addition: check if projectile will hit media and continue (PMB flag) // set will_go_through for later processing if (film_profile.a1_smg) { // Be careful about parentheses here! will_go_through = (definition->flags&_penetrates_media_boundary) != 0; // Push the projectile upward or downward, if necessary if (will_go_through) { if (projectile->elevation == 0) {} else if (projectile->elevation < HALF_CIRCLE) new_location.z++; else if (projectile->elevation > HALF_CIRCLE) new_location.z--; } } } if (film_profile.a1_smg) { // LP addition: don't detonate if going through media // if PMB is set; otherwise, detonate if doing so. // Some of the later routines may set both "hit landscape" and "hit media", // so be careful. if (flags&_projectile_hit_landscape && !(flags&_projectile_hit_media)) detonation_effect= NONE; } else { if (flags&_projectile_hit_landscape) detonation_effect = NONE; } if (detonation_effect!=NONE) new_effect(&new_location, new_polygon_index, detonation_effect, object->facing); L_Call_Projectile_Detonated(projectile->type, projectile->owner_index, new_polygon_index, new_location); if (!film_profile.infinity_smg || (!(definition->flags&_penetrates_media_boundary) || !(flags&_projectile_hit_media))) { if ((definition->flags&_persistent_and_virulent) && !destroy_persistent_projectile && monster_obstruction_index!=NONE) { bool reassign_projectile = true; if (film_profile.prevent_dead_projectile_owners) { monster_data *monster = get_monster_data(monster_obstruction_index); reassign_projectile = MONSTER_IS_PLAYER(monster) || !MONSTER_IS_DYING(monster); } if (reassign_projectile) projectile->owner_index= monster_obstruction_index; /* keep going, but donÕt hit this target again */ } // LP addition: don't remove a projectile that will hit media and continue (PMB flag) else if (!will_go_through) { remove_projectile(projectile_index); } } else if (film_profile.infinity_smg) { SET_PROJECTILE_CROSSED_MEDIA_BOUNDARY_STATUS(projectile, true); } } } } // Move the projectile if it hit nothing or it will go through media surface if (!(flags&_projectile_hit) || will_go_through) // else { /* move to the new_polygon_index */ translate_map_object(projectile->object_index, &new_location, new_polygon_index); /* should we leave a contrail at our old location? */ if ((projectile->ticks_since_last_contrail+=1)>=definition->ticks_between_contrails) { if (definition->maximum_contrails==NONE || projectile->contrail_count<definition->maximum_contrails) { projectile->contrail_count+= 1; projectile->ticks_since_last_contrail= 0; if (definition->contrail_effect!=NONE) new_effect(&old_location, old_polygon_index, definition->contrail_effect, object->facing); } } if ((flags&_flyby_of_current_player) && !PROJECTILE_HAS_MADE_A_FLYBY(projectile)) { SET_PROJECTILE_FLYBY_STATUS(projectile, true); play_object_sound(projectile->object_index, definition->flyby_sound); } /* if we have a maximum range and we have exceeded it then remove the projectile */ if (definition->maximum_range!=NONE) { if ((projectile->distance_travelled+= speed)>=definition->maximum_range) { remove_projectile(projectile_index); } } } } } }
static int Lua_Monster_Get_Action(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); Lua_MonsterAction::Push(L, monster->action); return 1; }
static int Lua_Monster_Get_Mode(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); Lua_MonsterMode::Push(L, monster->mode); return 1; }
static int Lua_Monster_Get_Vertical_Velocity(lua_State *L) { monster_data* monster = get_monster_data(Lua_Monster::Index(L, 1)); lua_pushnumber(L, (double) monster->vertical_velocity / WORLD_ONE); return 1; }
static int Lua_Monster_Get_Vitality(lua_State *L) { monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1)); lua_pushnumber(L, monster->vitality); return 1; }