Skip to content

Conversation

@PieterVdc
Copy link
Member

implements #4120

PieterVdc and others added 5 commits July 16, 2025 16:04
Introduces a new Lua API function `lua_Add_shot_to_level` for spawning shots at a specified location and owner. Adds `script_process_new_shot` to handle shot creation, including position validation and wall collision checks. Also adds initial camera Lua API scaffolding in a new file.
@PieterVdc PieterVdc marked this pull request as ready for review July 16, 2025 17:56
@PieterVdc PieterVdc marked this pull request as draft July 16, 2025 19:49
@PieterVdc PieterVdc linked an issue Jul 17, 2025 that may be closed by this pull request
@Loobinex
Copy link
Member

image

@Loobinex Loobinex marked this pull request as ready for review August 22, 2025 15:40
@Loobinex Loobinex marked this pull request as draft August 22, 2025 15:40
@PieterVdc PieterVdc marked this pull request as ready for review February 12, 2026 20:45
Copilot AI review requested due to automatic review settings February 12, 2026 20:45
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements the ability to create shots from Lua code (addresses issue #4120), enabling Word of Power-like effects and directed shots. The implementation adds three main features: a new AddShotToLevel Lua function for creating shots, camera access through Player.camera to get camera direction for directed shots, and a Thing:set_velocity method to apply velocity to things.

Changes:

  • Adds script_process_new_shot C function and AddShotToLevel Lua API for creating shots from code
  • Exposes player camera to Lua with access to position, yaw, pitch, roll, zoom, and view mode
  • Adds Thing:set_velocity method to set velocity using angle and distance parameters

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/thing_shots.c Implements script_process_new_shot to create shots with hit type and target, handles wall collision
src/thing_shots.h Adds function declaration for script_process_new_shot
src/lua_params.c Adds luaL_checkHitType and luaL_optCheckThing, changes Thing return values from NULL to INVALID_THING
src/lua_params.h Declares new parameter checking functions
src/lua_api_things.c Implements lua_set_velocity method using angles_to_vector
src/lua_api_player.c Adds camera field to Player API
src/lua_api_camera.c New file implementing Camera Lua object with getter/setter for camera properties
src/lua_api.c Implements lua_Add_shot_to_level and registers Camera type
keeperfx_vs2010.vcxproj Adds lua_api_camera.c to Visual Studio project
keeperfx_vs2010.vcxproj.filters Adds lua_api_camera.c to source files filter
Makefile Adds obj/lua_api_camera.o to build
config/fxdata/lua/config-api/native_types.lua Adds shot_type and hit_type aliases
config/fxdata/lua/classes/Thing.lua Documents set_velocity method
config/fxdata/lua/bindings/things.lua Documents AddShotToLevel function
Comments suppressed due to low confidence (1)

src/lua_params.c:25

  • The header file thing_navigate.h is included twice, on lines 16 and 25. One of these duplicate includes should be removed.
#include "thing_navigate.h"
#include "thing_effects.h"
#include "keeperfx.hpp"
#include "lua_base.h"
#include "lvl_script_lib.h"
#include "map_data.h"
#include "player_utils.h"
#include "room_library.h"
#include "thing_data.h"
#include "thing_navigate.h"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

---@param shot_type shot_type The shot name from fxdata\magic.cfg
---@param location location
---@param player playersingle When used it sets the owner of the object.
---@param hit_type hittypes What the shot can hit
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type annotation uses 'hittypes' but this type alias is not defined in native_types.lua. It should be 'hit_type' instead (which is defined on line 20 of native_types.lua).

Suggested change
---@param hit_type hittypes What the shot can hit
---@param hit_type hit_type What the shot can hit

Copilot uses AI. Check for mistakes.
Comment on lines +170 to +172
if (strcmp(key, "camera") == 0) {
lua_pushCamera(L, plyr_idx);
} else if (strcmp(key, "heart") == 0) {
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new 'camera' field added to Player is not documented in Player.lua. Following the pattern of other Player fields (like CONTROLS, MONEY, etc. in Player.lua lines 25-55), a documentation entry should be added for the camera field. Additionally, a Camera.lua class file should be created in config/fxdata/lua/classes/ to document Camera's fields (pos, yaw, pitch, roll, horizontal_fov, zoom, view_mode) similar to how other classes like Thing.lua and Player.lua document their fields.

Copilot uses AI. Check for mistakes.
Comment on lines +502 to +507
if ((index < THit_None) || (index >= THit_TypesCount))
{
luaL_argerror(L, index, "Invalid hittype");
return THit_None;
}
return index;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The luaL_checkHitType function is checking if the parameter index (stack position) is within the enum range instead of retrieving and checking the actual value from the Lua stack. This will always fail since index will be 4 (the stack position) which is greater than or equal to THit_TypesCount.

This function should:

  1. Retrieve the value from the Lua stack at position 'index' using lua_tointeger or use luaL_checkNamedCommand with a hit_type_desc descriptor
  2. Check if that retrieved value is within the valid range (THit_None to THit_TypesCount-1)
  3. Return the retrieved value

Based on the Lua type definition (hit_type as string like "THit_None"), this should probably use luaL_checkNamedCommand with a NamedCommand descriptor for hit types, similar to how shot_desc is used.

Suggested change
if ((index < THit_None) || (index >= THit_TypesCount))
{
luaL_argerror(L, index, "Invalid hittype");
return THit_None;
}
return index;
int hit_type;
if (lua_isnumber(L, index))
{
hit_type = (int)lua_tointeger(L, index);
}
else if (lua_isstring(L, index))
{
hit_type = luaL_checkNamedCommand(L, index, hit_type_desc);
}
else
{
luaL_argerror(L, index, "Invalid hittype");
return THit_None;
}
if ((hit_type < THit_None) || (hit_type >= THit_TypesCount))
{
luaL_argerror(L, index, "Invalid hittype");
return THit_None;
}
return hit_type;

Copilot uses AI. Check for mistakes.
return playerId;
}

static const struct luaL_Reg slab_methods[] = {
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy-paste error: this should be 'camera_methods' not 'slab_methods' since this is in the camera API file.

Suggested change
static const struct luaL_Reg slab_methods[] = {
static const struct luaL_Reg camera_methods[] = {

Copilot uses AI. Check for mistakes.
} else if (try_get_from_methods(L, 1, key)) {
return 1;
} else {
return luaL_error(L, "Unknown field or method '%s' for Player", key);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message refers to "Player" but should refer to "Camera" since this is the camera_get_field function.

Suggested change
return luaL_error(L, "Unknown field or method '%s' for Player", key);
return luaL_error(L, "Unknown field or method '%s' for Camera", key);

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +39
int luaL_checkCamera(lua_State *L, int idx)
{
if (!lua_istable(L, idx)) {
return luaL_argerror(L, idx, "Expected a table");
}

lua_getfield(L, idx, "playerId");
if (!lua_isnumber(L, -1)) {
return luaL_argerror(L, idx, "Table must have a numeric 'playerId' field");
}
PlayerNumber playerId = lua_tointeger(L, -1);
lua_pop(L, 1);

return playerId;
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The luaL_checkCamera function extracts the playerId from the Camera table but doesn't validate that it's a valid player ID. It should validate that playerId is within the valid range (0 to PLAYERS_COUNT-1 or similar) before returning it, similar to how luaL_checkPlayerSingle validates the player ID in lua_params.c lines 274-277.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lua: Create shot from code

2 participants