diff --git a/templates/carcassonne/carcassonne.html.j2 b/templates/carcassonne/carcassonne.html.j2
index ccb0761..f5dac9e 100644
--- a/templates/carcassonne/carcassonne.html.j2
+++ b/templates/carcassonne/carcassonne.html.j2
@@ -1,7 +1,7 @@
-{% if not done %}
+{% if not done and current_player.uuid != me.uuid %}
{% endif %}
@@ -121,6 +131,9 @@
{% endif %}
{% if phase == 'claim' %}
+ {% for follower in me.followers %}
+ {{ follower.resting_svg() }}
+ {% endfor %}
@@ -139,16 +152,46 @@
};
let claimables = document.getElementsByClassName('claimable');
for (let i = 0; i < claimables.length; ++i) {
+ claimables[i].setAttribute('droppable', true);
claimables[i].onclick = (e) => {
c.elements.claim.value = e.target.getAttribute('data-uuid');
document.getElementById('btn-claim').click();
};
};
+ follower = null;
+ document.addEventListener('dragstart', e => {
+ follower = e.target;
+ follower.style.opacity = 0.5;
+ e.dataTransfer.effectAllowed = 'move';
+ });
+ document.addEventListener('dragenter', e => {
+ e.target.classList.add('hover');
+ e.dataTransfer.dropEffect = 'move';
+ });
+ document.addEventListener('dragleave', e => {
+ e.target.classList.remove('hover');
+ });
+ document.addEventListener('dragend', e => {
+ follower.style.opacity = '';
+ });
+ document.addEventListener('dragover', e => {
+ e.preventDefault();
+ });
+ document.addEventListener('drop', e => {
+ follower.style.opacity = '';
+ if (!e.target.hasAttribute('data-uuid')) {
+ return;
+ }
+ c.elements.follower.value = follower.getAttribute('data-uuid');
+ c.elements.claim.value = e.target.getAttribute('data-uuid');
+ console.log(c.elements.follower.value + ' ' + c.elements.claim.value);
+ document.getElementById('btn-claim').click();
+ });
- {% else %}
+ {% else %}{# my turn #}
It is {{ game._players[current_player.uuid].name }}'s turn.
- {% endif %}
- {% endif %}
+ {% endif %}{# my turn #}
+ {% endif %}{# done #}
Name | Followers | Score |
{% for player in players | sort(attribute='score', reverse=true) %}
diff --git a/webgames/carcassonne.py b/webgames/carcassonne.py
index ee8a9ce..93c8e76 100644
--- a/webgames/carcassonne.py
+++ b/webgames/carcassonne.py
@@ -305,13 +305,15 @@ class Resource:
b.joined = a
return a
- def claim(self, player, card):
+ def claim(self, player, card, fuuid = None):
a = self.root()
if len(a.owners) > 0:
raise RuntimeError('Cannot claim already-claimed resource')
if len([1 for f in player.followers if f.resource is None]) == 0:
raise RuntimeError('Player has no followers left')
for f in player.followers:
+ if fuuid and f.uuid != fuuid:
+ continue
if f.resource is None:
a.owners.add(f)
f.claim(self, card)
@@ -333,7 +335,7 @@ class Resource:
owners = {}
for follower in r.owners:
owners.setdefault(follower.player.uuid, 0)
- owners[follower.player.uuid] += 1
+ owners[follower.player.uuid] += follower.weight
if not game_end:
r.unclaim()
nmax = max(owners.values(), default=0)
@@ -698,6 +700,7 @@ class Follower:
self.cy = None
self.lx = 50
self.ly = 50
+ self.weight = 1
def claim(self, r, card):
if self.resource is not None:
@@ -749,6 +752,37 @@ class Follower:
tmpl = env.get_template(f'carcassonne/follower.svg')
return tmpl.render(x=(self.cx+xoff)*100, y=(self.cy+yoff)*100, lx=self.lx, ly=self.ly, color=self.player.color.value.html)
+ def resting_svg(self):
+ svg = ''
+ color = '#666666'
+ drag = ''
+ if self.resource is None:
+ svg += f''
+ color = self.player.color.value.html
+ drag = 'draggable="true"'
+ svg += f''
+ return svg
+
+class BigFollower(Follower):
+
+ def __init__(self, player):
+ super().__init__(player)
+ self.weight = 2
+
+ def svg(self, env, xoff, yoff):
+ return super().svg(env, xoff, yoff).replace(')" d=', ') scale(1.5)" d=', 1)
+
+ def resting_svg(self):
+ svg = ''
+ color = '#666666'
+ drag = ''
+ if self.resource is None:
+ svg += f''
+ color = self.player.color.value.html
+ drag = 'draggable="true"'
+ svg += f''
+ return svg
+
class Carcassonne(Puzzle):
@@ -773,7 +807,6 @@ class Carcassonne(Puzzle):
def add_player(self, uuid: UUID) -> None:
p = Player(uuid, len(self._turn_order))
self._players[uuid] = p
- self._followers.extend(p.followers)
self._turn_order.append(uuid)
self._turn += 1
@@ -791,6 +824,10 @@ class Carcassonne(Puzzle):
def begin(self, options, urlbase):
self._urlbase = urlbase
self._deck = Card.generate_deck(options.getall('extensions'), self._field)
+ for player in self._players.values():
+ if 'inns-cathedrals' in options.getall('extensions'):
+ player.followers.append(BigFollower(player))
+ self._followers.extend(player.followers)
random.shuffle(self._turn_order)
self.next_turn()
@@ -864,9 +901,11 @@ class Carcassonne(Puzzle):
if self._phase != Phase.CLAIM:
return
cuuid = action.get('claim')
+ fuuid = action.get('follower', None)
if cuuid:
cuuid = UUID(hex=cuuid)
- self._claimable[cuuid].claim(self._players[puuid], self._card)
+ fuuid = UUID(hex=fuuid) if fuuid else None
+ self._claimable[cuuid].claim(self._players[puuid], self._card, fuuid)
self.next_turn()
except BaseException as e:
print(e)