From 8ce67e4b7884a38a72d55034fb05b5ab40fa19dd Mon Sep 17 00:00:00 2001 From: s3lph Date: Sun, 7 Nov 2021 20:45:14 +0100 Subject: [PATCH] Add big (double-counting for ownership) followers --- templates/carcassonne/carcassonne.html.j2 | 53 ++++++++++++++++++++--- webgames/carcassonne.py | 47 ++++++++++++++++++-- 2 files changed, 91 insertions(+), 9 deletions(-) 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 #} {% 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)
NameFollowersScore