Ihnatus branch for 2.6 Longturn server/client

Can you help improve your favourite game? Hardcore C mages, talented artists, and players with any level of experience are welcome!
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

I have started a branch of 2.6 mods some of which may go to the main or Longturn releases. Network compatibility with 2.6 protocol is kept.
Features:
  • Bombardment revealing may be restricted with option "bombardment_reveal":
    "ALL" reveals all participants of bombardment (current behaviour),
    "BEST" reveals only the strongest defender,
    "ATTACKER" reveals the bombarder only,
    "NONE" hides the bombarder if otherwise unseen (in 2.6 that means mostly bombarding from behind city walls).
    Whatever is the option, the bombarding side knows if it has succeeded in reducing at least 1 hp from any unit, and the defender knows nationality and type of the bombarder.
  • Option "cargo_visibility": "NONE" = don't see any non-allied units (default behaviour), "FORTIFY" = see if they are fortifying or fortified, "ACTIVITIES" = see if they do any terrain-related activity (it's just implausible that workers can stay hidden manipulating huge land masses), "ALL" = just see all of them (e.g. transports in your ruleset are horses and bikes).
  • Removed exploits of bouncing units around for terrain change or stack conflicts: they now keep UWT and lose movepoints if they have landed.
  • For the Gtk3.22 client, if you click a tech that may possibly be researched in a moment with you current bulbs, you get a confirmation popup.
  • Different client Lua callbacks are added to help you not lose anything. Callbacks now may send feedback to the C code; so, "event" callback may change the place the message is displayed (output/chat/box/nowhere).
    "unit_remove" (Unit unit) - when unit is going out of sight by any reason (defore processing it).
    "unit_moved" (Unit unit, Tile t_from, Tile t_to) - after we processed a package of unit info about a unit that was on another position just before.
    "unit_captured"(Unit unit, Player gainer) - before we process a package of unit info when we just have seen the unit ID on another side. "unit_remove" and "unit_create" are also called in this case (but if you can't see the captured unit any more, you get only "unit_remove" of all callbacks).
    "unit_create"(Unit unit) - after we have processed an info about a unit not in sight just before (or that belonged to another player).
    "combat_info"(Unit attacker, Unit defender, int att_hp, int def_hp, bool veteranship_achieved) - when a combat was seen. The last parameter requires more testing though.
    "city_create"(City city) - a city newly seen.
    "city_transferred"(City city, Player gainer, Player loser)
    "city_remove"(City city) - we see the tile without the city that was there.
    "event"(string plain_text, Tile ptile, int event, int turn, Player sender, table objects) - an event message received. event is a value from E table. objects is a sequence of links (Unit, City or Tile type) mentioned in the message; your callback may create a key "show" in it: boolean value false means that the message goes hidden, string "Popup" (any case) displays it in a window, string "Messages" puts it into message window, any other string sends it to the console.
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

A patch adds some new common functionality (I don't keep along with Pneu's branch so some his fun is not here neither automatically mergeable):
  • find.player and find.city now work with string arguments
  • direction.name(dir)
  • effects.player_output_bonus(Player plr, output_type, string eft_name) --output_type may be "Trade" etc. or OUTPUT.TRADE etc.
  • Player.team_number
  • Player.is_male
  • Player,nturns_idle
  • Player:waste_level_at(Tile where, outp_type, Tile govcenter_pos?) -- outp_type see above, calculates corruption for virtual cities using effects.player_output_bonus() and given or current govcenter position to get waste levels, ignores "Output_Waste_Pct" (Courthouse) effect (warning: lies like one breathes in many rulesets, you'd better write a calculator yourself)
  • City.martial_law --number of citizens potentially pacified by troops
  • City.food_stock, .shield_stock, .airlift, .did_buy, .did_sell, .before_change_shields, .caravan_shields, .disbanded_shields, .last_turns_shield_surplus
  • City.supported_count --number of units supported, including free
  • City.production --Unit_Type or Building_Type currently being produced
  • City:waste_level(outp_type = "Shield", int gc_dist?) --waste level for outp_type (see above), 1.0 means all wasted, gc_dist maybe specified instead of actual distance to nearest known govcenter
  • City:happy_count(int citizen = CITIZEN.HAPPY, int level = FEELING.FINAL) --number of citizens with given happiness state at given feeling calculation level, constants CITIZEN.* and FEELING.* may be specified to override default params
  • Tile.owner
  • Tile.continent --number
  • Tile:real_map_distance(Tile other), Tile:map_distance(Tile other) --Real map distance in "airplane steps", diagonal==1, and Manhattan one (diagonal==2)
  • Tile:govcenter_dist(Player p) -- Real distance to nearest govcenter of p, important for corruption
  • Tile:output(output_type, City working_city?, bool celebrating?) -- optionally, how many it gives if worked by some_city, optionally, if it would celebrate.
  • Unit.hp, .fuel, .veteran, .moves_left --all int
  • Unit.activity --string, e.g. "Sentry"
  • Unit.orders_index -- Number of current order in the list starting from 1, nil if no order list. The list will be dealed by upcoming patches.
  • Unit:move_rate()
  • Unit:activity_rate() -- Dimensioned in 1/10 movepoints, sum on a tile to get total rate. Ignores if unit has movepoints to perform an activity now or can do any rate-related activity
  • Unit_Type.move_rate, .fuel, .happy_cost
Last edited by Ignatus on Thu Jul 02, 2020 10:05 pm, edited 2 times in total.
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

Next patch adds to common API:
  • game object now has subtable terrain_control, its fields are also delegated up to game object:
    • int ocean_reclaim_requirement_pct;
    • int land_channel_requirement_pct;
    • int terrain_thaw_requirement_pct;
    • int terrain_freeze_requirement_pct;
    • int lake_max_size;
    • int min_start_native_area;
    • int move_fragments; /* alias: game.SINGLE_MOVE */
    • int igter_cost; /* alias: game.IGTER_MOVE_COST */
    • bool pythagorean_diagonal
  • Player:dipl_rel(Player other_player, string what) --tests "DiplRel" requirement with range="Local" and name = what
  • City:surplus(otype) /* Final surplus in each category. */
  • City:waste(otype) /* Waste/corruption in each category. */
  • City:unhappy_penalty(otype) /* Penalty from unhappy cities. */
  • City:prod(otype) /* Production is total minus waste and penalty. */
  • City:citizen_base(otype) /* Base production from citizens. */
  • City:usage(otype) /* Amount of each resource being used. */
  • City:nationalities() --table {[Player] = count}, nil if nationalities are off
  • City:specialist(string spec_rule_name) --count of specialists
  • City:traderoutes_number
  • City:trade_routes() -- returns table {[City partner] = int trade}
  • City:trade_routes_iterate() -- just is pairs(City:trade_routes)
  • A change in client code to make the following pair of functions workable: caravan bonus style and trade revenue style options are dumped into C game.server structure. It works only for servers with the same definitions (but it's a LT client, so log2N style works by keyword "LOGARITHMIC").
  • City:trade_with(City) -- (possible) trade between cities, based on known data.
  • City:caravan_bonus(City target, bool establish?) -- how much trade and/or science you get if a caravan arrives to target. establish is by default true iff there is no active trade route. For foreign cities, the client does not understand if their owner knows the tiles around and thus the function brings some errors
  • City:supported_iterate() -- Iterates by supported units list
  • Unit.activity_target -- extra name or nil
  • Unit:orders() -- if a unit has orders, returns a sequence of tables {{order = ORDER.MOVE etc., activity = activity_name, direction=Direction, target = extra_rule_name}}. Second and third values are boolean: if the orders are repeated and if they are interrupted by spotting an enemy.
Last edited by Ignatus on Fri Oct 16, 2020 8:07 am, edited 2 times in total.
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

Mod for clients:
  • client.player -- it's you
  • client.option, game.server_option -- tables that contain client and known server options, the values are tables, integers or strings depending on option types, may be iterated by pairs()
  • client.state -- "Initial", "Disconnected", "Preparing", "Observing", "Playing" or "Gameover"
  • client.center(Tile tile or map_x, map_y) -- centers the view at tile
Last edited by Ignatus on Thu Jul 09, 2020 10:06 pm, edited 1 time in total.
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

A n example of a script. Function trade_plan(player) prints on the Lua console possible domestic trade routes sorted firstly by trade output (from two cities), then by one-time bonus. Does not check number of trade routes per city, existence of a trade route influences only the bonus.
Attachments
lt-mp.lua.zip
(493 Bytes) Downloaded 279 times
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

New patch - advanced client control
  • focus module to control your units selection: focus.add(unit), focus.remove(unit), focus.contains(unit), focus.number(), focus.iterate(), focus.list()
  • city.occupied -- anybody is at home
  • city:change_production(unit_type or building_type) --sends to the server request to change the production
  • unit.occupied -- the plus sign at transporter
  • unit:selected -- a.k.a. focus.contains(unit)
  • unit:select() -- focus.add(unit)
  • unit:unselect() --focus.remove(unit)
  • Generic control methods:
    • unit:give_orders({order_list},bool repeat?, bool vigilant?) -- order_list like in unit:orders() but you may shortcut {{order=ORDER.MOVE,dir=direction.str2dir"Northwest"},{order=ORDER.ACTIVITY,activity="Irrigate",target="Irrigation"}} to just {"Northwest", "Irrigate"}
    • unit:request_activity(string activity_name,string target?) -- does an activity on the tile, some activities may be supported only by this or ony by the previous function. Target is an extra name, sometimes when it's required it may be identified automatically
    • unit:do_action(action,target?,value?) -- does some action. action is Action object (I'll add find.action(id) later), action name e.g. "Establish Trade Route" or int action id. target is an object (queried only for .id field) or an int id, as well as value; value is needed only for actions "Targeted Sabotage City" (must be a building type, "Production" or, by default, "random") and "Targeted Steal Tech" (must be a tech type or, by default, "random"). Target may be omitted if there is only one unit or city on adjacent tiles or if the unit is in the target city (for example, this comand makes all caravans adjacent to or in cities try to establish trade routes, move points are sometimes not needed: for u in client.player:units_iterate() do if u.utype:rule_name()=="Caravan" then u:do_action("Establish trade route")end end
  • Specific control methods: unit:airlift(city to_what), unit:load(Unit transport), unit:unload_from(Unit transport?) --[[this one works if you own transport and not unit]], unit:unload(Unit other?) --[[this one finds who transports whom and unloads sanely]], bool unit:goto(tile) --[[returns false if can't find a route]], unit:upgrade(), unit:build_city(name?)--[[also adds to an existing city; otherwise, if name is not supplied and there is a client setting, the name will be asked]]
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

Some more common API:
  • find.action(id or name)
  • Action.target_kind -- "City" or "Unit"
  • Unit_Type:
    • string .graphic_str, .graphic_alt -- e.g. "u.worker"
    • int .vision_radius_sq
    • Unit_Type .obsoleted_by, .converted_to
    • table :veteran_system() -- returns a sequence (with greens at [0]) of tables, each one with keys "rule_name", "power_fact" and "move_bonus"; on server only, you can get also "raise_chance" and "work_raise_cance" (all numbers in %)
  • Player properties and method:
    • .team_rule_name
    • .spaceship_state -- nil, "Started", "Launched" or "Arrived"
    • .spaceship_success_rate -- 0.0 to 1.0
    • .spaceship_travel_time -- in years, 0.0 if no spaceship
    • :researching() -- embassy data - two values: Tech_Type, number_of_bulbs_accumulated
  • City:vision_radius_sq(vlayer?) -- squared vision from a city by present data, vlayer can be VISION.MAIN (default) or VISION.INVIS (for cities, the latter gives always 2, but not for units)
  • Unit:
    • string .veteran_rule_name --e.g. "green"
    • Player .nationality --in client, defined only for your own units
    • :attack_power(Unit defender), :defense_power(Unit attacker) -- in current state, multipled on 10
    • :win_chance(Unit defender). You can calculate battle chance without specific units via game.win_chance(a_s,a_hp,a_fp,d_s,d_hp,d_fp), calculating all combat stats yourself.
    • :vision_radius_sq(Tile where?, vlayer?) -- by default, on current tile on VISION.MAIN
    • :act_prob_vs(action,target) -- for some actions, calculates a pair of values that represent minimal and maximal estimation of action probability performed by the unit against the target (city or unit); so, 200, 200 means a certain case and 0, 0 is valid by rules but never bringing a desired result. If the action is not valid for the target and/or the actor orthe calculator is not implemented, returns in the first value nil, in the second an explanation string.
    • :action_possible(action, target) -- boolean wrapper of the former one, in valid but uncalculatable cases returns false
    • :can_do_activity(string activity,string target,Tile where?) -- checks if the unit could currently do this activity to this extra at the tile (current location by default)
  • Tile.worked -- returns a city working the tile, in client, may be virtual with only its id valid. But you know the id (if any) for any tile you see.
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

New commits didn't add more api but amended existing functions. find.player() and find.city() by names tended to work in an unexpected manner when the player/city name could be interpreted as integer, tolua type resolution mechanism was replaced by my own one. City:caravan_bonus(City) and city:trade_with(City) were brought to make some plausible assumptions about foreign city trade output for server settings that require the data (but foreign city trade from routes still is ignored).
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

In the new update, a very bad bug was fixed - unused Direction values causd the application to fail (it is in the main branch, I've made a patch for v.2.6.3). Now, Direction's are normal objects: have fields id and name, function find.direction(id or name), properties .next_cw, .next_ccw and .opposite. They are compared as you would expect, and the directions not valid in current (or any) topology result in nil.

Another common feature is better specialist support: string functions/properties/iterators (return e.g. "elvis") game.specialist(id), game.default_specialist, game.specialists_iterate().

Now, client API to operate city workers:
  • City.cma_name -- nil if city has no governor, "custom" if the governor is not saved, or a name known to local client
  • City:change_specialist(string from_s, string to_s) -- e.g. "elvis" to "scientist"
  • bool City:work(Tile), :release(Tile) -- put worker on a tile or make former worker a default specialist. Return if the tile is in city radius.Supplying city center auto-arranges all workers!
  • bool City:toggle(Tile, bool can_auto_arrange?) -- calls either of the functions which one is valid for a tile, does not auto-arrange unless can_auto_arrange is true
  • City:auto_arrange()
Ignatus
Elite
Posts: 644
Joined: Mon Nov 06, 2017 12:05 pm
Location: St.Petersburg, Russia
Contact:

Re: Ihnatus branch for 2.6 Longturn server/client

Post by Ignatus »

A bit of documentation for Unit:give_orders() client method. First (and most times the only) parameter of the method is a sequence each member of which is either an order (given as a table, a number, a string or a direction) or a subsequence with string field 'times' showing how many times to repeat it. After recursively opening any 'times' subsequences, the number of orders must not exceed 2001.

Number given as order is always an order number, direction gives a move/action-move order, strings are tried consequently to match an extra rule name (except "Mine"), activity name, direction name or order character (for most orders, only the first character is checked). All strings except table keys are case-insensitive. Full table form is {order = (number or character), activity = string, direction = (Direction or direction_string or direction_digit), target = extra_name} with useless members set to nil (that's the form which common API method unit:orders() return). The orders table:

Code: Select all

    ORDER.MOVE = 0, "M" -- move a step into a direction dir
    ORDER.ACTIVITY = 1, "A" --do an activity
    ORDER.FULL_MP = 2, "W" -- wait until movepoints are full, stacking these orders gives no effect
    ORDER.BUILD_CITY = 3, "B" --build or join to a city
    ORDER.DISBAND = 4, "D"
    ORDER.BUILD_WONDER = 5, "U" -- help wonder
    ORDER.TRADE_ROUTE = 6, "T", "E" --establish TR when the caravan is in a city
    ORDER.HOMECITY = 7, "H" -- in the table form, string /^help ?wonder$/i is equivalent to "U"
    ORDER.ACTION_MOVE = 8, "X" -- or i/^action_?move$/
ORDER.ACTION_MOVE differs from ORDER.MOVE in that if the unit is capable of any action against a unit or the city on the tile towards the direction, the unit stops and asks the player what to do. Attack, capture or bombard may happen by this order if no 2.6-defined action is possible. ORDER.MOVE will stop even without vigilant flag if there is a non-allied unit or (even empty enemy) city on the unit's way (but you still can occupy an empty claiming base). Note that all other orders including ORDER.TRADE_ROUTE don't move the unit and act on the same tile.That means, unlikely v.2.5, your client can't make fully server-side order to establish a trade route with a non-allied city, the player will have to respond on the dialog in the final way point.

UPD: Note the new named field "actmove" thatt you can add to the main order sequence. If you set it to "auto" or don't set at all, your unit will interpret all moves specified as directions only as normal moves but the last one, if the destination tile is seen containing a non-allied unit or city, will be recorded as an action one. Value "auto_each" will check all the way, if any move with an unspecified order brings you to a tile with a non-allied unit or city, this move will be an action-move. Value "all" or true will render all unspecified moves as action-moves, and value "no" or false will do the opposite.

ORDER.ACTIVITY ('a') requires setting the activity. You can't set "Idle", "Explore", "Fortified" or "Goto" activity by :give_orders() method, and "Fortifying" or "Sentry" may be only the last order. "Road", "Irrigate". "Mine" or "Base" activities require target extra with the approproate extra cause, it's mostly supplied by the method automatically; currently, the server code works in such a way that, unlikely v.2.5, transform-mine and transform-irrigate do not work wether you supply any target or no TODO: automate changing extras in consequent orders when building e.g. {{times=3, "Road"}} means road, then railroad, then maglev. "Pillage" also needs a target but if not specified server tries to find some one, or puts the unit idle.

ORDER.BUILD_CITY ('b') is the same for building or joining to a city.

ORDER.FULL_MP ('w') means that the unit won't move until all its movepoints are restored. Stacking several these orders has no effect.
Post Reply