Add big (double-counting for ownership) followers
This commit is contained in:
parent
709ee94ad6
commit
8ce67e4b78
2 changed files with 91 additions and 9 deletions
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{% if not done %}
|
||||
{% if not done and current_player.uuid != me.uuid %}
|
||||
<meta http-equiv="refresh" content="3" />
|
||||
{% endif %}
|
||||
<style>
|
||||
|
@ -22,6 +22,10 @@
|
|||
stroke: cyan;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
svg .claimable.hover {
|
||||
stroke: cyan;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
svg .empty {
|
||||
fill: transparent;
|
||||
|
@ -98,9 +102,15 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
input[type="number"], input[value="Place Tile"], select {
|
||||
input[type="number"], input[value="Place Tile"], input[type="radio"], select {
|
||||
display: none;
|
||||
}
|
||||
input[name="follower"]:checked + label.follower-label .follower {
|
||||
stroke-width: 3px;
|
||||
stroke: black;
|
||||
}
|
||||
|
||||
svg [droppable="true"]
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -121,6 +131,9 @@
|
|||
<input type="submit" value="Place Tile" name="action" id="btn-place" />
|
||||
{% endif %}
|
||||
{% if phase == 'claim' %}
|
||||
{% for follower in me.followers %}
|
||||
{{ follower.resting_svg() }}
|
||||
{% endfor %}
|
||||
<select name="claim">
|
||||
{{ claimable }}
|
||||
</select>
|
||||
|
@ -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();
|
||||
});
|
||||
</script>
|
||||
{% else %}
|
||||
{% else %}{# my turn #}
|
||||
It is <font color="{{ current_player.color.value.html }}">{{ game._players[current_player.uuid].name }}'s</font> turn.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}{# my turn #}
|
||||
{% endif %}{# done #}
|
||||
<table border="1">
|
||||
<tr><td>Name</td><td>Followers</td><td>Score</td></tr>
|
||||
{% for player in players | sort(attribute='score', reverse=true) %}
|
||||
|
|
|
@ -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'<input type="radio" id="follower-{self.uuid}" name="follower" value="{self.uuid}" />'
|
||||
color = self.player.color.value.html
|
||||
drag = 'draggable="true"'
|
||||
svg += f'<label class="follower-label" data-uuid="{self.uuid}" for="follower-{self.uuid}" {drag}><svg width="30" height="40" viewBox="-15 -20 30 40"><path class="follower" fill="{color}" d="M -5 -5 C -20 -20, 20 -20, 5 -5 L 10 0 L 10 5 L 5 0 L 5 10 L 10 15 L 5 15 L 0 10 L -5 15 L -10 15 L -5 10 L -5 0 L -10 5 L -10 0 Z" /></svg></label>'
|
||||
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'<input type="radio" id="follower-{self.uuid}" name="follower" value="{self.uuid}" />'
|
||||
color = self.player.color.value.html
|
||||
drag = 'draggable="true"'
|
||||
svg += f'<label class="follower-label" data-uuid="{self.uuid}" for="follower-{self.uuid}" {drag}><svg width="30" height="40" viewBox="-15 -20 30 40"><path class="follower" fill="{color}" transform="scale(1.5)" d="M -5 -5 C -20 -20, 20 -20, 5 -5 L 10 0 L 10 5 L 5 0 L 5 10 L 10 15 L 5 15 L 0 10 L -5 15 L -10 15 L -5 10 L -5 0 L -10 5 L -10 0 Z" /></svg></label>'
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue