52PCGame

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1443|回复: 4

[日志新闻] Imperator Development Diary - 15th of April 日志46 mod脚本

[复制链接]

128

主题

280

帖子

8003

积分

制置使

Rank: 14Rank: 14Rank: 14Rank: 14

积分
8003
威望
7998
金圆券
37222 PB
小红花
144
臭鸡蛋
2
法币
3396 FB

黄马褂

发表于 2019-4-16 22:06 | 显示全部楼层 |阅读模式
https://forum.paradoxplaza.com/forum/index.php?threads/imperator-development-diary-15th-of-april.1166676/


Hello and welcome to another Development Diary for Imperator: Rome!
Today will be a different type of Diary compared to some previous ones as we will be focusing entirely on some of the new technical things that Imperator brings to our scripting capabilities. In other words we will be looking at what new things we are adding that you will be able to use to mod the game.
As in any Paradox Game there will be a wide list of triggers, effects, scopes, etc, but this diary will focus on more high level new things and systems, such as the new script value system or the scriptable gui system.
These things are likely best described by those who created them so with that I will leave the word to @blackninja9939 who will talk about scopes, variables and the scriptable GUI and then @Meneth who will be introducing the wonderful world of Scriptvalues.

SCOPES:​


Hello all! I'm Matthew Clohessy and I work as a programmer at PDS. Up until six months ago I was a Content Designer before moving roles, some of you might've seen me around in various modding sections of the forums before as I used to mod Crusader Kings 2 a lot. Over the past year whilst working on <insert cool projects here> I've been doing a variety of improvements to the new Jomini script system to make it a lot more usable, versatile and consistent than the old versions.

Jomini is our Grand Strategy Library which is a midlayer between the game projects and the Clausewitz engine, it contains things that a GSG game can share such as the idea of the game state update, multiplayer, provinces and of course our script system.

Here I'll give you a brief overview of some of the brand new things in the Jomini script system as well as updated and improved versions of systems we had in older games.

With that preamble out of the way lets dive in! The idea of scope types and switching between them is in Jomini, the current Jomini scope types are: no scope, bool, value, color and flag. Yes numbers and bools etc. are a scope type, it has its pros and cons. We refer to these scope types as primitive scopes due to their basic nature and generally not having an object attached to it just the raw ID.
Every event or interaction has a “top scope” which stores root, saved scopes and local variables.

Event Targets are how we 1-1 switch between scope objects, they are comprised of one or more “links” separated by dots. Eg: root.mother.father
As they are separated by dots they can be used in one line so you can do
set_character_religion = root.father.mother.religion
A link can have multiple input types to lead to one output type, allowing polymorphic links that can do more than one thing! So “culture” can move from a province, character, country, pop etc. to their culture.

A scope object can be saved with an arbitrary name to reference later on in the top scope, in our older games these were called event targets. The name was changed as internally both were called event targets before and one is shorter to type for script. Eg:
Code:
father = { save_scope_as = cool_person }scope:cool_person = { kill_painfully = yes }

Gone are the days of needing things like father = { character = root.mother.father } as a condition to see if two characters are the same.
Now we can just do father = root.mother.father, this works for any event target so you can compare things very simply.

This also allows the comparison of numeric values using >, <, >=, <=, = and !=

Numeric links can be used as the value in an effect such as mother = { add_loyalty = root.prominence }

SCRIPT LISTS:&#8203;


Script lists are how we move from one scope to one or more from a list of similar objects. Eg: any_sibling

With the new system we internally only register the list builder such as sibling, the code then automatically generates the various versions for the script.
Currently we have four versions created: any_, every_, random_ and ordered_
The first three should be recognizable, but they’ve all been extended with new functionality
  • Any: Is a trigger that returns true if any of the list meet certain conditions, can have an optional count or percent parameter to indicate X many or Y percent of the list must meet the conditions
  • Every: Runs effects on all members of the list if they meet certain conditions. Can have multiple alternative_limits for backup conditions if the previous set was not met.
  • Random: Runs effects one one member of the list if they meet certain conditions. Can also have alternative_limits as well as a weight to influence which random object to run effects on.
  • Ordered: Runs effect on the entry in a list based on position or range of positions. The list can be ordered by any script value such as loyalty or gold. Can have a limit and alternative_limits on it to filter members of the list.
VARIABLES:&#8203;


Any non-primitive scope type can be made to store variables in it, which scope types to have them is a game level decision so if you find a scope that does not make a request for it to be added, variables themselves can be any scope type. You can store a value, bool, flag or character etc. inside of them.
This allows for recording a saved scope on a specific object instead of just in a top scope.

Variables can be stored in three places: a scope object (character, country etc.), locally in a top scope (like a normal saved scope) or globally in the game state.

Variables themselves are treated as a scope object referring to whatever is stored in them allow you to scope to them.
One could have a best friend variable on a character which they save someone as the value then scope to that best friend variable to give the character a gift later on.

The event target link to scope to a variable depends on the storage type:
Code:
var:namelocal_var:nameglobal_var:name

There are effects and triggers to manipulate and check numeric variables to change their value etc.

LISTS:&#8203;


You can create a custom list of event scopes or variables which can be iterated over as a script list.
Code:
every_character = {    limit = {        has_variable = olympic_attendee    }    add_to_list = olympic_competitor_list}random_in_list = {    list = olympic_competitor_list    die_very_painfully = yes}

You can remove items from lists and check for their presence etc.

SWEET SWEET DOCUMENTATION:&#8203;


We have previously made attempts at automatic documentation with varied success, some bits could be outdated or incorrect, some core information was not printed at all etc.
Now the script documentation console command has been moved to Jomini and it outputs to separate files in your games log folder:
  • All effects, the scopes they can be used in and a brief description, if they are a script list the scope they lead to.
  • All triggers, the scopes they can be used in and a brief description, if they are a script list the scope they lead to.
  • All scope types, character, country, value etc.
  • All event target links, the scopes they can be used from, the scope they output to and a brief description.
  • All saved scopes created by the code.
  • All modifiers, the scope they can be applied to eg: levy_reinforcement_rate
  • All on actions, if they are from code or script and the expected scope they are called in

GUI & LOCALIZATION SYSTEM:&#8203;


We have a new GUI system for the games which works with its own specif setup of scripting, it is also the same system used for the localization system. Collectively this is called the Data System
Everything you can run must be either registered in by the code or made as a scripted gui.

All things you can use in the data are split into four categories:
  • Types, the type of an object which corresponds to its class/struct in the code
  • Promotes, moving from an object of one type to an object of another
  • Functions, calling a function on an object which returns something
  • Callbacks, calling a function on an object which does not return anything

Another thing to keep in mind is that the data system obeys (for the most part) how const works in C++. Without getting too technical functions, promote and callbacks can be marked as const only, which means that object which are const cannot call non-const. This is unlikely to affect you if you use the scripted guis though.

Scripted GUI&#8203;


The scripted gui lets you evaluate and execute arbitrary script via the UI in a manner that will keep the game synchronized in multiplayer. You define the script in common/scripted_guis and can then reference that in data entries.

For example a cheat button to give you gold and take it from another character:
Code:
# common/scripted_guischeat_gold_button = {    scope = character    saved_scopes = {        second    }    is_shown = { # Can be omitted as always true        always = yes    }    is_valid = {        gold < 5000    }    effect = {        add_gold = 500        scope:second = {            add_gold = -500        }    }}# in a gui entrybutton = {    name = "my_cheat_button"    datacontext = "[GetScriptedGui('cheat_gold_button')"    texture = "gfx/interface/icons/shared_icons/bankruptcy.dds"    visible = "[ScriptedGui.IsShown( GuiScope.SetRoot( SomeCharacter.MakeScope ).AddScope( SomeOtherCharacter.MakeScope ).End )]"    enabled = "[ScriptedGui.IsValid( GuiScope.SetRoot( SomeCharacter.MakeScope ).AddScope( SomeOtherCharacter.MakeScope ).End )]"       tooltip = "[ScriptedGui.BuildTooltip( GuiScope.SetRoot( SomeCharacter.MakeScope ).AddScope( SomeOtherCharacter.MakeScope ).End )]"}

The AI will currently not use these buttons, you could however make hidden pulse events to have them evaluate the same actions.

And with that it is time for @Meneth to talk about what Script values are and why we love them.

Script Values&#8203;


Good afternoon. I'm Magne "Meneth" Skj&#230;ran, and I'm a programmer at PDS. I used to work on Crusader Kings II, where I among other things made a variety of improvements to the script system.
For a while now, I've been working on <redacted>, and I've also recently had a 1 month stint on Imperator.
As part of my work, I added a script math system to Jomini. Jomini is the layer between Clausewitz and the game that handles things like script system basics that don't relate to any specific game.
This is not something we've had in any previous game; the closest one could get was heavy use of variables, which was highly limiting.
I'm here today to talk in some detail about this system, outlining what it can do, so let's start from the beginning.

Script values&#8203;


The script math system builds on the script value system. Most of our games have some version of this: the ability to define named values in one file for use in multiple places:
some_value_name = 1000
Which can then be used wherever:
Code:
add_gold = some_value_name

In our older games, the support for this could at times be spotty. In games based on Jomini, this is supported almost anywhere numbers can be used.
In the Jomini games, these values can also be things that aren't just simple numbers. You can for instance do things like:
Code:
add_gold = scope:some_country.gold # Adds as much gold as "some_country" has

Mathematical operations&#8203;


With the script math system, you can now do simple math in script. Instead of "some_value_name = 1000", you can insert math:

Code:
some_value_name = {    value = scope:some_country.gold    add = 50    multiply = 100}

Which would result in ( "some country"'s gold + 50 ) * 100.
We support the following operations:

  • value = ... # Sets the value to the right-hand-side (RHS)
  • add = ... # Adds the RHS
  • subtract = ... # Subtracts the RHS
  • multiply = ... # Multiplies with the RHS
  • divide = ... # Divides with the RHS
  • modulo = ... # Takes the remainder from dividing with the RHS
  • min = ... # Increases the value to the RHS if it is lower
  • max = ... # Decreases the value to the RHS if it is higher
  • floor = yes # Rounds down. 1.2 -> 1, -1.8 -> -2
  • ceiling = yes # Rounds up
  • round = yes # Rounds to the nearest integer
As you can see, this allows you do to complex math, letting you implement things like costs that depend on a lot of factors in a simple manner.

Inlining&#8203;


Taking the system further, anything that supports taking a script value by name (E.G., add_gold = some_value_name) also supports doing that math inline.
So instead of "add_gold = some_value_name", you can do this:

Code:
add_gold = {    value = scope:some_country.gold    add = 50    multiply = 100}

Which will give the exact same result. This is very handy when a value is only used in a single place, since you can then easily see and tweak it where it is being used.
You can even do this inside the math itself. Imagine you want to do the math "gold * ( prestige + 50 )". While you could do this by reordering the math, that'd be pretty tedious. With inlining, you don't have to:

Code:
add_gold = {    value = gold    multiply = {        value = prestige        add = 50    }}

There's no limit on how far you can nest the math.

Conditional logic
&#8203;

Beyond just simple math, you can also have conditional logic. For instance, perhaps you want a reward to be higher if a country has a specific innovation:
Code:
add_gold = {    value = 100    if = {        limit = { has_innovation = some_innovation }        multiply = 3    }    else_if = {        limit = { has_innovation = some_other_innovation }        multiply = 2    }}

This will result in 300 if the country has some_innovation, 200 if it only has some_other_innovation, and 100 if it has neither.

Ranges&#8203;


For effects, you can also randomize numbers.
You can do this in two ways.
First there's a very simple syntax:
Code:
add_gold = { 10 100 }

Which would result in a random amount between 10 and 100.

This would also work:
Code:
add_gold = { some_value some_other_value }

However, this syntax does not work with inlining of math. So for that, we have two statements; integer_range and fixed_range.
integer_range will give an integer number in the designated range (E.G., 1, 2, 3). fixed_range will give a fixed-point number (E.G., 0.1, 0.2, 0.345).
An example of this:
Code:
add_gold = {    integer_range = {        min = { value = gold multiply = 2 }        max = { value = gold multiply = 10 }    }}

This would give between 2 and 10 times the country's gold.

Lists&#8203;


We also support list operations, allowing you to work with collections of items and base the math on each individual item in the collection.
Any list that works in normal script (E.G., every_country, every_subject, every_character) will also work in script math.
The script below for example would add the gold of all your subjects:
Code:
add_gold = {    every_subject= {        add = gold    }}

You can also change scope. Perhaps you want to add all of your overlord's subjects' gold instead:
Code:
add_gold = {    overlord = {        every_subject = {            add = gold        }    }}

&#8203;

As you can see, this system makes it simple to do a lot of things that in our past games was either difficult or even impossible to do in script.
We've used the system a lot in Imperator, and we look forward to seeing what modders will do with it as well.

&#8203;


And with that this developer diary is at an end. Since script does not lend itself to pretty screenshots here is one from the various screens you can get when the game ends. It's appearance and the text will differ depending on how well you did, this was gotten by making the game end in our devclash save, where I'm in control of the proud nation of Bactria. The game seems to think we've achieved little of note sadly

回复

使用道具 举报

3

主题

167

帖子

293

积分

少尉

Rank: 6Rank: 6

积分
293
威望
293
金圆券
1512 PB
小红花
0
臭鸡蛋
2
法币
0 FB
发表于 2019-4-22 10:22 | 显示全部楼层
看得一脸懵逼
回复

使用道具 举报

2

主题

15

帖子

72

积分

下士

Rank: 2Rank: 2

积分
72
威望
72
金圆券
547 PB
小红花
0
臭鸡蛋
0
法币
0 FB
发表于 2019-4-23 10:47 | 显示全部楼层
P社游戏还是靠mod才好玩啊
回复

使用道具 举报

5

主题

84

帖子

98

积分

中士

Rank: 3

积分
98
威望
98
金圆券
709 PB
小红花
0
臭鸡蛋
0
法币
0 FB
发表于 2019-4-23 15:33 | 显示全部楼层
这也就程序员能看懂
回复

使用道具 举报

54

主题

4万

帖子

3万

积分

伯爵

Rank: 13Rank: 13Rank: 13

积分
34665
威望
34665
金圆券
2994 PB
小红花
43
臭鸡蛋
4
法币
0 FB

水兵勋章水勇勋章水军勋章水将勋章水王勋章新兵勋章初等老兵勋章次等老兵勋章优秀服役勋章杰出服役勋章优秀会员勋章春节国庆节52复国日春之曦语夏之岚秋之韵端午节勋章奥运会勋章欧洲杯勋章帝国黄马甲

发表于 2019-4-23 17:42 | 显示全部楼层
似乎跟其他五萌差别不太大,又可以愉快的修改了呢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|52PCGame

GMT+8, 2024-3-29 23:40 , Processed in 0.044591 second(s), 16 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表