Skip to content

Commit d6683c5

Browse files
committed
Stub creature possession
1 parent f34f51f commit d6683c5

21 files changed

+323
-43
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (C) 2014-2024 OpenKeeper
3+
*
4+
* OpenKeeper is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* OpenKeeper is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with OpenKeeper. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
package toniarts.openkeeper.game.component;
18+
19+
import com.simsilica.es.EntityComponent;
20+
21+
/**
22+
* Simple tagging component for entity being possessed
23+
*
24+
* @author Toni Helenius <[email protected]>
25+
*/
26+
public class Possessed implements EntityComponent {
27+
28+
/**
29+
* We mark the mana drain here so that we can easily get the information.
30+
* Mana component should be used in other calculations
31+
*/
32+
public int manaDrain;
33+
public double manaCheckTime;
34+
35+
public Possessed() {
36+
// For serialization
37+
}
38+
39+
public Possessed(int manaDrain, double manaCheckTime) {
40+
this.manaDrain = manaDrain;
41+
this.manaCheckTime = manaCheckTime;
42+
}
43+
44+
}

src/toniarts/openkeeper/game/controller/GameController.java

+7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.badlogic.gdx.ai.GdxAI;
2020
import com.jme3.util.SafeArrayList;
2121
import com.simsilica.es.EntityData;
22+
import com.simsilica.es.EntityId;
2223
import java.io.IOException;
2324
import java.lang.System.Logger;
2425
import java.lang.System.Logger.Level;
@@ -650,6 +651,12 @@ public GameResult getGameResult() {
650651
return gameResult;
651652
}
652653

654+
@Override
655+
public void setPossession(EntityId target, short playerId) {
656+
players.get(playerId).setPossession(target != null);
657+
playerService.setPossession(target, playerId);
658+
}
659+
653660
@Override
654661
public void close() {
655662
if (steeringCalculatorLoop != null) {

src/toniarts/openkeeper/game/controller/IGameController.java

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package toniarts.openkeeper.game.controller;
1818

19+
import com.simsilica.es.EntityId;
1920
import java.util.Collection;
2021
import toniarts.openkeeper.game.data.GameResult;
2122
import toniarts.openkeeper.game.logic.IEntityPositionLookup;
@@ -71,4 +72,12 @@ public interface IGameController {
7172

7273
public IGameWorldController getGameWorldController();
7374

75+
/**
76+
* Set player possession mode on/off
77+
*
78+
* @param target possession target, null if possession ends
79+
* @param playerId player ID that posesses
80+
*/
81+
public void setPossession(EntityId target, short playerId);
82+
7483
}

src/toniarts/openkeeper/game/controller/ShotsController.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public void createShot(short shotTypeId, int shotData1, int shotData2, short pla
7272
objectsController.loadObject((short) shotData1, playerId, position, 0);
7373
}
7474
case POSSESS_CREATURE -> {
75-
75+
creaturesController.createController(target).setPossession(true);
7676
}
7777
case MODIFY_HEALTH -> {
7878
EntityController.setDamage(entityData, target, -shotData1);

src/toniarts/openkeeper/game/controller/creature/CreatureController.java

+35
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import toniarts.openkeeper.game.component.Gold;
4848
import toniarts.openkeeper.game.component.Health;
4949
import toniarts.openkeeper.game.component.InHand;
50+
import toniarts.openkeeper.game.component.Mana;
5051
import toniarts.openkeeper.game.component.Mobile;
5152
import toniarts.openkeeper.game.component.Navigation;
5253
import toniarts.openkeeper.game.component.Objective;
@@ -55,6 +56,7 @@
5556
import toniarts.openkeeper.game.component.PlayerObjective;
5657
import toniarts.openkeeper.game.component.PortalGem;
5758
import toniarts.openkeeper.game.component.Position;
59+
import toniarts.openkeeper.game.component.Possessed;
5860
import toniarts.openkeeper.game.component.RoomStorage;
5961
import toniarts.openkeeper.game.component.Slapped;
6062
import toniarts.openkeeper.game.component.TaskComponent;
@@ -1253,4 +1255,37 @@ public boolean isRecuperating() {
12531255
return entityData.getComponent(entityId, CreatureRecuperating.class) != null;
12541256
}
12551257

1258+
@Override
1259+
public void setPossession(boolean possessed) {
1260+
if (possessed) {
1261+
startPossession();
1262+
} else {
1263+
endPossession();
1264+
}
1265+
}
1266+
1267+
private void startPossession() {
1268+
CreatureComponent creatureComponent = entityData.getComponent(entityId, CreatureComponent.class);
1269+
int manaDrain = creatureComponent != null ? creatureComponent.posessionManaCost : 0;
1270+
Mana mana = entityData.getComponent(entityId, Mana.class);
1271+
entityData.setComponent(entityId, new Mana(mana != null ? -manaDrain - mana.manaGeneration : -manaDrain));
1272+
entityData.setComponent(entityId, new Possessed(manaDrain, gameTimer.getGameTime()));
1273+
entityData.removeComponent(entityId, CreatureAi.class);
1274+
entityData.removeComponent(entityId, Navigation.class);
1275+
}
1276+
1277+
private void endPossession() {
1278+
entityData.setComponent(entityId, new CreatureAi(gameTimer.getGameTime(), CreatureState.IDLE, getCreature().getCreatureId()));
1279+
1280+
// Return the mana flow
1281+
Possessed possessed = entityData.getComponent(entityId, Possessed.class);
1282+
Mana mana = entityData.getComponent(entityId, Mana.class);
1283+
int manaGeneration = mana.manaGeneration + possessed.manaDrain;
1284+
if (manaGeneration == 0) {
1285+
entityData.removeComponent(entityId, Mana.class);
1286+
} else {
1287+
entityData.setComponent(entityId, new Mana(manaGeneration));
1288+
}
1289+
}
1290+
12561291
}

src/toniarts/openkeeper/game/controller/creature/ICreatureController.java

+7
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,11 @@ public interface ICreatureController extends IGameLogicUpdatable, INavigable, IE
247247
*/
248248
public boolean isRecuperating();
249249

250+
/**
251+
* Sets creature possession on/off
252+
*
253+
* @param possessed should the creature be posessed or AI driven
254+
*/
255+
public void setPossession(boolean possessed);
256+
250257
}

src/toniarts/openkeeper/game/controller/player/PlayerManaControl.java

+4
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,8 @@ public void addListener(PlayerManaListener listener) {
7474
public void removeListener(PlayerManaListener listener) {
7575
listeners.remove(listener);
7676
}
77+
78+
public boolean hasEnoughMana(int manaDrain) {
79+
return keeper.getMana() - manaDrain + keeper.getManaGain() - keeper.getManaLoose() > 0;
80+
}
7781
}

src/toniarts/openkeeper/game/data/Keeper.java

+9
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public class Keeper implements Comparable<Keeper>, IIndexable, Savable {
4848
private int manaLoose;
4949
private int maxMana;
5050
private Point dungeonHeartLocation;
51+
private boolean possession;
5152
private List<ResearchableEntity> availableRooms = new ArrayList<>();
5253
private List<ResearchableEntity> availableSpells = new ArrayList<>();
5354
private List<Short> availableCreatures = new ArrayList<>();
@@ -219,6 +220,14 @@ public void setDungeonHeartLocation(Point dungeonHeartLocation) {
219220
this.dungeonHeartLocation = dungeonHeartLocation;
220221
}
221222

223+
public boolean isPossession() {
224+
return possession;
225+
}
226+
227+
public void setPossession(boolean possession) {
228+
this.possession = possession;
229+
}
230+
222231
public List<ResearchableEntity> getAvailableRooms() {
223232
return availableRooms;
224233
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (C) 2014-2024 OpenKeeper
3+
*
4+
* OpenKeeper is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* OpenKeeper is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with OpenKeeper. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
package toniarts.openkeeper.game.logic;
18+
19+
import com.simsilica.es.Entity;
20+
import com.simsilica.es.EntityData;
21+
import com.simsilica.es.EntitySet;
22+
import java.util.Collection;
23+
import java.util.HashMap;
24+
import java.util.Map;
25+
import java.util.Set;
26+
import toniarts.openkeeper.game.component.Owner;
27+
import toniarts.openkeeper.game.component.Possessed;
28+
import toniarts.openkeeper.game.controller.IGameController;
29+
import toniarts.openkeeper.game.controller.IPlayerController;
30+
import toniarts.openkeeper.game.controller.player.PlayerManaControl;
31+
32+
/**
33+
* Maintains possessed state, sees when we need to stop possessing
34+
*
35+
* @author Toni Helenius <[email protected]>
36+
*/
37+
public class PossessedSystem implements IGameLogicUpdatable {
38+
39+
private final EntitySet possessedEntities;
40+
private final Map<Short, PlayerManaControl> manaControls;
41+
private final EntityData entityData;
42+
private final IGameController gameController;
43+
44+
public PossessedSystem(Collection<IPlayerController> playerControllers, EntityData entityData, IGameController gameController) {
45+
this.gameController = gameController;
46+
this.entityData = entityData;
47+
manaControls = HashMap.newHashMap(playerControllers.size());
48+
for (IPlayerController playerController : playerControllers) {
49+
PlayerManaControl manaControl = playerController.getManaControl();
50+
if (manaControl != null) {
51+
manaControls.put(playerController.getKeeper().getId(), manaControl);
52+
}
53+
}
54+
55+
// Listen for posessed entities
56+
possessedEntities = entityData.getEntities(Possessed.class, Owner.class);
57+
processAddedEntities(possessedEntities);
58+
}
59+
60+
@Override
61+
public void processTick(float tpf, double gameTime) {
62+
if (possessedEntities.applyChanges()) {
63+
64+
processAddedEntities(possessedEntities.getAddedEntities());
65+
66+
processDeletedEntities(possessedEntities.getRemovedEntities());
67+
}
68+
69+
for (Entity entity : possessedEntities) {
70+
71+
// See if the player is running out of mana
72+
Possessed possessed = entity.get(Possessed.class);
73+
Owner owner = entity.get(Owner.class);
74+
if (possessed.manaCheckTime + 1 < gameTime) {
75+
continue;
76+
}
77+
78+
if (!manaControls.get(owner.ownerId).hasEnoughMana(possessed.manaDrain)) {
79+
entityData.removeComponent(entity.getId(), Possessed.class);
80+
} else {
81+
entityData.setComponent(entity.getId(), new Possessed(possessed.manaDrain, gameTime));
82+
}
83+
}
84+
}
85+
86+
@Override
87+
public void start() {
88+
89+
}
90+
91+
@Override
92+
public void stop() {
93+
possessedEntities.release();
94+
}
95+
96+
private void processAddedEntities(Set<Entity> entities) {
97+
for (Entity entity : entities) {
98+
gameController.setPossession(entity.getId(), entity.get(Owner.class).ownerId);
99+
}
100+
}
101+
102+
private void processDeletedEntities(Set<Entity> entities) {
103+
for (Entity entity : entities) {
104+
gameController.setPossession(null, entity.get(Owner.class).ownerId);
105+
}
106+
}
107+
}

src/toniarts/openkeeper/game/network/game/GameClientService.java

+7
Original file line numberDiff line numberDiff line change
@@ -417,5 +417,12 @@ public void onResearchStatusChanged(short keeperId, ResearchableEntity researcha
417417
l.onResearchStatusChanged(keeperId, researchableEntity);
418418
}
419419
}
420+
421+
@Override
422+
public void setPossession(EntityId target) {
423+
for (GameSessionListener l : listeners.getArray()) {
424+
l.setPossession(target);
425+
}
426+
}
420427
}
421428
}

src/toniarts/openkeeper/game/network/game/GameHostedService.java

+15
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,16 @@ public void onResearchStatusChanged(short keeperId, ResearchableEntity researcha
376376
}
377377
}
378378

379+
@Override
380+
public void setPossession(EntityId target, short playerId) {
381+
for (Map.Entry<ClientInfo, GameSessionImpl> gameSession : players.entrySet()) {
382+
if (gameSession.getKey().getKeeper().getId() == playerId) {
383+
gameSession.getValue().setPossession(target);
384+
break;
385+
}
386+
}
387+
}
388+
379389
private class ServerMessageListener implements MessageListener<HostedConnection> {
380390

381391
public ServerMessageListener() {
@@ -698,5 +708,10 @@ public void onResearchStatusChanged(short keeperId, ResearchableEntity researcha
698708
getCallback().onResearchStatusChanged(keeperId, researchableEntity);
699709
}
700710

711+
@Override
712+
public void setPossession(EntityId target) {
713+
getCallback().setPossession(target);
714+
}
715+
701716
}
702717
}

src/toniarts/openkeeper/game/state/GameClientState.java

+5
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,11 @@ private Comparable getResearchableEntityType(KwdFile kwdFile, ResearchableType r
620620

621621
return null;
622622
}
623+
624+
@Override
625+
public void setPossession(EntityId target) {
626+
playerState.setPossession(target);
627+
}
623628
}
624629

625630
public IMapInformation getMapClientService() {

0 commit comments

Comments
 (0)