Added some transitions.
This commit is contained in:
60
src/display/animation/easing.c
Normal file
60
src/display/animation/easing.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "easing.h"
|
||||||
|
|
||||||
|
float easeLinear(float t) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInQuad(float t) {
|
||||||
|
return t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutQuad(float t) {
|
||||||
|
return t * (2 - t);
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInOutQuad(float t) {
|
||||||
|
return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInCubic(float t) {
|
||||||
|
return t * t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutCubic(float t) {
|
||||||
|
return (t - 1) * (t - 1) * (t - 1) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInOutCubic(float t) {
|
||||||
|
return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInQuart(float t) {
|
||||||
|
return t * t * t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutQuart(float t) {
|
||||||
|
return 1 - (t-1)*(t-1)*(t-1)*(t-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInOutQuart(float t) {
|
||||||
|
return t < .5 ? 8*t*t*t*t : 1-8*(t-1)*(t-1)*(t-1)*(t-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInQuint(float t) {
|
||||||
|
return t*t*t*t*t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutQuint(float t) {
|
||||||
|
return 1 + (t-1)*(t-1)*(t-1)*(t-1)*(t-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeInOutQuint(float t) {
|
||||||
|
return t<.5 ? 16*t*t*t*t*t : 1+16*(t-1)*(t-1)*(t-1)*(t-1)*(t-1);
|
||||||
|
}
|
@ -6,6 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
typedef float easefunction_t(float t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ease time for a given real time duration span.
|
* Returns the ease time for a given real time duration span.
|
||||||
* @param start At what point in time the animation started
|
* @param start At what point in time the animation started
|
||||||
@ -15,22 +17,16 @@
|
|||||||
*/
|
*/
|
||||||
#define easeTimeToEase(start, current, duration) ((current-start)/duration)
|
#define easeTimeToEase(start, current, duration) ((current-start)/duration)
|
||||||
|
|
||||||
|
float easeLinear(float t);
|
||||||
// Easing Functions, most were sourced from https://gist.github.com/gre/1650294
|
float easeInQuad(float t);
|
||||||
#define easeLinear(t) t
|
float easeOutQuad(float t);
|
||||||
|
float easeInOutQuad(float t);
|
||||||
#define easeInQuad(t) (t*t)
|
float easeInCubic(float t);
|
||||||
#define easeOutQuad(t) (t*(2-t))
|
float easeOutCubic(float t);
|
||||||
#define easeInOutQuad(t) (t < .5 ? 2*t*t : -1+(4-2*t)*t)
|
float easeInOutCubic(float t);
|
||||||
|
float easeInQuart(float t);
|
||||||
#define easeInCubic(t) (t*t*t)
|
float easeOutQuart(float t);
|
||||||
#define easeOutCubic(t) ((t-1)*(t-1)*(t-1)+1)
|
float easeInOutQuart(float t);
|
||||||
#define easeInOutCubic(t) (t < .5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1)
|
float easeInQuint(float t);
|
||||||
|
float easeOutQuint(float t);
|
||||||
#define easeInQuart(t) (t*t*t*t)
|
float easeInOutQuint(float t);
|
||||||
#define easeOutQuart(t) (1 - (t-1)*(t-1)*(t-1)*(t-1))
|
|
||||||
#define easeInOutQuart(t) (t < .5 ? 8*t*t*t*t : 1-8*(t-1)*(t-1)*(t-1)*(t-1))
|
|
||||||
|
|
||||||
#define easeInQuint(t) (t*t*t*t*t)
|
|
||||||
#define easeOutQuint(t) (1 + (t-1)*(t-1)*(t-1)*(t-1)*(t-1))
|
|
||||||
#define easeInOutQuint(t) (t<.5 ? 16*t*t*t*t*t : 1+16*(t-1)*(t-1)*(t-1)*(t-1)*(t-1))
|
|
@ -7,6 +7,32 @@
|
|||||||
|
|
||||||
#include "timeline.h"
|
#include "timeline.h"
|
||||||
|
|
||||||
|
void _timelineActionDeltaUpdateStart(
|
||||||
|
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
||||||
|
) {
|
||||||
|
if(action->data == NULL) return;
|
||||||
|
*((float *)action->data) = timeline->initials[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _timelineActionDeltaUpdateDuration(
|
||||||
|
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
||||||
|
) {
|
||||||
|
float n;
|
||||||
|
if(action->data == NULL) return;
|
||||||
|
n = timeline->easings[i](
|
||||||
|
timelineActionGetTimeRaw(timeline, action)
|
||||||
|
);
|
||||||
|
*((float *)action->data) = timeline->initials[i] + (timeline->deltas[i] * n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _timelineActionDeltaUpdateEnd(
|
||||||
|
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
||||||
|
) {
|
||||||
|
if(action->data == NULL) return;
|
||||||
|
*((float *)action->data) = timeline->initials[i] + timeline->deltas[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void timelineInit(timeline_t *timeline) {
|
void timelineInit(timeline_t *timeline) {
|
||||||
timeline->current = 0;
|
timeline->current = 0;
|
||||||
timeline->diff = 0;
|
timeline->diff = 0;
|
||||||
@ -68,10 +94,48 @@ bool timelineIsFinished(timeline_t *timeline) {
|
|||||||
timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
|
timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
|
||||||
float duration
|
float duration
|
||||||
) {
|
) {
|
||||||
if(timeline->actionCount == TIMELINE_ACTION_COUNT_MAX) return NULL;
|
|
||||||
timelineaction_t *action = timeline->actions + (timeline->actionCount++);
|
timelineaction_t *action = timeline->actions + (timeline->actionCount++);
|
||||||
action->loop = false;
|
action->loop = false;
|
||||||
action->start = start, action->duration = duration;
|
action->start = start, action->duration = duration;
|
||||||
action->onStart = action->onEnd = action->onDuration = NULL;
|
action->onStart = action->onEnd = action->onDuration = NULL;
|
||||||
return action;
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
timelineaction_t * timelineAddDeltaAction(timeline_t *timeline,
|
||||||
|
float start, float duration, float initial, float delta,
|
||||||
|
easefunction_t *easing, float *destination
|
||||||
|
) {
|
||||||
|
timelineaction_t *action;
|
||||||
|
timeline->initials[timeline->actionCount] = initial;
|
||||||
|
timeline->deltas[timeline->actionCount] = delta;
|
||||||
|
timeline->easings[timeline->actionCount] = (
|
||||||
|
easing == NULL ? &easeLinear : easing
|
||||||
|
);
|
||||||
|
action = timelineAddAction(timeline, start, duration);
|
||||||
|
action->data = destination;
|
||||||
|
action->onStart = &_timelineActionDeltaUpdateStart;
|
||||||
|
action->onDuration = &_timelineActionDeltaUpdateDuration;
|
||||||
|
action->onEnd = &_timelineActionDeltaUpdateEnd;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
timelineaction_t * timelineAddDeltaActionTo(timeline_t *timeline,
|
||||||
|
float start, float duration, float initial, float end,
|
||||||
|
easefunction_t *easing, float *destination
|
||||||
|
) {
|
||||||
|
return timelineAddDeltaAction(
|
||||||
|
timeline, start, duration, initial, end-initial, easing, destination
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
float timelineActionGetTimeRaw(timeline_t *timeline, timelineaction_t *action) {
|
||||||
|
return (timeline->current - action->start) / action->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
float timelineActionGetTime(timeline_t *tl, timelineaction_t *at) {
|
||||||
|
return mathClamp(timelineActionGetTimeRaw(tl, at), 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timelineClear(timeline_t *timeline) {
|
||||||
|
timeline->actionCount = 0;
|
||||||
}
|
}
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../libs.h"
|
#include "../../libs.h"
|
||||||
|
#include "../../util/math.h"
|
||||||
|
#include "easing.h"
|
||||||
|
|
||||||
/** Maximum number of actions a timeline can support, smaller than 0xFF */
|
/** Maximum number of actions a timeline can support, smaller than 0xFF */
|
||||||
#define TIMELINE_ACTION_COUNT_MAX 128
|
#define TIMELINE_ACTION_COUNT_MAX 128
|
||||||
@ -72,6 +74,14 @@ typedef struct _timeline_t {
|
|||||||
|
|
||||||
/** Actions within the timeline */
|
/** Actions within the timeline */
|
||||||
timelineaction_t actions[TIMELINE_ACTION_COUNT_MAX];
|
timelineaction_t actions[TIMELINE_ACTION_COUNT_MAX];
|
||||||
|
|
||||||
|
/** For delta actions, storage of the initial values */
|
||||||
|
float initials[TIMELINE_ACTION_COUNT_MAX];
|
||||||
|
/** For delta actions, storage of their deltas. */
|
||||||
|
float deltas[TIMELINE_ACTION_COUNT_MAX];
|
||||||
|
/** Easing functions to use for delta functions */
|
||||||
|
easefunction_t *easings[TIMELINE_ACTION_COUNT_MAX];
|
||||||
|
|
||||||
uint8_t actionCount;
|
uint8_t actionCount;
|
||||||
} timeline_t;
|
} timeline_t;
|
||||||
|
|
||||||
@ -110,4 +120,68 @@ bool timelineIsFinished(timeline_t *timeline);
|
|||||||
*/
|
*/
|
||||||
timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
|
timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
|
||||||
float duration
|
float duration
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a special action kind that can treat delta style animations. These are
|
||||||
|
* animations that have a start, and an end value, that will be tracked for you
|
||||||
|
* and keep you up to date.
|
||||||
|
*
|
||||||
|
* @param timeline Timeline to add to.
|
||||||
|
* @param start Starting time.
|
||||||
|
* @param duration Animation duration.
|
||||||
|
* @param initial Initial value for the animation.
|
||||||
|
* @param delta Delta value for the animation.
|
||||||
|
* @param easing Pointer to an easing function to use, set to NULL for linear.
|
||||||
|
* @param destination A constant floating point to update.
|
||||||
|
* @return The queued timeline action.
|
||||||
|
*/
|
||||||
|
timelineaction_t * timelineAddDeltaAction(timeline_t *timeline,
|
||||||
|
float start, float duration, float initial, float delta,
|
||||||
|
easefunction_t *easing, float *destination
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand for timelineAddDeltaAction that will calculate the delta based on
|
||||||
|
* and end position.
|
||||||
|
*
|
||||||
|
* @param timeline Timeline to add to.
|
||||||
|
* @param start Starting time.
|
||||||
|
* @param duration Animation duration.
|
||||||
|
* @param initial Initial value for the animation.
|
||||||
|
* @param end End value for the animation.
|
||||||
|
* @param easing Pointer to an easing function to use, set to NULL for linear.
|
||||||
|
* @param destination A constant floating point to update.
|
||||||
|
* @return The queued timeline action.
|
||||||
|
*/
|
||||||
|
timelineaction_t * timelineAddDeltaActionTo(timeline_t *timeline,
|
||||||
|
float start, float duration, float initial, float end,
|
||||||
|
easefunction_t *easing, float *destination
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timeline action's animation time. This is a representation of
|
||||||
|
* 0 - 1 where 0 means the animation is at the start, and 1 meaning the
|
||||||
|
* animation is at full completion. This is not clamped and may exceed 1.
|
||||||
|
*
|
||||||
|
* @param timeline Timeline the action belongs to.
|
||||||
|
* @param action Action itself.
|
||||||
|
* @return 0 - 1+, where 0 = start, 1 = duration, >1 is time since duration.
|
||||||
|
*/
|
||||||
|
float timelineActionGetTimeRaw(timeline_t *timeline, timelineaction_t *action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timeline action's animation time between 0 - 1, clamped.
|
||||||
|
*
|
||||||
|
* @param tl Timeline to get delta from.
|
||||||
|
* @param at Timeline action.
|
||||||
|
* @return 0 - 1, where 0 = start, 1 = duration.
|
||||||
|
*/
|
||||||
|
float timelineActionGetTime(timeline_t *tl, timelineaction_t *at);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all actions from the timeline.
|
||||||
|
*
|
||||||
|
* @param timeline Timeline to clear.
|
||||||
|
*/
|
||||||
|
void timelineClear(timeline_t *timeline);
|
@ -15,6 +15,12 @@ void cameraLookAt(camera_t *camera,
|
|||||||
matrixLookAt(&camera->view, x, y, z, targetX, targetY, targetZ, 0, 1, 0);
|
matrixLookAt(&camera->view, x, y, z, targetX, targetY, targetZ, 0, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cameraLookAtStruct(camera_t *camera, cameralookat_t look) {
|
||||||
|
cameraLookAt(camera,
|
||||||
|
look.x, look.y, look.z, look.lookX, look.lookY, look.lookZ
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void cameraLook(camera_t *camera,
|
void cameraLook(camera_t *camera,
|
||||||
float x, float y, float z,
|
float x, float y, float z,
|
||||||
float pitch, float yaw, float roll
|
float pitch, float yaw, float roll
|
||||||
|
@ -17,6 +17,10 @@ typedef struct {
|
|||||||
matrix_t projection;
|
matrix_t projection;
|
||||||
} camera_t;
|
} camera_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float x, y, z, lookX, lookY, lookZ;
|
||||||
|
} cameralookat_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a camera look at a position in world space while itself being positioned
|
* Make a camera look at a position in world space while itself being positioned
|
||||||
* within world space.
|
* within world space.
|
||||||
@ -34,6 +38,14 @@ void cameraLookAt(camera_t *camera,
|
|||||||
float targetX, float targetY, float targetZ
|
float targetX, float targetY, float targetZ
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand for look at that uses the look struct.
|
||||||
|
*
|
||||||
|
* @param camera Camera to position.
|
||||||
|
* @param look Look vectors.
|
||||||
|
*/
|
||||||
|
void cameraLookAtStruct(camera_t *camera, cameralookat_t look);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a camera look in a direction based on a rotation direction.
|
* Make a camera look in a direction based on a rotation direction.
|
||||||
*
|
*
|
||||||
|
@ -59,7 +59,7 @@ void _pokerGameActionBetOnUpdate(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case POKER_TURN_TYPE_ALL_IN:
|
case POKER_TURN_TYPE_ALL_IN:
|
||||||
discussion.reason = POKER_DISCUSSION_REASON_PLAYER_CALLING;
|
discussion.reason = POKER_DISCUSSION_REASON_PLAYER_ALL_IN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POKER_TURN_TYPE_FOLD:
|
case POKER_TURN_TYPE_FOLD:
|
||||||
|
@ -77,6 +77,13 @@ void pokerDiscussionGet(
|
|||||||
discussion->emotions[0] = VN_CHARACTER_EMOTION_BOASTFUL;
|
discussion->emotions[0] = VN_CHARACTER_EMOTION_BOASTFUL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case POKER_DISCUSSION_REASON_PLAYER_ALL_IN:
|
||||||
|
discussion->count++;
|
||||||
|
discussion->messages[0] = "All in.";
|
||||||
|
discussion->players[0] = data->playerCause;
|
||||||
|
discussion->emotions[0] = VN_CHARACTER_EMOTION_ANGRY_PROUD;
|
||||||
|
break;
|
||||||
|
|
||||||
// Flops
|
// Flops
|
||||||
case POKER_DISCUSSION_REASON_FLOP:
|
case POKER_DISCUSSION_REASON_FLOP:
|
||||||
discussion->count++;
|
discussion->count++;
|
||||||
|
@ -23,9 +23,10 @@
|
|||||||
#define POKER_DISCUSSION_REASON_PLAYER_CHECKING 0x05
|
#define POKER_DISCUSSION_REASON_PLAYER_CHECKING 0x05
|
||||||
#define POKER_DISCUSSION_REASON_PLAYER_CALLING 0x06
|
#define POKER_DISCUSSION_REASON_PLAYER_CALLING 0x06
|
||||||
#define POKER_DISCUSSION_REASON_PLAYER_RAISING 0x07
|
#define POKER_DISCUSSION_REASON_PLAYER_RAISING 0x07
|
||||||
#define POKER_DISCUSSION_REASON_FLOP 0x08
|
#define POKER_DISCUSSION_REASON_PLAYER_ALL_IN 0x08
|
||||||
#define POKER_DISCUSSION_REASON_DEAL 0x09
|
#define POKER_DISCUSSION_REASON_FLOP 0x09
|
||||||
#define POKER_DISCUSSION_REASON_BETTING_DONE 0x0A
|
#define POKER_DISCUSSION_REASON_DEAL 0x0A
|
||||||
|
#define POKER_DISCUSSION_REASON_BETTING_DONE 0x0B
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
pokergame_t *poker;
|
pokergame_t *poker;
|
||||||
|
@ -14,6 +14,9 @@ void pokerWorldInit(
|
|||||||
) {
|
) {
|
||||||
vncharacter_t *character;
|
vncharacter_t *character;
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
|
world->seat = POKER_GAME_SEAT_DEALER;
|
||||||
|
world->seatTime = 0;
|
||||||
|
|
||||||
// Initialize the skywal
|
// Initialize the skywal
|
||||||
skywallInit(&world->skywall);
|
skywallInit(&world->skywall);
|
||||||
@ -34,16 +37,21 @@ void pokerWorldInit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pokerWorldLookAtPlayer(vnscene_t *scene, uint8_t playerIndex) {
|
void pokerWorldLookAtPlayer(
|
||||||
uint8_t seat;
|
vnscene_t *scene, uint8_t playerIndex
|
||||||
seat = pokerGameSeatFromIndex(playerIndex);
|
) {
|
||||||
scene->cameraLookX = POKER_WORLD_SEAT_POSITION_X(seat);
|
uint8_t seat = pokerGameSeatFromIndex(playerIndex);
|
||||||
scene->cameraLookZ = POKER_WORLD_SEAT_POSITION_Z(seat);
|
vnSceneLookAt(scene,
|
||||||
|
scene->cameraLook.x,
|
||||||
|
scene->cameraLook.y,
|
||||||
|
scene->cameraLook.z,
|
||||||
|
POKER_WORLD_SEAT_POSITION_X(seat),
|
||||||
|
scene->cameraLook.lookY,
|
||||||
|
POKER_WORLD_SEAT_POSITION_Z(seat)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pokerWorldRender(
|
void pokerWorldRender(pokerworld_t *world, pokergameassets_t *assets) {
|
||||||
pokerworld_t *world, pokergameassets_t *assets
|
|
||||||
) {
|
|
||||||
// Render the wall
|
// Render the wall
|
||||||
shaderUseTexture(&assets->shader, &assets->roomTexture);
|
shaderUseTexture(&assets->shader, &assets->roomTexture);
|
||||||
shaderUsePosition(&assets->shader, 0,2,0, 0,0,0);
|
shaderUsePosition(&assets->shader, 0,2,0, 0,0,0);
|
||||||
|
@ -9,11 +9,13 @@
|
|||||||
#include "../../libs.h"
|
#include "../../libs.h"
|
||||||
#include "../../display/shader.h"
|
#include "../../display/shader.h"
|
||||||
#include "../../display/primitive.h"
|
#include "../../display/primitive.h"
|
||||||
|
#include "../../display/animation/easing.h"
|
||||||
#include "../../display/primitives/skywall.h"
|
#include "../../display/primitives/skywall.h"
|
||||||
#include "../../vn/vnscene.h"
|
#include "../../vn/vnscene.h"
|
||||||
#include "../../vn/vncharacter.h"
|
#include "../../vn/vncharacter.h"
|
||||||
#include "../../poker/player.h"
|
#include "../../poker/player.h"
|
||||||
#include "../../poker/dealer.h"
|
#include "../../poker/dealer.h"
|
||||||
|
#include "../../engine/engine.h"
|
||||||
#include "pokergameassets.h"
|
#include "pokergameassets.h"
|
||||||
|
|
||||||
|
|
||||||
@ -48,6 +50,10 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
primitive_t skywall;
|
primitive_t skywall;
|
||||||
|
|
||||||
|
/** Which seat the game should look at */
|
||||||
|
uint8_t seat;
|
||||||
|
float seatTime;
|
||||||
} pokerworld_t;
|
} pokerworld_t;
|
||||||
|
|
||||||
|
|
||||||
@ -66,12 +72,14 @@ void pokerWorldInit(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the camera to look at a specific player. You can use this to look at
|
* Adjusts the camera to look at a specific player. You can use this to look at
|
||||||
* the dealer by referencing the POKER_PLAYER_COUNT as the index.
|
* the dealer by referencing the POKER_PLAYER_HUMAN_INDEX as the index.
|
||||||
*
|
*
|
||||||
* @param scene Scene to adjust.
|
* @param scene Visual Novel Engine scene.
|
||||||
* @param playerIndex Player index to look at.
|
* @param playerIndex Player index to look at.
|
||||||
*/
|
*/
|
||||||
void pokerWorldLookAtPlayer(vnscene_t *scene, uint8_t playerIndex);
|
void pokerWorldLookAtPlayer(
|
||||||
|
vnscene_t *scene, uint8_t playerIndex
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the poker world.
|
* Render the poker world.
|
||||||
@ -79,9 +87,7 @@ void pokerWorldLookAtPlayer(vnscene_t *scene, uint8_t playerIndex);
|
|||||||
* @param world Poker Game World.
|
* @param world Poker Game World.
|
||||||
* @param assets Assets to use.
|
* @param assets Assets to use.
|
||||||
*/
|
*/
|
||||||
void pokerWorldRender(
|
void pokerWorldRender(pokerworld_t *world, pokergameassets_t *assets);
|
||||||
pokerworld_t *world, pokergameassets_t *assets
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup the poker world.
|
* Cleanup the poker world.
|
||||||
|
@ -14,6 +14,7 @@ bool pokerPlayerIsAlive(pokerplayer_t *player) {
|
|||||||
void pokerPlayerReset(pokerplayer_t *player) {
|
void pokerPlayerReset(pokerplayer_t *player) {
|
||||||
player->cardCount = 0;
|
player->cardCount = 0;
|
||||||
player->currentBet = 0;
|
player->currentBet = 0;
|
||||||
|
player->timesRaised = 0;
|
||||||
|
|
||||||
// Invert then bitwise AND to turn off.
|
// Invert then bitwise AND to turn off.
|
||||||
player->state &= ~(
|
player->state &= ~(
|
||||||
|
@ -53,6 +53,9 @@ typedef struct {
|
|||||||
|
|
||||||
/** Current bet in current round player has placed */
|
/** Current bet in current round player has placed */
|
||||||
int32_t currentBet;
|
int32_t currentBet;
|
||||||
|
|
||||||
|
/** How many times for the current flop that the player has raised */
|
||||||
|
int32_t timesRaised;
|
||||||
} pokerplayer_t;
|
} pokerplayer_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,12 +9,13 @@
|
|||||||
|
|
||||||
pokerturn_t pokerTurnGet(poker_t *poker, uint8_t playerIndex) {
|
pokerturn_t pokerTurnGet(poker_t *poker, uint8_t playerIndex) {
|
||||||
int32_t random, maxBet, bluffBet, callBet;
|
int32_t random, maxBet, bluffBet, callBet;
|
||||||
float winProbability, expectedGain, confidence, potOdds;
|
float confidence, expectedGain, potOdds;
|
||||||
bool isBluff;
|
bool isBluff;
|
||||||
int32_t amount;
|
int32_t amount;
|
||||||
pokerplayer_t *player;
|
pokerplayer_t *player;
|
||||||
pokerplayerwinning_t winning;
|
pokerplayerwinning_t winning;
|
||||||
uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1;
|
uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1;
|
||||||
|
pokerturn_t turn;
|
||||||
|
|
||||||
player = poker->players + playerIndex;
|
player = poker->players + playerIndex;
|
||||||
|
|
||||||
@ -23,42 +24,53 @@ pokerturn_t pokerTurnGet(poker_t *poker, uint8_t playerIndex) {
|
|||||||
return pokerTurnOut(poker, playerIndex);
|
return pokerTurnOut(poker, playerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we basically need to determine the AI's action here. The AI really only
|
// The following logic is heavily inspired by;
|
||||||
// needs to do one thing, decide whether or not they want to Bet or Not.
|
// https://github.com/gorel/C-Poker-AI/blob/master/src/common/pokerai.c
|
||||||
// In future I may make checking optional, but for now there's really no
|
// But with some changes and smarts added by me. The original source code will
|
||||||
// reason not to.
|
// essentially just run a crap tun of simulated games and get the times that
|
||||||
pokerWinnerPlayerGet(&poker->dealer, player, &winning);
|
// they are expected to win from those games, but I'm just going to use the
|
||||||
|
// odds of the winning hand.
|
||||||
|
|
||||||
// Get the current winning hand.
|
|
||||||
|
// Is this preflop?
|
||||||
if(poker->dealer.cardsFacing == 0 && player->cardCount >= 2) {
|
if(poker->dealer.cardsFacing == 0 && player->cardCount >= 2) {
|
||||||
|
// Get the hand weight
|
||||||
cardNumber0 = cardGetNumber(player->cards[0]);
|
cardNumber0 = cardGetNumber(player->cards[0]);
|
||||||
cardNumber1 = cardGetNumber(player->cards[1]);
|
cardNumber1 = cardGetNumber(player->cards[1]);
|
||||||
suitNumber0 = cardGetSuit(player->cards[0]);
|
suitNumber0 = cardGetSuit(player->cards[0]);
|
||||||
suitNumber1 = cardGetSuit(player->cards[1]);
|
suitNumber1 = cardGetSuit(player->cards[1]);
|
||||||
|
|
||||||
|
// Get delta between cards
|
||||||
i = mathAbs(cardNumber0 - cardNumber1);
|
i = mathAbs(cardNumber0 - cardNumber1);
|
||||||
|
|
||||||
|
// Get card weight
|
||||||
confidence = (float)cardNumber0 + (float)cardNumber1;
|
confidence = (float)cardNumber0 + (float)cardNumber1;
|
||||||
if(cardNumber0 == cardNumber1) {
|
if(cardNumber0 == cardNumber1) {// Pairs
|
||||||
confidence += 6;
|
confidence += 6;
|
||||||
} else if(suitNumber0 == suitNumber1) {
|
} else if(suitNumber0 == suitNumber1) {// Same suit
|
||||||
confidence += 4;
|
confidence += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get difference from cards for guessing flush
|
||||||
if(i > 4) {
|
if(i > 4) {
|
||||||
confidence -= 4;
|
confidence -= 4;
|
||||||
} else if(i > 2) {
|
} else if(i > 2) {
|
||||||
confidence -= i;
|
confidence -= i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the confidence delta 0-1
|
||||||
confidence = confidence / 30.0f;
|
confidence = confidence / 30.0f;
|
||||||
} else {
|
} else {
|
||||||
|
// Simulate my hand being the winning hand, use that as the confidence
|
||||||
|
pokerWinnerPlayerGet(&poker->dealer, player, &winning);
|
||||||
confidence = pokerWinnerGetTypeConfidence(winning.type);
|
confidence = pokerWinnerGetTypeConfidence(winning.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now we know how confident the AI is, let's put a chip value to that weight
|
||||||
|
// How many chips to call?
|
||||||
callBet = poker->bet.currentBet - player->currentBet;
|
callBet = poker->bet.currentBet - player->currentBet;
|
||||||
winProbability = confidence;
|
|
||||||
|
|
||||||
|
// Do they need chips to call, or is it possible to check?
|
||||||
if(callBet > 0) {
|
if(callBet > 0) {
|
||||||
potOdds = (float)callBet / ((float)callBet + (float)poker->bet.pot);
|
potOdds = (float)callBet / ((float)callBet + (float)poker->bet.pot);
|
||||||
} else {
|
} else {
|
||||||
@ -66,26 +78,36 @@ pokerturn_t pokerTurnGet(poker_t *poker, uint8_t playerIndex) {
|
|||||||
1.0f / (float)pokerBetGetRemainingPlayerCount(&poker->bet, poker->players)
|
1.0f / (float)pokerBetGetRemainingPlayerCount(&poker->bet, poker->players)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expectedGain = winProbability / potOdds;
|
|
||||||
|
|
||||||
|
// Now determine the expected ROI
|
||||||
|
expectedGain = confidence / potOdds;
|
||||||
|
|
||||||
|
// Now get a random 0-100
|
||||||
random = randInt32() % 100;
|
random = randInt32() % 100;
|
||||||
maxBet = (int32_t)(poker->bet.currentBet / 1.75f) - (random / 2);//?
|
|
||||||
maxBet -= callBet;//?
|
// Determine the max bet that the AI is willing to make
|
||||||
|
maxBet = (int32_t)(poker->bet.currentBet / 1.75f) - (random / 2) - callBet;
|
||||||
|
|
||||||
|
// Determine what's a good bluff bet.
|
||||||
bluffBet = random * maxBet / 100 / 2;
|
bluffBet = random * maxBet / 100 / 2;
|
||||||
|
|
||||||
|
// Now prep the output
|
||||||
isBluff = false;
|
isBluff = false;
|
||||||
amount = 0;
|
amount = 0;
|
||||||
|
|
||||||
if(expectedGain < 0.8 && winProbability < 0.8) {
|
// Now the actual AI can happen. This is basically a weight to confidence
|
||||||
|
// ratio. The higher the gains and the confidence then the more likely the AI
|
||||||
|
// is to betting. There are also bluff chances within here.
|
||||||
|
if(expectedGain < 0.8 && confidence < 0.8) {
|
||||||
if(random < 95) {
|
if(random < 95) {
|
||||||
amount = 0;//FOLD
|
amount = 0;
|
||||||
} else {
|
} else {
|
||||||
amount = bluffBet;
|
amount = bluffBet;
|
||||||
isBluff = true;
|
isBluff = true;
|
||||||
}
|
}
|
||||||
} else if ((expectedGain < 1.0 && winProbability < 0.85) || winProbability < 0.1) {
|
} else if ((expectedGain < 1.0 && confidence < 0.85) || confidence < 0.1) {
|
||||||
if (random < 80) {
|
if (random < 80) {
|
||||||
amount = 0;//FOLD
|
amount = 0;
|
||||||
} else if(random < 5) {
|
} else if(random < 5) {
|
||||||
amount = callBet;
|
amount = callBet;
|
||||||
isBluff = true;
|
isBluff = true;
|
||||||
@ -93,13 +115,13 @@ pokerturn_t pokerTurnGet(poker_t *poker, uint8_t playerIndex) {
|
|||||||
amount = bluffBet;
|
amount = bluffBet;
|
||||||
isBluff = true;
|
isBluff = true;
|
||||||
}
|
}
|
||||||
} else if ((expectedGain < 1.3 && winProbability < 0.9) || winProbability < 0.5) {
|
} else if ((expectedGain < 1.3 && confidence < 0.9) || confidence < 0.5) {
|
||||||
if (random < 60 || winProbability < 0.5) {
|
if (random < 60 || confidence < 0.5) {
|
||||||
amount = callBet;
|
amount = callBet;
|
||||||
} else {
|
} else {
|
||||||
amount = maxBet;
|
amount = maxBet;
|
||||||
}
|
}
|
||||||
} else if (winProbability < 0.95 || poker->dealer.cardsFacing < 0x04) {
|
} else if (confidence < 0.95 || poker->dealer.cardsFacing < 0x04) {
|
||||||
if(random < 30) {
|
if(random < 30) {
|
||||||
amount = callBet;
|
amount = callBet;
|
||||||
} else {
|
} else {
|
||||||
@ -109,21 +131,24 @@ pokerturn_t pokerTurnGet(poker_t *poker, uint8_t playerIndex) {
|
|||||||
amount = (poker->bet.currentBet - callBet) * 9 / 10;
|
amount = (poker->bet.currentBet - callBet) * 9 / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let's not get caught in a raising loop with AI.
|
||||||
|
if(player->timesRaised >= POKER_TURN_MAX_RAISES) amount = callBet;
|
||||||
|
|
||||||
printf("Raw Amount %i\n", amount);
|
// Did we actually bet?
|
||||||
|
|
||||||
// TODO: Make sure we don't get stuck in a raise loop.
|
|
||||||
if(amount > 0) {
|
if(amount > 0) {
|
||||||
amount = mathMin(amount, callBet);
|
amount = mathMin(amount, callBet);
|
||||||
return pokerTurnRaise(poker, playerIndex, amount);
|
turn = pokerTurnRaise(poker, playerIndex, amount);
|
||||||
}
|
turn.confidence = confidence;
|
||||||
|
} else if(pokerTurnCanPlayerCheck(poker, playerIndex)) {
|
||||||
if(pokerTurnCanPlayerCheck(poker, playerIndex)) {
|
turn = pokerTurnCheck(poker, playerIndex);
|
||||||
return pokerTurnCheck(poker, playerIndex);
|
turn.confidence = 1;
|
||||||
|
} else {
|
||||||
|
turn = pokerTurnFold(poker, playerIndex);
|
||||||
|
turn.confidence = 1 - confidence;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing worth doing, so let's just fold here.
|
|
||||||
return pokerTurnFold(poker, playerIndex);
|
return turn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pokerTurnAction(poker_t *poker, pokerplayer_t *player, pokerturn_t *turn) {
|
void pokerTurnAction(poker_t *poker, pokerplayer_t *player, pokerturn_t *turn) {
|
||||||
@ -132,14 +157,17 @@ void pokerTurnAction(poker_t *poker, pokerplayer_t *player, pokerturn_t *turn) {
|
|||||||
case POKER_TURN_TYPE_CALL:
|
case POKER_TURN_TYPE_CALL:
|
||||||
case POKER_TURN_TYPE_ALL_IN:
|
case POKER_TURN_TYPE_ALL_IN:
|
||||||
pokerBetPlayer(&poker->bet, player, turn->chips);
|
pokerBetPlayer(&poker->bet, player, turn->chips);
|
||||||
|
player->timesRaised++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POKER_TURN_TYPE_CHECK:
|
case POKER_TURN_TYPE_CHECK:
|
||||||
pokerBetPlayer(&poker->bet, player, 0);
|
pokerBetPlayer(&poker->bet, player, 0);
|
||||||
|
player->timesRaised = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POKER_TURN_TYPE_FOLD:
|
case POKER_TURN_TYPE_FOLD:
|
||||||
player->state |= POKER_PLAYER_STATE_FOLDED;
|
player->state |= POKER_PLAYER_STATE_FOLDED;
|
||||||
|
player->timesRaised = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#define POKER_TURN_TYPE_CALL_ALL_IN 0x04
|
#define POKER_TURN_TYPE_CALL_ALL_IN 0x04
|
||||||
#define POKER_TURN_TYPE_CHECK 0x05
|
#define POKER_TURN_TYPE_CHECK 0x05
|
||||||
|
|
||||||
|
#define POKER_TURN_MAX_RAISES 0x02
|
||||||
|
|
||||||
/** The turn that a player/the AI decided to do for its turn */
|
/** The turn that a player/the AI decided to do for its turn */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** What type of action the turn is */
|
/** What type of action the turn is */
|
||||||
|
@ -12,12 +12,16 @@ void vnSceneInit(vnscene_t *scene, font_t *font, texture_t *text) {
|
|||||||
vnConversationInit(&scene->conversation, font, text);
|
vnConversationInit(&scene->conversation, font, text);
|
||||||
scene->conversation.textbox.linesMax = 3;
|
scene->conversation.textbox.linesMax = 3;
|
||||||
|
|
||||||
scene->cameraX = 0;
|
// Init the animation
|
||||||
scene->cameraY = 0;
|
timelineInit(&scene->timeline);
|
||||||
scene->cameraZ = 0;
|
|
||||||
scene->cameraLookX = 0;
|
// Reset Camera
|
||||||
scene->cameraLookY = 0;
|
scene->cameraLook.x = 0;
|
||||||
scene->cameraLookZ = -5;
|
scene->cameraLook.y = 0;
|
||||||
|
scene->cameraLook.z = 0;
|
||||||
|
scene->cameraLook.lookX = 0;
|
||||||
|
scene->cameraLook.lookY = 0;
|
||||||
|
scene->cameraLook.lookZ = 0;
|
||||||
|
|
||||||
// Reset character count
|
// Reset character count
|
||||||
scene->characterCount = 0x00;
|
scene->characterCount = 0x00;
|
||||||
@ -26,6 +30,9 @@ void vnSceneInit(vnscene_t *scene, font_t *font, texture_t *text) {
|
|||||||
void vnSceneUpdate(vnscene_t *scene, engine_t *engine) {
|
void vnSceneUpdate(vnscene_t *scene, engine_t *engine) {
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
|
// Tick the animations.
|
||||||
|
timelineUpdate(&scene->timeline, engine->time.delta);
|
||||||
|
|
||||||
// Update the conversation
|
// Update the conversation
|
||||||
vnConversationUpdate(&scene->conversation, engine);
|
vnConversationUpdate(&scene->conversation, engine);
|
||||||
|
|
||||||
@ -40,11 +47,8 @@ void vnSceneDispose(vnscene_t *scene) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vnSceneRenderWorld(vnscene_t *scene, engine_t *engine, shader_t *shader) {
|
void vnSceneRenderWorld(vnscene_t *scene, engine_t *engine, shader_t *shader) {
|
||||||
// Adjust 3D Space position
|
// Adjust Camera Position.
|
||||||
cameraLookAt(&scene->camera,
|
cameraLookAtStruct(&scene->camera, scene->cameraLook);
|
||||||
scene->cameraX, scene->cameraY, scene->cameraZ,
|
|
||||||
scene->cameraLookX, scene->cameraLookY, scene->cameraLookZ
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set Camera Perspective
|
// Set Camera Perspective
|
||||||
cameraPerspective(&scene->camera, 35,
|
cameraPerspective(&scene->camera, 35,
|
||||||
@ -90,4 +94,45 @@ void vnSceneRenderGui(vnscene_t *scene, engine_t *engine, shader_t *shader) {
|
|||||||
|
|
||||||
// Render Conversation Element
|
// Render Conversation Element
|
||||||
vnConversationRender(&scene->conversation, engine, shader);
|
vnConversationRender(&scene->conversation, engine, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vnSceneLookAt(vnscene_t *scene,
|
||||||
|
float x, float y, float z, float lookX, float lookY, float lookZ
|
||||||
|
) {
|
||||||
|
float d, s;
|
||||||
|
timeline_t *t;
|
||||||
|
easefunction_t *f;
|
||||||
|
|
||||||
|
d = 1.0f;
|
||||||
|
s = scene->timeline.current;
|
||||||
|
t = &scene->timeline;
|
||||||
|
f = &easeOutQuart;
|
||||||
|
|
||||||
|
// Clear the timeline
|
||||||
|
timelineClear(t);
|
||||||
|
|
||||||
|
// Positions
|
||||||
|
timelineAddDeltaActionTo(t, s, d,
|
||||||
|
scene->cameraLook.x, x, f, &scene->cameraLook.x
|
||||||
|
);
|
||||||
|
timelineAddDeltaActionTo(t, s, d,
|
||||||
|
scene->cameraLook.y, y, f, &scene->cameraLook.y
|
||||||
|
);
|
||||||
|
timelineAddDeltaActionTo(t, s, d,
|
||||||
|
scene->cameraLook.z, z, f, &scene->cameraLook.z
|
||||||
|
);
|
||||||
|
|
||||||
|
timelineAddDeltaActionTo(t, s, d,
|
||||||
|
scene->cameraLook.lookX, lookX, f, &scene->cameraLook.lookX
|
||||||
|
);
|
||||||
|
timelineAddDeltaActionTo(t, s, d,
|
||||||
|
scene->cameraLook.lookY, lookY, f, &scene->cameraLook.lookY
|
||||||
|
);
|
||||||
|
timelineAddDeltaActionTo(t, s, d,
|
||||||
|
scene->cameraLook.lookZ, lookZ, f, &scene->cameraLook.lookZ
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vnSceneLookAtCharacter(vnscene_t *scene, uint8_t c, float distance) {
|
||||||
|
vncharacter_t *character = scene->characters + c;
|
||||||
}
|
}
|
@ -12,17 +12,19 @@
|
|||||||
#include "ui/vntextbox.h"
|
#include "ui/vntextbox.h"
|
||||||
#include "../display/camera.h"
|
#include "../display/camera.h"
|
||||||
#include "../display/shader.h"
|
#include "../display/shader.h"
|
||||||
|
#include "../display/animation/timeline.h"
|
||||||
|
#include "../display/animation/easing.h"
|
||||||
|
#include "../util/math.h"
|
||||||
|
|
||||||
/** Maximum number of Visual Novel Characters the scene can support */
|
/** Maximum number of Visual Novel Characters the scene can support */
|
||||||
#define VN_SCENE_CHARACTERS_MAX 6
|
#define VN_SCENE_CHARACTERS_MAX 6
|
||||||
|
#define VN_SCENE_DISTANCE_DEFAULT -5.0f
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float cameraX;
|
timeline_t timeline;
|
||||||
float cameraY;
|
|
||||||
float cameraZ;
|
// Camera Targets
|
||||||
float cameraLookX;
|
cameralookat_t cameraLook;
|
||||||
float cameraLookY;
|
|
||||||
float cameraLookZ;
|
|
||||||
|
|
||||||
/** Camera used for rendering, updated frequently */
|
/** Camera used for rendering, updated frequently */
|
||||||
camera_t camera;
|
camera_t camera;
|
||||||
@ -45,4 +47,8 @@ void vnSceneRenderWorld(vnscene_t *scene, engine_t *engine, shader_t *shader);
|
|||||||
|
|
||||||
void vnSceneRenderCharacters(vnscene_t *scene, shader_t *shader);
|
void vnSceneRenderCharacters(vnscene_t *scene, shader_t *shader);
|
||||||
|
|
||||||
void vnSceneRenderGui(vnscene_t *scene, engine_t *engine, shader_t *shader);
|
void vnSceneRenderGui(vnscene_t *scene, engine_t *engine, shader_t *shader);
|
||||||
|
|
||||||
|
void vnSceneLookAt(vnscene_t *scene,
|
||||||
|
float x, float y, float z, float lookX, float lookY, float lookZ
|
||||||
|
);
|
Reference in New Issue
Block a user