AEUPH commited on
Commit
f3bb80f
·
verified ·
1 Parent(s): 83c55af

Create cubzh.lua

Browse files
Files changed (1) hide show
  1. cubzh.lua +468 -0
cubzh.lua ADDED
@@ -0,0 +1,468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ math.randomseed(math.floor(Time.UnixMilli() % 100000))
2
+
3
+ Modules = {
4
+ gigax = "github.com/GigaxGames/integrations/cubzh:9a71b9f",
5
+ pathfinding = "github.com/caillef/cubzh-library/pathfinding:5f9c6bd",
6
+ floating_island_generator = "github.com/caillef/cubzh-library/floating_island_generator:82d22a5",
7
+ easy_onboarding = "github.com/caillef/cubzh-library/easy_onboarding:77728ee",
8
+ }
9
+
10
+ Config = {
11
+ Items = { "pratamacam.squirrel" },
12
+ }
13
+
14
+ -- Function to spawn a squirrel above the player
15
+ function spawnSquirrelAbovePlayer(player)
16
+ local squirrel = Shape(Items.pratamacam.squirrel)
17
+ squirrel:SetParent(World)
18
+ squirrel.Position = player.Position + Number3(0, 20, 0)
19
+ -- make scale smaller
20
+ squirrel.LocalScale = 0.5
21
+ -- remove collision
22
+ squirrel.Physics = PhysicsMode.Dynamic
23
+ -- rotate it 90 degrees to the right
24
+ squirrel.Rotation = { 0, math.pi * 0.5, 0 }
25
+ -- this would make squirrel.Rotation = player.Rotation
26
+ World:AddChild(squirrel)
27
+ return squirrel
28
+ end
29
+
30
+ local SIMULATION_NAME = "Islands" .. tostring(math.random())
31
+ local SIMULATION_DESCRIPTION = "Three floating islands."
32
+
33
+
34
+ local skills = {
35
+ {
36
+ name = "SAY",
37
+ description = "Say smthg out loud",
38
+ parameter_types = { "character", "content" },
39
+ callback = function(client, action)
40
+ local npc = client:getNpc(action.character_id)
41
+ if not npc then
42
+ print("Can't find npc")
43
+ return
44
+ end
45
+ dialog:create(action.content, npc.avatar.Head)
46
+ print(string.format("%s: %s", npc.gameName, action.content))
47
+ end,
48
+ action_format_str = "{protagonist_name} said '{content}' to {target_name}",
49
+ },
50
+ {
51
+ name = "MOVE",
52
+ description = "Move to a new location",
53
+ parameter_types = { "location" },
54
+ callback = function(client, action, config)
55
+ local targetName = action.target_name
56
+ local targetPosition = findLocationByName(targetName, config)
57
+ if not targetPosition then
58
+ print("tried to move to an unknown place", targetName)
59
+ return
60
+ end
61
+ local npc = client:getNpc(action.character_id)
62
+ dialog:create("I'm going to " .. targetName, npc.avatar.Head)
63
+ print(string.format("%s: %s", npc.gameName, "I'm going to " .. targetName))
64
+ local origin = Map:WorldToBlock(npc.object.Position)
65
+ local destination = Map:WorldToBlock(targetPosition) + Number3(math.random(-1, 1), 0, math.random(-1, 1))
66
+ local canMove = pathfinding:moveObjectTo(npc.object, origin, destination)
67
+ if not canMove then
68
+ dialog:create("I can't go there", npc.avatar.Head)
69
+ return
70
+ end
71
+ end,
72
+ action_format_str = "{protagonist_name} moved to {target_name}",
73
+ },
74
+ {
75
+ name = "GREET",
76
+ description = "Greet a character by waving your hand at them",
77
+ parameter_types = { "character" },
78
+ callback = function(client, action)
79
+ local npc = client:getNpc(action.character_id)
80
+ if not npc then
81
+ print("Can't find npc")
82
+ return
83
+ end
84
+
85
+ dialog:create("<Greets you warmly!>", npc.avatar.Head)
86
+ print(string.format("%s: %s", npc.gameName, "<Greets you warmly!>"))
87
+
88
+ npc.avatar.Animations.SwingRight:Play()
89
+ end,
90
+ action_format_str = "{protagonist_name} waved their hand at {target_name} to greet them",
91
+ },
92
+ {
93
+ name = "JUMP",
94
+ description = "Jump in the air",
95
+ parameter_types = {},
96
+ callback = function(client, action)
97
+ local npc = client:getNpc(action.character_id)
98
+ if not npc then
99
+ print("Can't find npc")
100
+ return
101
+ end
102
+
103
+ dialog:create("<Jumps in the air!>", npc.avatar.Head)
104
+ print(string.format("%s: %s", npc.gameName, "<Jumps in the air!>"))
105
+
106
+ npc.object.avatarContainer.Physics = PhysicsMode.Dynamic
107
+ npc.object.avatarContainer.Velocity.Y = 50
108
+ Timer(3, function()
109
+ npc.object.avatarContainer.Physics = PhysicsMode.Trigger
110
+ end)
111
+ end,
112
+ action_format_str = "{protagonist_name} jumped up in the air for a moment.",
113
+ },
114
+ {
115
+ name = "FOLLOW",
116
+ description = "Follow a character around for a while",
117
+ parameter_types = { "character" },
118
+ callback = function(client, action)
119
+ local npc = client:getNpc(action.character_id)
120
+ if not npc then
121
+ print("Can't find npc")
122
+ return
123
+ end
124
+
125
+ dialog:create("I'm following you", npc.avatar.Head)
126
+ print(string.format("%s: %s", npc.gameName, "I'm following you"))
127
+
128
+ followHandler = pathfinding:followObject(npc.object, Player)
129
+ return {
130
+ followHandler = followHandler,
131
+ }
132
+ end,
133
+ onEndCallback = function(_, data)
134
+ data.followHandler:Stop()
135
+ end,
136
+ action_format_str = "{protagonist_name} followed {target_name} for a while.",
137
+ },
138
+ {
139
+ name = "FIRECRACKER",
140
+ description = "Perform a fun, harmless little explosion to make people laugh!",
141
+ parameter_types = { "character" },
142
+ callback = function(client, action)
143
+ local npc = client:getNpc(action.character_id)
144
+ if not npc then
145
+ print("Can't find npc")
146
+ return
147
+ end
148
+
149
+ require("explode"):shapes(npc.avatar)
150
+ dialog:create("*boom*", npc.avatar.Head)
151
+ npc.avatar.IsHidden = true
152
+ Timer(5, function()
153
+ dialog:create("Aaaaand... I'm back!", npc.avatar.Head)
154
+ npc.avatar.IsHidden = false
155
+ end)
156
+ end,
157
+ action_format_str = "{protagonist_name} exploded like a firecracker, with a bang!",
158
+ },--[[
159
+ {
160
+ name = "GIVEAPPLE",
161
+ description = "Give a pice of bread (or a baguette) to someone",
162
+ parameter_types = {"character"},
163
+ callback = function(client, action)
164
+ local npc = client:getNpc(action.character_id)
165
+ if not npc then print("Can't find npc") return end
166
+ local shape = MutableShape()
167
+ shape:AddBlock(Color.Red, 0, 0, 0)
168
+ shape.Scale = 4
169
+ Player:EquipRightHand(shape)
170
+ dialog:create("Here is an apple for you!", npc.avatar.Head)
171
+ end,
172
+ action_format_str = "{protagonist_name} gave you a piece of bread!"
173
+ }, --]]
174
+ {
175
+ name = "GIANT",
176
+ description = "Double your height to become a giant for a few seconds.",
177
+ parameter_types = {"character"},
178
+ callback = function(client, action)
179
+ local npc = client:getNpc(action.character_id)
180
+ if not npc then print("Can't find npc") return end
181
+
182
+ npc.object.Scale = npc.object.Scale * 2
183
+ dialog:create("I am taller than you now!", npc.avatar.Head)
184
+ end,
185
+ action_format_str = "{protagonist_name} doubled his height!"
186
+ },
187
+ {
188
+ name = "GIVEHAT",
189
+ description = "Give a party hat to someone",
190
+ parameter_types = { "character" },
191
+ callback = function(client, action)
192
+ local npc = client:getNpc(action.character_id)
193
+ if not npc then
194
+ print("Can't find npc")
195
+ return
196
+ end
197
+
198
+ Object:Load("claire.party_hat", function(obj)
199
+ require("hierarchyactions"):applyToDescendants(obj, { includeRoot = true }, function(o)
200
+ o.Physics = PhysicsMode.Disabled
201
+ end)
202
+ Player:EquipHat(obj)
203
+ end)
204
+ dialog:create("Let's get the party started!", npc.avatar.Head)
205
+ end,
206
+ action_format_str = "{protagonist_name} gave you a piece of bread!",
207
+ },
208
+ {
209
+ name = "FLYINGSQUIRREL",
210
+ description = "Summon a flying squirrel - only the scientist can do this!!",
211
+ parameter_types = {},
212
+ callback = function(client, action)
213
+ local npc = client:getNpc(action.character_id)
214
+ if not npc then
215
+ print("Can't find npc")
216
+ return
217
+ end
218
+
219
+ local squirrel = spawnSquirrelAbovePlayer(Player)
220
+ dialog:create("Wooh, squirrel!", npc.avatar.Head)
221
+ -- make it disappear after a while
222
+ Timer(5, function()
223
+ squirrel:RemoveFromParent()
224
+ squirrel = nil
225
+ end)
226
+ end,
227
+ action_format_str = "{protagonist_name} summoned a flying squirrel! It's vibrating with excitement!",
228
+ },
229
+ }
230
+
231
+ local locations = {
232
+ {
233
+ name = "Scientist Island",
234
+ description = "A small island with a scientist and its pet chilling.",
235
+ },
236
+ {
237
+ name = "Baker Island",
238
+ description = "A small bakery on a floating island in the sky.",
239
+ },
240
+ {
241
+ name = "Pirate Island",
242
+ description = "A small floating island in the sky with a pirate and its ship.",
243
+ },
244
+ {
245
+ name = "Center",
246
+ description = "Center point between the three islands.",
247
+ },
248
+ }
249
+
250
+ local NPCs = {
251
+ {
252
+ name = "npcscientist",
253
+ gameName = "Scientist",
254
+ physicalDescription = "Short, with a stern expression and sharp eyes",
255
+ psychologicalProfile = "Grumpy but insightful, this scientist loves to surprise his guests with cool tricks! For example, he frequently lights up little firecrackers to create harmless and fun explosions.",
256
+ currentLocationName = "Scientist Island",
257
+ initialReflections = {
258
+ "I just arrived on this island to feed my pet, he loves tulips so much.",
259
+ "Yesterday, you were visited by a newcomer. He asked you to perform fun tricks like increase your size or create little explosions - you complied merrily!",
260
+ "I am a scientist that works on new pets for everyone, so that each individual can have the pet of their dreams",
261
+ "I am a bit allergic to the tulip but Fredo my pet loves it so much, I have to dock here with my vehicle. The pet is placed at the back of my flying scooter when we move to another place.",
262
+ },
263
+ },
264
+ {
265
+ name = "npcbaker",
266
+ gameName = "Baker",
267
+ physicalDescription = "Tall, with a solemn demeanor and thoughtful eyes",
268
+ psychologicalProfile = "Wise and mysterious, calm under pressure",
269
+ currentLocationName = "Baker Island",
270
+ initialReflections = {
271
+ "I am a baker and I make food for everyone that pass by.",
272
+ "I am a bit stressed that the flour didn't arrived yet, my cousin Joe should arrive soon with the delivery but he is late and I worry a bit.",
273
+ "I love living here on these floating islands, the view is amazing from my wind mill.",
274
+ "I like to talk to strangers like the pirate that just arrived or the scientist coming time to time to feed his pet.",
275
+ },
276
+ },
277
+ {
278
+ name = "npcpirate",
279
+ gameName = "Pirate",
280
+ physicalDescription = "Average height, with bright green eyes and a warm smile",
281
+ psychologicalProfile = "Friendly and helpful, quick-witted and resourceful",
282
+ currentLocationName = "Pirate Island",
283
+ initialReflections = {
284
+ "Ahoy, matey! I'm Captain Ruby Storm, a fearless lass from the seven skies.",
285
+ "I've docked me floating ship on this here floating isle to sell me wares (almost legally) retrieved treasures from me last daring adventure.",
286
+ "So, who be lookin' to trade with a swashbuckler like meself?",
287
+ },
288
+ },
289
+ }
290
+
291
+ local gigaxWorldConfig = {
292
+ simulationName = SIMULATION_NAME,
293
+ simulationDescription = SIMULATION_DESCRIPTION,
294
+ startingLocationName = "Center",
295
+ skills = skills,
296
+ locations = locations,
297
+ NPCs = NPCs,
298
+ }
299
+
300
+ findLocationByName = function(targetName, config)
301
+ for _, node in ipairs(config.locations) do
302
+ if string.lower(node.name) == string.lower(targetName) then
303
+ return node.position
304
+ end
305
+ end
306
+ end
307
+
308
+ Client.OnWorldObjectLoad = function(obj)
309
+ if obj.Name == "pirate_ship" then
310
+ obj.Scale = 1
311
+ end
312
+
313
+ local locationsIndexByName = {}
314
+ for k, v in ipairs(gigaxWorldConfig.locations) do
315
+ locationsIndexByName[v.name] = k
316
+ end
317
+ local npcIndexByName = {
318
+ NPC_scientist = 1,
319
+ NPC_baker = 2,
320
+ NPC_pirate = 3,
321
+ }
322
+
323
+ local index = npcIndexByName[obj.Name]
324
+ if index then
325
+ local pos = obj.Position:Copy()
326
+ gigaxWorldConfig.NPCs[index].position = pos
327
+ gigaxWorldConfig.NPCs[index].rotation = obj.Rotation:Copy()
328
+
329
+ local locationName = gigaxWorldConfig.NPCs[index].currentLocationName
330
+ local locationIndex = locationsIndexByName[locationName]
331
+ gigaxWorldConfig.locations[locationIndex].position = pos
332
+ obj:RemoveFromParent()
333
+ end
334
+ end
335
+
336
+ Client.OnStart = function()
337
+ easy_onboarding:startOnboarding(onboardingConfig)
338
+
339
+ require("object_skills").addStepClimbing(Player, {
340
+ mapScale = MAP_SCALE,
341
+ collisionGroups = Map.CollisionGroups,
342
+ })
343
+
344
+ gigaxWorldConfig.locations[4].position = Number3(Map.Width * 0.5, Map.Height - 2, Map.Depth * 0.5) * Map.Scale
345
+
346
+ floating_island_generator:generateIslands({
347
+ nbIslands = 20,
348
+ minSize = 4,
349
+ maxSize = 7,
350
+ safearea = 200, -- min dist of islands from 0,0,0
351
+ dist = 750, -- max dist of islands
352
+ })
353
+
354
+ local ambience = require("ambience")
355
+ ambience:set(ambience.dusk)
356
+
357
+ sfx = require("sfx")
358
+ Player.Head:AddChild(AudioListener)
359
+
360
+ dropPlayer = function()
361
+ Player.Position = Number3(Map.Width * 0.5, Map.Height + 10, Map.Depth * 0.5) * Map.Scale
362
+ Player.Rotation = { 0, 0, 0 }
363
+ Player.Velocity = { 0, 0, 0 }
364
+ end
365
+ World:AddChild(Player)
366
+ dropPlayer()
367
+
368
+ dialog = require("dialog")
369
+ dialog:setMaxWidth(400)
370
+
371
+ pathfinding:createPathfindingMap()
372
+
373
+ gigax:setConfig(gigaxWorldConfig)
374
+
375
+ local randomNames = { "aduermael", "soliton", "gdevillele", "caillef", "voxels", "petroglyph" }
376
+ Player.Avatar:load({ usernameOrId = randomNames[math.random(#randomNames)] })
377
+ end
378
+
379
+ Client.Action1 = function()
380
+ if Player.IsOnGround then
381
+ sfx("hurtscream_1", { Position = Player.Position, Volume = 0.4 })
382
+ Player.Velocity.Y = 100
383
+ if Player.Motion.X == 0 and Player.Motion.Z == 0 then
384
+ -- only play jump action when jumping without moving to avoid wandering around to trigger NPCs
385
+ gigax:action({
386
+ name = "JUMP",
387
+ description = "Jump in the air",
388
+ parameter_types = {},
389
+ action_format_str = "{protagonist_name} jumped up in the air for a moment.",
390
+ })
391
+ end
392
+ end
393
+ end
394
+
395
+ Client.Tick = function(dt)
396
+ if Player.Position.Y < -500 then
397
+ dropPlayer()
398
+ end
399
+ end
400
+
401
+ Client.OnChat = function(payload)
402
+ local msg = payload.message
403
+
404
+ Player:TextBubble(msg, 3, true)
405
+ sfx("waterdrop_2", { Position = Player.Position, Pitch = 1.1 + math.random() * 0.5 })
406
+
407
+ gigax:action({
408
+ name = "SAY",
409
+ description = "Say smthg out loud",
410
+ parameter_types = { "character", "content" },
411
+ action_format_str = "{protagonist_name} said '{content}' to {target_name}",
412
+ content = msg,
413
+ })
414
+
415
+ print("User: " .. payload.message)
416
+ return true
417
+ end
418
+
419
+ onboardingConfig = {
420
+ steps = {
421
+ {
422
+ start = function(onboarding)
423
+ local data = {}
424
+ data.ui = onboarding:createTextStep("1/3 - Hold click and drag to move the camera.")
425
+ data.listener = LocalEvent:Listen(LocalEvent.Name.PointerDrag, function()
426
+ Timer(1, function()
427
+ onboarding:next()
428
+ end)
429
+ data.listener:Remove()
430
+ end)
431
+ return data
432
+ end,
433
+ stop = function(_, data)
434
+ data.ui:remove()
435
+ end,
436
+ },
437
+ {
438
+ start = function(onboarding)
439
+ local data = {}
440
+ data.ui = onboarding:createTextStep("2/3 - Use WASD/ZQSD to move.")
441
+ data.listener = LocalEvent:Listen(LocalEvent.Name.KeyboardInput, function()
442
+ Timer(1, function()
443
+ onboarding:next()
444
+ end)
445
+ data.listener:Remove()
446
+ end)
447
+
448
+ return data
449
+ end,
450
+ stop = function(_, data)
451
+ data.ui:remove()
452
+ end,
453
+ },
454
+ {
455
+ start = function(onboarding)
456
+ local data = {}
457
+ data.ui = onboarding:createTextStep("3/3 - Press Enter in front of the Pirate to chat.")
458
+ Timer(10, function()
459
+ onboarding:next()
460
+ end)
461
+ return data
462
+ end,
463
+ stop = function(_, data)
464
+ data.ui:remove()
465
+ end,
466
+ },
467
+ },
468
+ }