Smart Terrain Tutorial

From Mod Wiki

(Difference between revisions)
Jump to: navigation, search
Revision as of 18:37, 1 July 2008 (edit)
Dezodor (Talk | contribs)

← Previous diff
Revision as of 19:10, 1 July 2008 (edit) (undo)
Soduka (Talk | contribs)

Next diff →
Line 1: Line 1:
Lately some people asked me how to create and script smart terrains. To avoid responding for each single email i decided to create this little tutorial. Before i start i would like to tell you that i'm not an expert in this kind of stuff and some things are still not clear for me so i might not be able to explain it properly. Lately some people asked me how to create and script smart terrains. To avoid responding for each single email i decided to create this little tutorial. Before i start i would like to tell you that i'm not an expert in this kind of stuff and some things are still not clear for me so i might not be able to explain it properly.
-My english isn't perfect so please bear with me. Also i will use ST as Smart Terrain abbreviation. This tutorial treats about npc's STs but for mutants it's almost the same. I assume you are familiar with:+My English isn't perfect so please bear with me. Also i will use ST as Smart Terrain abbreviation. This tutorial treats about npc's STs but for mutants it's almost the same. I assume you are familiar with:
- lua programming - lua programming

Revision as of 19:10, 1 July 2008

Lately some people asked me how to create and script smart terrains. To avoid responding for each single email i decided to create this little tutorial. Before i start i would like to tell you that i'm not an expert in this kind of stuff and some things are still not clear for me so i might not be able to explain it properly. My English isn't perfect so please bear with me. Also i will use ST as Smart Terrain abbreviation. This tutorial treats about npc's STs but for mutants it's almost the same. I assume you are familiar with:

- lua programming - all.spawn editing - waypoints (patrols) - ai schemes

First you have to think about your ST, where to spawn it, how many npcs/mutants will "work" for your ST, when ST should be activated/terminated, how many states your ST will have and so on. I guess the best way would be to show you how to get it working by an example. So let's say we want to spawn ST in Cordon for 3 bandits.

1. Spawning ST:

[2515]
; cse_abstract properties
section_name = smart_terrain
name = esc_bandits_smart_terrain
position = 131.02030944824,0.065616846084595,-248.9094543457
direction = 0,0,0

; cse_alife_object properties
game_vertex_id = 635
distance = 9.09999942779541
level_vertex_id = 363757
object_flags = 0xffffff3e
custom_data = <<END
[smart_terrain]
type = esc_bandits_smart_terrain
cond = {-infoportion}
capacity = 3
squad = 1
groups = 5
respawn = esc_respawn_inventory_box_0002
END

; cse_shape properties
shapes = shape0
shape0:type = sphere
shape0:offset = 0,0,0
shape0:radius = 20.55957102775574

; cse_alife_space_restrictor properties
restrictor_type = 3

; se_smart_terrain properties

this is actually the most important stuff:

type = esc_bandits_smart_terrain
cond = {-infoportion}
capacity = 3
squad = 1
groups = 5
respawn = esc_respawn_inventory_box_0002

type is a name of our new ST (required) cond describes conditions which have to be met (optional) capacity ST npcs/mutants quantity i.e. how many npcs/mutants our ST can handle (required) squad, groups no idea what they are used for, maybe they are not used at all but i might be wrong (both are optional) respawn name of the stash (blue box) where items will be spawn when ST respawn will be called (optional)

2. Spawning npcs/mutants and assigning (binding) them to our ST: in this case for each mutant/npc we have to add to its logic:

custom_data = <<END
[smart_terrains]
esc_bandits_smart_terrain = true
END

3. Adding job (logic) for each npc/mutant from our ST (for each state). Let's say our ST have two states: state 0 (describes what npcs/mutants are doing during day) and state 1 (during night). We have 3 bandits, so say:

- bandit1: walker (state 0) and kamp (state 1) - bandit2: guard (state 0) and sleeper (state 1) - bandit3: walker (state 0 and 1 <= he's doing the same at day and night)

There are at least 3 ways to add logic (job) for each npc/mutant, we will use the most common one, i.e. we will add logic to config\misc\gulag_escape.ltx file. It may looks like this:

;-- bandit1 (walker -> state 0, i.e. during day)
[logic@esc_bandits_smart_terrain_bandit1_walker]
active = walker@esc_bandits_smart_terrain_bandit1

[walker@esc_bandits_smart_terrain_bandit1]
path_walk = bandit1_walk
danger = danger_condition@esc_bandits_smart_terrain
def_state_moving1 = patrol
def_state_moving2 = patrol
def_state_moving3 = patrol
meet = no_meet

;-- bandit1 (kamp -> state 1, i.e. during night)
[logic@esc_bandits_smart_terrain_bandit1_kamp]
active = kamp@esc_bandits_smart_terrain_bandit1

[kamp@esc_bandits_smart_terrain_bandit1]
center_point = bandit_kamp
path_walk = bandit_kamp_task

;-- bandit2 (guard -> state 0, i.e. during day)
[logic@esc_bandits_smart_terrain_bandit2_walker]
active = walker@esc_bandits_smart_terrain_bandit2

[walker@esc_bandits_smart_terrain_bandit2]
path_walk = bandit2_walk
path_look = bandit2_look
danger = danger_condition@esc_bandits_smart_terrain

;-- bandit2 (sleeper -> state 1, i.e. during night)
[logic@esc_bandits_smart_terrain_bandit2_sleeper]
active = sleeper@esc_bandits_smart_terrain_bandit2

[sleeper@esc_bandits_smart_terrain_bandit2]
path_main = bandit2_sleep
wakeable = false

;-- bandit3 (guard -> state 0 and 1, i.e. during day/night)
[logic@esc_bandits_smart_terrain_bandit3_walker]
active = walker@esc_bandits_smart_terrain_bandit3

[walker@esc_bandits_smart_terrain_bandit3]
path_walk = bandit3_walk
path_look = bandit3_look

[danger_condition@esc_bandits_smart_terrain]
ignore_distance_corpse = 0
ignore_distance = 0

4. Now we have to script our ST. In this case we will add our code to scripts\gulag_escape.script file. There are several things we need to do here (each of this steps is required):

- load logic (jobs) for each npc/mutant, for each state -> function load_job(...)

if type == "esc_bandits_smart_terrain" then
	t = {}
	;-- section is a "link" to logic defined in ltx file
	t.section = "logic@esc_bandits_smart_terrain_bandit1_walker"
	;-- no idea, probably describes after what time
	;-- npc will use this job again (?)
	t.idle = 0
	;-- no idea but i guess it's optional
	t.timeout = 0
	;-- priority
	t.prior = 100
	;-- npc will use this logic if ST switched to this state
	;-- in this case - state 0 (day)
	t.state = {0}
	;-- no idea about squad and group
	t.squad = squad
	t.group = groups[1]
	;-- no idea what means position_threshold
	t.position_threshold = 100
	;-- describes whether npc in this state is online or offline
	;-- online = true by default
	t.online = true
	;-- describes restrictors (where npc can/can't go)
	t.in_rest = ""
	t.out_rest = ""
	;-- because of the way how jobs are assigning by
	;-- smart_terrain.script you never know which job
	;-- will be used by which npc; if you want to ensure
	;-- that certain job is used by certain npc then
	;-- you have to use predicate function; in this case
	;-- we want this job to be used by expert (master) bandit
	t.predicate = function(obj_info) return obj_info.rank >= 900 end
	table.insert(sj, t)

	t = {section = "logic@esc_bandits_smart_terrain_bandit1_kamp",
	idle = 0, timeout = 0, prior = 100, state = {1},squad = squad,
	group = groups[1], position_threshold = 100, online = true, in_rest = "",
	out_rest = "", predicate = function(obj_info) return obj_info.rank >= 900 end}
	table.insert(sj, t)

	;-- bandit2 -> state 0 (day)
	t = {section = "logic@esc_bandits_smart_terrain_bandit2_walker",
	idle = 0, prior = 5, state = {0}, squad = squad, group = groups[1],
	in_rest = "", out_rest = ""}
	table.insert(sj, t)

	;-- bandit2 -> state 1 (night)
	t = {section = "logic@esc_bandits_smart_terrain_bandit2_sleeper",
	idle = 0, prior = 5, state = {1}, squad = squad, group = groups[1],
	in_rest = "", out_rest = ""}
	table.insert(sj, t)

	;-- bandit3 -> state 0 (day) and state 1 (night)
	t = {section = "logic@esc_bandits_smart_terrain_bandit3_walker",
	idle = 0, prior = 5, state = {0, 1}, squad = squad, group = groups[1],
	in_rest = "", out_rest = ""}
	table.insert(sj, t)
end

One more thing about ST states, it's up to you how many states your ST have. The important thing is to add logic for each state. For instance your ST can have those states:

0 - npcs are offline 1 - npcs are online (day) 2 - npcs are online (night) 3 - npcs are online, they decided to assault other ST 4 - npcs are online and actor attacks them

And another thing, i'm sick when i have to fill so many tables, so i usually use this function:

function fill_tbl(section, idle, prior, states, squad, group, in_rest, out_rest, online, gulag_name)
	local tbl = {}

	tbl.section = "logic@" .. gulag_name .. "_" .. section
	tbl.idle = idle
	tbl.prior = prior	
	tbl.state = {}

	for index = 1, #states do
		table.insert(tbl.state, states[index])
	end

	tbl.squad = squad
	tbl.group = group
	tbl.in_rest = in_rest
	tbl.out_rest = out_rest
	tbl.online = online
	return tbl
end

So using above function, we can load logic like this:

if type == "esc_bandits_smart_terrain" then
	local t = table.insert(sj, fill_tbl("bandit1_walker", 0, 100, {0}, squad, groups[1], "", "", true, type))
	t.timeout = 0
	t.position_threshold = 100
	t.predicate = function(obj_info) return obj_info.rank >= 900 end
	table.insert(sj, t)


	t = table.insert(sj, fill_tbl("bandit1_kamp", 0, 100, {1}, squad, groups[1], "", "", true, type))
	t.timeout = 0
	t.position_threshold = 100
	t.predicate = function(obj_info) return obj_info.rank >= 900 end
	table.insert(sj, t)

	table.insert(sj, fill_tbl("bandit2_walker", 0, 5, {0}, squad, groups[1], "", "", true, type))
	table.insert(sj, fill_tbl("bandit2_sleeper", 0, 5, {1}, squad, groups[1], "", "", true, type))
	table.insert(sj, fill_tbl("bandit3_walker", 0, 5, {0, 1}, squad, groups[1], "", "", true, type))
end

- automatically change job for each npc/mutant -> function load_states(...)

if type == "esc_bandits_smart_terrain" then
	return function(gulag)
		if not db.actor then
			return gulag.state
		end
		if level.get_time_hours() >= 5 and level.get_time_hours() <= 22 then
			return 0  -- switch all mutants/npc to daily job
		else
			return 1  -- switch all mutants/npc to nightly job
		end
	end
end

- ensure that our ST will be used only by bandits -> function checkStalker(...)

if gulag_type == "esc_bandits_smart_terrain" then
	return npc_community == "bandit"
end

Links

Discussion: http://www.gsc-game.com/main.php?t=community&s=forums&s_game_type=xr&thm_page=77&thm_id=14712&sec_id=16&page=1#199726

Check our tool for smart terrain debugging and waypoint exporting:

Download: http://sdk.stalker-game.com/ru/images/d/d7/Smartterrain_and_Waypoint_Tools_by_dez0wave.zip

Mirror: http://ifolder.ru/7179080

Personal tools