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>
|
<!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) %}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue