starlit  Check-in [d2ab51532e]

Overview
Comment:somewhat improve buttons
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | trunk
Files: files | file ages | folders
SHA3-256: d2ab51532e382991cb3c83f280782dbfbd878f7bcc5b6a9cc623959e10c8059d
User & Date: lexi on 2025-03-25 17:47:31
Other Links: manifest | tags
Context
2025-03-25
17:47
somewhat improve buttons Leaf check-in: d2ab51532e user: lexi tags: trunk
2025-01-19
19:18
we have always been at war with east minecraft check-in: 4732f8d454 user: lexi tags: trunk
Changes

Modified asset.list from [33338e0378] to [7b9ff32a24].

228
229
230
231
232
233
234

235
236
237
238
239
240
241
mods/starlit/textures/starlit-ui-alert.png
mods/starlit/textures/starlit-ui-bar.png
mods/starlit/textures/starlit-ui-bg-digital.png
mods/starlit/textures/starlit-ui-bg-panel.png
mods/starlit/textures/starlit-ui-button-hw-hover.png
mods/starlit/textures/starlit-ui-button-hw-press.png
mods/starlit/textures/starlit-ui-button-hw.png

mods/starlit/textures/starlit-ui-button-sw-hover.png
mods/starlit/textures/starlit-ui-button-sw-press.png
mods/starlit/textures/starlit-ui-button-sw.png
mods/starlit/textures/starlit-ui-crosshair-nano.png
mods/starlit/textures/starlit-ui-crosshair-psi.png
mods/starlit/textures/starlit-ui-crosshair-weapon.png
mods/starlit/textures/starlit-ui-crosshair.png







>







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
mods/starlit/textures/starlit-ui-alert.png
mods/starlit/textures/starlit-ui-bar.png
mods/starlit/textures/starlit-ui-bg-digital.png
mods/starlit/textures/starlit-ui-bg-panel.png
mods/starlit/textures/starlit-ui-button-hw-hover.png
mods/starlit/textures/starlit-ui-button-hw-press.png
mods/starlit/textures/starlit-ui-button-hw.png
mods/starlit/textures/starlit-ui-button-sw-active.png
mods/starlit/textures/starlit-ui-button-sw-hover.png
mods/starlit/textures/starlit-ui-button-sw-press.png
mods/starlit/textures/starlit-ui-button-sw.png
mods/starlit/textures/starlit-ui-crosshair-nano.png
mods/starlit/textures/starlit-ui-crosshair-psi.png
mods/starlit/textures/starlit-ui-crosshair-weapon.png
mods/starlit/textures/starlit-ui-crosshair.png

Added mods/starlit-psionics/init.lua version [539da653d2].









































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
local lib = starlit.mod.lib

starlit.interface.install(starlit.type.ui {
	id = 'starlit_psionics:cultivate';
	pages = {
		index = {
			setupState = function(state, user) end;
			handle = function(state, user, act) end;
		};
	};
})

starlit.world.psi.meld {
	cultivate = {
		name = 'Cultivate';
		desc = 'Invest numina to develop new powers';
		powerKind = 'direct';
		cost = {}; -- cultivate costs are applied in the interface

		 -- all psions start with this power
		learnCost = 0, rarity = 0;
		ui = 'starlit_psionics:cultivate';
	};
}

starlit.world.psi.meld {
	cultivate = {
		name = 'Mend';
		desc = 'Burn numina to rapidly heal yourself';
		powerKind = 'passive';
		cost = { stat = {numina = 10} }; -- ψ/s

		learnCost = 1000, rarity = 5;
		bgProc = function(ctx) end;
	};
}

Added mods/starlit-psionics/mod.conf version [e85c7f4195].









>
>
>
>
1
2
3
4
name = starlit_psionics
title = starlit psionics
description = defines the base psi powers
depends = starlit

Modified mods/starlit-scenario/init.lua from [8a376bbedc] to [339ae3b1f1].

2
3
4
5
6
7
8








9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
local scenario = starlit.world.scenario
local log = starlit.logger 'scenario'

local function makeChip(label, schem, sw)
	local E = starlit.mod.electronics
	local files = {}
	local sz = 0








	for _, e in ipairs(schem) do
		local p = E.sw.findSchematicFor(e[1])
		if p then
			local file = {
				kind = 'sw', name = '', drm = e[2];
				body = {pgmId = p, conf = {}};
			}
			table.insert(files, file)
			sz = sz + E.chip.fileSize(file)
		end
	end
	for _, e in ipairs(sw) do
		local file = {
			kind = 'sw', name = '', drm = e[2];
			body = {pgmId = e[1], conf = {}};
		}
		table.insert(files, file)
		sz = sz + E.chip.fileSize(file)
	end
	local chip = ItemStack(assert(E.chip.findBest(function(c)
		return c.flash >= sz, c.ram + c.clockRate
	end)))
	local r = E.chip.read(chip)
	r.label = label
	r.files = files
	E.chip.write(chip, r)







>
>
>
>
>
>
>
>











<
<
<
<
<
<
<
<







2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27








28
29
30
31
32
33
34
local scenario = starlit.world.scenario
local log = starlit.logger 'scenario'

local function makeChip(label, schem, sw)
	local E = starlit.mod.electronics
	local files = {}
	local sz = 0
	for _, e in ipairs(sw) do
		local file = {
			kind = 'sw', name = '', drm = e[2];
			body = {pgmId = e[1], conf = {}};
		}
		table.insert(files, file)
		sz = sz + E.chip.fileSize(file)
	end
	for _, e in ipairs(schem) do
		local p = E.sw.findSchematicFor(e[1])
		if p then
			local file = {
				kind = 'sw', name = '', drm = e[2];
				body = {pgmId = p, conf = {}};
			}
			table.insert(files, file)
			sz = sz + E.chip.fileSize(file)
		end
	end








	local chip = ItemStack(assert(E.chip.findBest(function(c)
		return c.flash >= sz, c.ram + c.clockRate
	end)))
	local r = E.chip.read(chip)
	r.label = label
	r.files = files
	E.chip.write(chip, r)

Modified mods/starlit-suit/init.lua from [078f484c1f] to [ef81e2c820].

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
		tex = {
			plate = {
				id = 'starlit-suit-survival-plate';
				tint = lib.color {hue = 210, sat = .5, lum = .5};
			};
			lining = {
				id = 'starlit-suit-survival-lining';
				tint = lib.color {hue = 180, sat = .2, lum = .7};
			};
		};
		tints = {'suit_plate', 'suit_lining'};
		temp = {
			desc = facDesc('survival','cc');
			maxHeat = 0.7; -- can produce a half-degree Δ per second
			maxCool = 0.5;







|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
		tex = {
			plate = {
				id = 'starlit-suit-survival-plate';
				tint = lib.color {hue = 210, sat = .5, lum = .5};
			};
			lining = {
				id = 'starlit-suit-survival-lining';
				tint = lib.color {hue = 260, sat = .3, lum = .3};
			};
		};
		tints = {'suit_plate', 'suit_lining'};
		temp = {
			desc = facDesc('survival','cc');
			maxHeat = 0.7; -- can produce a half-degree Δ per second
			maxCool = 0.5;

Modified mods/starlit/food.lua from [09c96accb0] to [ee714c2ec0].

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
		props = props;
		color = f.color;
	};
end

F.foreach('starlit:gen-food', {}, function(id, f)
	core.register_item(id, {
		type = f.itemType or 'none';
		inventory_image = f.tex;
		short_description = f.name;
		description = foodTip(nil, f);
		on_use = function(st, luser)
			local user = starlit.activeUsers[luser:get_player_name()]
			st:take_item(1)
			local imp = F.impact(st,f)







|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
		props = props;
		color = f.color;
	};
end

F.foreach('starlit:gen-food', {}, function(id, f)
	core.register_item(id, {
		type = f.itemType or 'craft';
		inventory_image = f.tex;
		short_description = f.name;
		description = foodTip(nil, f);
		on_use = function(st, luser)
			local user = starlit.activeUsers[luser:get_player_name()]
			st:take_item(1)
			local imp = F.impact(st,f)

Modified mods/starlit/init.lua from [ae90c8058c] to [ae88cd06e3].

92
93
94
95
96
97
98

99
100
101
102
103
104
105
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473










474
475
476
477
478
479
480
481
482

483
484
485
486
487
488
489
490
			trees = lib.registry.mk 'starlit:trees';
			biomes = lib.registry.mk 'starlit:biome';
		};
		climate = {
			weather = lib.registry.mk 'starlit:weather';
			weatherMap = {}
		};

		scenario = {};
		planet = {
			gravity = 7.44;
			orbit = 189; -- 1 year is 189 days
			revolve = 20; -- 1 day is 20 irl minutes
		};
		fact = lib.registry.mk 'starlit:fact';
................................................................................
		-- of the default hp_max. since we crank up
		-- hp by a factor of 50~40, damage should be
		-- cranked by similarly
	end
	return delta
end, true)

function core.handle_node_drops(pos, drops, digger)
	local function jitter(pos)
		local function r(x) return x+math.random(-0.01, 0.01) end
		return vector.new(
			r(pos.x),
			r(pos.y),
			r(pos.z)
		)
	end










	for i, it in ipairs(drops) do
		if type(it) == 'string' then it = ItemStack(it) end
		if not it:is_empty() then
			local ent = core.add_item(jitter(pos), it)
			if ent ~= nil then -- avoid crash when dropping unknown item
				local dp = vector.new(0,0,0)
				if digger then dp = digger:get_pos() end
				local delta = dp - ent:get_pos()
				ent:add_velocity(vector.new(delta.x,0,delta.z));

			end
		end
	end
end


-- TODO timer iterates live UI








>







 







<
|







>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
>





<
|

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
...
459
460
461
462
463
464
465

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

499
500
			trees = lib.registry.mk 'starlit:trees';
			biomes = lib.registry.mk 'starlit:biome';
		};
		climate = {
			weather = lib.registry.mk 'starlit:weather';
			weatherMap = {}
		};
		psi = lib.registry.mk 'starlit:psi';
		scenario = {};
		planet = {
			gravity = 7.44;
			orbit = 189; -- 1 year is 189 days
			revolve = 20; -- 1 day is 20 irl minutes
		};
		fact = lib.registry.mk 'starlit:fact';
................................................................................
		-- of the default hp_max. since we crank up
		-- hp by a factor of 50~40, damage should be
		-- cranked by similarly
	end
	return delta
end, true)


do local function jitter(pos)
		local function r(x) return x+math.random(-0.01, 0.01) end
		return vector.new(
			r(pos.x),
			r(pos.y),
			r(pos.z)
		)
	end

	function starlit.throwItem(luser, stack)
			local ent = core.add_item(jitter(luser:get_pos()), stack)
			a = luser:get_look_dir()
			a = a * math.random(1, 10);
			a.y = a.y + 0.5
			ent:add_velocity(a)
	end

	function core.handle_node_drops(pos, drops, digger)
		for i, it in ipairs(drops) do
			if type(it) == 'string' then it = ItemStack(it) end
			if not it:is_empty() then
				local ent = core.add_item(jitter(pos), it)
				if ent ~= nil then -- avoid crash when dropping unknown item
					local dp = vector.new(0,0,0)
					if digger then dp = digger:get_pos() end
					local delta = dp - ent:get_pos()
					ent:add_velocity(vector.new(delta.x,0,delta.z));
				end
			end
		end
	end
end


	-- TODO timer iterates live UI

Modified mods/starlit/interfaces.lua from [7199aa7738] to [51ed588904].

1
2
3
4
5
6
7
8
9
10
11
12
..
37
38
39
40
41
42
43

44
45
46
47
48
49
50
...
503
504
505
506
507
508
509





510
511
512
513
514
515
516
517
local lib = starlit.mod.lib

function starlit.ui.setupForUser(user)
	local function cmode(mode)
		if user.actMode == mode then return {hue = 150, sat = 0, lum = .3} end
	end
	user.entity:set_inventory_formspec(starlit.ui.build {
		kind = 'vert', mode = 'sw';
		padding = .5, spacing = 0.1;
		{kind = 'hztl';
			{kind = 'contact', w=1.5,h=1.5, id = 'mode_nano',
				img='starlit-ui-icon-nano.png', close=true, color = cmode'nano'};
................................................................................
		if user.actMode == mode then
			user:actModeSet 'off'
		else
			user:actModeSet(mode)
		end
	end


	local modes = { nano = true, psi = false, weapon = true }
	for e,s in pairs(modes) do
		if fields['mode_' .. e] then
			if s and (user:naked() or user:getSuit():powerState() == 'off') then
				user:suitSound 'starlit-error'
			else
				setSuitMode(e)
................................................................................
				local suit = user:getSuit()
				local suitDef = suit:def()
				local chipW, chipH = listWrap(suitDef.slots.chips, 5)
				local batW, batH = listWrap(suitDef.slots.batteries, 5)
				local canW, canH = listWrap(suitDef.slots.canisters, 5)
				local suitMode = suit:powerState()
				local function modeColor(mode)





					if mode == suitMode then return {hue = 180, sat = 0, lum = .5} end
				end
				return starlit.ui.build {
					kind = 'vert', mode = 'sw';
					padding = 0.5, spacing = 0.1;
					{kind = 'hztl',
						{kind = 'img', desc='Batteries', img = 'starlit-item-battery.png', w=1,h=1};
						{kind = 'list', target = 'current_player', inv = 'starlit_suit_bat',




|







 







>







 







>
>
>
>
>
|







1
2
3
4
5
6
7
8
9
10
11
12
..
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
local lib = starlit.mod.lib

function starlit.ui.setupForUser(user)
	local function cmode(mode)
		if user.actMode == mode then return {hue = 290, sat = 0, lum = .1} end
	end
	user.entity:set_inventory_formspec(starlit.ui.build {
		kind = 'vert', mode = 'sw';
		padding = .5, spacing = 0.1;
		{kind = 'hztl';
			{kind = 'contact', w=1.5,h=1.5, id = 'mode_nano',
				img='starlit-ui-icon-nano.png', close=true, color = cmode'nano'};
................................................................................
		if user.actMode == mode then
			user:actModeSet 'off'
		else
			user:actModeSet(mode)
		end
	end

	-- disable suit modes if the suit is off or the user is naked
	local modes = { nano = true, psi = false, weapon = true }
	for e,s in pairs(modes) do
		if fields['mode_' .. e] then
			if s and (user:naked() or user:getSuit():powerState() == 'off') then
				user:suitSound 'starlit-error'
			else
				setSuitMode(e)
................................................................................
				local suit = user:getSuit()
				local suitDef = suit:def()
				local chipW, chipH = listWrap(suitDef.slots.chips, 5)
				local batW, batH = listWrap(suitDef.slots.batteries, 5)
				local canW, canH = listWrap(suitDef.slots.canisters, 5)
				local suitMode = suit:powerState()
				local function modeColor(mode)
					local c = {
						off = {hue = 0, sat = 0, lum = 0};
						powerSave = {hue = 60, sat = 0, lum = 0};
						on = {hue = 100, sat = 0, lum = 0};
					}
					if mode == suitMode then return c[mode] end
				end
				return starlit.ui.build {
					kind = 'vert', mode = 'sw';
					padding = 0.5, spacing = 0.1;
					{kind = 'hztl',
						{kind = 'img', desc='Batteries', img = 'starlit-item-battery.png', w=1,h=1};
						{kind = 'list', target = 'current_player', inv = 'starlit_suit_bat',

Added mods/starlit/psi.lua version [8b15304149].



>
1
local lib = starlit.mod.lib

Modified mods/starlit/suit.lua from [d40c92ebbb] to [0ecf5e03a5].

82
83
84
85
86
87
88

89
90
91
92
93
94
95
...
284
285
286
287
288
289
290



291
292
293
294
295
296
297
...
375
376
377
378
379
380
381

382
383
384
385
386
387
388
389
390
391
392

393
394
395
396
397
398
399
					user:suitSound('starlit-insert-snap')
				elseif list == 'starlit_suit_chips' then
					--user:suitSound('starlit-suit-chip-out')
				elseif list == 'starlit_suit_canisters' then
					user:suitSound('starlit-insert-snap')
				end
			end

		end;
		def = function(self)
			return self.item:get_definition()._starlit.suit
		end;
		--[[
		pullCanisters = function(self, inv)
			starlit.item.container.dropPrefix(inv, 'starlit_canister')
................................................................................
			};
			suit = def;
		};
	});
end)

local slotProps = {



	starlit_cfg = {
		itemClass = 'inv';
	};
	starlit_suit_bat = {
		suitSlot = true;
		powerLock = true;
		itemClass = 'dynamo';
................................................................................
	return true
end)

core.register_on_player_inventory_action(function(luser, act, inv, p)
	local user = starlit.activeUsers[luser:get_player_name()]
	local function slotChange(slot,a,item)
		local s = slotProps[slot]

		if slot == 'starlit_suit' then
			user:updateSuit()
			if user:naked() then
				starlit.type.suit.purgeInventories(user.entity)
				user.power.nano = {}
			end
		elseif s and s.suitSlot then
			local s = user:getSuit()
			s:onItemMove(user, slot, a, item)
			s:onReconfigure(user.entity:get_inventory())
			user:setSuit(s)

		else return end
		user:updateHUD()
	end

	if act == 'put' or act == 'take' then
		local item = p.stack
		slotChange(p.listname, act, item)







>







 







>
>
>







 







>








|
|
|
>







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
					user:suitSound('starlit-insert-snap')
				elseif list == 'starlit_suit_chips' then
					--user:suitSound('starlit-suit-chip-out')
				elseif list == 'starlit_suit_canisters' then
					user:suitSound('starlit-insert-snap')
				end
			end
			return true -- move allowed
		end;
		def = function(self)
			return self.item:get_definition()._starlit.suit
		end;
		--[[
		pullCanisters = function(self, inv)
			starlit.item.container.dropPrefix(inv, 'starlit_canister')
................................................................................
			};
			suit = def;
		};
	});
end)

local slotProps = {
-- 	main = {
-- 		free = true;
-- 	};
	starlit_cfg = {
		itemClass = 'inv';
	};
	starlit_suit_bat = {
		suitSlot = true;
		powerLock = true;
		itemClass = 'dynamo';
................................................................................
	return true
end)

core.register_on_player_inventory_action(function(luser, act, inv, p)
	local user = starlit.activeUsers[luser:get_player_name()]
	local function slotChange(slot,a,item)
		local s = slotProps[slot]
		local allow = true
		if slot == 'starlit_suit' then
			user:updateSuit()
			if user:naked() then
				starlit.type.suit.purgeInventories(user.entity)
				user.power.nano = {}
			end
		elseif s and s.suitSlot then
			local s = user:getSuit()
			if s:onItemMove(user, slot, a, item) then
				s:onReconfigure(user.entity:get_inventory())
				user:setSuit(s)
			else return end
		else return end
		user:updateHUD()
	end

	if act == 'put' or act == 'take' then
		local item = p.stack
		slotChange(p.listname, act, item)

Modified mods/starlit/user.lua from [1a0e392600] to [8da9d84fa1].

214
215
216
217
218
219
220
221


222
223
224
225
226
227
228
...
352
353
354
355
356
357
358






359
360
361
362
363
364

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
			return val, (val - min) / d
		end;

		---------------
		-- phenotype --
		---------------
		lookupSpecies = function(self)
			return starlit.world.species.lookup(self.persona.species, self.persona.speciesVariant)


		end;
		phenoTrait = function(self, trait, dflt)
-- 			local s,v = self:lookupSpecies()
-- 			return v.traits[trait] or s.traits[trait] or 0
			return self.pheno:trait(trait, dflt)
		end;
		damageModifier = function(self, kind, amt)
................................................................................
			local luser = self.entity
			local bar = {def = def}
			local img = lib.image 'starlit-ui-bar.png'
			local colorized = img
			if type(def.color) ~= 'function' then
				colorized = colorized:shift(def.color)
			end







			bar.id = luser:hud_add {
				type = 'statbar';
				position = def.pos;
				offset = def.ofs;
				name = def.name;

				text = colorized:render();
				text2 = img:tint{hue=0, sat=-1, lum = -0.5}:fade(0.5):render();
				number = def.size;
				item = def.size;
				direction = def.dir;
				alignment = def.align;
				size = {x=4,y=24};
			}
			bar.update = function()
				local sv, sf = def.stat(self, bar, def)
				luser:hud_change(bar.id, 'number', def.size * sf)
				if type(def.color) == 'function' then
					local clr = def.color(sv, luser, sv, sf)
					luser:hud_change(bar.id, 'text', img:tint(clr):render())
				end
			end
			return bar, {x=3 * def.size, y=16} -- x*2??? what
		end;
		createHUD = function(self)
			local function basicStat(statName)
				return function(user, bar)
					return self:effectiveStat(statName)
				end
			end







|
>
>







 







>
>
>
>
>
>






>


<







|





|







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
			return val, (val - min) / d
		end;

		---------------
		-- phenotype --
		---------------
		lookupSpecies = function(self)
			return starlit.world.species.lookup(
				self.persona.species,
				self.persona.speciesVariant)
		end;
		phenoTrait = function(self, trait, dflt)
-- 			local s,v = self:lookupSpecies()
-- 			return v.traits[trait] or s.traits[trait] or 0
			return self.pheno:trait(trait, dflt)
		end;
		damageModifier = function(self, kind, amt)
................................................................................
			local luser = self.entity
			local bar = {def = def}
			local img = lib.image 'starlit-ui-bar.png'
			local colorized = img
			if type(def.color) ~= 'function' then
				colorized = colorized:shift(def.color)
			end

			local function adjustNumber(n)
				-- produce a value that is realized as whole number
				-- of images, rather than half-images
				return math.floor(n/2)*2;
			end

			bar.id = luser:hud_add {
				type = 'statbar';
				position = def.pos;
				offset = def.ofs;
				name = def.name;
				number = adjustNumber(def.size);
				text = colorized:render();
				text2 = img:tint{hue=0, sat=-1, lum = -0.5}:fade(0.5):render();

				item = def.size;
				direction = def.dir;
				alignment = def.align;
				size = {x=4,y=24};
			}
			bar.update = function()
				local sv, sf = def.stat(self, bar, def)
				luser:hud_change(bar.id, 'number', adjustNumber(def.size * sf))
				if type(def.color) == 'function' then
					local clr = def.color(sv, luser, sv, sf)
					luser:hud_change(bar.id, 'text', img:tint(clr):render())
				end
			end
			return bar, {x=3 * def.size, y=16} -- x*3??? what
		end;
		createHUD = function(self)
			local function basicStat(statName)
				return function(user, bar)
					return self:effectiveStat(statName)
				end
			end

Modified starlit.ct from [f4a136801c] to [259abbd299].

146
147
148
149
150
151
152


153
154
155
156
157
158
159
160
161
162










































































163
164
165
166
** naturally diminishes, but very slowly
* [*illness]: not everything on Farthest Shadow's ecosystem is, shall we say, biocompatible. measured in percent
** affects [*morale]: the higher your illness, the more quickly you bleed morale

your primary stats are shown on your HUD. ancillary stats can be viewed in the "body" panel.

### psionics


there are four types of psionic abilities: Manual, Maneuver, Ritual, and Contextual.

you can assign two Manual abilities at any given time and access them with the mouse buttons in Psionics mode.

you can select a Psi Maneuver in the Psionics panel and activate it by holding [*Aux1].

a Ritual is triggered directly from the psionics menu. as the name implies, these are complex, powerful abilities that require large amounts of Psi and time to meditate before they trigger, and any interruption will cancel the ability (though it will not restore any lost psi). the most famous Ritual is of course Conjoin Metric, which Starlit astropaths use in conjunction with powerful amplifiers to perform long-distance FTL jumps -- but without centuries of dedication to the art, the best you can hope for if you manage to learn this storied power is to move yourself a few kilometers.

a Contextual ability is triggered in a specific situation, usually by interacting with a certain kind of object. Contextual abilities often require specialized equipment, to the point that many Starlit practitioners maintain their own Psionics Lab.











































































## legal
starlit source code (*.lua, *.conf, *.txt, *.csd files) is released under the GNU AGPLv3.
assets (images, sounds, models, and anything else in the repo that doesn't qualify as source code) are released under the CC-BY-NC-SA 3.0 license.
sound files with the prefix `default-` are taken from Luanti Game, whose assets are available under the CC-BY-SA 3.0 license.







>
>






|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
** naturally diminishes, but very slowly
* [*illness]: not everything on Farthest Shadow's ecosystem is, shall we say, biocompatible. measured in percent
** affects [*morale]: the higher your illness, the more quickly you bleed morale

your primary stats are shown on your HUD. ancillary stats can be viewed in the "body" panel.

### psionics
psionics draws from your reserve of numina to allow your spirit to directly affect the material world, or other spirits. numina accretes slowly, though high morale will speed this up.

there are four types of psionic abilities: Manual, Maneuver, Ritual, and Contextual.

you can assign two Manual abilities at any given time and access them with the mouse buttons in Psionics mode.

you can select a Psi Maneuver in the Psionics panel and activate it by holding [*Aux1].

a Ritual is triggered directly from the psionics menu. as the name implies, these are complex, powerful abilities that require large amounts of Psi and time to meditate before they trigger, and any interruption will cancel the ability (though it will not restore any lost psi). the most famous Ritual is of course Rift, which Starlit astropaths use in conjunction with powerful amplifiers to perform long-distance FTL jumps -- but without centuries of dedication to the art, the best you can hope for if you manage to learn this storied power is to move yourself a few kilometers.

a Contextual ability is triggered in a specific situation, usually by interacting with a certain kind of object. Contextual abilities often require specialized equipment, to the point that many Starlit practitioners maintain their own Psionics Lab.

at the beginning of the game, you start with the power "Cultivate", which is used to develop your psionic talents.

to gain new psionic abilities, invest numina by triggering the Cultivate power. gaining new powers requires much more numina than using them, so you'll want to be careful about how much power you expend. once you have invested enough numina in your psionic advancement, you will be given a list of up to three new powers to choose from. the specific powers are partially randomized, though some have additional prerequisites. the environment in which you meditate can affect which powers are offered; some powers can only be achieved in certain biomes or circumstances. make sure you have a secure location to meditate in, however, as any interruption will disrupt your meditation, wasting the invested numina.

you can also invest numina to strengthen a power you already possess. this can be done using the powers "Fortify" and "Advance". Fortify produces extremely strong temporary power boosts without affecting the base power cost; these wear off as you use the Fortified power. Advance permanently enhances the power in small increments, but the base power cost increases for every Advancement. note, however, that the further you Advance a power, the more efficient its use of numina becomes.

there is a maximum amount of numina that a spirit can hold onto. this is determined by your species and sex, with females generally having larger numina pools. if this becomes limiting, it is possible to stockpile numina through the use of numinium crystals, a sort of psychic battery. these are not cheap to build, however, and doing so requires a psi-forge.

a manual psionic power belongs to one of three categories:
* [*Currents]: a [*Current] is a modifier that can be toggled on or off. quale determine the effect produced by a Carrier; for instance, you can produce a healing shockwave centered on your character by activating [*Purify] and firing [*Pulse]. multiple currents can be active at a time, though this consumes proportionally further power.
* [*Carriers]: a [*Carrier] determines how the selected [*Currents] are expressed into the world, both in terms of targeting and efficiency. Advancing a Carrier  improves its efficiency, and where relevant, range.
* [*]: a [*] power can be expressed in only one way; its Carrier is indivisble from its Current.

psionic powers you can learn include, but are not limited to:

#### Carriers
* [*Infuse]: applies Current directly to the user. this is the most efficient of all effectors.
* [*Reach]: affect a single target on an ongoing basis. less efficient with distance, but almost as efficient as [*Infuse] when the target is right beside you.
* [*Pulse]: release a wave of psionic force, applying Current to everything in range except yourself. this is the least efficient power.
* [*Lance]: produces a narrow beam that delivers the full force of its Current to the first thing it hits. Lances are chargeable; you can invest an arbitrary amount of numina into the chosen Currents by holding the bound key for a time before releasing it. Lances travel further the stronger their charge.
* [*Torrent]: produces a wide beam that weakens the further it travels, but affects all in its path
* [*Tide]: like [*Torrent], but even less efficient; the width of the beam expands as it travels, making it useful for targeting groups of enemies.
* [*Vortex]: like Lance, but explodes when it hits its target, affecting everything in range of the blast.
* [*Pierce]: fire off homing orbs that track nearby targets and applies Current on impact. the more Pierce is charged, the more orbs will be launched, and the greater their efficiency will be.
* [*Arc]: affects the nearest target, then jumps to the target nearest them, and so on. the more powerful Arc becomes, the greater the jump range, branching factor, and maximum jump count.

#### Currents
* [*Shatter]: a powerful destructive force. useful for cutting open passageways quickly, and harming your enemies.
* [*Purify]: banish ailments affecting you or nearby players
* [*Nullify]: weaken or break active psionic powers nearby
* [*Confine]: temporarily block a psionic being from being able to use their powers. to break a confinement, they will have to an amount of numina proportional to what you invested into it; the more powerful this ability becomes, the greater the multiplier.
* [*Siphon]: drain health and stamina from a target
* [*Reave]: destroy some of your target's numina
* [*Lift]: produces antigravity. the specific effect depends on the Carrier. Lift is very useful in combination with other Currents, especially with [*Reach] carriers, as it can render foes helpless for the duration of the effect.
** a [*Lift Lance], [*Pulse], or [*Vortex] tosses targets high into the air
** a [*Lift Infusion] allows you to raise yourself into the air. this is not as flexible as true psionic flight, as it can only raise you upwards.
** a [*Lift Reach] allows telekinetic control of the target
** a [*Lift Torrent] or [*Tide] work like Reach, but can affect multiple targets. extremely useful when used alongside Repulse.
** [*Persisted] Lift currents can leave targets helplessly trapped until the Current runs out of power
* [*Repulse]: like Lift, but throws targets back instead of up
** a [*Repulsion Lance] throws a target back violently
** a [*Repulsion Pulse] flings everything away from you
** a [*Repulsion Infusion] works like a charged psionic jump, as opposed to the hover effect of [*Lift].
** a [*Repulsion Reach] charges an object with latent velocity, which is applied all at once when the effect is released
** a [*Repulsion Vortex] hurls its victims away from the point of detonation
** a [*Repulsion Torrent] or [*Tide] creates a powerful gale pushing targets back
* [*Draw]: pull things toward you. can be used to disarm enemies
* [*Reflect]: intercepts projectiles and causes them to ricochet or dissolve. this can only be used with certain Carriers:
** [*Reflect Pulse]: produces a protective dome
** [*Reflect Torrent]: produces a circular barrier in front of you
** [*Reflect Tide]: produces a broad barrier in front of you
* [*Inflict]: severely damages target morale and stamina; increases fatigue and illness. a sadistic technique devised by the Kuradoqše.
* [*Broil]: increases the target's body heat dramatically
* [*Lattice]: a meta-Current, causes effects to persist for a given amount of time, to, for instance, suspend an enemy in the air and keep them trapped there long enough to give you a head start, or apply a damage-over-time effect. Lattice Currents only have a small effect from moment to moment, but they are more efficient than momentane Currents. the more you charge a persisted effect, the longer it will last and the more efficient it will become.

####
* [*Blip]: short-range teleportation. can be used to break free of psionic holds

#### Rituals
* [*Cultivate]
* [*Fortify]
* [*Advance]
* [*Coalesce]: manifest a spiritual object in the physical world by condensing your numina into a matter matrix. this is how numinium is created.
* [*Rift]: teleport directly to a memorized location.
* [*Ward]: surround yourself with a psionic barrier that must be worn down before anything can affect you.
* [*Shard]: create psionic projectiles that orbit you until you are attached; the projectiles will then home in on the attacker and do significant damage.
* [*Meditate]: sacrifice numina to improve your morale

#### Manuvers
* [*Rush]: psionic sprint
* [*Soar]: psionic flight -- much faster than suit flight systems, but too power-hungry to use over long distances.
* [*Shift]: teleport randomly a short distance to evade incoming attacks.
* [*Shroud]: make yourself imperceptible

## legal
starlit source code (*.lua, *.conf, *.txt, *.csd files) is released under the GNU AGPLv3.
assets (images, sounds, models, and anything else in the repo that doesn't qualify as source code) are released under the CC-BY-NC-SA 3.0 license.
sound files with the prefix `default-` are taken from Luanti Game, whose assets are available under the CC-BY-SA 3.0 license.