Add sway tracker to negotiations
This commit is contained in:
parent
87b160e950
commit
f1d23e78a7
|
@ -108,14 +108,36 @@ def handle_join_negotiation(json):
|
||||||
json['room'], len(participants)))
|
json['room'], len(participants)))
|
||||||
flask_socketio.emit('participants changed', {'participants': participants},
|
flask_socketio.emit('participants changed', {'participants': participants},
|
||||||
room = json['room'])
|
room = json['room'])
|
||||||
return True
|
# Update the user's negotation state with what is stored on the server
|
||||||
|
nego = get_negotiation(json['room'])
|
||||||
|
return nego.to_dict()
|
||||||
|
|
||||||
def get_room_participants(room):
|
def get_room_participants(room):
|
||||||
|
if '/' not in socketio.server.manager.get_namespaces():
|
||||||
|
return []
|
||||||
sessions = [s for s in socketio.server.manager.get_participants('/', room)]
|
sessions = [s for s in socketio.server.manager.get_participants('/', room)]
|
||||||
participants = [p for s,p in session_map.items() if s in sessions]
|
participants = [p for s,p in session_map.items() if s in sessions]
|
||||||
app.logger.debug(participants)
|
app.logger.debug(participants)
|
||||||
return participants
|
return participants
|
||||||
|
|
||||||
|
@socketio.on('update negotiation')
|
||||||
|
@pony.orm.db_session
|
||||||
|
def handle_update_negotiation(json):
|
||||||
|
r = flask.Response()
|
||||||
|
app.logger.info('Received update request: {}'.format(json))
|
||||||
|
uid, user = get_uid(r)
|
||||||
|
nego = get_negotiation(json['room'])
|
||||||
|
app.logger.info('Room owner is {}'.format(nego.owner.uid))
|
||||||
|
if nego.owner.uid != uid:
|
||||||
|
# Refuse the update from non-owners
|
||||||
|
app.logger.warning('Refusing update of {} from non-owner {}'.format(json['room'], uid))
|
||||||
|
return False
|
||||||
|
del json['room']
|
||||||
|
nego.set(**json)
|
||||||
|
pony.orm.commit()
|
||||||
|
flask_socketio.emit('negotiation updated', {**json}, room = nego.name)
|
||||||
|
return True
|
||||||
|
|
||||||
@socketio.on('leave negotiation')
|
@socketio.on('leave negotiation')
|
||||||
def handle_leave_disconnect(json):
|
def handle_leave_disconnect(json):
|
||||||
r = flask.Response()
|
r = flask.Response()
|
||||||
|
@ -186,9 +208,64 @@ if __name__ == '__main__':
|
||||||
uid = pony.orm.Required(str)
|
uid = pony.orm.Required(str)
|
||||||
display_name = pony.orm.Optional(str)
|
display_name = pony.orm.Optional(str)
|
||||||
negotiations = pony.orm.Set('Negotiation')
|
negotiations = pony.orm.Set('Negotiation')
|
||||||
|
|
||||||
|
# Negotiations have a state. Maybe storing a state machine object (pickle?)
|
||||||
|
# would be an idea. But maybe not.
|
||||||
|
#
|
||||||
|
# Let's start with understanding negotiations
|
||||||
|
# 1. Prep Work: Before a negotiation begins, each take may do Prep Work
|
||||||
|
# 2. The takers decide who their Lead Negotiator will be. Once set, this
|
||||||
|
# cannot be changed.
|
||||||
|
# 3. The Lead Negotiation makes a First Impression
|
||||||
|
# This is a leadership check which has four effects:
|
||||||
|
# 1. The number of rounds of negotiation: max(floor(black+ld/2), 5)
|
||||||
|
# 2. The starting position (crit success +1 sway, crit failure: -1 sway)
|
||||||
|
# 3. Whether or not the negotiation length is known to takers. T/F based
|
||||||
|
# simple succes.
|
||||||
|
# 4. Who leads the negotiations (starting round): takers on success, Market otherwise.
|
||||||
|
# 4. Negotiation Round(s)
|
||||||
|
# 1. Lead negotiator plays a negotiation tactic
|
||||||
|
# 2. Other negotiator plays a negotiation tactic
|
||||||
|
# 3. Check negotiation end condition
|
||||||
|
# 4. If not ended, a non-negotiator taker may play scam
|
||||||
|
# 5. Wrap-up
|
||||||
|
# 1. Taker negotiator rolls Leadership. Success moves up to meet Market,
|
||||||
|
# failure moves market down to meet takers.
|
||||||
|
# 2a. Takers may accept the deal.
|
||||||
|
# 2b. Takers may back out. Next negotiation starts on lowest tracker, has
|
||||||
|
# no prep work, scams, or will.
|
||||||
|
# 3. Competition undercuts. If able, the competition will undercut by one
|
||||||
|
# spot on the way tracker. _Any_ taker may make a CHA check to stop this,
|
||||||
|
# but on failure the takers must lower theire price to match the competition.
|
||||||
|
#
|
||||||
class Negotiation(db.Entity):
|
class Negotiation(db.Entity):
|
||||||
name = pony.orm.PrimaryKey(str)
|
name = pony.orm.PrimaryKey(str)
|
||||||
owner = pony.orm.Required(User)
|
owner = pony.orm.Required(User)
|
||||||
|
client_name = pony.orm.Optional(str)
|
||||||
|
negotiatior_name = pony.orm.Optional(str)
|
||||||
|
taker_crew_name = pony.orm.Optional(str)
|
||||||
|
# Manual negotation
|
||||||
|
manual_negotiation = pony.orm.Optional(bool)
|
||||||
|
# Pre-negotiation details
|
||||||
|
takers = pony.orm.Optional(int)
|
||||||
|
lead_negotiator = pony.orm.Optional(str)
|
||||||
|
is_first_negotiation = pony.orm.Optional(bool)
|
||||||
|
first_impression_black = pony.orm.Optional(int)
|
||||||
|
# One of critfail, fail, success, critsuccess
|
||||||
|
first_impression_state = pony.orm.Optional(str)
|
||||||
|
negotiation_round = pony.orm.Optional(int)
|
||||||
|
# One of leadnego, secondnego, scam
|
||||||
|
negotiation_phase = pony.orm.Optional(str)
|
||||||
|
taker_sway = pony.orm.Optional(int)
|
||||||
|
market_sway = pony.orm.Optional(int)
|
||||||
|
# If negotiation_round = (calculed length) && negotiation_phase = scam then
|
||||||
|
# the negotiation is no into the wrap up section
|
||||||
|
# One of critfail, fail, success, critsuccess
|
||||||
|
wrapup_state = pony.orm.Optional(int)
|
||||||
|
job_accepted = pony.orm.Optional(bool)
|
||||||
|
may_be_undercut = pony.orm.Optional(bool)
|
||||||
|
undercut = pony.orm.Optional(bool)
|
||||||
|
|
||||||
db.bind(**app.config['PONY'])
|
db.bind(**app.config['PONY'])
|
||||||
db.generate_mapping(create_tables=True)
|
db.generate_mapping(create_tables=True)
|
||||||
Pony(app)
|
Pony(app)
|
||||||
|
|
|
@ -964,6 +964,53 @@ img {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.negotiation-wrapper {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.negotiation-sidebar {
|
||||||
|
max-width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.negotiation-panel {
|
||||||
|
min-width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* maybe this should be grids */
|
||||||
|
.swaytracker .slot {
|
||||||
|
min-height: 50px;
|
||||||
|
min-width: 150px;
|
||||||
|
max-width: 13%;
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swaytracker th {
|
||||||
|
color: #600000;
|
||||||
|
background: white;
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swaytracker .market-position .active {
|
||||||
|
height: 50px;
|
||||||
|
background-image: url("/static/images/active-market.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
.swaytracker .taker-position .active {
|
||||||
|
height: 50px;
|
||||||
|
background-image: url("/static/images/active-taker.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
.swaytracker .slot span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swaytracker .slot p {
|
||||||
|
margin: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
#wrapper {
|
#wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -27,9 +27,12 @@
|
||||||
// const negotiation = new Negotiation("{{negotiation.name}}")
|
// const negotiation = new Negotiation("{{negotiation.name}}")
|
||||||
var socket = io();
|
var socket = io();
|
||||||
var room = "{{negotiation.name}}";
|
var room = "{{negotiation.name}}";
|
||||||
|
|
||||||
socket.on('connect', function() {
|
socket.on('connect', function() {
|
||||||
console.log("Trying to join room " + room);
|
console.log("Trying to join room " + room);
|
||||||
socket.emit('join negotiation', {"room": room});
|
socket.emit('join negotiation', {"room": room}, function(e) {
|
||||||
|
update_from_data(e);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
window.addEventListener('beforeunload', function(e) {
|
window.addEventListener('beforeunload', function(e) {
|
||||||
console.log("Trying to leave room " + room);
|
console.log("Trying to leave room " + room);
|
||||||
|
@ -60,5 +63,65 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
socket.on('negotiation updated', function(e) {
|
||||||
|
update_from_data(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
function update_from_data(e) {
|
||||||
|
console.log(e);
|
||||||
|
if ('taker_sway' in e) {
|
||||||
|
// Update taker way
|
||||||
|
var current_taker_sway = $('.swaytracker .taker-position .active').attr('id');
|
||||||
|
change_swayslot(current_taker_sway, 't' + e.taker_sway);
|
||||||
|
}
|
||||||
|
if ('market_sway' in e) {
|
||||||
|
var current_market_sway = $('.swaytracker .market-position .active').attr('id');
|
||||||
|
change_swayslot(current_market_sway, 'm' + e.market_sway);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function swayslot_on_dragstart(event) {
|
||||||
|
var ev = event.originalEvent;
|
||||||
|
ev.dataTransfer.setData("text/plain", ev.target.id);
|
||||||
|
let img = new Image();
|
||||||
|
img.src = '/static/images/drag.png';
|
||||||
|
ev.dataTransfer.setDragImage(img, 0, 0);
|
||||||
|
ev.dataTransfer.dropEffect = "move";
|
||||||
|
}
|
||||||
|
function swayslot_on_dragover(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.originalEvent.dataTransfer.dropEffect = "move";
|
||||||
|
}
|
||||||
|
function swayslot_on_drop(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var source = event.originalEvent.dataTransfer.getData('text/plain');
|
||||||
|
// Check to see if this is in the same track (id starts with same letter)
|
||||||
|
var this_id = $(this).attr('id');
|
||||||
|
if (this_id[0] == source[0] && this_id != source) {
|
||||||
|
var key = (this_id[0] == 't' ? 'taker_sway' : 'market_sway');
|
||||||
|
var value = this_id[1];
|
||||||
|
var data = {
|
||||||
|
"room": room,
|
||||||
|
};
|
||||||
|
data[key] = value;
|
||||||
|
socket.emit('update negotiation', data, function (confirmation) {
|
||||||
|
if (confirmation) {
|
||||||
|
change_swayslot(source, this_id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function change_swayslot(from, to) {
|
||||||
|
$("#" + from).removeClass('active').unbind('dragstart').attr('draggable', false);
|
||||||
|
$('#' + to).addClass('active').on('dragstart', swayslot_on_dragstart).attr('draggable', true);
|
||||||
|
}
|
||||||
|
// Drag/drog for the swaytracker
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
$('.swaytracker .active').on('dragstart', swayslot_on_dragstart);
|
||||||
|
$('.swaytracker .active').attr('draggable', true);
|
||||||
|
$('.swaytracker .market-position .slot').on('dragover', swayslot_on_dragover);
|
||||||
|
$('.swaytracker .taker-position .slot').on('dragover', swayslot_on_dragover);
|
||||||
|
$('.swaytracker .market-position .slot').on('drop', swayslot_on_drop);
|
||||||
|
$('.swaytracker .taker-position .slot').on('drop', swayslot_on_drop);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
@TODO Panel
|
<div id="swaytracker">
|
||||||
|
{% include 'partials/swaytracker.html' %}
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<div class="negotiation-owner">
|
<div class="negotiation-owner">
|
||||||
<p>Negotiation {{negotiation.name}} is being run by {{room_owner_display_name}}</p>
|
<p>The Market for this negotiation is {{room_owner_display_name}}</p>
|
||||||
{% if room_owner_display_name == uid %}
|
{% if room_owner_display_name == uid %}
|
||||||
<p>Change your display name</p>
|
<p>Change your display name</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if
|
||||||
|
|
||||||
<div class="participants">
|
<div class="participants">
|
||||||
<h4>Participants</h4>
|
<h4>Participants</h4>
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<table class="swaytracker">
|
||||||
|
<tr class="market-position">
|
||||||
|
<th>Market</th>
|
||||||
|
<td id="m0" class="slot"></td>
|
||||||
|
<td id="m1" class="slot"></td>
|
||||||
|
<td id="m2" class="slot"></td>
|
||||||
|
<td id="m3" class="slot"></td>
|
||||||
|
<td id="m4" class="slot"></td>
|
||||||
|
<td id="m5" class="slot"></td>
|
||||||
|
<td id="m6" class="slot active"></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="descriptions">
|
||||||
|
<th></th>
|
||||||
|
<td class="slot">
|
||||||
|
<span>As a favour</span>
|
||||||
|
<p>Contract is offered at the Demand price only and the client (market) earns a "- Rep" spot to use in future negotiations.</p>
|
||||||
|
</td>
|
||||||
|
<td class="slot">
|
||||||
|
<span>Buyer's Market</span>
|
||||||
|
<p>Contract is offered at the Demand price only.</p>
|
||||||
|
</td>
|
||||||
|
<td class="slot">
|
||||||
|
<span>At Value</span>
|
||||||
|
<p>Contract is offered at the value of Supply and Demand</p>
|
||||||
|
</td>
|
||||||
|
<td class="slot">
|
||||||
|
<span>Labour</span>
|
||||||
|
<p>Client agrees to add the Crew's "Break Point" in bounty to the value of Supply and Demand</p>
|
||||||
|
</td>
|
||||||
|
<td class="slot">
|
||||||
|
<span>Hazard Pay</span>
|
||||||
|
<p>Add one bounty per leg per taker to the value of the contract</p>
|
||||||
|
</td>
|
||||||
|
<td class="slot">
|
||||||
|
<span>100% Markup</span>
|
||||||
|
<p>Double the cost of the Supply and Demand for the job</p>
|
||||||
|
</td>
|
||||||
|
<td class="slot">
|
||||||
|
<span>Expenses</span>
|
||||||
|
<p>The upkeep of items is factored into the value of the contract. Takers pay no upkeep this session.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="taker-position">
|
||||||
|
<th>Takers</th>
|
||||||
|
<td id="t0" class="slot"></td>
|
||||||
|
<td id="t1" class="slot active"></td>
|
||||||
|
<td id="t2" class="slot"></td>
|
||||||
|
<td id="t3" class="slot"></td>
|
||||||
|
<td id="t4" class="slot"></td>
|
||||||
|
<td id="t5" class="slot"></td>
|
||||||
|
<td id="t6" class="slot"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
Loading…
Reference in New Issue