starlit  Check-in [0e67c606c9]

Overview
Comment:fixes, sounds; add license info
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0e67c606c9587afd9971a06a609319ab118dd70b27b91adf54e06ca6fc648a8d
User & Date: lexi on 2024-05-01 16:25:38
Other Links: manifest | tags
Context
2024-05-02
00:22
plant growth, edibles, fixes check-in: e829ca194a user: lexi tags: trunk
2024-05-01
16:25
fixes, sounds; add license info check-in: 0e67c606c9 user: lexi tags: trunk
13:46
cleanups, fixes, begin canister rework, begin ecology check-in: a810a756ce user: lexi tags: trunk
Changes

Modified mods/starlit-electronics/sw.lua from [d777bc86b5] to [e776ef774d].

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
51
52
53
54
55
56
57

58
59
60
61
62
63
64
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
					}
					table.insert(items, st)
				else -- gas, liquid
					table.insert(charges, {id = k, mass = v})
				end
			end
		end
		print(dump(items))
		return items, charges
	end

	return function(user, ctx)
		local function cleanup()
			user.action.prog.shred = nil
			if user.action.sfx.shred then
................................................................................
			cleanup()
			return false
		end
		local shredTime = 1.0
		local soundPitch = 1.0 -- TODO
		local pdraw = prop.powerDraw or 0


		local node = minetest.get_node(what)
		local nd = minetest.registered_nodes[node.name]
		local elt, fab, vary
		if nd._starlit then
			fab = nd._starlit.recover or nd._starlit.fab
			vary = nd._starlit.recover_vary
		end
................................................................................
				})
				user.action.fx.shred = starlit.fx.nano.shred(user, what, prop, shredTime, node)
			else
				user.action.prog.shred = user.action.prog.shred + ctx.how.delta or 0
			end
			--print('shred progress: ', user.action.prog.shred)
			if user.action.prog.shred >= shredTime then
				if minetest.dig_node(what) then
					--print('shred complete')
					user:suitSound 'starlit-success'
					if fab then
						local vf = fab
						if vary then
							local rng = (starlit.world.seedbank+0xa891f62)[minetest.hash_node_position(what)]
							vf = vf + vary(rng, {})
						end
						local items, charges = fabToItemsAndCharges(vf)
						for i, it in ipairs(items) do user:give(it) end
						-- TODO give gasses, liquids
					end
				else
					user:suitSound 'starlit-error'
				end
				cleanup()
			end
		elseif ctx.how.state == 'halt' then
			cleanup()
		end
		return true







<







 







>







 







|
|
|
|
|
|
|
|
|
|
|
|
<
<
<







25
26
27
28
29
30
31

32
33
34
35
36
37
38
..
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116



117
118
119
120
121
122
123
					}
					table.insert(items, st)
				else -- gas, liquid
					table.insert(charges, {id = k, mass = v})
				end
			end
		end

		return items, charges
	end

	return function(user, ctx)
		local function cleanup()
			user.action.prog.shred = nil
			if user.action.sfx.shred then
................................................................................
			cleanup()
			return false
		end
		local shredTime = 1.0
		local soundPitch = 1.0 -- TODO
		local pdraw = prop.powerDraw or 0

		if minetest.is_protected(what, user.entity:get_player_name()) then return end
		local node = minetest.get_node(what)
		local nd = minetest.registered_nodes[node.name]
		local elt, fab, vary
		if nd._starlit then
			fab = nd._starlit.recover or nd._starlit.fab
			vary = nd._starlit.recover_vary
		end
................................................................................
				})
				user.action.fx.shred = starlit.fx.nano.shred(user, what, prop, shredTime, node)
			else
				user.action.prog.shred = user.action.prog.shred + ctx.how.delta or 0
			end
			--print('shred progress: ', user.action.prog.shred)
			if user.action.prog.shred >= shredTime then
				minetest.remove_node(what)
				--print('shred complete')
				user:suitSound 'starlit-success'
				if fab then
					local vf = fab
					if vary then
						local rng = (starlit.world.seedbank+0xa891f62)[minetest.hash_node_position(what)]
						vf = vf + vary(rng, {})
					end
					local items, charges = fabToItemsAndCharges(vf)
					for i, it in ipairs(items) do user:give(it) end
					-- TODO give gasses, liquids



				end
				cleanup()
			end
		elseif ctx.how.state == 'halt' then
			cleanup()
		end
		return true

Modified mods/starlit-scenario/init.lua from [2d3d2d3760] to [a141e7b70f].

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88


89
90
91
92
93
94
95
	end
	table.sort(sorted, function(a,b) return a.can.vol < b.can.vol end)

	local liq = starlit.world.material[kind].db[name]

	local can
	for i, v in ipairs(sorted) do
		if v.can.vol <= liq.density * mass then
			can = ItemStack(i)
			break
		end
	end
	if can == nil then log.fatal('failed to find canister size for gift %s', kind) end

	local st = starlit.item.canister.meta(can)
	st.write('contents', {kind = kind, id = name, mass = mass})



	return can
end


table.insert(scenario, {
	id = 'starlit_scenario:imperialExpat';
	name = 'Imperial Expat';







|
|





|
|
<
>
>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95
96
	end
	table.sort(sorted, function(a,b) return a.can.vol < b.can.vol end)

	local liq = starlit.world.material[kind].db[name]

	local can
	for i, v in ipairs(sorted) do
		if v.can.vol >= liq.density * mass then
			can = ItemStack(v.id)
			break
		end
	end
	if can == nil then log.fatal('failed to find canister size for gift %s', kind) end

-- 	print('mass = ',mass)
	starlit.item.canister.replace(can, {kind = kind, id = name, mass = mass})

-- 	print('content', dump(starlit.item.canister.contents(can)))
-- 	print("can", dump(can:get_meta():get_string 'starlit:canister_contents'))
	return can
end


table.insert(scenario, {
	id = 'starlit_scenario:imperialExpat';
	name = 'Imperial Expat';

Modified mods/starlit/element.lua from [e6ca28c621] to [4c0283cfa3].

171
172
173
174
175
176
177
178
179
180
181
182

183
184
185
186
187
188
189
...
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
...
246
247
248
249
250
251
252



























253
			};
		};
	});


end)

local function canisterMeta(stack)
	return lib.marshal.metaStore {
		contents = {key = 'starlit:canister_contents', type = starlit.store.volume};
	} (stack)
end


local function canisterDesc(stack, def)
	def = def or stack:get_definition()._starlit.canister
	local props = {
		{title = 'Volume', affinity = 'info', desc = lib.math.si('L', def.vol,nil,nil,2)};
	};
	if stack then
................................................................................
				desc = lib.math.si('g', e:get_count());
				affinity = 'good';
			})
		end ]]
		local itemMeta = canisterMeta(stack)
		local e = itemMeta.read 'contents'
		local mass = lib.math.si('g', e.mass, nil, nil, 2)
		local def, meas
		if e.kind == 'liquid' then
			def = M.liquid.db[e.id]
			local vol =  lib.math.si('L', e.mass * def.composition.density, nil, nil, 2)
			meas = string.format("%s %s (%s %s)", vol, def.name, e.mass, def.composition:formula())
		elseif e.kind == 'gas' then
			def = M.gas.db[e.id]
			meas = string.format("%s %s (%s)", mass, def.name, def.composition:formula())
		end
		local comp = def.composition
		table.insert(props, {
			title = meas;
			desc = def.desc;
			affinity = 'info';
		})
	end
	return starlit.ui.tooltip {
		title = def.name, desc = def.desc or 'A canister that can store a charge of gas or liquid';
		color = lib.color(0.2,0.1,0.1);
		props = props;
................................................................................
					};
				};
			};
		};
	})
end)




























starlit.item.canister.meta = canisterMeta







<
|
|
<
<
>







 







|

|
|
|

|
|




|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
171
172
173
174
175
176
177

178
179


180
181
182
183
184
185
186
187
...
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
...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
			};
		};
	});


end)


local canisterMeta = lib.marshal.metaStore {
	contents = {key = 'starlit:canister_contents', type = starlit.store.volume};


}

local function canisterDesc(stack, def)
	def = def or stack:get_definition()._starlit.canister
	local props = {
		{title = 'Volume', affinity = 'info', desc = lib.math.si('L', def.vol,nil,nil,2)};
	};
	if stack then
................................................................................
				desc = lib.math.si('g', e:get_count());
				affinity = 'good';
			})
		end ]]
		local itemMeta = canisterMeta(stack)
		local e = itemMeta.read 'contents'
		local mass = lib.math.si('g', e.mass, nil, nil, 2)
		local mdef, meas
		if e.kind == 'liquid' then
			mdef = M.liquid.db[e.id]
			local vol =  lib.math.si('L', e.mass * mdef.density, nil, nil, 2)
			meas = string.format("%s %s (%s %s)", vol, mdef.name, e.mass, mdef.composition:formula())
		elseif e.kind == 'gas' then
			mdef = M.gas.db[e.id]
			meas = string.format("%s %s (%s)", mass, mdef.name, mdef.composition:formula())
		end
		local comp = def.composition
		table.insert(props, {
			title = meas;
			desc = mdef.desc;
			affinity = 'info';
		})
	end
	return starlit.ui.tooltip {
		title = def.name, desc = def.desc or 'A canister that can store a charge of gas or liquid';
		color = lib.color(0.2,0.1,0.1);
		props = props;
................................................................................
					};
				};
			};
		};
	})
end)

function starlit.item.canister.contents(st)
	local m = canisterMeta(st)
	return m.read 'contents'
end

function starlit.item.canister.update(st)
	st:get_meta():set_string('description', canisterDesc(st))
end

function starlit.item.canister.replace(st, rec)
	local m = canisterMeta(st)
	m.write('contents', rec)
	starlit.item.canister.update(st)
end

function starlit.item.canister.empty(st, rec)
	local m = st:get_meta()
	m:set_string('starlit:canister_contents', '')
	m:set_string('description', '')
end

function starlit.item.canister.insert(st, rec)
	local m = canisterMeta(st)
	-- TODO
	starlit.item.canister.update(st)
end

-- starlit.item.canister.meta = canisterMeta

Modified mods/starlit/fab.lua from [9968a2e2d9] to [800ac068f1].

82
83
84
85
86
87
88

89
90
91
92
93
94
95
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
}

local order = {
	'element', 'metal', 'liquid', 'gas', 'item'
}

local lib = starlit.mod.lib

local fab fab = lib.class {
	__name = 'starlit:fab';
	
	opClass = opClass;
	strClass = strClass;
	order = order;
	construct = function(q) return q end;
................................................................................
			table.sort(el, function(a,b)
				return eldb[a].n > eldb[b].n
			end)
			return el, em, s
		end;

		formula = function(self)
			print('make formula', dump(self))
			local ts,f=0
			if self.element then
				f = {}
				local el, em, s = self:elementSeq()
				local eldb = starlit.world.material.element.db
				for i, e in ipairs(el) do
					local sym, n = eldb[e].sym, em[e]







>







 







<







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
...
115
116
117
118
119
120
121

122
123
124
125
126
127
128
}

local order = {
	'element', 'metal', 'liquid', 'gas', 'item'
}

local lib = starlit.mod.lib

local fab fab = lib.class {
	__name = 'starlit:fab';
	
	opClass = opClass;
	strClass = strClass;
	order = order;
	construct = function(q) return q end;
................................................................................
			table.sort(el, function(a,b)
				return eldb[a].n > eldb[b].n
			end)
			return el, em, s
		end;

		formula = function(self)

			local ts,f=0
			if self.element then
				f = {}
				local el, em, s = self:elementSeq()
				local eldb = starlit.world.material.element.db
				for i, e in ipairs(el) do
					local sym, n = eldb[e].sym, em[e]

Modified mods/starlit/init.lua from [6f8dfbcd79] to [c40c4aaae1].

347
348
349
350
351
352
353



354
355
356
357
358
359
360
...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381


382
383
384
385
386
387
388

local function pointChanged(a,b)
	return a.type ~= b.type
		or a.type == 'node'   and vector.new(a.under) ~= vector.new(b.under)
		or a.type == 'object' and a.ref ~= b.ref 
end
local function triggerPower(_, luser, point)



	local user = starlit.activeUsers[luser:get_player_name()]
	local oldTgt = user.action.tgt
	user.action.tgt = point
	if bit.band(user.action.bits, 0x100)==0 then
		user.action.bits = bit.bor(user.action.bits, 0x100)
		--return user:trigger('secondary', {state = 'prog', delta = 0})
	elseif pointChanged(oldTgt, point) then
................................................................................
	if not triggerPower(...) then
		minetest.item_place(...)
	end
end
core.noneitemdef_default.on_use           = function(...) triggerPower(...) end
core.noneitemdef_default.on_secondary_use = function(...) triggerPower(...) end
]]
print(dump(core.noneitemdef_default))
minetest.register_item(":", {
	type = "none",
	wield_image = "wieldhand.png",
	wield_scale = {x=1,y=1,z=2.5},
	on_secondary_use = function(...) triggerPower(...) end;
-- 	on_use = function(...) print'base' end;
	after_use = function(...) triggerPower(...) end;


})
minetest.register_item("starlit:_hand_dig", {
	type = "none",
	wield_image = "wieldhand.png",
	wield_scale = {x=1,y=1,z=2.5},
	tool_capabilities = {
		groupcaps = {







>
>
>







 







<






|
>
>







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
...
370
371
372
373
374
375
376

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392

local function pointChanged(a,b)
	return a.type ~= b.type
		or a.type == 'node'   and vector.new(a.under) ~= vector.new(b.under)
		or a.type == 'object' and a.ref ~= b.ref 
end
local function triggerPower(_, luser, point)
	for k,v in pairs(starlit.activeUsers) do
	print (k,v) end
	print("trigger", luser, luser:get_player_name())
	local user = starlit.activeUsers[luser:get_player_name()]
	local oldTgt = user.action.tgt
	user.action.tgt = point
	if bit.band(user.action.bits, 0x100)==0 then
		user.action.bits = bit.bor(user.action.bits, 0x100)
		--return user:trigger('secondary', {state = 'prog', delta = 0})
	elseif pointChanged(oldTgt, point) then
................................................................................
	if not triggerPower(...) then
		minetest.item_place(...)
	end
end
core.noneitemdef_default.on_use           = function(...) triggerPower(...) end
core.noneitemdef_default.on_secondary_use = function(...) triggerPower(...) end
]]

minetest.register_item(":", {
	type = "none",
	wield_image = "wieldhand.png",
	wield_scale = {x=1,y=1,z=2.5},
	on_secondary_use = function(...) triggerPower(...) end;
-- 	on_use = function(...) print'base' end;
	after_use = function(i,u,n,p)
		if (u:is_player()) then triggerPower(i,u,p) end
	end;
})
minetest.register_item("starlit:_hand_dig", {
	type = "none",
	wield_image = "wieldhand.png",
	wield_scale = {x=1,y=1,z=2.5},
	tool_capabilities = {
		groupcaps = {

Modified mods/starlit/interfaces.lua from [f0b5b90e43] to [5877ccf3fb].

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
						table.insert(pgm.file.body.conf, {key='disable',value='yes'})
					end
					-- update the chip *wince*
					pgm.fd:write(pgm.file)
					user.entity:get_inventory():set_stack('starlit_suit_chips',
					pgm.chipSlot, pgm.chip)
					user:reconfigureSuit()
					user:suitSound('starlit-configure')

				end
				return true, true
			end;
			render = function(state, user)
				local suit = user:getSuit()
				local swm







|







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
						table.insert(pgm.file.body.conf, {key='disable',value='yes'})
					end
					-- update the chip *wince*
					pgm.fd:write(pgm.file)
					user.entity:get_inventory():set_stack('starlit_suit_chips',
					pgm.chipSlot, pgm.chip)
					user:reconfigureSuit()
					user:suitSound 'starlit-configure'

				end
				return true, true
			end;
			render = function(state, user)
				local suit = user:getSuit()
				local swm

Modified mods/starlit/terrain.lua from [b5b4e3205a] to [43cb3c61b6].

1
2
3
4
5









6




7
8
9
10
11
12
13
..
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
local T = starlit.translator
local lib = starlit.mod.lib

starlit.terrain = {}
local soilSounds = {}









local grassSounds = {}





minetest.register_node('starlit:soil', {
	description = T 'Soil';
	tiles = {'default_dirt.png'};
	groups = {dirt = 1};
	drop = '';
	sounds = soilSounds;
................................................................................


minetest.register_node('starlit:sand', {
	description = T 'Sand';
	tiles = {'default_sand.png'};
	groups = {dirt = 1};
	drop = '';
	sounds = soilSounds;
	_starlit = {
		kind = 'block';
		fab = starlit.type.fab { element = { silicon = 25 } };
	};
})
minetest.register_craftitem('starlit:soil_clump', {
	short_description = T 'Soil';
................................................................................
	groups = {soil = 1};
	_starlit = {
		fab = starlit.type.fab { element = { carbon = 12 / 4 } };
	};
})

function starlit.terrain.createGrass(def)
	local function grassfst(i)
		local nextNode = def.name
		if i >= 0 then
			nextNode = nextNode .. '_walk_' .. tostring(i)
		end
		return {
			onWalk = function(pos)
				minetest.set_node_at(pos, def.name .. '_walk_2');
			end;
			onDecay = function(pos,delta)
				minetest.set_node_at(pos, nextNode);
			end;
			onDestroy = function(pos) end;
			fab = def.fab;
			recover = def.recover;
			recover_vary = def.recover_vary;
		};
	end
	local drop = {
		max_items = 4;
		items = {
			{
				items = {'starlit:soil'}, rarity = 2;
				tool_groups = { 'shovel', 'trowel' };
			};
................................................................................
				name = 'default_dirt.png^' .. def.img ..'_side.png';
				tileable_vertical = false;
			};
		};
		groups = {grass = 1, dirt = 1, sub_walk = 1};
		drop = '';
		sounds = grassSounds;
		_starlit = grassfst(2);
	})
	for i=2,0,-1 do
		local opacity = tostring((i/2.0) * 255)

		minetest.register_node(def.name, {
			description = def.desc;
			tiles = {
				def.img .. '.png^(default_footprint.png^[opacity:'..opacity..')';
				'default_dirt.png';
				{
					name = 'default_dirt.png^' .. def.img ..'_side.png';
					tileable_vertical = false;


				};
			};
			groups = {grass = 1, sub_walk = 1, sub_decay = 5};
			drop = '';
			_starlit = grassfst(i-1);
			sounds = grassSounds;
		})
	end
end


starlit.terrain.createGrass {
	name = 'starlit:greengraze';
	desc = T 'Greengraze';
	img = 'default_grass';




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







 







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|
<
<
<
<
<
|
<
<
<
<
<
<
>
>
|
<
<
<
<
<
|
<







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
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
..
54
55
56
57
58
59
60


















61
62
63
64
65
66
67
..
76
77
78
79
80
81
82
83





84






85
86
87





88

89
90
91
92
93
94
95
local T = starlit.translator
local lib = starlit.mod.lib

starlit.terrain = {}
local soilSounds = {
	footstep = 'default-dirt-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
}
local sandSounds = {
	footstep = 'default-sand-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
}
local grassSounds = {
	footstep = 'default-grass-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
}

minetest.register_node('starlit:soil', {
	description = T 'Soil';
	tiles = {'default_dirt.png'};
	groups = {dirt = 1};
	drop = '';
	sounds = soilSounds;
................................................................................


minetest.register_node('starlit:sand', {
	description = T 'Sand';
	tiles = {'default_sand.png'};
	groups = {dirt = 1};
	drop = '';
	sounds = sandSounds;
	_starlit = {
		kind = 'block';
		fab = starlit.type.fab { element = { silicon = 25 } };
	};
})
minetest.register_craftitem('starlit:soil_clump', {
	short_description = T 'Soil';
................................................................................
	groups = {soil = 1};
	_starlit = {
		fab = starlit.type.fab { element = { carbon = 12 / 4 } };
	};
})

function starlit.terrain.createGrass(def)


















	local drop = {
		max_items = 4;
		items = {
			{
				items = {'starlit:soil'}, rarity = 2;
				tool_groups = { 'shovel', 'trowel' };
			};
................................................................................
				name = 'default_dirt.png^' .. def.img ..'_side.png';
				tileable_vertical = false;
			};
		};
		groups = {grass = 1, dirt = 1, sub_walk = 1};
		drop = '';
		sounds = grassSounds;
		_starlit = {





			fab = def.fab;






			recover = def.recover;
			recover_vary = def.recover_vary;
		};





	})

end


starlit.terrain.createGrass {
	name = 'starlit:greengraze';
	desc = T 'Greengraze';
	img = 'default_grass';

Modified mods/starlit/user.lua from [43bf528964] to [a0e5424f99].

743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
		end;

		canInteract = function(self, with)
			return true; -- TODO
		end;

		trigger = function(self, which, how)
			--print('trigger', which, dump(how))
			local p
			local wld = self.entity:get_wielded_item()
			if which == 'maneuver' then
				p = self.power.maneuver
			elseif which == 'retarget' then
				self.action.prog = {}
			elseif wld and not wld:is_empty() then







<







743
744
745
746
747
748
749

750
751
752
753
754
755
756
		end;

		canInteract = function(self, with)
			return true; -- TODO
		end;

		trigger = function(self, which, how)

			local p
			local wld = self.entity:get_wielded_item()
			if which == 'maneuver' then
				p = self.power.maneuver
			elseif which == 'retarget' then
				self.action.prog = {}
			elseif wld and not wld:is_empty() then

Modified mods/starlit/world.lua from [d9bc181e37] to [c6867ae3a2].

103
104
105
106
107
108
109

110
111
112
113
114
115
116
117
118
119
120












121
122
123
124
125
126
127
128
129
130



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
	local function regStage(n, st)
		local base = {
			description = b.name;
			drawtype = "plantlike";
			tiles = { tostring(st.tex) };
			paramtype = "light";
			paramtype2 = "meshoptions";

			walkable = false;
			buildable_to = true;
			groups = {
				plant = 1;
				plant_grow = stageCt ~= n and 1 or 0;
			};
			drop = st.drop;
			_starlit = {
				plant = {
					id = id, stage = n;
				};












			};
		}
		if st.swap then
			base.node_dig_prediction = stageID(st.swap)
			function base.on_dig(pos, node, digger)
				node.name = stageID(st.swap)
				minetest.swap_node(pos, node)
				return true
			end
		end



		return base
	end
	for i, v in ipairs(b.stages) do
		local n = regStage(i, v)
		b.stageNodes[i] = n
		minetest.register_node(stageID(i), n)
	end
	b.fullyGrown = stageID(stageCt)

	local dec = {
		deco_type = 'simple';
		decoration = b.fullyGrown;
		height = 1;
		param2 = 0;
	}
	for k,v in pairs(b.decoration) do dec[k] = v end
	b.decoration = minetest.register_decoration(dec)
end)

local toward = lib.math.toward
local hfinterval = 1.5







>











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




|





>
>
>













|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
	local function regStage(n, st)
		local base = {
			description = b.name;
			drawtype = "plantlike";
			tiles = { tostring(st.tex) };
			paramtype = "light";
			paramtype2 = "meshoptions";
			place_param2 = b.meshOpt;
			walkable = false;
			buildable_to = true;
			groups = {
				plant = 1;
				plant_grow = stageCt ~= n and 1 or 0;
			};
			drop = st.drop;
			_starlit = {
				plant = {
					id = id, stage = n;
				};
				recover = starlit.type.fab {
					time = { shred = .3; };
					cost = { shredPower = 1; };
				};
				recover_vary = function(rng, ctx)
					return starlit.type.fab {
						element = {
							carbon    = rng:int(0,1);
							potassium = rng:int(0,1);
						}
					};
				end;
			};
		}
		if st.swap then
			base.node_dig_prediction = stageID(st.swap)
			function base.after_dig_node(pos, node, digger)
				node.name = stageID(st.swap)
				minetest.swap_node(pos, node)
				return true
			end
		end
		if st.biolum then
			base.light_source = math.floor(st.biolum * (n/stageCt))
		end
		return base
	end
	for i, v in ipairs(b.stages) do
		local n = regStage(i, v)
		b.stageNodes[i] = n
		minetest.register_node(stageID(i), n)
	end
	b.fullyGrown = stageID(stageCt)

	local dec = {
		deco_type = 'simple';
		decoration = b.fullyGrown;
		height = 1;
		param2 = b.meshOpt or 0;
	}
	for k,v in pairs(b.decoration) do dec[k] = v end
	b.decoration = minetest.register_decoration(dec)
end)

local toward = lib.math.toward
local hfinterval = 1.5

Modified mods/vtlib/marshal.lua from [670a4be42e] to [500f446f0a].

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
	return {
		sz = c.sz;
		name = string.format("%sfixed<%s,%s,%s>",
			sign and 's' or 'u',
			bits, base, prec
		);
		enc = function(v)
			return c.enc(v)
		end;
		dec = function(s)
			local v = c.dec(s)
			return v / mul
		end;
	}
end







|







254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
	return {
		sz = c.sz;
		name = string.format("%sfixed<%s,%s,%s>",
			sign and 's' or 'u',
			bits, base, prec
		);
		enc = function(v)
			return c.enc(v * mul)
		end;
		dec = function(s)
			local v = c.dec(s)
			return v / mul
		end;
	}
end

Modified mods/vtlib/math.lua from [988785061c] to [9f5dd95326].

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

		if math.abs(val) > 1 then
			if uncommonScales or cmaj then
				local denom = 10^amt
				local vd = val/denom
				if prec then vd = lib.math.trim(vd, prec) end
				if math.abs(val) >= (10^(amt)) then
					return string.format("%s %s%s",
						vd, (full and pmaj or smaj), unit)
				end
			end
		elseif math.abs(val) < 1 then
			if uncommonScales or cmin then
				local denom = 10^-amt
				local vd = val/denom
				if prec then vd = lib.math.trim(vd, prec) end
				if math.abs(val) <= (10^-(amt-1)) then
					return string.format("%s %s%s",
						vd, (full and pmin or smin), unit)
				end
			end
		end
	end

	return string.format("%s %s", val, unit)
end

function fn.lerp(t, a, b) return (1-t)*a + t*b end

function fn.trim(fl, prec)
	local fac = 10^prec
	return math.floor(fl * fac) / fac







|
|








|
|





|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

		if math.abs(val) > 1 then
			if uncommonScales or cmaj then
				local denom = 10^amt
				local vd = val/denom
				if prec then vd = lib.math.trim(vd, prec) end
				if math.abs(val) >= (10^(amt)) then
					return string.format("%s%s%s",
						vd, (full and (' ' .. pmaj) or smaj), unit)
				end
			end
		elseif math.abs(val) < 1 then
			if uncommonScales or cmin then
				local denom = 10^-amt
				local vd = val/denom
				if prec then vd = lib.math.trim(vd, prec) end
				if math.abs(val) <= (10^-(amt-1)) then
					return string.format("%s%s%s",
						vd, (full and (' ' .. pmin) or smin), unit)
				end
			end
		end
	end

	return string.format("%s%s", val, unit)
end

function fn.lerp(t, a, b) return (1-t)*a + t*b end

function fn.trim(fl, prec)
	local fac = 10^prec
	return math.floor(fl * fac) / fac

Modified starlit.ct from [5320fb7a47] to [3827ce4fcb].

72
73
74
75
76
77
78





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.












>
>
>
>
>
72
73
74
75
76
77
78
79
80
81
82
83
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 Minetest Game, whose assets are available under the CC-BY-SA 3.0 license.