Add big (double-counting for ownership) followers

This commit is contained in:
s3lph 2021-11-07 20:45:14 +01:00
parent 709ee94ad6
commit 8ce67e4b78
2 changed files with 91 additions and 9 deletions

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
{% if not done %} {% if not done and current_player.uuid != me.uuid %}
<meta http-equiv="refresh" content="3" /> <meta http-equiv="refresh" content="3" />
{% endif %} {% endif %}
<style> <style>
@ -22,6 +22,10 @@
stroke: cyan; stroke: cyan;
stroke-width: 3px; stroke-width: 3px;
} }
svg .claimable.hover {
stroke: cyan;
stroke-width: 3px;
}
svg .empty { svg .empty {
fill: transparent; fill: transparent;
@ -98,9 +102,15 @@
pointer-events: none; pointer-events: none;
} }
input[type="number"], input[value="Place Tile"], select { input[type="number"], input[value="Place Tile"], input[type="radio"], select {
display: none; display: none;
} }
input[name="follower"]:checked + label.follower-label .follower {
stroke-width: 3px;
stroke: black;
}
svg [droppable="true"]
</style> </style>
</head> </head>
<body> <body>
@ -121,6 +131,9 @@
<input type="submit" value="Place Tile" name="action" id="btn-place" /> <input type="submit" value="Place Tile" name="action" id="btn-place" />
{% endif %} {% endif %}
{% if phase == 'claim' %} {% if phase == 'claim' %}
{% for follower in me.followers %}
{{ follower.resting_svg() }}
{% endfor %}
<select name="claim"> <select name="claim">
{{ claimable }} {{ claimable }}
</select> </select>
@ -139,16 +152,46 @@
}; };
let claimables = document.getElementsByClassName('claimable'); let claimables = document.getElementsByClassName('claimable');
for (let i = 0; i < claimables.length; ++i) { for (let i = 0; i < claimables.length; ++i) {
claimables[i].setAttribute('droppable', true);
claimables[i].onclick = (e) => { claimables[i].onclick = (e) => {
c.elements.claim.value = e.target.getAttribute('data-uuid'); c.elements.claim.value = e.target.getAttribute('data-uuid');
document.getElementById('btn-claim').click(); 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> </script>
{% else %} {% else %}{# my turn #}
It is <font color="{{ current_player.color.value.html }}">{{ game._players[current_player.uuid].name }}'s</font> turn. It is <font color="{{ current_player.color.value.html }}">{{ game._players[current_player.uuid].name }}'s</font> turn.
{% endif %} {% endif %}{# my turn #}
{% endif %} {% endif %}{# done #}
<table border="1"> <table border="1">
<tr><td>Name</td><td>Followers</td><td>Score</td></tr> <tr><td>Name</td><td>Followers</td><td>Score</td></tr>
{% for player in players | sort(attribute='score', reverse=true) %} {% for player in players | sort(attribute='score', reverse=true) %}

View file

@ -305,13 +305,15 @@ class Resource:
b.joined = a b.joined = a
return a return a
def claim(self, player, card): def claim(self, player, card, fuuid = None):
a = self.root() a = self.root()
if len(a.owners) > 0: if len(a.owners) > 0:
raise RuntimeError('Cannot claim already-claimed resource') raise RuntimeError('Cannot claim already-claimed resource')
if len([1 for f in player.followers if f.resource is None]) == 0: if len([1 for f in player.followers if f.resource is None]) == 0:
raise RuntimeError('Player has no followers left') raise RuntimeError('Player has no followers left')
for f in player.followers: for f in player.followers:
if fuuid and f.uuid != fuuid:
continue
if f.resource is None: if f.resource is None:
a.owners.add(f) a.owners.add(f)
f.claim(self, card) f.claim(self, card)
@ -333,7 +335,7 @@ class Resource:
owners = {} owners = {}
for follower in r.owners: for follower in r.owners:
owners.setdefault(follower.player.uuid, 0) owners.setdefault(follower.player.uuid, 0)
owners[follower.player.uuid] += 1 owners[follower.player.uuid] += follower.weight
if not game_end: if not game_end:
r.unclaim() r.unclaim()
nmax = max(owners.values(), default=0) nmax = max(owners.values(), default=0)
@ -698,6 +700,7 @@ class Follower:
self.cy = None self.cy = None
self.lx = 50 self.lx = 50
self.ly = 50 self.ly = 50
self.weight = 1
def claim(self, r, card): def claim(self, r, card):
if self.resource is not None: if self.resource is not None:
@ -749,6 +752,37 @@ class Follower:
tmpl = env.get_template(f'carcassonne/follower.svg') 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) 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): class Carcassonne(Puzzle):
@ -773,7 +807,6 @@ class Carcassonne(Puzzle):
def add_player(self, uuid: UUID) -> None: def add_player(self, uuid: UUID) -> None:
p = Player(uuid, len(self._turn_order)) p = Player(uuid, len(self._turn_order))
self._players[uuid] = p self._players[uuid] = p
self._followers.extend(p.followers)
self._turn_order.append(uuid) self._turn_order.append(uuid)
self._turn += 1 self._turn += 1
@ -791,6 +824,10 @@ class Carcassonne(Puzzle):
def begin(self, options, urlbase): def begin(self, options, urlbase):
self._urlbase = urlbase self._urlbase = urlbase
self._deck = Card.generate_deck(options.getall('extensions'), self._field) 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) random.shuffle(self._turn_order)
self.next_turn() self.next_turn()
@ -864,9 +901,11 @@ class Carcassonne(Puzzle):
if self._phase != Phase.CLAIM: if self._phase != Phase.CLAIM:
return return
cuuid = action.get('claim') cuuid = action.get('claim')
fuuid = action.get('follower', None)
if cuuid: if cuuid:
cuuid = UUID(hex=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() self.next_turn()
except BaseException as e: except BaseException as e:
print(e) print(e)