81 Commits
v0.1 ... master

Author SHA1 Message Date
cf0df54548 Update map assets references in project.json
Because BASE Editor is reusing binary deserializer for JSON serializer,
the map assets 'source' property in project.json points to binary files
with ".dat" extension. It does not impact on how the editor works
because the asset sources are recreated when importing using UIDs, so
just to be consistent all the .json file references were replaced with
the .dat ones.
2025-07-11 15:06:08 +02:00
e8cc766ded Improve support for Nix dev shell 2025-07-11 14:41:10 +02:00
2e4459b92c Change initial world time 2025-07-11 14:30:14 +02:00
d66aabd58a Use BASE editor CLI interface to build app seamlessly 2025-07-11 10:09:47 +02:00
1e8ff04930 Improve Nix derivation 2025-07-10 15:12:16 +02:00
8edbc48ff1 Migrate Nix shell config to Flake 2023-12-09 22:34:56 +01:00
9d42bb8ee3 Enable BASE on NixOS platform 2023-12-07 22:48:42 +01:00
d08ba8eb5a Fix missing Forrest tileset 2023-11-16 14:17:59 +01:00
990ad6519e Improve the game start with some simple Grandma dialog 2023-11-16 14:17:59 +01:00
0be7b2fa43 Remove non-existing assets from project.json 2023-11-16 11:11:40 +01:00
356f792523 Implement day-night cycle | put some lights to the maps 2023-11-07 19:27:15 +01:00
e9ee8f7541 Migrate to new JSON format 2023-11-04 14:46:58 +01:00
eaa5f5d547 Implement some sample dialogs | apply BASE engine updates 2023-11-02 16:02:03 +01:00
3b99bc561a Apply BASE new MapLabels feature 2023-11-01 16:59:50 +01:00
f74548713d Apply BASE editor's SQL database format 2023-10-27 13:54:51 +02:00
898582fdb1 Apply BASE attribute methods improvements 2022-11-23 16:31:19 +01:00
6fefa32c7d Create new Forrest map 2022-09-06 15:37:00 +02:00
1d5afb0530 Add support for throwing weapon 2022-09-03 00:12:26 +02:00
a8f4679ee6 Extract game start point configuration to database 2022-09-02 22:25:28 +02:00
4357c631be Remove FPS profiler from DemoRunner 2022-09-02 22:14:25 +02:00
c967562498 Improve enemy loot generation 2022-09-02 22:10:44 +02:00
181061eb64 Enable displaying the FPS graph in HUD 2022-09-02 01:16:15 +02:00
f5790df5aa Fix HUD positioning issue 2022-09-01 15:08:35 +02:00
b051f20bd7 Add "Equipment" button to Game Menu 2022-09-01 13:33:47 +02:00
796c0ec9b0 Improve "New game" action after game over 2022-09-01 13:30:30 +02:00
25c9abd427 Use BASE API utility MapObject class 2022-09-01 11:38:17 +02:00
6678c352bb Improve MapObject to support CompletableFuture actions 2022-09-01 00:02:11 +02:00
5d9c7e6de2 Fix Escape key handling 2022-08-31 23:54:46 +02:00
8c4d114dad Simplify input handler 2022-08-31 23:54:46 +02:00
9bf75a8458 Replace Context's globals with DemoRunner field references 2022-08-31 23:54:46 +02:00
bf19c7bcf4 Add basic support for creature dialogs 2022-08-31 11:59:06 +02:00
3cdec6b303 Refactor MenuManager to GuiManager 2022-08-31 11:57:16 +02:00
fd5610fca0 Refactor stackable items codebase 2022-08-31 11:55:45 +02:00
92c2f3347a Increase player equipment size to 6x6 2022-08-31 01:05:56 +02:00
9ff0d6c99d Enable disarming already armed equipment 2022-08-31 01:01:04 +02:00
76264407f4 Add support for medicaments 2022-08-30 22:49:48 +02:00
5cf94454cf Import some assets and create maps in new format 2022-08-30 21:22:32 +02:00
c86f042cf8 Apply BASE API improvements 2022-08-30 19:14:33 +02:00
18883b66c2 Apply new map binary format | remove old maps 2022-08-26 17:31:50 +02:00
7d909d1d52 Create junk items 2022-08-26 12:23:22 +02:00
3eceb93559 Add support for chests 2022-08-26 11:29:14 +02:00
9ccd509b19 Add support for enemies' loot 2022-08-26 10:46:13 +02:00
dadb48e6d6 Add ammo to enemies 2022-08-25 23:27:49 +02:00
fe828f9026 Add basic support for ammo 2022-08-25 21:52:50 +02:00
1a96932bca Create basic scaffolding for stackable items 2022-08-25 20:46:28 +02:00
2c1fc56a5f Improve equipment window 2022-08-25 20:05:15 +02:00
a8a12a022a Apply BASE Widgets' attributes engine improvement 2022-08-25 19:58:40 +02:00
e366f85de1 Enable collecting items from map to equipment 2022-08-25 13:59:22 +02:00
8946297bd9 Perform general code cleaning & refactoring 2022-08-25 12:27:24 +02:00
4f7c6c6dc3 Create PoC of Equipment window 2022-08-25 12:24:06 +02:00
b157d7bf26 Add icons for weapons 2022-08-24 23:14:21 +02:00
60acb5749d Refactor some code and create new Forrest map 2022-08-23 23:21:50 +02:00
a6c0eebba2 Create some test icons 2022-08-23 16:07:25 +02:00
329e8a18c5 Update characters' speed 2022-08-23 14:54:01 +02:00
933608b753 Apply BASE engine refactor 2022-08-23 00:25:17 +02:00
1253139bfe Apply BASE engine improvemenst #2 2022-08-22 17:58:23 +02:00
d51a425b28 Apply BASE engine improvements 2022-08-22 11:52:52 +02:00
ccd3e44130 Enable automatically picking proper weapon for enemies and update codebase to latest BASE engine 2022-08-19 14:38:10 +02:00
9124f5c58a Add support for enemies' friendly fire 2022-08-19 12:26:40 +02:00
7b778845ba Add support for enemy spawners 2022-08-19 11:33:13 +02:00
f98806f2f9 Improve HUD log and debug functions 2022-08-19 11:32:35 +02:00
0f365410b0 Create common AI strategy which supports all weapon types 2022-08-18 23:01:05 +02:00
1e3e2e6abb Add some new entities 2022-08-18 22:40:48 +02:00
1e4a9a02c9 Add support for archer AI 2022-08-18 22:39:58 +02:00
0bfe53cd8e Add support for map objects 2022-08-18 18:59:31 +02:00
bf04597af6 Use autogenerated DAOs 2022-08-18 18:57:32 +02:00
ffdc9e930a Improve ranged weapons and use dice rolls to determine range and HP 2022-08-18 15:01:31 +02:00
b4f385db5c Apply BASE engine improvements 2022-08-18 14:55:01 +02:00
dd7a4bf304 Add some new entities 2022-08-18 12:05:17 +02:00
e28667c14e Add support for animal AI 2022-08-18 12:02:01 +02:00
2bd9d077cc Create bar with player HP 2022-08-18 10:23:12 +02:00
a2d95855c5 Create action log panel in HUD 2022-08-18 09:44:40 +02:00
ad30a8dcf5 Create simple HUD with debug data 2022-08-17 23:50:44 +02:00
1eda877a09 Implement simple camp & hunt AI for enemies 2022-08-17 23:46:31 +02:00
8dcbf5a972 Add support for ranged weapons 2022-08-17 22:36:17 +02:00
f28f647368 Add sound and animation to enemy death 2022-08-17 21:41:18 +02:00
da77d25f6d Add sound and animations to melee weapon attack 2022-08-17 21:31:05 +02:00
785e1ac524 Implement simple follow & attack AI for enemies 2022-08-17 19:12:10 +02:00
f581805efd Make all characters (including player and enemies) mortal 2022-08-17 18:34:45 +02:00
620970fb10 Create enemies system 2022-08-17 17:44:09 +02:00
bbf0109080 Create melee weapons system 2022-08-17 17:11:45 +02:00
122 changed files with 4517 additions and 450 deletions

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

4
.gitignore vendored
View File

@@ -1 +1,5 @@
.direnv
build/
data.trace.db
*.jar
result

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

184
data.sql Normal file
View File

@@ -0,0 +1,184 @@
SET DB_CLOSE_DELAY -1;
;
CREATE USER IF NOT EXISTS "" SALT '' HASH '' ADMIN;
CREATE SEQUENCE "PUBLIC"."SYSTEM_SEQUENCE_CE051218_6282_4D4E_BC8B_083D4B720B25" START WITH 13 BELONGS_TO_TABLE;
CREATE SEQUENCE "PUBLIC"."SYSTEM_SEQUENCE_704587BB_DC0E_44AB_A7F0_3DE0CA44FE3F" START WITH 2 BELONGS_TO_TABLE;
CREATE MEMORY TABLE "PUBLIC"."RANGED_WEAPON"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"TYPE" VARCHAR NOT NULL,
"COOLDOWN" INT NOT NULL,
"DAMAGE" VARCHAR NOT NULL,
"ANIMATION" VARCHAR NOT NULL,
"SOUND" VARCHAR NOT NULL,
"RANGE" VARCHAR NOT NULL,
"PUNCH_ANIMATION" VARCHAR NOT NULL,
"PUNCH_SOUND" VARCHAR NOT NULL,
"MISS_ANIMATION" VARCHAR NOT NULL,
"MISS_SOUND" VARCHAR NOT NULL,
"ICON" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."RANGED_WEAPON" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_4" PRIMARY KEY("ID");
-- 2 +/- SELECT COUNT(*) FROM PUBLIC.RANGED_WEAPON;
INSERT INTO "PUBLIC"."RANGED_WEAPON" VALUES
('wooden_bow', 'Wooden Bow', 'bow', 1000, '1d6+1', 'Arrow', 'Arrow', '5d4', 'Punch', 'Arrow punch', 'Poof', 'Arrow punch', 'Generic,12,11'),
('iron_bow', 'Iron Bow', 'bow', 700, '2d6+2', 'Arrow', 'Arrow', '6d4', 'Punch', 'Arrow punch', 'Poof', 'Arrow punch', 'Generic,12,10');
CREATE MEMORY TABLE "PUBLIC"."AMMUNITION"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"APPLIES_TO" VARCHAR NOT NULL,
"DAMAGE" VARCHAR NOT NULL,
"ICON" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."AMMUNITION" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_F" PRIMARY KEY("ID");
-- 1 +/- SELECT COUNT(*) FROM PUBLIC.AMMUNITION;
INSERT INTO "PUBLIC"."AMMUNITION" VALUES
('wooden_arrow', 'Wooden Arrow', 'bow', '1', 'Generic,8,10');
CREATE MEMORY TABLE "PUBLIC"."MELEE_WEAPON"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"COOLDOWN" INT NOT NULL,
"DAMAGE" VARCHAR NOT NULL,
"ANIMATION" VARCHAR NOT NULL,
"SOUND" VARCHAR,
"ICON" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."MELEE_WEAPON" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_2" PRIMARY KEY("ID");
-- 2 +/- SELECT COUNT(*) FROM PUBLIC.MELEE_WEAPON;
INSERT INTO "PUBLIC"."MELEE_WEAPON" VALUES
('wooden_sword', 'Wooden Sword', 1000, '1d4+1', 'Slash', 'Sword slash', 'Generic,5,10'),
('wooden_dagger', 'Wooden Dagger', 300, '1d2', 'Slash', 'Sword slash', 'Generic,7,1');
CREATE MEMORY TABLE "PUBLIC"."OBJECT"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"CHARSET" VARCHAR NOT NULL,
"FRAME" SMALLINT,
"INTERACT_SOUND" VARCHAR
);
ALTER TABLE "PUBLIC"."OBJECT" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_C" PRIMARY KEY("ID");
-- 3 +/- SELECT COUNT(*) FROM PUBLIC.OBJECT;
INSERT INTO "PUBLIC"."OBJECT" VALUES
('black_fsm_right_doors', 'Doors', 'FSM Doors', 0, 'Arrow punch'),
('enforced_chest_left', 'Enforced Chest', 'Chests', 3, 'Arrow punch'),
('plain_chest_down', 'Plain Chest', 'Chests', 0, 'Arrow punch');
CREATE MEMORY TABLE "PUBLIC"."JUNK"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"ICON" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."JUNK" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_22" PRIMARY KEY("ID");
-- 4 +/- SELECT COUNT(*) FROM PUBLIC.JUNK;
INSERT INTO "PUBLIC"."JUNK" VALUES
('bone', 'Bone', 'Generic,21,2'),
('eye', 'Eye', 'Generic,21,3'),
('tooth', 'Tooth', 'Generic,21,5'),
('fur', 'Fur', 'Generic,21,6');
CREATE MEMORY TABLE "PUBLIC"."MEDICAMENTS"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"ICON" VARCHAR NOT NULL,
"HP" VARCHAR NOT NULL,
"ANIMATION" VARCHAR NOT NULL,
"SOUND" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."MEDICAMENTS" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_E" PRIMARY KEY("ID");
-- 1 +/- SELECT COUNT(*) FROM PUBLIC.MEDICAMENTS;
INSERT INTO "PUBLIC"."MEDICAMENTS" VALUES
('small_life_potion', 'Small life potion', 'Generic,2,11', '2d4+2', 'Poof', 'Arrow punch');
CREATE MEMORY TABLE "PUBLIC"."ENEMY_DROP"(
"ID" INT DEFAULT NEXT VALUE FOR "PUBLIC"."SYSTEM_SEQUENCE_CE051218_6282_4D4E_BC8B_083D4B720B25" NOT NULL NULL_TO_DEFAULT SEQUENCE "PUBLIC"."SYSTEM_SEQUENCE_CE051218_6282_4D4E_BC8B_083D4B720B25",
"ENEMY" VARCHAR NOT NULL,
"ITEM" VARCHAR NOT NULL,
"CHANCE" DECIMAL NOT NULL,
"AMOUNT" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."ENEMY_DROP" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_8" PRIMARY KEY("ID");
-- 7 +/- SELECT COUNT(*) FROM PUBLIC.ENEMY_DROP;
INSERT INTO "PUBLIC"."ENEMY_DROP" VALUES
(1, 'deku', 'throwing:deku_arrow', 0.8, '2d4+5'),
(6, 'skeleton', 'junk:bone', 0.7, '1'),
(7, 'skeleton_archer', 'junk:bone', 0.7, '1'),
(8, 'skeleton', 'melee:wooden_sword', 0.5, '1'),
(9, 'skeleton_archer', 'ranged:wooden_bow', 0.3, '1'),
(10, 'skeleton_archer', 'ammo:wooden_arrow', 0.7, '1d4+3'),
(11, 'deku', 'junk:eye', 0.7, '1d2');
CREATE MEMORY TABLE "PUBLIC"."CONFIG"(
"KEY" VARCHAR NOT NULL,
"VALUE" VARCHAR
);
ALTER TABLE "PUBLIC"."CONFIG" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_7" PRIMARY KEY("KEY");
-- 5 +/- SELECT COUNT(*) FROM PUBLIC.CONFIG;
INSERT INTO "PUBLIC"."CONFIG" VALUES
('start_game', 'Hero Home,Main,Start'),
('screen', '1000x800'),
('camera_scale', '2'),
('full_day_duration', '600'),
('initial_time', '08:30');
CREATE MEMORY TABLE "PUBLIC"."LEVELS"(
"LEVEL" INT DEFAULT NEXT VALUE FOR "PUBLIC"."SYSTEM_SEQUENCE_704587BB_DC0E_44AB_A7F0_3DE0CA44FE3F" NOT NULL NULL_TO_DEFAULT SEQUENCE "PUBLIC"."SYSTEM_SEQUENCE_704587BB_DC0E_44AB_A7F0_3DE0CA44FE3F",
"MAX_HP" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."LEVELS" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_85" PRIMARY KEY("LEVEL");
-- 1 +/- SELECT COUNT(*) FROM PUBLIC.LEVELS;
INSERT INTO "PUBLIC"."LEVELS" VALUES
(1, '3000');
CREATE MEMORY TABLE "PUBLIC"."THROWING_WEAPON"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"COOLDOWN" INT NOT NULL,
"DAMAGE" VARCHAR NOT NULL,
"ANIMATION" VARCHAR NOT NULL,
"SOUND" VARCHAR NOT NULL,
"RANGE" VARCHAR NOT NULL,
"PUNCH_ANIMATION" VARCHAR NOT NULL,
"PUNCH_SOUND" VARCHAR NOT NULL,
"MISS_ANIMATION" VARCHAR NOT NULL,
"MISS_SOUND" VARCHAR NOT NULL,
"ICON" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."THROWING_WEAPON" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_40" PRIMARY KEY("ID");
-- 2 +/- SELECT COUNT(*) FROM PUBLIC.THROWING_WEAPON;
INSERT INTO "PUBLIC"."THROWING_WEAPON" VALUES
('deku_arrow', 'Deku''s arrow', 500, '2d4', 'Arrow', 'Arrow', '5d4', 'Punch', 'Arrow punch', 'Poof', 'Arrow punch', 'Generic,8,10'),
('shuriken', 'Shuriken', 100, '3d6', 'Shuriken', 'Arrow', '5d4', 'Punch', 'Arrow punch', 'Poof', 'Arrow punch', 'Generic,9,2');
CREATE MEMORY TABLE "PUBLIC"."ENEMY"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"CHARSET" VARCHAR NOT NULL,
"DEAD_CHARSET" VARCHAR,
"HP" VARCHAR NOT NULL,
"SPEED" VARCHAR NOT NULL,
"BLOCKING" BOOL NOT NULL,
"MELEE_WEAPON" VARCHAR,
"RANGED_WEAPON" VARCHAR,
"THROWING_WEAPON" VARCHAR,
"DIE_ANIMATION" VARCHAR NOT NULL,
"DIE_SOUND" VARCHAR NOT NULL
);
ALTER TABLE "PUBLIC"."ENEMY" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_3" PRIMARY KEY("ID");
-- 8 +/- SELECT COUNT(*) FROM PUBLIC.ENEMY;
INSERT INTO "PUBLIC"."ENEMY" VALUES
('deku', 'Deku', 'Deku', 'Corpse', '2d4', '10d2', TRUE, NULL, NULL, 'deku_arrow,1d4+2', 'Poof', 'Deku death'),
('garo', 'Garo', 'Garo', 'Corpse', '7d4', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('blanca', 'Blanca', 'Blanca', 'Corpse', '10d4', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('turtle', 'Turtle', 'Turtle', 'Corpse', '5d4', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('silver_bat', 'Silver Bat', 'Silver Bat', 'Corpse', '1d4+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('eagle', 'Eagle', 'Eagle', 'Corpse', '2d4+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('skeleton', 'Skeleton', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('skeleton_archer', 'Skeleton Archer', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_dagger', 'wooden_bow,wooden_arrow,2d4+3', NULL, 'Poof', 'Deku death');
CREATE MEMORY TABLE "PUBLIC"."FRIEND"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"CHARSET" VARCHAR NOT NULL,
"SPEED" VARCHAR NOT NULL,
"BLOCKING" BOOLEAN DEFAULT FALSE NOT NULL,
"DIALOG_COLOR" VARCHAR DEFAULT '0xFFFFFF' NOT NULL
);
ALTER TABLE "PUBLIC"."FRIEND" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_7C" PRIMARY KEY("ID");
-- 3 +/- SELECT COUNT(*) FROM PUBLIC.FRIEND;
INSERT INTO "PUBLIC"."FRIEND" VALUES
('turtle', 'Turtle', 'Turtle', '10d2', TRUE, 'AA00DD'),
('neko', 'Neko', 'Neko', '14', TRUE, 'AA00DD'),
('grandma', 'Grandma', 'Grandma', '7', TRUE, 'DD00AA');
ALTER TABLE "PUBLIC"."ENEMY_DROP" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_8A" FOREIGN KEY("ENEMY") REFERENCES "PUBLIC"."ENEMY"("ID") NOCHECK;
ALTER TABLE "PUBLIC"."ENEMY" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_3F" FOREIGN KEY("MELEE_WEAPON") REFERENCES "PUBLIC"."MELEE_WEAPON"("ID") NOCHECK;

111
flake.lock generated Normal file
View File

@@ -0,0 +1,111 @@
{
"nodes": {
"base": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"gradle2nix": "gradle2nix",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1752221128,
"narHash": "sha256-dFWsRVenkLOtbBx67JfAjVD5PyiKJY4TMCbXbf7bGT4=",
"ref": "refs/heads/master",
"rev": "41cc804cc3855553587eafd13597054d93097972",
"revCount": 600,
"type": "git",
"url": "https://git.orleander.pl/bartek/base.git"
},
"original": {
"type": "git",
"url": "https://git.orleander.pl/bartek/base.git"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gradle2nix": {
"inputs": {
"flake-utils": [
"base",
"flake-utils"
],
"nixpkgs": [
"base",
"nixpkgs"
]
},
"locked": {
"lastModified": 1743629487,
"narHash": "sha256-MjnEgT9MhO2HknLhrx7GvBRVxdOzSKydIJMyzawe2Fk=",
"owner": "tadfisher",
"repo": "gradle2nix",
"rev": "293ecbdc10d32d9d4bdc2d23213b9be09ce247ee",
"type": "github"
},
"original": {
"owner": "tadfisher",
"ref": "v2",
"repo": "gradle2nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1751943650,
"narHash": "sha256-7orTnNqkGGru8Je6Un6mq1T8YVVU/O5kyW4+f9C1mZQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88983d4b665fb491861005137ce2b11a9f89f203",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-25.05",
"type": "indirect"
}
},
"root": {
"inputs": {
"base": "base",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

30
flake.nix Normal file
View File

@@ -0,0 +1,30 @@
{
description = "The BASE engine demo game";
inputs = {
nixpkgs.url = "nixpkgs/nixos-25.05";
flake-utils.url = "github:numtide/flake-utils";
base.url = "git+https://git.orleander.pl/bartek/base.git";
base.inputs.nixpkgs.follows = "nixpkgs";
base.inputs.flake-utils.follows = "flake-utils";
};
outputs = inputs @ {
self,
nixpkgs,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {inherit system;};
in {
packages = rec {
game = pkgs.callPackage ./game.nix (inputs // {inherit system;});
default = game;
};
devShells.default = pkgs.callPackage ./shell.nix {inherit system;};
});
}

44
game.nix Normal file
View File

@@ -0,0 +1,44 @@
{
pkgs,
base,
lib,
stdenv,
system,
makeWrapper,
jdk17,
xorg,
openjfx17,
glib,
alsa-lib,
libGL,
gtk3,
...
}:
stdenv.mkDerivation rec {
pname = "base-demo";
version = "0.0.1";
src = ./.;
nativeBuildInputs = [base.packages.${system}.default makeWrapper];
buildPhase = ''
base-editor -bHp $src/project.json -o build
'';
installPhase = ''
mkdir -p $out/bin
mkdir -p $out/share/java
cp build/out/game.jar $out/share/java/base-demo-game.jar
makeWrapper "${jdk17}/bin/java" $out/bin/base-demo \
--add-flags "-jar $out/share/java/base-demo-game.jar" \
--prefix LD_LIBRARY_PATH : "${xorg.libXtst}/lib" \
--prefix LD_LIBRARY_PATH : "${openjfx17}/lib" \
--prefix LD_LIBRARY_PATH : "${glib.out}/lib" \
--prefix LD_LIBRARY_PATH : "${alsa-lib}/lib" \
--prefix LD_LIBRARY_PATH : "${libGL}/lib" \
--prefix LD_LIBRARY_PATH : "${gtk3}/lib"
'';
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,140 @@
{
"uid": "d1b85d85-c52a-46f5-b81e-444847f8ddae",
"rows": 17,
"columns": 20,
"tileWidth": 32,
"tileHeight": 32,
"layers": [{
"name": "All Lights",
"objectLayer": {
"passageMap": ["ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW"],
"objects": [{
"x": 6,
"y": 1,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\ntorch(here);"
}, {
"x": 5,
"y": 7,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\ntorch(here);"
}, {
"x": 13,
"y": 12,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\ntorch(here);"
}, {
"x": 17,
"y": 7,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\ntorch(here);"
}, {
"x": 15,
"y": 7,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\ntorch(here);"
}, {
"x": 10,
"y": 2,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\nlight(here);"
}, {
"x": 11,
"y": 2,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\ntorch(here);"
}, {
"x": 2,
"y": 1,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\nvar light \u003d light(here);\nlight.setPositionOffset(0, 15f);"
}, {
"x": 5,
"y": 1,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\nvar light \u003d light(here);\nlight.setPositionOffset(0, 15f);"
}]
}
}, {
"name": "Floor",
"tileLayer": {
"tilesetUID": "eb5bbf17-efaa-4213-90c3-2785a32f3c37",
"tiles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 33, 33, 33, 33, 33, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 33, 33, 33, 33, 33, 33, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 33, 33, 33, 33, 33, 33, 33, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 34, 0, 0, 0, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
}, {
"name": "Carpets",
"autoTileLayer": {
"autotileUID": "f6bcd0ea-f293-4864-bd13-d1c4e8b79080",
"tiles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"animated": false,
"animationDuration": 1.0,
"connect": false
}
}, {
"name": "Walls",
"autoTileLayer": {
"autotileUID": "b475367a-7bf8-44ee-b916-6e81a78f97d9",
"tiles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"animated": false,
"animationDuration": 1.0,
"connect": false
}
}, {
"name": "Floor objects",
"tileLayer": {
"tilesetUID": "60362451-85ed-4bbe-8ac1-225056f48b40",
"tiles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 52, 162, 163, 52, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 68, 178, 179, 68, 10, 10, 0, 0, 81, 215, 141, 0, 0, 0, 0, 0, 0, 0, 0, 184, 147, 194, 195, 148, 26, 26, 0, 38, 6, 8, 45, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 132, 0, 0, 0, 0, 23, 22, 24, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 212, 145, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 145, 244, 145, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 142, 215, 0, 0, 0, 0, 0, 0, 0, 167, 0, 215, 126, 215, 0, 0, 0, 0, 12, 11, 13, 14, 13, 0, 170, 0, 0, 0, 0, 183, 0, 0, 0, 0, 168, 0, 0, 0, 28, 27, 29, 29, 29, 0, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 0, 32, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 77, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 58, 0, 0, 93, 0, 0, 0, 0, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
}, {
"name": "Main",
"objectLayer": {
"passageMap": ["ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "BLOCK", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "ALLOW", "BLOCK"],
"objects": [{
"x": 3,
"y": 12,
"code": "/* \n * Following final parameters are available to use:\n * x: int - the x coordinate of tile the object has been created on\n * y: int - the y coordinate of tile the object has been created on \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map\n */\nwarp(here, A.maps.hero_house.main.home);"
}, {
"x": 5,
"y": 4,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map\n */\nfriend(here, \"neko\")\n\t.randomMovementAI(4f)\n\t.interaction(this::triggerNekoDialog);"
}, {
"x": 7,
"y": 9,
"code": "/* \n * Following final parameters are available to use:\n * x: int - the x coordinate of tile the object has been created on\n * y: int - the y coordinate of tile the object has been created on \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map\n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\nchest(here, \"plain_chest_down\")\n\t.addItem(new MeleeWeapon(\"wooden_sword\"))\n\t.addItem(new Medicament(\"small_life_potion\", 4))\n\t.shuffle();"
}, {
"x": 18,
"y": 12,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map \n * handler: HeroHomeHandler - current map handler\n * runner: DemoRunner - the game runner of the project\n * context: Context - the game context\n */\nchest(here, \"enforced_chest_left\")\n\t.addItem(new MeleeWeapon(\"wooden_sword\"))\n\t.addItem(new Medicament(\"small_life_potion\", 4))\n\t.shuffle();"
}, {
"x": 13,
"y": 15,
"code": "/* \n * Following final parameters are available to use:\n * here: MapPin - the composite object containing current map UID, \n * layer\u0027s index and x,y coordinates of the current tile \n * x: int - the x coordinate of the current tile\n * y: int - the y coordinate of the current tile \n * layer: ObjectLayer - current object layer\n * map: GameMap - current map\n */\nfriend(here, \"grandma\")\n\t.followPath(this::grandmaPath)\n\t.interaction(this::triggerGrandmaDialog);"
}],
"labels": [{
"label": "entry",
"x": 3,
"y": 11
}, {
"label": "Start",
"x": 10,
"y": 14
}, {
"label": "Grandma Waking",
"x": 11,
"y": 14
}, {
"label": "Grandma Origin",
"x": 11,
"y": 7
}]
}
}, {
"name": "Objects above",
"tileLayer": {
"tilesetUID": "60362451-85ed-4bbe-8ac1-225056f48b40",
"tiles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 168, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 13, 0, 0, 13, 13, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
}, {
"name": "Ceiling",
"autoTileLayer": {
"autotileUID": "6584a279-e937-497e-a056-b1e77bff2439",
"tiles": [10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10, 0, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 10, 0, 0, 10, 10, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
"animated": false,
"animationDuration": 1.0,
"connect": false
}
}],
"handler": "com.bartlomiejpluta.demo.map.HeroHomeHandler",
"javaImports": "import com.bartlomiejpluta.demo.world.weapon.*;\nimport com.bartlomiejpluta.demo.world.potion.*;\nimport com.bartlomiejpluta.base.lib.animation.*;"
}

View File

@@ -1,9 +0,0 @@
BASE Demo*com.bartlomiejpluta.demo.runner.DemoRunner`
$f845355e-b9ad-4884-a217-dd3a4c18a3fa(f845355e-b9ad-4884-a217-dd3a4c18a3fa.datForrest Temple"d
$d314b030-f865-432e-a356-3845f8aac7bc(d314b030-f865-432e-a356-3845f8aac7bc.pngForrest Temple ](2Z
$815a5c5c-4979-42f5-a42a-ccbbff9a97e5(815a5c5c-4979-42f5-a42a-ccbbff9a97e5.pngLuna (:`
$2261c04f-b02e-4486-b388-8a0fa41622e9(2261c04f-b02e-4486-b388-8a0fa41622e9.ttfRoboto RegularB\
$ab9d40b4-eb28-45d7-bff2-9432a05eb41a(ab9d40b4-eb28-45d7-bff2-9432a05eb41a.xml
Start MenuB[
$56ca6b39-f949-4212-9c23-312db25887e0(56ca6b39-f949-4212-9c23-312db25887e0.xml Game Menu

287
project.json Normal file
View File

@@ -0,0 +1,287 @@
{
"name": "BASE Demo",
"runner": "com.bartlomiejpluta.demo.runner.DemoRunner",
"maps": [{
"uid": "d1b85d85-c52a-46f5-b81e-444847f8ddae",
"source": "d1b85d85-c52a-46f5-b81e-444847f8ddae.dat",
"name": "Hero Home"
}, {
"uid": "b602601a-e9b0-44bf-bc0d-5f31c9964ba1",
"source": "b602601a-e9b0-44bf-bc0d-5f31c9964ba1.dat",
"name": "Hero House"
}, {
"uid": "8fbb151f-682a-4357-ba92-157e4097898f",
"source": "8fbb151f-682a-4357-ba92-157e4097898f.dat",
"name": "Forrest"
}],
"tileSets": [{
"uid": "eb5bbf17-efaa-4213-90c3-2785a32f3c37",
"source": "eb5bbf17-efaa-4213-90c3-2785a32f3c37.png",
"name": "FSM 1",
"rows": 16,
"columns": 8
}, {
"uid": "bf5a8b2c-4635-4433-8781-d8fed02c7197",
"source": "bf5a8b2c-4635-4433-8781-d8fed02c7197.png",
"name": "FSM 2",
"rows": 16,
"columns": 16
}, {
"uid": "fa940a9c-aa18-4037-9c20-ca660182d5f4",
"source": "fa940a9c-aa18-4037-9c20-ca660182d5f4.png",
"name": "FSM 3",
"rows": 16,
"columns": 16
}, {
"uid": "60362451-85ed-4bbe-8ac1-225056f48b40",
"source": "60362451-85ed-4bbe-8ac1-225056f48b40.png",
"name": "FSM 4",
"rows": 16,
"columns": 16
}, {
"uid": "6d5672b0-64e6-48a7-8b48-bf73d37ca7d2",
"source": "6d5672b0-64e6-48a7-8b48-bf73d37ca7d2.png",
"name": "FSM 5",
"rows": 16,
"columns": 16
}, {
"uid": "413e09cf-ba41-4fe8-ac47-9697b5ad0245",
"source": "413e09cf-ba41-4fe8-ac47-9697b5ad0245.png",
"name": "Forrest",
"rows": 35,
"columns": 16
}],
"characterSets": [{
"uid": "0dcbaf26-d634-4ca8-9691-7a8ff966f702",
"source": "0dcbaf26-d634-4ca8-9691-7a8ff966f702.png",
"name": "Garo",
"rows": 4,
"columns": 4
}, {
"uid": "61393836-8127-4277-853f-87b48022ae43",
"source": "61393836-8127-4277-853f-87b48022ae43.png",
"name": "Corpse",
"rows": 4,
"columns": 4
}, {
"uid": "e605b2b1-3cab-499f-882d-160ab65b49d8",
"source": "e605b2b1-3cab-499f-882d-160ab65b49d8.png",
"name": "Skeleton",
"rows": 4,
"columns": 4
}, {
"uid": "0ea0fe55-53b2-4eea-8fab-2011e694127b",
"source": "0ea0fe55-53b2-4eea-8fab-2011e694127b.png",
"name": "Luna",
"rows": 4,
"columns": 4
}, {
"uid": "92ac46ff-8cf2-4748-907f-873030c8e378",
"source": "92ac46ff-8cf2-4748-907f-873030c8e378.png",
"name": "Chests2",
"rows": 4,
"columns": 4
}, {
"uid": "fbea4628-e1d3-4acc-800a-ed54c1bb51b6",
"source": "fbea4628-e1d3-4acc-800a-ed54c1bb51b6.png",
"name": "Blanca",
"rows": 4,
"columns": 4
}, {
"uid": "7a723b64-e54a-4fff-852d-108349133111",
"source": "7a723b64-e54a-4fff-852d-108349133111.png",
"name": "Eagle2",
"rows": 4,
"columns": 4
}, {
"uid": "c7ec2341-e5fc-4285-9ecb-a2dfc8a0ed67",
"source": "c7ec2341-e5fc-4285-9ecb-a2dfc8a0ed67.png",
"name": "Turtle",
"rows": 4,
"columns": 4
}, {
"uid": "f1113db3-4a6c-4a07-9b64-32ba8e653e4f",
"source": "f1113db3-4a6c-4a07-9b64-32ba8e653e4f.png",
"name": "Silver Bat",
"rows": 4,
"columns": 4
}, {
"uid": "1779ae2b-474a-4599-8fc3-be34f7d66965",
"source": "1779ae2b-474a-4599-8fc3-be34f7d66965.png",
"name": "Deku",
"rows": 4,
"columns": 4
}, {
"uid": "a6863639-d563-4d88-af8e-c6d087ee2ffb",
"source": "a6863639-d563-4d88-af8e-c6d087ee2ffb.png",
"name": "FSM Doors",
"rows": 4,
"columns": 4
}, {
"uid": "35f770a6-5d94-4ddf-a132-dc3788a3adaf",
"source": "35f770a6-5d94-4ddf-a132-dc3788a3adaf.png",
"name": "Neko",
"rows": 4,
"columns": 4
}, {
"uid": "4a636044-2dbd-4ef3-8bdf-b63501c85ae3",
"source": "4a636044-2dbd-4ef3-8bdf-b63501c85ae3.png",
"name": "Grandma",
"rows": 4,
"columns": 4
}, {
"uid": "f529cbfc-c29d-470b-8804-e50d6a1efc98",
"source": "f529cbfc-c29d-470b-8804-e50d6a1efc98.png",
"name": "Chests",
"rows": 4,
"columns": 16
}],
"fonts": [{
"uid": "2261c04f-b02e-4486-b388-8a0fa41622e9",
"source": "2261c04f-b02e-4486-b388-8a0fa41622e9.ttf",
"name": "Roboto Regular"
}],
"widgets": [{
"uid": "ab9d40b4-eb28-45d7-bff2-9432a05eb41a",
"source": "ab9d40b4-eb28-45d7-bff2-9432a05eb41a.xml",
"name": "Start Menu"
}, {
"uid": "56ca6b39-f949-4212-9c23-312db25887e0",
"source": "56ca6b39-f949-4212-9c23-312db25887e0.xml",
"name": "Game Menu"
}, {
"uid": "00bd0625-b3b8-4abf-97b7-91f42bce28ec",
"source": "00bd0625-b3b8-4abf-97b7-91f42bce28ec.xml",
"name": "HUD"
}, {
"uid": "c473a91a-ff25-4e71-9bec-b35e48102aeb",
"source": "c473a91a-ff25-4e71-9bec-b35e48102aeb.xml",
"name": "Equipment"
}, {
"uid": "53ca3e54-0f8d-44fa-8281-acd9c5bba743",
"source": "53ca3e54-0f8d-44fa-8281-acd9c5bba743.xml",
"name": "Eq Item Menu"
}, {
"uid": "d78413cd-0dad-4b51-8dd1-54e33535fe53",
"source": "d78413cd-0dad-4b51-8dd1-54e33535fe53.xml",
"name": "Loot Menu"
}, {
"uid": "1c2b2ba2-66bf-40ee-97bf-6e5065b7b420",
"source": "1c2b2ba2-66bf-40ee-97bf-6e5065b7b420.xml",
"name": "Dialog"
}, {
"uid": "5a5aea0a-8c8b-4730-8e45-9ec6ccc5c4f6",
"source": "5a5aea0a-8c8b-4730-8e45-9ec6ccc5c4f6.xml",
"name": "Dialog Choice"
}],
"animations": [{
"uid": "e6f067f1-eba0-4e62-99c3-2fd867e6f142",
"source": "e6f067f1-eba0-4e62-99c3-2fd867e6f142.png",
"name": "Poof",
"rows": 4,
"columns": 5
}, {
"uid": "312cc4e6-8c44-43e7-828a-e7e2a77836f3",
"source": "312cc4e6-8c44-43e7-828a-e7e2a77836f3.png",
"name": "Arrow",
"rows": 2,
"columns": 2
}, {
"uid": "54f657bd-8108-464c-9bbe-63944fc14f6b",
"source": "54f657bd-8108-464c-9bbe-63944fc14f6b.png",
"name": "Punch",
"rows": 3,
"columns": 5
}, {
"uid": "0ddac391-4086-4e9c-8310-59db649419ff",
"source": "0ddac391-4086-4e9c-8310-59db649419ff.png",
"name": "Slash",
"rows": 2,
"columns": 5
}, {
"uid": "c8883e76-ae93-4673-8893-d2ec72c1e199",
"source": "c8883e76-ae93-4673-8893-d2ec72c1e199.png",
"name": "Shuriken",
"rows": 2,
"columns": 3
}, {
"uid": "aeb17449-c342-4dab-9057-5fb05183fd03",
"source": "aeb17449-c342-4dab-9057-5fb05183fd03.png",
"name": "Heart Emoji",
"rows": 6,
"columns": 4
}, {
"uid": "78563669-8a6c-4024-82c8-7e4da5b76edd",
"source": "78563669-8a6c-4024-82c8-7e4da5b76edd.png",
"name": "Zzz",
"rows": 7,
"columns": 4
}],
"sounds": [{
"uid": "1311327d-4b74-4252-94da-23ee4129e357",
"source": "1311327d-4b74-4252-94da-23ee4129e357.ogg",
"name": "Sword slash"
}, {
"uid": "e452e215-f581-40fe-a5cf-f555d3db83b8",
"source": "e452e215-f581-40fe-a5cf-f555d3db83b8.ogg",
"name": "Deku death"
}, {
"uid": "cd8a40f2-1e2e-4e1d-a13f-b4fe210a04df",
"source": "cd8a40f2-1e2e-4e1d-a13f-b4fe210a04df.ogg",
"name": "Arrow"
}, {
"uid": "7c33cfee-e6a8-42b8-8b1d-c801b242dcf0",
"source": "7c33cfee-e6a8-42b8-8b1d-c801b242dcf0.ogg",
"name": "Arrow punch"
}],
"iconSets": [{
"uid": "ddc1e14f-0d1f-4291-a29d-0dc5d8e9242b",
"source": "ddc1e14f-0d1f-4291-a29d-0dc5d8e9242b.png",
"name": "Generic",
"rows": 35,
"columns": 12
}],
"autoTiles": [{
"uid": "f6bcd0ea-f293-4864-bd13-d1c4e8b79080",
"source": "f6bcd0ea-f293-4864-bd13-d1c4e8b79080.png",
"name": "FSM 1",
"rows": 4,
"columns": 8,
"layout": "LAYOUT_2X3"
}, {
"uid": "88042125-4c6d-4dfa-ad1d-8e78b6df9ee9",
"source": "88042125-4c6d-4dfa-ad1d-8e78b6df9ee9.png",
"name": "FSM 2",
"rows": 4,
"columns": 8,
"layout": "LAYOUT_2X2"
}, {
"uid": "6584a279-e937-497e-a056-b1e77bff2439",
"source": "6584a279-e937-497e-a056-b1e77bff2439.png",
"name": "FSM 3",
"rows": 3,
"columns": 8,
"layout": "LAYOUT_2X3"
}, {
"uid": "b475367a-7bf8-44ee-b916-6e81a78f97d9",
"source": "b475367a-7bf8-44ee-b916-6e81a78f97d9.png",
"name": "FSM 4",
"rows": 3,
"columns": 8,
"layout": "LAYOUT_2X2"
}, {
"uid": "04ac5ad8-4100-4016-97b3-a51a728ca49d",
"source": "04ac5ad8-4100-4016-97b3-a51a728ca49d.png",
"name": "Candacis Spring 1",
"rows": 3,
"columns": 2,
"layout": "LAYOUT_2X3"
}, {
"uid": "fc294b9e-105a-4120-8caa-393d78fdf414",
"source": "fc294b9e-105a-4120-8caa-393d78fdf414.png",
"name": "Candacis Spring 2",
"rows": 1,
"columns": 3,
"layout": "LAYOUT_2X3"
}]
}

6
shell.nix Normal file
View File

@@ -0,0 +1,6 @@
{pkgs, ...}:
pkgs.mkShell {
name = "base-demo-game-development-shell";
LD_LIBRARY_PATH = with pkgs; "${xorg.libXtst}/lib:${openjfx17}/lib:${glib.out}/lib:${alsa-lib}/lib:${libGL}/lib:${gtk3}/lib";
}

View File

@@ -0,0 +1,40 @@
package com.bartlomiejpluta.demo.ai;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.lib.ai.RandomMovementAI;
import com.bartlomiejpluta.base.lib.ai.RunawayAI;
import com.bartlomiejpluta.demo.entity.Creature;
import com.bartlomiejpluta.demo.entity.Enemy;
public class AnimalAI implements AI {
private final Enemy animal;
private final Creature creature;
private final int range;
private final AI idleAI;
private final AI runawayAI;
public AnimalAI(Enemy animal, Creature creature, int range) {
this.animal = animal;
this.creature = creature;
this.range = range;
this.idleAI = new RandomMovementAI<>(animal, 4);
this.runawayAI = new RunawayAI<>(animal, creature);
}
@Override
public void nextActivity(ObjectLayer layer, float dt) {
if (animal.isMoving()) {
return;
}
var distance = animal.manhattanDistance(creature);
if (animal.getHp() < animal.getMaxHp() && distance < range) {
runawayAI.nextActivity(layer, dt);
return;
}
idleAI.nextActivity(layer, dt);
}
}

View File

@@ -0,0 +1,42 @@
package com.bartlomiejpluta.demo.ai;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.lib.ai.KeepStraightDistanceAI;
import com.bartlomiejpluta.base.lib.ai.RandomMovementAI;
import com.bartlomiejpluta.base.util.pathfinder.AstarPathFinder;
import com.bartlomiejpluta.demo.entity.Creature;
import com.bartlomiejpluta.demo.entity.Enemy;
public class ArcherAI extends KeepStraightDistanceAI<Enemy, Creature> {
private static final int ASTAR_MAX_NODES = 100;
private static final int IDLE_MOVEMENT_INTERVAL = 4;
private final int range;
private final AI idle;
public ArcherAI(Enemy enemy, Creature target, int minRange, int maxRange, int range) {
super(new AstarPathFinder(ASTAR_MAX_NODES), enemy, target, minRange, maxRange);
this.range = range;
this.idle = new RandomMovementAI<>(enemy, IDLE_MOVEMENT_INTERVAL);
}
@Override
protected boolean sees(Enemy enemy, Creature target, ObjectLayer layer) {
return enemy.manhattanDistance(target) < range;
}
@Override
protected void interact(Enemy enemy, Creature target, ObjectLayer layer, float dt) {
enemy.attack();
}
@Override
protected void follow(Enemy enemy, Creature target, ObjectLayer layer, float dt) {
// noop
}
@Override
protected void idle(Enemy enemy, Creature target, ObjectLayer layer, float dt) {
idle.nextActivity(layer, dt);
}
}

View File

@@ -0,0 +1,42 @@
package com.bartlomiejpluta.demo.ai;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.lib.ai.FollowObjectAI;
import com.bartlomiejpluta.base.lib.ai.RandomMovementAI;
import com.bartlomiejpluta.base.util.pathfinder.AstarPathFinder;
import com.bartlomiejpluta.demo.entity.Creature;
import com.bartlomiejpluta.demo.entity.Enemy;
public class SimpleEnemyAI extends FollowObjectAI<Enemy, Creature> {
private static final int ASTAR_MAX_NODES = 100;
private static final int IDLE_MOVEMENT_INTERVAL = 4;
private final AI idle;
private final int range;
public SimpleEnemyAI(Enemy enemy, Creature target, int range) {
super(new AstarPathFinder(ASTAR_MAX_NODES), enemy, target);
this.range = range;
this.idle = new RandomMovementAI<>(enemy, IDLE_MOVEMENT_INTERVAL);
}
@Override
protected boolean sees(Enemy enemy, Creature target, ObjectLayer layer, int distance) {
return distance < range;
}
@Override
protected void interact(Enemy enemy, Creature target, ObjectLayer layer, float dt) {
enemy.attack();
}
@Override
protected void follow(Enemy enemy, Creature target, ObjectLayer layer, float dt) {
// noop
}
@Override
protected void idle(Enemy enemy, Creature target, ObjectLayer layer, float dt) {
idle.nextActivity(layer, dt);
}
}

View File

@@ -0,0 +1,25 @@
package com.bartlomiejpluta.demo.ai;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.demo.entity.Creature;
import com.bartlomiejpluta.demo.entity.Enemy;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class SimpleSniperAI implements AI {
private final Enemy enemy;
private Creature target;
private int range;
@Override
public void nextActivity(ObjectLayer layer, float dt) {
var enemyCoords = enemy.getCoordinates();
var targetCoords = target.getCoordinates();
if (enemy.manhattanDistance(target) <= range && (enemyCoords.x() == targetCoords.x() || enemyCoords.y() == targetCoords.y())) {
var direction = enemy.getDirectionTowards(target);
enemy.setFaceDirection(direction);
enemy.attack();
}
}
}

View File

@@ -0,0 +1,84 @@
package com.bartlomiejpluta.demo.ai;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.MoveEvent;
import com.bartlomiejpluta.base.lib.ai.RunawayAI;
import com.bartlomiejpluta.demo.entity.Creature;
import com.bartlomiejpluta.demo.entity.Enemy;
import lombok.NonNull;
public class WeaponBasedAI implements AI {
private static final int RANGE = 20;
private static final int MIN_RANGE = 3;
private static final int MAX_RANGE = 12;
private final Enemy enemy;
private final Creature target;
private final RunawayAI<Enemy, Creature> runawayAI;
private final SimpleEnemyAI meleeAI;
private final ArcherAI archerAI;
public WeaponBasedAI(@NonNull Enemy enemy, @NonNull Creature target) {
this.enemy = enemy;
this.target = target;
this.runawayAI = new RunawayAI<>(enemy, target);
this.meleeAI = new SimpleEnemyAI(enemy, target, RANGE);
this.archerAI = new ArcherAI(enemy, target, MIN_RANGE, MAX_RANGE, RANGE);
}
public void recomputePath() {
meleeAI.recomputePath();
archerAI.recomputePath();
}
public void recomputePath(@NonNull MoveEvent event) {
meleeAI.recomputePath(event);
archerAI.recomputePath(event);
}
@Override
public void nextActivity(ObjectLayer layer, float dt) {
var lastAttacker = enemy.getLastAttacker();
if (lastAttacker instanceof Creature attacker) {
if (attacker.isAlive()) {
runawayAI.setDanger(attacker);
meleeAI.setTarget(attacker);
archerAI.setTarget(attacker);
} else {
runawayAI.setDanger(target);
meleeAI.setTarget(target);
archerAI.setTarget(target);
}
}
var meleeWeapon = enemy.getMeleeWeapon();
var rangedWeapon = enemy.getRangedWeapon();
var throwingWeapon = enemy.getThrowingWeapon();
if (meleeWeapon == null && rangedWeapon == null && throwingWeapon == null) {
runawayAI.nextActivity(layer, dt);
return;
}
if ((rangedWeapon == null && throwingWeapon == null) || (rangedWeapon != null && enemy.getAmmunition() == null && throwingWeapon == null) || enemy.manhattanDistance(target) == 1) {
enemy.setWeapon(meleeWeapon);
meleeAI.nextActivity(layer, dt);
return;
}
if (throwingWeapon != null) {
enemy.setWeapon(throwingWeapon);
archerAI.nextActivity(layer, dt);
return;
}
enemy.setWeapon(rangedWeapon);
archerAI.nextActivity(layer, dt);
// if (enemy.getWeapon() instanceof MeleeWeapon) {
// meleeAI.nextActivity(layer, dt);
// }
}
}

View File

@@ -1,15 +0,0 @@
package com.bartlomiejpluta.demo.entity;
import lombok.*;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.lib.entity.EntityDelegate;
public class Character extends EntityDelegate {
protected final Context context;
public Character(@NonNull Context context, @NonNull Entity entity) {
super(entity);
this.context = context;
}
}

View File

@@ -0,0 +1,61 @@
package com.bartlomiejpluta.demo.entity;
import com.bartlomiejpluta.demo.world.item.Item;
import lombok.Getter;
import lombok.NonNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
public class Chest extends MapObject {
@Getter
private final Item[] content = new Item[Enemy.MAX_LOOT];
public Chest(@NonNull String id) {
super(id);
}
@Override
protected CompletableFuture<?> interact() {
return runner.getGuiManager().openChestWindow(this);
}
public Chest addItem(Item item) {
for (int i = 0; i < content.length; ++i) {
if (content[i] == null) {
content[i] = item;
return this;
}
}
throw new IllegalStateException("Chest is full!");
}
public Chest addItem(Item item, int slot) {
if(slot >= content.length) {
throw new IllegalStateException("The [" + slot + "] slot exceeds the chest size (" + content.length + ")!");
}
if (content[slot] != null) {
throw new IllegalStateException("The [" + slot + "] slot is already filled!");
}
content[slot] = item;
return this;
}
public Chest shuffle() {
var random = new Random();
for(int i = content.length - 1; i > 0; --i) {
var index = random.nextInt(i + 1);
var tmp = content[index];
content[index] = content[i];
content[i] = tmp;
}
return this;
}
}

View File

@@ -0,0 +1,156 @@
package com.bartlomiejpluta.demo.entity;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.light.Light;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.demo.world.item.Item;
import com.bartlomiejpluta.demo.world.weapon.Ammunition;
import com.bartlomiejpluta.demo.world.weapon.RangedWeapon;
import com.bartlomiejpluta.demo.world.weapon.Weapon;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class Creature extends NamedCharacter {
private static final Logger log = LoggerFactory.getLogger(Creature.class);
protected int attackCooldown = 0;
@Getter
protected boolean alive = true;
@Getter
protected boolean immortal = false;
@Getter
protected int maxHp;
@Getter
protected int hp;
@Getter
@Setter
private Weapon weapon;
@Getter
@Setter
private Ammunition ammunition;
@Getter
private NamedCharacter lastAttacker;
@Getter
protected Light light;
public Creature(@NonNull Character entity) {
super(entity);
}
public void attack() {
if (weapon == null) {
return;
}
if (attackCooldown >= weapon.getCooldown()) {
if (weapon.attack(this)) {
if (weapon instanceof RangedWeapon) {
ammunition.decrease();
if (ammunition.getCount() == 0) {
ammunition = null;
}
}
attackCooldown = 0;
}
}
}
public void hit(NamedCharacter source, int dmg) {
this.lastAttacker = source;
if (immortal) {
return;
}
hp -= dmg;
}
public void useEquipmentItem(Item item) {
if (item instanceof Weapon weapon) {
setWeapon(weapon);
return;
}
if (item instanceof Ammunition ammunition) {
setAmmunition(ammunition);
}
}
public void heal(int hp) {
this.hp = Math.min(this.hp + hp, this.maxHp);
}
public void setLight(Light light) {
this.light = light;
if(getLayer() != null) {
var layer = getLayer().getMap().getLayer(0);
if(light != null) {
layer.addLight(light);
} else if (this.light != null){
layer.removeLight(this.light);
}
}
this.light = light;
}
@Override
public void onAdd(ObjectLayer layer) {
super.onAdd(layer);
if(light != null) {
layer.getMap().getLayer(0).addLight(light);
}
}
@Override
public void onRemove(ObjectLayer layer) {
super.onRemove(layer);
if(light != null) {
layer.getMap().getLayer(0).removeLight(light);
}
}
@Override
public void update(float dt) {
super.update(dt);
if (weapon != null && attackCooldown < weapon.getCooldown()) {
attackCooldown += (int) (dt * 1000f);
}
if (hp <= 0 && alive && getLayer() != null) {
alive = false;
die();
}
if(light != null) {
light.setPosition(getPosition());
}
}
protected void die() {
if (isMoving()) {
abortMove();
}
}
public abstract String getName();
public abstract void removeItemFromEquipment(Item item);
}

View File

@@ -0,0 +1,48 @@
package com.bartlomiejpluta.demo.entity;
import A.maps;
import com.bartlomiejpluta.base.api.map.layer.object.MapPin;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import lombok.NonNull;
import java.util.concurrent.CompletableFuture;
public class Door extends MapObject {
private final String mapUid;
private final int targetX;
private final int targetY;
private final int layerId;
private final Player player;
public Door(@NonNull MapPin label, @NonNull String id) {
super(id);
this.mapUid = label.getMap();
this.layerId = label.getLayer();
this.targetX = label.getX();
this.targetY = label.getY();
player = DemoRunner.instance().getPlayer();
setPositionOffset(0, 16);
}
public Door(@NonNull String mapName, @NonNull String layerName, int targetX, int targetY, @NonNull String id) {
super(id);
var map = maps.byName(mapName);
this.mapUid = map.$;
this.targetX = targetX;
this.targetY = targetY;
this.layerId = map.layer(layerName).$;
player = DemoRunner.instance().getPlayer();
setPositionOffset(0, 16);
}
@Override
protected CompletableFuture<?> interact() {
context.openMap(mapUid);
context.getMap().getObjectLayer(layerId).addEntity(player);
player.setCoordinates(targetX, targetY);
reset();
return CompletableFuture.completedFuture(null);
}
}

View File

@@ -0,0 +1,155 @@
package com.bartlomiejpluta.demo.entity;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.context.ContextHolder;
import com.bartlomiejpluta.base.api.move.MoveEvent;
import com.bartlomiejpluta.base.lib.ai.NoopAI;
import com.bartlomiejpluta.base.lib.animation.AnimationRunner;
import com.bartlomiejpluta.base.lib.animation.SimpleAnimationRunner;
import com.bartlomiejpluta.base.util.random.DiceRoller;
import com.bartlomiejpluta.demo.ai.*;
import com.bartlomiejpluta.demo.event.EnemyDiedEvent;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import com.bartlomiejpluta.demo.util.LootGenerator;
import com.bartlomiejpluta.demo.world.item.Item;
import com.bartlomiejpluta.demo.world.weapon.Ammunition;
import com.bartlomiejpluta.demo.world.weapon.MeleeWeapon;
import com.bartlomiejpluta.demo.world.weapon.RangedWeapon;
import com.bartlomiejpluta.demo.world.weapon.ThrowingWeapon;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import java.util.Random;
public class Enemy extends Creature implements NPC {
public static final int MAX_LOOT = 4 * 4;
private final Random random = new Random();
private final DB.model.EnemyModel template;
private final AnimationRunner dieAnimation;
@Getter
private final Item[] loot = new Item[MAX_LOOT];
@Getter
private final String name;
private AI ai = NoopAI.INSTANCE;
@Getter
private MeleeWeapon meleeWeapon;
@Getter
private RangedWeapon rangedWeapon;
@Getter
@Setter
private ThrowingWeapon throwingWeapon;
public Enemy(@NonNull String id) {
this(DB.dao.enemy.find(id));
}
public Enemy(@NonNull DB.model.EnemyModel template) {
super(ContextHolder.INSTANCE.getContext().createCharacter(A.charsets.byName(template.getCharset()).$));
this.template = template;
name = template.getName();
maxHp = DiceRoller.roll(template.getHp());
hp = maxHp;
var speed = DiceRoller.roll(template.getSpeed()) / 10f;
setSpeed(speed);
setAnimationSpeed(speed / 2.0f);
setBlocking(template.isBlocking());
var meleeWeaponTemplate = template.getMeleeWeapon();
var rangedWeaponTemplate = template.getRangedWeapon();
var throwingWeaponTemplate = template.getThrowingWeapon();
if (meleeWeaponTemplate != null) {
this.meleeWeapon = new MeleeWeapon(meleeWeaponTemplate);
}
if (rangedWeaponTemplate != null) {
var split = rangedWeaponTemplate.split(",");
this.rangedWeapon = new RangedWeapon(split[0]);
setAmmunition(new Ammunition(split[1], DiceRoller.roll(split[2])));
}
if (throwingWeaponTemplate != null) {
var split = throwingWeaponTemplate.split(",");
this.throwingWeapon = new ThrowingWeapon(split[0], DiceRoller.roll(split[1]));
}
this.dieAnimation = new SimpleAnimationRunner(A.animations.byName(template.getDieAnimation()).$);
}
@Override
public AI getStrategy() {
return ai;
}
@Override
public void removeItemFromEquipment(Item item) {
// noop
}
@Override
public void die() {
super.die();
changeCharacterSet(A.charsets.byName(template.getDeadCharset()).$);
setScale(0.5f);
setBlocking(false);
setZIndex(-1);
ai = NoopAI.INSTANCE;
dieAnimation.run(context, getLayer(), this);
context.playSound(A.sounds.byName(template.getDieSound()).$);
context.fireEvent(new EnemyDiedEvent(this));
LootGenerator.generate(template.getId(), loot);
}
public Enemy followAndAttack(Creature target, int range) {
var ai = new SimpleEnemyAI(this, target, range);
addEventListener(MoveEvent.TYPE, ai::recomputePath);
addEventListener(EnemyDiedEvent.TYPE, e -> ai.recomputePath());
this.ai = ai;
return this;
}
public Enemy campAndHunt(Creature target, int range) {
this.ai = new SimpleSniperAI(this, target, range);
return this;
}
public Enemy asAnimal(Creature source, int range) {
this.ai = new AnimalAI(this, source, range);
return this;
}
public Enemy archer(Creature target, int minRange, int maxRange, int range) {
var ai = new ArcherAI(this, target, minRange, maxRange, range);
addEventListener(MoveEvent.TYPE, ai::recomputePath);
addEventListener(EnemyDiedEvent.TYPE, e -> ai.recomputePath());
this.ai = ai;
return this;
}
public Enemy defaultAI() {
var ai = new WeaponBasedAI(this, DemoRunner.instance().getPlayer());
addEventListener(MoveEvent.TYPE, ai::recomputePath);
addEventListener(EnemyDiedEvent.TYPE, e -> ai.recomputePath());
this.ai = ai;
return this;
}
}

View File

@@ -0,0 +1,102 @@
package com.bartlomiejpluta.demo.entity;
import DB.model.FriendModel;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.context.ContextHolder;
import com.bartlomiejpluta.base.lib.ai.FollowPathAI;
import com.bartlomiejpluta.base.lib.ai.NoopAI;
import com.bartlomiejpluta.base.lib.ai.RandomMovementAI;
import com.bartlomiejpluta.base.util.path.Path;
import com.bartlomiejpluta.base.util.random.DiceRoller;
import com.bartlomiejpluta.demo.world.item.Item;
import lombok.Getter;
import lombok.NonNull;
import org.joml.Vector2ic;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public class Friend extends Creature implements NPC {
@Getter
private AI strategy = NoopAI.INSTANCE;
private AI priorStrategy;
private boolean interacting;
@Getter
private final String name;
@Getter
private final int dialogNameColor;
private Function<Friend, CompletableFuture<Object>> interaction;
public Friend(@NonNull String id) {
this(DB.dao.friend.find(id));
}
public Friend(@NonNull FriendModel template) {
super(ContextHolder.INSTANCE.getContext().createCharacter(A.charsets.byName(template.getCharset()).$));
name = template.getName();
setSpeed(DiceRoller.roll(template.getSpeed()) / 10f);
setBlocking(template.isBlocking());
dialogNameColor = Integer.parseInt(template.getDialogColor(), 16);
}
@Override
public void removeItemFromEquipment(Item item) {
}
public CompletableFuture<Object> interact(Character trigger) {
if (interaction != null && !interacting) {
setFaceDirection(getDirectionTowards(trigger));
var movement = getMovement();
if (movement != null) {
movement.abort();
}
priorStrategy = strategy;
strategy = NoopAI.INSTANCE;
interacting = true;
return interaction.apply(this).thenApply(o -> {
strategy = priorStrategy;
interacting = false;
return o;
});
}
return CompletableFuture.completedFuture(null);
}
public Friend interaction(Function<Friend, CompletableFuture<Object>> interaction) {
this.interaction = interaction;
return this;
}
public Friend followPath(@NonNull Path<Friend> path) {
var ai = new FollowPathAI<>(this);
ai.setPath(path);
this.strategy = ai;
return this;
}
public Friend followPath(@NonNull Function<Friend, Path<Friend>> pathSupplier) {
var ai = new FollowPathAI<>(this);
ai.setPath(pathSupplier.apply(this));
this.strategy = ai;
return this;
}
public Friend randomMovementAI(float intervalSeconds, Vector2ic origin, int radius) {
this.strategy = new RandomMovementAI<>(this, intervalSeconds, origin, radius);
return this;
}
public Friend randomMovementAI(float intervalSeconds) {
this.strategy = new RandomMovementAI<>(this, intervalSeconds);
return this;
}
}

View File

@@ -0,0 +1,40 @@
package com.bartlomiejpluta.demo.entity;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.context.ContextHolder;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import lombok.Getter;
import lombok.NonNull;
import java.util.concurrent.CompletableFuture;
import static java.util.concurrent.CompletableFuture.completedFuture;
public abstract class MapObject extends com.bartlomiejpluta.base.util.world.MapObject {
protected final Context context;
protected final DemoRunner runner;
@Getter
private final String name;
private final String interactSound;
public MapObject(@NonNull String id) {
this(DB.dao.object.find(id));
}
public MapObject(@NonNull DB.model.ObjectModel template) {
super(ContextHolder.INSTANCE.getContext().createCharacter(A.charsets.byName(template.getCharset()).$), template.getFrame());
this.context = ContextHolder.INSTANCE.getContext();
this.runner = DemoRunner.instance();
this.name = template.getName();
this.interactSound = A.sounds.byName(template.getInteractSound()).$;
}
@Override
protected @NonNull CompletableFuture<?> onInteractionBegin() {
if (interactSound != null) {
context.playSound(interactSound);
}
return completedFuture(null);
}
}

View File

@@ -0,0 +1,48 @@
package com.bartlomiejpluta.demo.entity;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.context.ContextHolder;
import com.bartlomiejpluta.base.lib.animation.AnimationRunner;
import com.bartlomiejpluta.base.lib.animation.SimpleAnimationRunner;
import com.bartlomiejpluta.base.lib.character.CharacterDelegate;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import lombok.NonNull;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public abstract class NamedCharacter extends CharacterDelegate {
protected final Context context;
protected final DemoRunner runner;
public NamedCharacter(Character character) {
super(character);
this.context = ContextHolder.INSTANCE.getContext();
this.runner = DemoRunner.instance();
}
public abstract String getName();
public int getDialogNameColor() {
return 0xFFFFFF;
}
public CompletableFuture<Void> runEmoji(@NonNull String animation) {
return runEmoji(animation, null);
}
public CompletableFuture<Void> runEmoji(@NonNull String animation, Consumer<SimpleAnimationRunner> customizer) {
var runner = AnimationRunner
.simple(animation)
.scale(0.4f)
.animationSpeed(1.6f)
.offset(0, -30);
if (customizer != null) {
customizer.accept(runner);
}
return runner.run(context, this);
}
}

View File

@@ -1,12 +1,259 @@
package com.bartlomiejpluta.demo.entity;
import lombok.*;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.util.random.DiceRoller;
import com.bartlomiejpluta.demo.world.item.Item;
import com.bartlomiejpluta.demo.world.item.ItemStack;
import com.bartlomiejpluta.demo.world.weapon.Ammunition;
import com.bartlomiejpluta.demo.world.weapon.ThrowingWeapon;
import com.bartlomiejpluta.demo.world.weapon.Weapon;
import lombok.NonNull;
import org.joml.Vector2i;
public class Player extends Character {
import java.util.Arrays;
public Player(@NonNull Context context, @NonNull Entity entity) {
super(context, entity);
}
public class Player extends Creature {
public static final int EQUIPMENT_SIZE = 6 * 6;
private final Item[] equipment = new Item[EQUIPMENT_SIZE];
private int interactionCooldown = 0;
public Player(@NonNull Character entity) {
super(entity);
reset();
}
public void reset() {
var data = DB.dao.levels.find(1);
this.maxHp = DiceRoller.roll(data.getMaxHp());
this.hp = this.maxHp;
alive = true;
changeCharacterSet(A.charsets.luna.$);
setScale(1f);
setSpeed(4f);
setAnimationSpeed(1f);
setBlocking(true);
var light = context.createLight();
light.setAttenuation(4f, 0, 0.001f);
light.setIntensity(1f, 1f, 1f);
setLight(light);
Arrays.fill(equipment, null);
}
public void interact() {
if (interactionCooldown > 0) {
return;
}
var coords = getCoordinates().add(getFaceDirection().vector, new Vector2i());
var entities = getLayer().getEntities();
for (var i = 0; i < entities.size(); ++i) {
var entity = entities.get(i);
if (entity.getCoordinates().equals(coords)) {
// Use some map object which player is looking at
if(entity instanceof MapObject object) {
object.triggerInteraction();
return;
}
// Interact with friend creature which player is looking at
if(entity instanceof Friend friend) {
friend.interact(this).thenApply(o -> interactionCooldown = INTERACTION_COOLDOWN);
return;
}
}
if (entity.getCoordinates().equals(getCoordinates())) {
// Pick some item from the ground
if (entity instanceof Item item) {
pushItemToEquipment(item);
getLayer().removeEntity(item);
interactionCooldown = INTERACTION_COOLDOWN;
return;
}
// Search the enemy corpse
if (entity instanceof Enemy enemy && !enemy.isAlive()) {
runner.getGuiManager().openLootWindow(enemy);
interactionCooldown = INTERACTION_COOLDOWN;
return;
}
}
}
}
public boolean pushItemToEquipment(@NonNull Item item) {
if (item instanceof Ammunition ammo) {
if (getAmmunition() != null && ammo.getId().equals(getAmmunition().getId())) {
getAmmunition().increase(ammo.getCount());
return true;
}
}
if (item instanceof ThrowingWeapon weapons) {
if (getWeapon() instanceof ThrowingWeapon currentWeapons && currentWeapons.getId().equals(weapons.getId())) {
currentWeapons.increase(weapons.getCount());
return true;
}
}
if (item instanceof ItemStack stack) {
return pushItemStackToEquipment(stack);
}
return pushSingleItemToEquipment(item);
}
private boolean pushItemStackToEquipment(@NonNull ItemStack items) {
var availableSlot = -1;
for (int i = 0; i < equipment.length; ++i) {
if (equipment[i] instanceof ItemStack stack && stack.getId().equals(items.getId())) {
stack.increase(items.getCount());
return true;
}
if (availableSlot == -1 && equipment[i] == null) {
availableSlot = i;
}
}
if (availableSlot > -1) {
equipment[availableSlot] = items;
return true;
}
return false;
}
private boolean pushSingleItemToEquipment(@NonNull Item item) {
for (int i = 0; i < equipment.length; ++i) {
if (equipment[i] == null) {
equipment[i] = item;
return true;
}
}
return false;
}
public Item getEquipmentItem(int index) {
return equipment[index];
}
@Override
public void removeItemFromEquipment(@NonNull Item item) {
for (int i = 0; i < equipment.length; ++i) {
if (equipment[i] == item) {
equipment[i] = null;
return;
}
}
}
public void dropItemFromEquipment(@NonNull Item item) {
removeItemFromEquipment(item);
item.setCoordinates(getCoordinates());
getLayer().addEntity(item);
if (item == getWeapon()) {
setWeapon(null);
}
if (item == getAmmunition()) {
setAmmunition(null);
}
}
@Override
public void setWeapon(Weapon newWeapon) {
var currentWeapon = getWeapon();
if (newWeapon == null) {
disarmWeapon(currentWeapon);
return;
}
if (currentWeapon instanceof ThrowingWeapon currentWeapons && newWeapon instanceof ThrowingWeapon weapons && currentWeapons.getId().equals(weapons.getId())) {
updateStackableWeapon(currentWeapons, weapons);
return;
}
changeWeaponForWeapon(currentWeapon, newWeapon);
}
private void disarmWeapon(Weapon currentWeapon) {
if (!(currentWeapon instanceof ThrowingWeapon)) {
pushItemToEquipment(currentWeapon);
}
super.setWeapon(null);
}
private void updateStackableWeapon(ThrowingWeapon currentWeapon, ThrowingWeapon newWeapon) {
currentWeapon.increase(newWeapon.getCount());
removeItemFromEquipment(newWeapon);
}
private void changeWeaponForWeapon(Weapon currentWeapon, Weapon newWeapon) {
super.setWeapon(newWeapon);
removeItemFromEquipment(newWeapon);
if (currentWeapon != null) {
pushItemToEquipment(currentWeapon);
}
}
@Override
public void setAmmunition(Ammunition ammunition) {
var currentAmmo = getAmmunition();
if (currentAmmo != null && currentAmmo.getId().equals(ammunition.getId())) {
currentAmmo.increase(ammunition.getCount());
removeItemFromEquipment(ammunition);
return;
}
if (ammunition != null) {
removeItemFromEquipment(ammunition);
}
if (currentAmmo != null) {
pushItemToEquipment(currentAmmo);
}
super.setAmmunition(ammunition);
}
@Override
public void die() {
super.die();
runner.returnToStartMenu();
}
@Override
public String getName() {
return "Luna";
}
@Override
public int getDialogNameColor() {
return 0x00AA00;
}
@Override
public void update(float dt) {
super.update(dt);
if (interactionCooldown > 0) {
interactionCooldown = (int) Math.max(0, interactionCooldown - dt * 1000);
}
}
private static final int INTERACTION_COOLDOWN = 300;
}

View File

@@ -0,0 +1,20 @@
package com.bartlomiejpluta.demo.event;
import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.lib.event.BaseEvent;
import com.bartlomiejpluta.demo.entity.Enemy;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class EnemyDiedEvent extends BaseEvent {
public static final EventType<EnemyDiedEvent> TYPE = new EventType<>("ENEMY_DIED_EVENT");
private final Enemy enemy;
@Override
public EventType<EnemyDiedEvent> getType() {
return TYPE;
}
}

View File

@@ -0,0 +1,22 @@
package com.bartlomiejpluta.demo.event;
import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.lib.event.BaseEvent;
import com.bartlomiejpluta.demo.entity.Creature;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class HitEvent extends BaseEvent {
public static final EventType<HitEvent> TYPE = new EventType<>("HIT_EVENT");
private final Creature attacker;
private final Creature target;
private final int damage;
@Override
public EventType<HitEvent> getType() {
return TYPE;
}
}

View File

@@ -0,0 +1,69 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.Color;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.lib.gui.BaseComponent;
import lombok.NonNull;
import java.util.Map;
public class Bar extends BaseComponent {
private final Color stroke;
private final Color fill;
private float value = 1.0f;
private float actualValue = 1.0f;
private final float speed = 0.05f;
public Bar(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
this.stroke = gui.createColor();
this.fill = gui.createColor();
stroke.setAlpha(1f);
fill.setAlpha(1f);
}
public void setValue(@NonNull Float value) {
this.value = value;
}
public void setStrokeColor(Integer hex) {
stroke.setRGB(hex);
}
public void setFillColor(Integer hex) {
fill.setRGB(hex);
}
@Override
public float getContentWidth() {
return width;
}
@Override
public float getContentHeight() {
return height;
}
@Override
public void draw(Screen screen, GUI gui) {
var remainingDistance = value - actualValue;
actualValue += remainingDistance * speed;
gui.beginPath();
gui.drawRectangle(x + paddingLeft, y + paddingTop, Math.max(width * actualValue, 0), height);
gui.setFillColor(fill);
gui.fill();
gui.closePath();
gui.beginPath();
gui.drawRectangle(x + paddingLeft, y + paddingTop, width, height);
gui.setStrokeColor(stroke);
gui.stroke();
gui.closePath();
}
}

View File

@@ -1,47 +1,54 @@
package com.bartlomiejpluta.demo.gui;
import lombok.*;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.Color;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.input.KeyAction;
import com.bartlomiejpluta.base.api.input.KeyEvent;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.api.input.*;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.*;
import com.bartlomiejpluta.base.lib.gui.Label;
import com.bartlomiejpluta.base.lib.gui.TextAlignment;
import lombok.Setter;
import java.util.Map;
public class Button extends Label {
private Color color;
private final Color color;
@Setter
private Runnable action;
@Setter
private Runnable action;
public Button(Context context, GUI gui) {
super(context, gui);
this.color = gui.createColor();
this.color.setRGBA(1, 1, 1, 0);
public Button(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
this.color = gui.createColor();
this.color.setRGBA(1, 1, 1, 0);
setText("");
setFontSize(17f);
setAlignment(GUI.ALIGN_TOP | GUI.ALIGN_CENTER);
setColor(0.4f, 0.7f, 0.0f, 1f);
setPadding(10f);
addEventListener(KeyEvent.TYPE, this::handleKeyEvent);
}
setText("");
setFontSize(17f);
setAlignment(TextAlignment.TOP, TextAlignment.CENTER);
setColor(0.4f, 0.7f, 0.0f, 1f);
setPadding(10f);
addEventListener(KeyEvent.TYPE, this::handleKeyEvent);
}
private void handleKeyEvent(KeyEvent event) {
if(event.getKey() == Key.KEY_ENTER && event.getAction() == KeyAction.PRESS && action != null) {
event.consume();
action.run();
}
}
private void handleKeyEvent(KeyEvent event) {
if (event.getKey() == Key.KEY_ENTER && event.getAction() == KeyAction.PRESS && action != null) {
event.consume();
action.run();
}
}
@Override
public void draw(Screen screen, GUI gui) {
color.setAlpha(focused ? 0.7f : 0f);
@Override
public void draw(Screen screen, GUI gui) {
color.setAlpha(focused ? 0.7f : 0f);
gui.beginPath();
gui.drawRectangle(x, y, getWidth(), getHeight());
gui.setFillColor(color);
gui.fill();
gui.beginPath();
gui.drawRectangle(x, y, getWidth(), getHeight());
gui.setFillColor(color);
gui.fill();
super.draw(screen, gui);
}
super.draw(screen, gui);
}
}

View File

@@ -1,35 +1,40 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.Color;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.api.gui.Paint;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.*;
import com.bartlomiejpluta.base.lib.gui.BaseWindow;
public abstract class DecoratedWindow extends BaseWindow {
private Paint paint;
private Color inner;
private Color outer;
import java.util.Map;
public DecoratedWindow(Context context, GUI gui) {
super(context, gui);
public class DecoratedWindow extends BaseWindow {
private final Paint paint;
private final Color inner;
private final Color outer;
this.inner = gui.createColor();
this.outer = gui.createColor();
this.paint = gui.createPaint();
public DecoratedWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
inner.setRGBA(0.1f, 0.1f, 0.1f, 1f);
outer.setRGBA(0.2f, 0.2f, 0.2f, 1f);
}
this.inner = gui.createColor();
this.outer = gui.createColor();
this.paint = gui.createPaint();
@Override
public void draw(Screen screen, GUI gui) {
gui.beginPath();
gui.drawRectangle(x, y, getWidth(), getHeight());
gui.setFillPaint(paint);
gui.boxGradient(x, y, getWidth(), getHeight(), 10f, 100f, inner, outer, paint);
gui.fill();
gui.stroke();
inner.setRGBA(0.1f, 0.1f, 0.1f, 1f);
outer.setRGBA(0.2f, 0.2f, 0.2f, 1f);
}
super.draw(screen, gui);
}
@Override
public void draw(Screen screen, GUI gui) {
gui.beginPath();
gui.drawRectangle(x, y, getWidth(), getHeight());
gui.setFillPaint(paint);
gui.boxGradient(x, y, getWidth(), getHeight(), 10f, 100f, inner, outer, paint);
gui.fill();
gui.stroke();
super.draw(screen, gui);
}
}

View File

@@ -0,0 +1,54 @@
package com.bartlomiejpluta.demo.gui;
import A.fonts;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.TextView;
import com.bartlomiejpluta.base.lib.gui.VOptionChoice;
import java.util.Collections;
import java.util.Map;
public class DialogChoiceWindow extends DecoratedWindow {
@Ref("speaker")
private TextView speaker;
@Ref("choice")
private VOptionChoice choice;
@SuppressWarnings("unchecked")
@Override
public void onOpen(WindowManager manager, Object[] args) {
super.onOpen(manager, args);
speaker.setText((String) args[0]);
speaker.setColor((int) args[1]);
var index = 0;
choice.removeAllChildren();
var options = (String[]) args[2];
for(var option : options) {
var button = new Button(context, gui, Collections.emptyMap());
choice.add(button);
button.setText(option);
button.setColor(0xFFFFFF);
button.setWidthMode(SizeMode.RELATIVE);
button.setWidth(1f);
button.setFont(fonts.roboto_regular.$);
button.setFontSize(20f);
button.setAction(onChoose(index));
++index;
}
choice.focus();
}
private Runnable onChoose(int index) {
return () -> resolve(index);
}
public DialogChoiceWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
}
}

View File

@@ -0,0 +1,66 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.input.KeyAction;
import com.bartlomiejpluta.base.api.input.KeyEvent;
import com.bartlomiejpluta.base.lib.gui.PrintedTextView;
import com.bartlomiejpluta.base.lib.gui.TextView;
import java.util.Map;
public class DialogWindow extends DecoratedWindow {
@Ref("speaker")
private TextView speaker;
@Ref("message")
private PrintedTextView text;
public DialogWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
addEventListener(KeyEvent.TYPE, this::handleKey);
}
private void handleKey(KeyEvent event) {
if (event.getKey() == Key.KEY_ESCAPE) {
event.consume();
return;
}
if (event.getKey() == Key.KEY_ENTER && event.getAction() == KeyAction.PRESS) {
if (text.isPrinting()) {
text.printAll();
event.consume();
return;
}
manager.close();
event.consume();
}
}
@Override
public void onOpen(WindowManager manager, Object[] args) {
super.onOpen(manager, args);
speaker.setText((String) args[0]);
speaker.setColor((int) args[1]);
text.setText((String) args[2]);
if (args.length > 3) {
setWindowPosition((WindowPosition) args[3]);
}
text.start();
}
@Override
public void onClose(WindowManager manager) {
super.onClose(manager);
text.setText("");
}
}

View File

@@ -0,0 +1,202 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.input.KeyAction;
import com.bartlomiejpluta.base.api.input.KeyEvent;
import com.bartlomiejpluta.base.lib.gui.HOptionChoice;
import com.bartlomiejpluta.base.lib.gui.Label;
import com.bartlomiejpluta.base.lib.gui.VGridOptionChoice;
import com.bartlomiejpluta.base.lib.gui.VOptionChoice;
import com.bartlomiejpluta.demo.entity.Player;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import com.bartlomiejpluta.demo.world.item.Item;
import com.bartlomiejpluta.demo.world.item.Useable;
import com.bartlomiejpluta.demo.world.potion.Medicament;
import com.bartlomiejpluta.demo.world.weapon.MeleeWeapon;
import com.bartlomiejpluta.demo.world.weapon.RangedWeapon;
import com.bartlomiejpluta.demo.world.weapon.ThrowingWeapon;
import java.util.Map;
import java.util.function.BiConsumer;
import static java.lang.String.format;
public class EquipmentWindow extends DecoratedWindow {
private final Player player;
private final Window popupMenuWindow;
private final Button useBtn;
private final Button dropBtn;
private final Button cancelBtn;
private final VOptionChoice popupMenu;
@Ref("layout")
private HOptionChoice layout;
@Ref("equipment")
private VGridOptionChoice equipment;
@Ref("inventory")
private VGridOptionChoice inventory;
@Ref("weapon")
private ItemIconView weaponSlot;
@Ref("ammo")
private ItemIconView ammoSlot;
@Ref("item-name")
private Label nameLbl;
@Ref("item-details")
private Label detailsLbl;
public EquipmentWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
this.player = DemoRunner.instance().getPlayer();
this.popupMenuWindow = gui.inflateWindow(A.widgets.eq_item_menu.$);
this.popupMenu = popupMenuWindow.reference("menu", VOptionChoice.class);
this.useBtn = popupMenuWindow.reference("use", Button.class);
this.dropBtn = popupMenuWindow.reference("drop", Button.class);
this.cancelBtn = popupMenuWindow.reference("cancel", Button.class);
addEventListener(KeyEvent.TYPE, this::handleKey);
}
private void handleKey(KeyEvent event) {
if (event.getKey() == Key.KEY_TAB && event.getAction() == KeyAction.PRESS) {
layout.selectNext();
layout.focus();
updateItemDetails(((VGridOptionChoice) layout.getSelectedComponent()).getSelectedComponent());
event.consume();
}
}
@Override
public void onOpen(WindowManager manager, Object... args) {
super.onOpen(manager, args);
cancelBtn.setAction(manager::close);
inventory.setOnSelect(this::updateItemDetails);
equipment.setOnSelect(this::updateItemDetails);
updateEquipment();
layout.select(1);
layout.focus();
}
@Override
public void onClose(WindowManager manager) {
super.onClose(manager);
layout.blur();
}
private void updateEquipment() {
var i = 0;
for (var child : inventory.getChildren()) {
var slot = (ItemIconView) child;
slot.setItem(player.getEquipmentItem(i++));
slot.setAction(this::handleInventoryClick);
}
weaponSlot.setItem(player.getWeapon());
weaponSlot.setAction(handleEquipmentClick(() -> {
player.setWeapon(null);
updateEquipment();
manager.close();
}));
ammoSlot.setItem(player.getAmmunition());
ammoSlot.setAction(handleEquipmentClick(() -> {
player.setAmmunition(null);
updateEquipment();
manager.close();
}));
}
private BiConsumer<ItemIconView, Item> handleEquipmentClick(Runnable deequip) {
return (slot, item) -> {
useBtn.setText("Disarm");
popupMenu.select(0);
popupMenu.focus();
manager.open(popupMenuWindow);
useBtn.setAction(deequip);
dropBtn.setAction(() -> {
player.dropItemFromEquipment(item);
slot.setItem(null);
updateItemDetails(slot);
manager.close();
});
};
}
private void handleInventoryClick(ItemIconView slot, Item item) {
useBtn.setText(getButtonTitle(item));
popupMenu.select(0);
popupMenu.focus();
manager.open(popupMenuWindow);
if (item instanceof Useable useable) {
useBtn.setAction(() -> {
useable.use(player);
updateEquipment();
manager.close();
});
}
dropBtn.setAction(() -> {
player.dropItemFromEquipment(item);
slot.setItem(null);
updateItemDetails(slot);
manager.close();
});
}
private void updateItemDetails(Component slot) {
var item = ((ItemIconView) slot).getItem();
if (item == null) {
nameLbl.setText("");
detailsLbl.setText("");
return;
}
nameLbl.setText(item.getName());
detailsLbl.setText("");
if (item instanceof MeleeWeapon weapon) {
detailsLbl.setText(format("Damage: %s\nCooldown: %s\n", weapon.getDmgRoller(), weapon.getCooldown()));
return;
}
if (item instanceof RangedWeapon weapon) {
detailsLbl.setText(format("Damage: %s\nRange: %s\nCooldown: %s\n", weapon.getDmgRoller(), weapon.getRangeRoller(), weapon.getCooldown()));
return;
}
if (item instanceof ThrowingWeapon weapon) {
detailsLbl.setText(format("Damage: %s\nRange: %s\nCooldown: %s\n", weapon.getDmgRoller(), weapon.getRangeRoller(), weapon.getCooldown()));
}
if (item instanceof Medicament medicament) {
detailsLbl.setText(format("Restores: %s HP\n", medicament.getRoller()));
}
}
private String getButtonTitle(Item item) {
if (item instanceof Useable useable) {
return useable.usageName();
}
return "Use";
}
}

View File

@@ -1,32 +1,28 @@
package com.bartlomiejpluta.demo.gui;
import lombok.*;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.*;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.api.gui.Ref;
import com.bartlomiejpluta.base.api.gui.WindowManager;
import com.bartlomiejpluta.base.lib.gui.VOptionChoice;
import java.util.Map;
public class GameMenuWindow extends DecoratedWindow implements Inflatable {
public class GameMenuWindow extends DecoratedWindow {
@Ref("resume_game")
@Getter
private Button resumeGameBtn;
@Ref("menu")
private VOptionChoice menu;
@Ref("start_menu")
@Getter
private Button startMenuBtn;
public GameMenuWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
}
@Ref("exit")
@Getter
private Button exitBtn;
public GameMenuWindow(Context context, GUI gui) {
super(context, gui);
}
@Override
public void onInflate() {
resumeGameBtn.focus();
}
@Override
public void onOpen(WindowManager manager, Object[] args) {
super.onOpen(manager, args);
menu.select(0);
menu.focus();
}
}

View File

@@ -0,0 +1,90 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.api.gui.Ref;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.lib.gui.BorderLayout;
import com.bartlomiejpluta.base.lib.gui.Label;
import com.bartlomiejpluta.base.lib.gui.TextView;
import com.bartlomiejpluta.demo.entity.Player;
import com.bartlomiejpluta.demo.event.EnemyDiedEvent;
import com.bartlomiejpluta.demo.event.HitEvent;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import com.bartlomiejpluta.demo.util.LimitedQueue;
import com.bartlomiejpluta.demo.world.time.WorldTime;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class HUD extends BorderLayout {
private static final int MAX_LOG_SIZE = 10;
private static final float LOG_VISIBILITY_DURATION = 8000f;
private static final float LOG_VISIBILITY_FADING_OUT = 1000f;
private final Player player;
private final WorldTime time;
private final Runtime runtime;
private final LimitedQueue<String> logger = new LimitedQueue<>(MAX_LOG_SIZE);
private float logVisibilityDuration = 0f;
@Ref("hp")
private Bar hp;
@Ref("debug")
private TextView debugTxt;
@Ref("log")
private Label logLbl;
public HUD(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
this.player = DemoRunner.instance().getPlayer();
this.runtime = Runtime.getRuntime();
this.time = DemoRunner.instance().getTime();
context.addEventListener(HitEvent.TYPE, this::logHitEvent);
context.addEventListener(EnemyDiedEvent.TYPE, this::logEnemyDiedEvent);
}
private void logHitEvent(HitEvent event) {
log(String.format("%s hits %s with damage = %d", event.getAttacker().getName(), event.getTarget().getName(), event.getDamage()));
}
private void log(String message) {
logger.add(message);
log.info(message);
logLbl.setText(logger.stream().collect(Collectors.joining("\n")));
logVisibilityDuration = LOG_VISIBILITY_DURATION;
}
private void logEnemyDiedEvent(EnemyDiedEvent event) {
log(String.format("%s has died with HP = %d", event.getEnemy().getName(), event.getEnemy().getHp()));
}
@Override
public void update(float dt) {
super.update(dt);
hp.setValue((float) player.getHp() / (float) player.getMaxHp());
if (logVisibilityDuration > 0) {
logVisibilityDuration -= dt * 1000;
} else {
logVisibilityDuration = 0;
}
}
@Override
public void draw(Screen screen, GUI gui) {
var coords = player.getCoordinates();
var pos = player.getPosition();
debugTxt.setText(String.format("Clock: %02d:%02d\nTime: %.2f\nMem: %.2f / %.2f [MB]\nCoords: %d : %d\nPos: %.2f : %.2f\nEntities: %d\n", time.getHour(), time.getMinute(), time.getProgress(), runtime.totalMemory() / 1024f / 1024f, runtime.maxMemory() / 1024f / 1024f, coords.x(), coords.y(), pos.x(), pos.y(), player.getLayer().getEntities().size()));
logLbl.setAlpha(Math.min(1f, logVisibilityDuration / LOG_VISIBILITY_FADING_OUT));
super.draw(screen, gui);
}
}

View File

@@ -0,0 +1,132 @@
package com.bartlomiejpluta.demo.gui;
import A.fonts;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.api.icon.Icon;
import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.input.KeyAction;
import com.bartlomiejpluta.base.api.input.KeyEvent;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.lib.gui.IconView;
import com.bartlomiejpluta.demo.util.IconUtil;
import com.bartlomiejpluta.demo.world.item.Item;
import com.bartlomiejpluta.demo.world.item.ItemStack;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import java.util.Map;
import java.util.function.BiConsumer;
public class ItemIconView extends IconView {
private final GUI gui;
private final Color normal;
private final Color hover;
private final Color textColor;
@Getter
private Item item;
private IconSet placeholderIconSet;
private Paint placeholderIconPaint;
private int placeholderIconSetRow;
private int placeholderIconSetColumn;
@Setter
private BiConsumer<ItemIconView, Item> action;
public ItemIconView(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
this.gui = gui;
this.normal = gui.createColor();
this.hover = gui.createColor();
this.textColor = gui.createColor();
normal.setRGBA(0x444444FF);
hover.setRGBA(0x888888FF);
textColor.setRGBA(0xFFFFFFFF);
super.setScale(2f);
addEventListener(KeyEvent.TYPE, this::handleKeyEvent);
}
public void setItem(Item item) {
this.item = item;
super.setIcon(item);
}
@Override
public void setIcon(Icon icon) {
throw new UnsupportedOperationException();
}
@Override
public void setIconSet(String iconSetUid) {
throw new UnsupportedOperationException();
}
@Override
public void setIconSetRow(@NonNull Integer iconSetRow) {
throw new UnsupportedOperationException();
}
@Override
public void setIconSetColumn(@NonNull Integer iconSetColumn) {
throw new UnsupportedOperationException();
}
@Attribute(value = "placeholder", separator = ",")
public void setPlaceholderIcon(String icon, int row, int column) {
this.placeholderIconPaint = gui.createPaint();
this.placeholderIconSet = gui.getIconSet(A.iconsets.byName(icon).$);
this.placeholderIconSetRow = row;
this.placeholderIconSetColumn = column;
}
private void handleKeyEvent(KeyEvent event) {
if (event.getKey() == Key.KEY_ENTER && event.getAction() == KeyAction.PRESS && item != null && action != null) {
event.consume();
action.accept(this, item);
}
}
@Override
protected float getContentWidth() {
return 68f;
}
@Override
protected float getContentHeight() {
return 68f;
}
@Override
public void draw(Screen screen, GUI gui) {
gui.beginPath();
gui.drawRectangle(x, y, getWidth(), getHeight());
gui.setFillColor(focused ? hover : normal);
gui.fill();
gui.closePath();
if (item == null && placeholderIconSet != null) {
gui.icon(this.x, this.y, 2, 2, 0, 0.2f, placeholderIconSet, placeholderIconSetRow, placeholderIconSetColumn, placeholderIconPaint);
return;
}
super.draw(screen, gui);
if (item != null && item instanceof ItemStack stack) {
gui.beginPath();
gui.setFontFace(fonts.roboto_regular.$);
gui.setFontSize(17);
gui.putText(x + 15, y + 5, String.valueOf(stack.getCount()));
gui.setFillColor(textColor);
gui.fill();
gui.closePath();
}
}
}

View File

@@ -0,0 +1,89 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.Label;
import com.bartlomiejpluta.base.lib.gui.VGridOptionChoice;
import com.bartlomiejpluta.demo.entity.Enemy;
import com.bartlomiejpluta.demo.entity.Player;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import com.bartlomiejpluta.demo.world.item.Item;
import java.util.Map;
public class LootWindow extends DecoratedWindow implements Inflatable {
private final Player player;
@Ref("title")
private Label titleLbl;
@Ref("loot")
private VGridOptionChoice lootMenu;
private Item[] loot;
private ItemIconView[] slots = new ItemIconView[Enemy.MAX_LOOT];
public LootWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
this.player = DemoRunner.instance().getPlayer();
}
@Override
public void onInflate() {
for (int i = 0; i < Enemy.MAX_LOOT; ++i) {
var itemView = new ItemIconView(context, gui, Map.of());
itemView.setMargin(5f);
lootMenu.add(itemView);
slots[i] = itemView;
itemView.setAction(this::handleClick);
}
}
@Override
public void onOpen(WindowManager manager, Object[] args) {
super.onOpen(manager, args);
this.loot = (Item[]) args[0];
this.titleLbl.setText((String) args[1]);
this.lootMenu.select(0, 0);
this.lootMenu.focus();
updateSlots();
}
@Override
public void onClose(WindowManager manager) {
super.onClose(manager);
clearSlots();
this.loot = null;
}
private void handleClick(ItemIconView slot, Item item) {
if (item == null) {
return;
}
if (player.pushItemToEquipment(item)) {
for (int i = 0; i < Enemy.MAX_LOOT; i++) {
if (loot[i] == item) {
loot[i] = null;
slot.setItem(null);
break;
}
}
}
}
private void updateSlots() {
for (int i = 0; i < Enemy.MAX_LOOT; ++i) {
slots[i].setItem(loot[i]);
}
}
private void clearSlots() {
for (var slot : slots) {
slot.setItem(null);
}
}
}

View File

@@ -0,0 +1,49 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.lib.gui.TextView;
import lombok.Setter;
import java.util.Map;
public class PrintTextView extends TextView {
@Setter
private Float duration;
private float acc;
private String originalText;
public void start() {
acc = 0f;
}
public boolean isPrinting() {
return originalText.length() != super.getText().length();
}
public void printAll() {
acc = originalText.length() * duration;
}
@Override
public void setText(String text) {
super.setText("");
this.originalText = text;
}
@Override
public void update(float dt) {
super.update(dt);
acc += dt;
super.setText(originalText.substring(0, Math.min(originalText.length(), (int) (acc / duration))));
}
public PrintTextView(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
}
}

View File

@@ -1,27 +1,27 @@
package com.bartlomiejpluta.demo.gui;
import lombok.*;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.*;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.api.gui.Ref;
import com.bartlomiejpluta.base.api.gui.WindowManager;
import com.bartlomiejpluta.base.lib.gui.VOptionChoice;
public class StartMenuWindow extends DecoratedWindow implements Inflatable {
import java.util.Map;
@Ref("new_game")
@Getter
private Button newGameBtn;
public class StartMenuWindow extends DecoratedWindow {
@Ref("exit")
@Getter
private Button exitBtn;
@Ref("menu")
private VOptionChoice menu;
public StartMenuWindow(Context context, GUI gui) {
super(context, gui);
}
public StartMenuWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
}
@Override
public void onInflate() {
newGameBtn.focus();
}
@Override
public void onOpen(WindowManager manager, Object[] args) {
super.onOpen(manager, args);
menu.select(0);
menu.focus();
}
}

View File

@@ -1,71 +1,175 @@
package com.bartlomiejpluta.demo.map;
import com.bartlomiejpluta.base.api.map.handler.MapHandler;
import com.bartlomiejpluta.base.api.map.model.GameMap;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.input.*;
import com.bartlomiejpluta.base.lib.camera.*;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.gui.WindowPosition;
import com.bartlomiejpluta.base.api.icon.Icon;
import com.bartlomiejpluta.base.api.input.Input;
import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.light.Light;
import com.bartlomiejpluta.base.api.map.handler.MapHandler;
import com.bartlomiejpluta.base.api.map.layer.object.MapPin;
import com.bartlomiejpluta.base.api.map.model.GameMap;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.lib.camera.CameraController;
import com.bartlomiejpluta.base.lib.camera.FollowingCameraController;
import com.bartlomiejpluta.base.util.input.InputUtil;
import com.bartlomiejpluta.base.util.world.CharacterSpawner;
import com.bartlomiejpluta.base.util.world.Warp;
import com.bartlomiejpluta.demo.entity.*;
import com.bartlomiejpluta.demo.event.EnemyDiedEvent;
import com.bartlomiejpluta.demo.menu.GuiManager;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import com.bartlomiejpluta.demo.entity.Player;
import com.bartlomiejpluta.demo.world.light.Torch;
import com.bartlomiejpluta.demo.world.potion.Medicament;
import lombok.NonNull;
import java.util.concurrent.CompletableFuture;
import static java.lang.Math.*;
public abstract class BaseMapHandler implements MapHandler {
protected Screen screen;
protected Context context;
protected DemoRunner runner;
protected Camera camera;
protected Player player;
protected ObjectLayer mainLayer;
protected CameraController cameraController;
protected Screen screen;
protected Context context;
protected DemoRunner runner;
protected GuiManager guiManager;
protected Camera camera;
protected GameMap map;
protected Player player;
protected CameraController cameraController;
@Override
public void onCreate(Context context, GameMap map) {
this.context = context;
this.screen = context.getScreen();
this.runner = (DemoRunner) context.getGameRunner();
this.camera = context.getCamera();
this.player = runner.getPlayer();
this.cameraController = FollowingCameraController
.on(screen, camera, map)
.follow(player.getPosition());
}
protected boolean dayNightCycle = false;
@Override
public void input(Input input) {
if(context.isPaused()) {
return;
}
protected boolean controls = true;
if(input.isKeyPressed(Key.KEY_LEFT_CONTROL)) {
if(input.isKeyPressed(Key.KEY_DOWN)) {
player.setFaceDirection(Direction.DOWN);
} else if(input.isKeyPressed(Key.KEY_UP)) {
player.setFaceDirection(Direction.UP);
} else if(input.isKeyPressed(Key.KEY_LEFT)) {
player.setFaceDirection(Direction.LEFT);
} else if(input.isKeyPressed(Key.KEY_RIGHT)) {
player.setFaceDirection(Direction.RIGHT);
}
} else {
if(input.isKeyPressed(Key.KEY_DOWN)) {
mainLayer.pushMovement(player.prepareMovement(Direction.DOWN));
} else if(input.isKeyPressed(Key.KEY_UP)) {
mainLayer.pushMovement(player.prepareMovement(Direction.UP));
} else if(input.isKeyPressed(Key.KEY_LEFT)) {
mainLayer.pushMovement(player.prepareMovement(Direction.LEFT));
} else if(input.isKeyPressed(Key.KEY_RIGHT)) {
mainLayer.pushMovement(player.prepareMovement(Direction.RIGHT));
}
}
}
@Override
public void onCreate(Context context, GameMap map) {
this.context = context;
this.screen = context.getScreen();
this.runner = DemoRunner.instance();
this.guiManager = runner.getGuiManager();
this.camera = context.getCamera();
this.map = map;
this.player = runner.getPlayer();
this.cameraController = FollowingCameraController
.on(screen, camera, map)
.follow(player.getPosition());
}
@Override
public void update(Context context, GameMap map, float dt) {
cameraController.update();
}
@Override
public void input(Input input) {
if (context.isPaused()) {
return;
}
if (guiManager.openedWindows() > 0) {
return;
}
if (input.isKeyPressed(Key.KEY_SPACE)) {
player.attack();
}
if (input.isKeyPressed(Key.KEY_ENTER)) {
player.interact();
}
if (!controls) {
return;
}
InputUtil.handleBasicControl(player, input);
}
@Override
public void update(Context context, GameMap map, float dt) {
cameraController.update();
if(!dayNightCycle) {
return;
}
var x = runner.getTime().getProgress();
map.setAmbientColor(
ambientColor(1.2f, -0.3f, 0, x),
ambientColor(1.4f, -0.6f, 0.05f, x),
ambientColor(1.7f, -1.1f, 0.2f, x)
);
}
private float ambientColor(float a, float b, float offset, float x) {
return ((float) max(sin(x * PI * a + b), 0) + offset) / (1 + offset);
}
public CompletableFuture<Object> dialog(NamedCharacter speaker, String message, WindowPosition position) {
return guiManager.showDialog(speaker.getName(), speaker.getDialogNameColor(), message, position);
}
public CompletableFuture<Object> dialog(NamedCharacter speaker, String message) {
return guiManager.showDialog(speaker.getName(), speaker.getDialogNameColor(), message, WindowPosition.BOTTOM);
}
public CompletableFuture<Integer> dialogChoice(NamedCharacter speaker, String... choices) {
return guiManager.showDialogChoice(speaker.getName(), speaker.getDialogNameColor(), choices);
}
protected <T extends Entity> T addEntity(T entity, MapPin tile) {
entity.setCoordinates(tile.getX(), tile.getY());
map.getObjectLayer(tile.getLayer()).addEntity(entity);
return entity;
}
public Enemy enemy(@NonNull MapPin tile, @NonNull String id) {
return addEntity(new Enemy(id), tile);
}
public Friend friend(@NonNull MapPin tile, @NonNull String id) {
return addEntity(new Friend(id), tile);
}
public Chest chest(@NonNull MapPin tile, @NonNull String id) {
return addEntity(new Chest(id), tile);
}
public Door door(@NonNull MapPin tile, @NonNull MapPin target, @NonNull String id) {
return addEntity(new Door(target, id), tile);
}
public CharacterSpawner spawner(@NonNull MapPin tile) {
return addEntity(new CharacterSpawner().trackEntities(EnemyDiedEvent.TYPE), tile);
}
public Medicament medicament(@NonNull MapPin tile, @NonNull String id, int count) {
return addEntity(new Medicament(id, count), tile);
}
public Icon icon(@NonNull MapPin tile, String iconSetUid, int row, int column) {
var icon = context.createIcon(iconSetUid, row, column);
icon.setScale(1f);
icon.setZIndex(-1);
return addEntity(icon, tile);
}
public Torch torch(MapPin tile) {
var torch = new Torch();
map.getLayer(tile.getLayer()).addLight(torch);
torch.setCoordinates(tile.toCoordinates());
return torch;
}
public Light light(MapPin tile) {
var light = context.createLight();
map.getLayer(tile.getLayer()).addLight(light);
light.setCoordinates(tile.toCoordinates());
light.setIntensity(1f, 1f, 1f);
light.setAttenuation(0.1f, 0, 0.001f);
return light;
}
public Warp warp(@NonNull MapPin tile, MapPin target) {
var warp = new Warp(target);
warp.setEntity(player);
return addEntity(warp, tile);
}
}

View File

@@ -0,0 +1,12 @@
package com.bartlomiejpluta.demo.map;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.map.model.GameMap;
public class ForrestHandler extends BaseMapHandler {
@Override
public void onCreate(Context context, GameMap map) {
super.onCreate(context, map);
dayNightCycle = true;
}
}

View File

@@ -1,17 +0,0 @@
package com.bartlomiejpluta.demo.map;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.input.Input;
import com.bartlomiejpluta.base.api.map.model.GameMap;
import com.bartlomiejpluta.base.api.screen.Screen;
public class ForrestTempleHandler extends BaseMapHandler {
public static final String UID = "f845355e-b9ad-4884-a217-dd3a4c18a3fa";
public static final int MAIN_LAYER = 4;
@Override
public void onCreate(Context context, GameMap map) {
super.onCreate(context, map);
this.mainLayer = map.getObjectLayer(MAIN_LAYER);
}
}

View File

@@ -0,0 +1,81 @@
package com.bartlomiejpluta.demo.map;
import A.animations;
import A.maps;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.map.model.GameMap;
import com.bartlomiejpluta.base.util.path.CharacterPath;
import com.bartlomiejpluta.base.util.pathfinder.AstarPathFinder;
import com.bartlomiejpluta.base.util.pathfinder.PathFinder;
import com.bartlomiejpluta.demo.entity.Friend;
import java.util.concurrent.CompletableFuture;
import static com.bartlomiejpluta.base.api.move.Direction.LEFT;
public class HeroHomeHandler extends BaseMapHandler {
private final PathFinder finder = new AstarPathFinder(100);
@Override
public void onCreate(Context context, GameMap map) {
super.onCreate(context, map);
map.setAmbientColor(0.05f, 0.01f, 0.01f);
}
protected CharacterPath<Friend> grandmaPath(Friend grandma) {
return new CharacterPath<Friend>()
.run(() -> controls = false)
.run(() -> player.runEmoji(A.animations.zzz.$, r -> r.repeat(5)))
.insertPath(finder.findPath(grandma.getLayer(), grandma, maps.hero_home.main.grandma_waking.toCoordinates()))
.wait(2f)
.turn(LEFT)
.wait(1f)
.suspend(() -> morningDialogWithGrandma(grandma))
.wait(1f)
.run(() -> controls = true)
.insertPath(finder.findPath(grandma.getLayer(), maps.hero_home.main.grandma_waking.toCoordinates(), maps.hero_home.main.grandma_origin.toCoordinates()))
.run(() -> grandma.randomMovementAI(4f, grandma.getCoordinates(), 4));
}
private CompletableFuture<Object> morningDialogWithGrandma(Friend grandma) {
return dialog(grandma, "Hello Honey, wake up, it's another beautiful day!")
.thenCompose(n -> dialog(player, "Ahhh, good morning Grandma!"))
.thenCompose(n -> dialog(grandma, "Have a wonderful day, Luna!"))
.thenCompose(n -> dialog(player, "Thank you Grandma, have a nice day too!"));
}
protected CompletableFuture<Object> triggerGrandmaDialog(Friend grandma) {
return dialog(grandma, "What are you going to do today, Luna?")
.thenCompose(n -> dialogChoice(player,
"I'm going to fix your roof, Grandma",
"I'd like to look for some hidden treasure around your house",
"I'm going to kill the Dekus outside",
"Hmm... I don't know yet..."
)).thenCompose(o -> dialog(grandma, switch (o) {
case 0 -> "Ohh, Luna! It would be amazing, thank you!";
case 1 -> "It seems you are going to have a wonderful adventure. Good luck!";
case 2 -> "Be careful! Dekus are capable to attack from a distance!";
case 3 -> "Hmm... our roof requires urgent fix... also there are some dangerous Dekus around our house...";
default -> null;
}).thenApply(n -> o))
.thenCompose(o -> dialog(player, switch (o) {
case 0 -> "You're welcome Grandma!";
case 1 -> "Thank you Grandma! Hopefully will found something interesting...";
case 2 -> "Oh, thanks. I believe I also would need to have some ranged weapon...";
case 3 -> "Okay, there is lot of things to be done then.";
default -> null;
}))
.thenCompose(n -> dialog(player, "Okay, I need to go. Thank you Grandma!"))
.thenCompose(n -> dialog(grandma, "Thank you Luna! Be careful!"));
}
protected CompletableFuture<Object> triggerNekoDialog(Friend neko) {
return dialog(player, "Ohhh, here you are Kitty...")
.thenCompose(n -> CompletableFuture.allOf(
player.runEmoji(animations.heart_emoji.$),
neko.runEmoji(animations.heart_emoji.$, r -> r.offset(0, -15).delay(100))
))
.thenCompose(n -> dialog(neko, "Meow, meow..."))
.thenCompose(n -> dialog(neko, "Purr, purr..."));
}
}

View File

@@ -0,0 +1,12 @@
package com.bartlomiejpluta.demo.map;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.map.model.GameMap;
public class HeroHouse extends BaseMapHandler {
@Override
public void onCreate(Context context, GameMap map) {
super.onCreate(context, map);
dayNightCycle = true;
}
}

View File

@@ -0,0 +1,133 @@
package com.bartlomiejpluta.demo.menu;
import A.widgets;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.input.KeyAction;
import com.bartlomiejpluta.base.api.input.KeyEvent;
import com.bartlomiejpluta.demo.entity.Chest;
import com.bartlomiejpluta.demo.entity.Enemy;
import com.bartlomiejpluta.demo.gui.*;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import lombok.NonNull;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class GuiManager {
private final DemoRunner runner;
private final Context context;
private final GUI gui;
private final WindowManager manager;
private final StartMenuWindow startMenu;
private final GameMenuWindow gameMenu;
private final EquipmentWindow equipment;
private final LootWindow loot;
private final DialogWindow dialog;
private final DialogChoiceWindow dialogChoice;
private final Consumer<KeyEvent> gameMenuHandler = this::handleGameMenuKeyEvent;
public GuiManager(@NonNull DemoRunner runner, @NonNull Context context) {
this.runner = runner;
this.context = context;
this.gui = context.newGUI();
this.manager = new WindowManager(context, DisplayMode.DISPLAY_TOP, UpdateMode.UPDATE_TOP);
this.gui.setRoot(this.manager);
this.startMenu = gui.inflateWindow(A.widgets.start_menu.$, StartMenuWindow.class);
this.startMenu.reference("new_game", Button.class).setAction(runner::newGame);
this.startMenu.reference("exit", Button.class).setAction(runner::exit);
this.equipment = gui.inflateWindow(A.widgets.equipment.$, EquipmentWindow.class);
this.gameMenu = gui.inflateWindow(A.widgets.game_menu.$, GameMenuWindow.class);
this.gameMenu.reference("resume_game", Button.class).setAction(this::resumeGame);
this.gameMenu.reference("equipment", Button.class).setAction(() -> manager.open(equipment));
this.gameMenu.reference("start_menu", Button.class).setAction(runner::returnToStartMenu);
this.gameMenu.reference("exit", Button.class).setAction(runner::exit);
this.dialog = gui.inflateWindow(A.widgets.dialog.$, DialogWindow.class);
this.dialogChoice = gui.inflateWindow(A.widgets.dialog_choice.$, DialogChoiceWindow.class);
this.loot = gui.inflateWindow(widgets.loot_menu.$, LootWindow.class);
}
private void handleGameMenuKeyEvent(KeyEvent event) {
if (event.getKey() == Key.KEY_E && event.getAction() == KeyAction.PRESS) {
if (manager.isEmpty()) {
manager.open(equipment);
} else if (manager.top() == equipment) {
manager.close();
}
event.consume();
}
if (event.getKey() == Key.KEY_ESCAPE && event.getAction() == KeyAction.PRESS) {
if (manager.size() > 0) {
manager.close();
} else {
manager.open(gameMenu);
context.pause();
}
if (manager.isEmpty()) {
context.resume();
}
event.consume();
}
}
public int openedWindows() {
return manager.size();
}
public CompletableFuture<Object> showStartMenu() {
manager.closeAll();
return manager.open(startMenu);
}
public void enableGameMenu() {
manager.closeAll();
context.getInput().addKeyEventHandler(gameMenuHandler);
manager.setDisplayMode(DisplayMode.DISPLAY_STACK);
}
public void disableGameMenu() {
context.getInput().removeKeyEventHandler(gameMenuHandler);
manager.setDisplayMode(DisplayMode.DISPLAY_TOP);
}
public CompletableFuture<Object> showDialog(@NonNull String speaker, int color, @NonNull String message, @NonNull WindowPosition position) {
return manager.open(dialog, speaker, color, message, position);
}
public CompletableFuture<Integer> showDialogChoice(@NonNull String speaker, int color, @NonNull String... choices) {
return manager.openForResult(Integer.class, dialogChoice, speaker, color, choices);
}
public CompletableFuture<Object> openLootWindow(@NonNull Enemy enemy) {
return manager.open(loot, enemy.getLoot(), "Loot");
}
public CompletableFuture<Object> openChestWindow(@NonNull Chest chest) {
return manager.open(loot, chest.getContent(), chest.getName());
}
public CompletableFuture<Object> openGameMenu() {
return manager.open(gameMenu);
}
public void closeAll() {
manager.closeAll();
}
private void resumeGame() {
manager.closeAll();
context.resume();
}
}

View File

@@ -1,88 +0,0 @@
package com.bartlomiejpluta.demo.menu;
import lombok.*;
import java.util.function.*;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.api.input.*;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.*;
import com.bartlomiejpluta.demo.runner.DemoRunner;
import com.bartlomiejpluta.demo.gui.*;
public class MenuManager {
private final DemoRunner runner;
private final Context context;
private final GUI gui;
private final WindowManager manager;
private final StartMenuWindow startMenu;
private final GameMenuWindow gameMenu;
private final Consumer<KeyEvent> gameMenuHandler = this::handleGameMenuKeyEvent;
public MenuManager(@NonNull DemoRunner runner, @NonNull Context context) {
this.runner = runner;
this.context = context;
this.gui = context.newGUI();
this.manager = new WindowManager(context, DisplayMode.DISPLAY_TOP, UpdateMode.UPDATE_TOP);
this.gui.setRoot(this.manager);
this.startMenu = (StartMenuWindow) gui.inflateWindow("ab9d40b4-eb28-45d7-bff2-9432a05eb41a");
this.startMenu.getNewGameBtn().setAction(runner::newGame);
this.startMenu.getExitBtn().setAction(runner::exit);
this.gameMenu = (GameMenuWindow) gui.inflateWindow("56ca6b39-f949-4212-9c23-312db25887e0");
this.gameMenu.getResumeGameBtn().setAction(this::resumeGame);
this.gameMenu.getStartMenuBtn().setAction(runner::returnToStartMenu);
this.gameMenu.getExitBtn().setAction(runner::exit);
}
private void handleGameMenuKeyEvent(KeyEvent event) {
if (event.getKey() == Key.KEY_ESCAPE && event.getAction() == KeyAction.PRESS) {
if(manager.size() > 0) {
manager.close();
} else {
manager.open(gameMenu);
}
if(manager.size() > 0) {
context.pause();
} else {
context.resume();
}
event.consume();
}
}
public void showStartMenu() {
manager.closeAll();
manager.open(startMenu);
}
public void enableGameMenu() {
manager.closeAll();
context.getInput().addKeyEventHandler(gameMenuHandler);
manager.setDisplayMode(DisplayMode.DISPLAY_STACK);
}
public void disableGameMenu() {
context.getInput().removeKeyEventHandler(gameMenuHandler);
manager.setDisplayMode(DisplayMode.DISPLAY_TOP);
}
public void closeAll() {
manager.closeAll();
}
private void resumeGame() {
manager.closeAll();
context.resume();
}
}

View File

@@ -1,100 +1,128 @@
package com.bartlomiejpluta.demo.runner;
import lombok.*;
import DB.dao;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.api.runner.GameRunner;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.demo.entity.Player;
import com.bartlomiejpluta.demo.menu.GuiManager;
import com.bartlomiejpluta.demo.world.time.WorldTime;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.input.Input;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.api.runner.GameRunner;
import com.bartlomiejpluta.demo.map.ForrestTempleHandler;
import com.bartlomiejpluta.demo.entity.Player;
import com.bartlomiejpluta.demo.menu.MenuManager;
public class DemoRunner implements GameRunner {
private static final Logger log = LoggerFactory.getLogger(DemoRunner.class);
@Getter
private WorldTime time;
private static DemoRunner INSTANCE;
private Screen screen;
private Context context;
private MenuManager menu;
private GUI hud;
@Getter
private GuiManager guiManager;
@Getter
private Player player;
@Override
public void init(Context context) {
this.context = context;
this.screen = context.getScreen();
configureScreen();
configureCamera();
initMenu();
initPlayer();
menu.showStartMenu();
screen.show();
public static DemoRunner instance() {
return INSTANCE;
}
private void configureScreen() {
var resolution = screen.getCurrentResolution();
screen.setSize(800, 600);
screen.setPosition((resolution.x() - 800)/2, (resolution.y() - 600)/2);
var resolution = screen.getCurrentResolution();
var config = dao.config.find("screen").getValue().split("x");
var width = Integer.parseInt(config[0]);
var height = Integer.parseInt(config[1]);
screen.setSize(width, height);
screen.setPosition((resolution.x() - width) / 2, (resolution.y() - height) / 2);
}
private void configureCamera() {
context.getCamera().setScale(2f);
context.getCamera().setScale(Float.parseFloat(dao.config.find("camera_scale").getValue()));
}
private void initMenu() {
this.menu = new MenuManager(this, context);
this.guiManager = new GuiManager(this, context);
}
private void initHUD() {
hud = context.newGUI();
hud.hide();
var hudComponent = hud.inflateComponent(A.widgets.hud.$);
hud.setRoot(hudComponent);
}
private void initPlayer() {
this.player = new Player(context, context.createEntity("815a5c5c-4979-42f5-a42a-ccbbff9a97e5"));
this.player = new Player(context.createCharacter(A.charsets.luna.$));
}
private void resetPlayer() {
this.player.changeEntitySet("815a5c5c-4979-42f5-a42a-ccbbff9a97e5");
this.player.setScale(1.0f);
this.player.setSpeed(0.07f);
this.player.setAnimationSpeed(0.005f);
this.player.setBlocking(true);
this.player.setCoordinates(0, 11);
}
public void newGame() {
menu.closeAll();
menu.enableGameMenu();
resetPlayer();
context.openMap(ForrestTempleHandler.UID);
context.getMap().getObjectLayer(ForrestTempleHandler.MAIN_LAYER).addEntity(this.player);
context.resume();
context.resetMaps();
guiManager.closeAll();
guiManager.enableGameMenu();
player.reset();
var start = dao.config.find("start_game").getValue().split(",");
var map = A.maps.byName(start[0]);
var layer = map.layer(start[1]);
var label = layer.label(start[2]);
time.setTime(dao.config.find("initial_time").getValue());
context.openMap(map.$);
context.getMap().getObjectLayer(layer.$).addEntity(this.player);
player.setCoordinates(label.getX(), label.getY());
context.resume();
hud.show();
}
public void returnToStartMenu() {
menu.closeAll();
context.pause();
context.closeMap();
menu.disableGameMenu();
menu.showStartMenu();
guiManager.closeAll();
hud.hide();
context.pause();
context.closeMap();
guiManager.disableGameMenu();
guiManager.showStartMenu();
}
public void exit() {
context.close();
context.close();
}
@Override
public void update(float dt) {
}
@Override
public void dispose() {
// Do something after game loop is end
}
@Override
public void init(Context context) {
DemoRunner.INSTANCE = this;
this.context = context;
this.screen = context.getScreen();
this.time = new WorldTime(context);
configureScreen();
configureCamera();
initPlayer();
initHUD();
initMenu();
guiManager.showStartMenu();
screen.show();
}
@Override
public void update(float dt) {
time.update(dt);
}
}

View File

@@ -0,0 +1,11 @@
package com.bartlomiejpluta.demo.util;
import com.bartlomiejpluta.base.api.context.ContextHolder;
import com.bartlomiejpluta.base.api.icon.Icon;
public class IconUtil {
public static Icon parseIcon(String iconDefinition) {
var parts = iconDefinition.split(",");
return ContextHolder.INSTANCE.getContext().createIcon(A.iconsets.byName(parts[0]).$, Integer.parseInt(parts[1]), Integer.parseInt(parts[2]));
}
}

View File

@@ -0,0 +1,21 @@
package com.bartlomiejpluta.demo.util;
import lombok.AllArgsConstructor;
import java.util.LinkedList;
@AllArgsConstructor
public class LimitedQueue<E> extends LinkedList<E> {
private int limit;
@Override
public boolean add(E o) {
super.add(o);
while (size() > limit) {
super.remove();
}
return true;
}
}

View File

@@ -0,0 +1,21 @@
package com.bartlomiejpluta.demo.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
public class ListUtil {
private static final Random random = new Random();
public static <T> T sample(List<T> list) {
return list.get(random.nextInt(list.size()));
}
public static List<Integer> randomIntSequence(int startInclusive, int endExclusive) {
var ints = new ArrayList<>(IntStream.range(startInclusive, endExclusive).boxed().toList());
Collections.shuffle(ints);
return ints;
}
}

View File

@@ -0,0 +1,67 @@
package com.bartlomiejpluta.demo.util;
import DB.EnemyDropDAO;
import DB.dao;
import com.bartlomiejpluta.base.lib.db.Relop;
import com.bartlomiejpluta.demo.world.item.Item;
import com.bartlomiejpluta.demo.world.item.ItemStack;
import com.bartlomiejpluta.demo.world.junk.Junk;
import com.bartlomiejpluta.demo.world.potion.Medicament;
import com.bartlomiejpluta.demo.world.weapon.Ammunition;
import com.bartlomiejpluta.demo.world.weapon.MeleeWeapon;
import com.bartlomiejpluta.demo.world.weapon.RangedWeapon;
import com.bartlomiejpluta.demo.world.weapon.ThrowingWeapon;
import lombok.NonNull;
import java.util.Map;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Function;
import static com.bartlomiejpluta.base.util.random.DiceRoller.roll;
import static com.bartlomiejpluta.demo.util.ListUtil.randomIntSequence;
public class LootGenerator {
private static final Random rand = new Random();
private static final Map<String, Function<String, Item>> itemGenerators = Map.of(
"melee", MeleeWeapon::new,
"ranged", RangedWeapon::new,
"junk", Junk::new
);
private static final Map<String, BiFunction<String, Integer, ItemStack>> stackableGenerator = Map.of(
"ammo", Ammunition::new,
"throwing", ThrowingWeapon::new,
"med", Medicament::new
);
public static void generate(@NonNull String enemy, @NonNull Item[] loot) {
var def = dao.enemy_drop.query()
.where(EnemyDropDAO.Column.ENEMY, Relop.EQ, enemy)
.orderBy("rand()")
.find();
var index = randomIntSequence(0, loot.length).iterator();
for (var template : def) {
var parts = template.getItem().split(":");
var item = itemGenerators.get(parts[0]);
if (item != null) {
for (int i = 0; i < roll(template.getAmount()) && index.hasNext(); ++i) {
if (rand.nextFloat() <= template.getChance()) {
loot[index.next()] = item.apply(parts[1]);
}
}
continue;
}
var stack = stackableGenerator.get(parts[0]);
if (stack != null && index.hasNext()) {
if (rand.nextFloat() <= template.getChance()) {
loot[index.next()] = stack.apply(parts[1], roll(template.getAmount()));
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
package com.bartlomiejpluta.demo.world.item;
import com.bartlomiejpluta.base.lib.icon.IconDelegate;
import com.bartlomiejpluta.demo.util.IconUtil;
import lombok.NonNull;
public abstract class BaseItem extends IconDelegate implements Item {
protected BaseItem(@NonNull String icon) {
super(IconUtil.parseIcon(icon));
setZIndex(-1);
}
}

View File

@@ -0,0 +1,7 @@
package com.bartlomiejpluta.demo.world.item;
import com.bartlomiejpluta.base.api.icon.Icon;
public interface Item extends Icon {
String getName();
}

View File

@@ -0,0 +1,17 @@
package com.bartlomiejpluta.demo.world.item;
public interface ItemStack extends Item {
String getId();
int getCount();
void setCount(int count);
void decrease();
void increase();
void increase(int count);
void decrease(int count);
}

View File

@@ -0,0 +1,38 @@
package com.bartlomiejpluta.demo.world.item;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
public abstract class StackableItem extends BaseItem implements ItemStack {
@Getter
@Setter
protected int count;
protected StackableItem(@NonNull String id, int count) {
super(id);
this.count = Math.max(0, count);
}
@Override
public void decrease() {
if (count > 0) {
--count;
}
}
@Override
public void increase() {
++count;
}
@Override
public void increase(int count) {
this.count += count;
}
@Override
public void decrease(int count) {
this.count = Math.max(0, count);
}
}

View File

@@ -0,0 +1,11 @@
package com.bartlomiejpluta.demo.world.item;
import com.bartlomiejpluta.demo.entity.Creature;
public interface Useable {
void use(Creature creature);
default String usageName() {
return "Use";
}
}

View File

@@ -0,0 +1,18 @@
package com.bartlomiejpluta.demo.world.item;
import com.bartlomiejpluta.demo.entity.Creature;
import lombok.NonNull;
public abstract class UseableStackableItem extends StackableItem implements Useable {
protected UseableStackableItem(@NonNull String id, int count) {
super(id, count);
}
@Override
public void use(Creature creature) {
if (--count == 0) {
creature.removeItemFromEquipment(this);
}
}
}

View File

@@ -0,0 +1,20 @@
package com.bartlomiejpluta.demo.world.junk;
import com.bartlomiejpluta.demo.world.item.BaseItem;
import lombok.Getter;
import lombok.NonNull;
public class Junk extends BaseItem {
@Getter
private final String name;
public Junk(@NonNull String id) {
this(DB.dao.junk.find(id));
}
public Junk(@NonNull DB.model.JunkModel template) {
super(template.getIcon());
this.name = template.getName();
}
}

View File

@@ -0,0 +1,29 @@
package com.bartlomiejpluta.demo.world.light;
import com.bartlomiejpluta.base.api.context.ContextHolder;
import com.bartlomiejpluta.base.lib.light.LightDelegate;
import java.util.Random;
public class Torch extends LightDelegate {
private final Random random = new Random();
private float acc = 0;
public Torch() {
super(ContextHolder.INSTANCE.getContext().createLight());
setIntensity(100f, 50f, 0f);
setConstantAttenuation(1f);
}
@Override
public void update(float dt) {
super.update(dt);
if (acc > 0.1f) {
setQuadraticAttenuation(0.1f * (1f + ((float) random.nextGaussian()) * 0.1f));
acc = 0;
}
acc += dt;
}
}

Some files were not shown because too many files have changed in this diff Show More