Sport
Usage guide of sport.ball and sport.golf: the field, teams and match rules, the golf course data, shot rules, settings and defaults, services, events, hooks, engines.
Sport: ball matches and golf (sport.* kits) #
Team ball games and a golf round, as rules and data. Readable offline: gripforge docs sport, or the MCP tool gripforge_docs (topic sport).
What it is for #
| Kit | What it adds |
|---|---|
sport.ball | a team ball game on a walled or open field: a ball (or a puck) with its own bounce, roll and wall physics, kicked by athletes on foot or hit by cars, a goal per team, score, kickoffs, a match clock, overtime, bots in simple roles |
sport.golf | a golf round on a course written as data: holes, surfaces, a bag of clubs, wind, a two-step swing (aim, then stop the power gauge), one to four local players and bots taking turns, a scorecard |
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "sport.ball" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "sport.ball",
config: { "mode": "foot", "teamSize": 3, "match": { "seconds": 180, "overtime": "golden_goal" } } }
Both kits require input.actions, world.ground and game.engine. Pair sport.ball with world.arena (same size, a gap of the goal's size in the end walls) or any flat ground; in mode: "cars" also install vehicle.driveable. sport.golf pairs with a camera kit that frames the ball (a top-down or third-person character kit, or a strategy camera).
sport.ball #
The field runs along z, centred on the origin: team 0 defends the -z end, team 1 the +z end. Settings are grouped; the main ones and their defaults:
| Group | Keys (default) |
|---|---|
| mode | mode foot (athletes who kick) or cars (everyone drives and hits the ball on impact) |
field | width 34 (x), length 52 (z, goal to goal), walls true, goalWidth, goal height and depth |
ball | radius 0.35, mass 1, bounce 0.55, rolling 2.5 (m/s squared), drag 0.05, maxSpeed, restSpeed 1, netBounce 0.1 |
kick | reach 1.6, minImpulse, maxImpulse, chargeSeconds, lift 0.18, cooldown, maxHeight 1.6 |
impact | bodyRadius, bodyHeight 1.9, bounce 0.6, carBoost 1.3, carLift 0.25 |
| teams | teams (names and colours; default Blue and one more), teamSize 3 (1 to 5), roles (default keeper, chase, defend, chase, defend), humans 1 (0: a bot-versus-bot match to watch), playerTeam 0 |
match | seconds 180, overtime golden_goal / timed / none, overtimeSeconds, scoreLimit 0, kickoffSeconds, goalPause, outOfBounds restart or kickoff (without walls), outPause 1, endGame true |
possession / hold | possession false: on foot the ball sticks to the feet of the athlete controlling it until a kick or a tackle |
ai | enabled true, speed 6, keeperRange 9, aim 0.7, shootRange, skill 1, pushCharge 0.05 |
Rules in short: on foot, hold the kick key to charge and release to kick where the character faces (within kick.reach of the ball, then kick.cooldown); a kick of charge c gives an impulse between minImpulse and maxImpulse, the ball leaves at impulse over mass, capped at maxSpeed. A goal is the whole ball over the line inside the mouth. Kickoff, then play, then goal, then kickoff; the team that conceded kicks off. At 0 the leader wins; a draw follows match.overtime. With match.endGame the end of the match ends the game: game.won or game.lost for the player's team.
Service sport.match: state(), ball(), ballPosition(), ballVelocity(), setBall(p, v?), kick(athlete, charge, dir?), kickoff(team?), restart(), score(), clock(), overtime(), athletes(), goals(), holder(), spotOf(athlete). Verbs sport_kickoff, sport_restart, conditions sport_score_at_least, sport_leading. Events sport.kickoff, sport.live, sport.kick, sport.touch, sport.goal, sport.out, sport.overtime, sport.ended, game.won, game.lost. The whole state is saved.
sport.golf #
| Group | Keys (default) |
|---|---|
| course | course (id of a golf_courses document; empty: the first one, else the built-in nine holes), holes 0 (only the first N holes; 0 is all) |
players | humans 1, bots 0, names, colors, order farthest or rotation, maxStrokes 12 (0: no limit) |
layout | fairwayWidth 30, bounds 45, teeSpacing 0.6 |
ball | radius 0.1, gravity 9.81, drag 0.01, restSpeed 0.5, maxSpeed 120, slope 1 |
hole | cupRadius 0.18, captureSpeed 2.5 (faster, the ball lips out) |
shot | gaugeSeconds 1.1, accuracy false (a third click stops a needle), maxError 8 degrees, minPower 0.05, aimRate 60, autoClub true, clubs (the bag; empty: every club) |
wind | enabled true, minSpeed 0, maxSpeed 8, effect 0.12, perHole true |
flow | shotPause 1, holePause 3, endGame true |
ai | thinkSeconds 1.2, error 3 degrees, powerError 0.08 |
hidePlayer | true: the character is hidden and parked at the ball so a follow camera frames the ball |
A course is a document { id, name, holes: [...] }; a hole has id, par (2 to 7), tee and cup ([x, z]), green ({ radius, at? }), fairway strips ({ from, to, width }), bunkers and water (circles or strips), bounds and a fixed wind. Surfaces are the registry golf_surfaces (friction, bounce, grip, power, penalty, drop, lost) and clubs the registry golf_clubs (carry, loft; a putter rolls the ball). Ball flight: gravity, drag and the wind; landing uses the surface bounce and grip; rolling uses its friction and the slope. A rest in water or out of bounds costs the surface's penalty strokes and drop.
Service sport.golf: state(), course(), hole(), players(), scorecard(), clubs(), club(), setClub(id), aimAt(point), aimYaw(yaw?), swing(power, accuracy?), cancel(), ball(player?), distanceToCup(player?), surfaceAt(x, z), wind(), setWind(direction, speed), nextHole(), restart(). Verbs golf_next_hole, golf_restart, golf_set_wind, conditions golf_hole_is, golf_leading. Events golf.round_started, golf.hole_started, golf.wind, golf.turn, golf.swing, golf.landed, golf.penalty, golf.holed, golf.hole_ended, golf.finished. Variables golf.hole, golf.par, golf.stroke, golf.player, golf.phase, golf.gauge, golf.club, golf.wind_speed, golf.distance, golf.to_par, golf.surface. The course position, cards, balls, gauge and wind are saved.
Hooks and modding #
| Hook | Payload | What a tap may do |
|---|---|---|
sport.kick | { entity, team, role, human, charge, power, lift } | change power and lift, cancel |
sport.goal | { team, scorer, own, golden, points } | change points (0 to 99), cancel (the goal is disallowed) |
sport.kickoff | { team, seconds, reason } | change who kicks off and the countdown |
sport.overtime | { rule, seconds, overtime, score } | change what comes next, cancel (the match ends drawn) |
golf.wind | { hole, index, direction, speed, fixed } | change the wind, cancel |
golf.turn | { player, hole, stroke, club, distance, surface } | change the player or the club |
golf.swing | { player, hole, stroke, club, power, accuracy, speed, loft, yaw } | change speed, loft, yaw; cancel |
golf.lie | { player, hole, surface, penalty, drop, at } | change the penalty or the drop, cancel |
golf.hole_out | { player, hole, par, strokes, pickedUp } | change the strokes on the card |
golf.finish | { course, winner, player, won, totals } | change the winner, cancel |
{ "id": "long_shots", "hook": "sport.kick", "match": { "human": true }, "mul": { "power": 1.25 } }
Touches, possession, tackles, balls out of bounds and the choices of the bots are facts, not hooks: react to their events. Moddable for sport.ball: field, ball, kick, impact, teams, teamSize, roles, match, possession, hold, ai (not mode, humans, playerTeam). For sport.golf: holes, players, layout, ball, hole, shot, wind, flow, ai, hidePlayer, and the collections golf_courses, golf_clubs, golf_surfaces.
Engines #
Both kits run as the same Rust logic on the web and in the native player, with the web interface fragment for the golf hud (hole, par, strokes, gauge, wind, club buttons for touch screens, card). Their engine targets are the web and the native player.
When it does not do what you expect #
| Symptom | Cause and fix |
|---|---|
| The ball cannot be kicked | the athlete is farther than kick.reach, the cooldown runs, the ball is higher than kick.maxHeight, or the phase is not live |
| A goal does not count | the ball was not entirely over the line inside the mouth, or a sport.goal tap cancelled it |
| The match never ends | scoreLimit is 0 and the clock is long, or overtime is golden_goal with a draw |
| A golf shot goes short | the surface's power (the rough 0.8, a bunker 0.6) or a headwind; check golf.surface |
| Putts never drop | the ball rolls faster than captureSpeed and lips out |
| The camera ignores the ball | hidePlayer is off or the camera kit has no target to follow |