Better character matcher
This commit is contained in:
parent
5856057c81
commit
61a9a64ec8
|
@ -195,6 +195,9 @@
|
|||
tray.setToolTip(l('title'));
|
||||
tray.on('click', (_) => this.trayClicked(tab));
|
||||
const view = new electron.remote.BrowserView();
|
||||
|
||||
// view.webContents.openDevTools();
|
||||
|
||||
view.setAutoResize({width: true, height: true});
|
||||
electron.ipcRenderer.send('tab-added', view.webContents.id);
|
||||
const tab = {active: false, view, user: undefined, hasNew: false, tray};
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
<div class="alert alert-info" v-show="loading">Loading character information.</div>
|
||||
<div class="alert alert-danger" v-show="error">{{error}}</div>
|
||||
</div>
|
||||
<div class="col-md-4 col-lg-3 col-xl-2" v-if="!loading && character">
|
||||
<div class="col-md-4 col-lg-3 col-xl-2" v-if="!loading && character && character.character && characterMatch && selfCharacter">
|
||||
<sidebar :character="character" :characterMatch="characterMatch" @memo="memo" @bookmarked="bookmarked" :oldApi="oldApi"></sidebar>
|
||||
</div>
|
||||
<div class="col-md-8 col-lg-9 col-xl-10 profile-body" v-if="!loading && character">
|
||||
<div class="col-md-8 col-lg-9 col-xl-10 profile-body" v-if="!loading && character && character.character && characterMatch && selfCharacter">
|
||||
<div id="characterView">
|
||||
<div>
|
||||
<div v-if="character.ban_reason" id="headerBanReason" class="alert alert-warning">
|
||||
|
@ -36,6 +36,7 @@
|
|||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane" :class="{active: tab === '0'}" id="overview">
|
||||
<match-report :characterMatch="characterMatch"></match-report>
|
||||
<div v-bbcode="character.character.description" style="margin-bottom: 10px"></div>
|
||||
<character-kinks :character="character" :oldApi="oldApi" ref="tab0"></character-kinks>
|
||||
</div>
|
||||
|
@ -84,6 +85,7 @@
|
|||
import Sidebar from './sidebar.vue';
|
||||
import core from '../../chat/core';
|
||||
import { Matcher, MatchReport } from './matcher';
|
||||
import MatchReportView from './match-report.vue';
|
||||
|
||||
|
||||
interface ShowableVueTab extends Vue {
|
||||
|
@ -99,7 +101,8 @@
|
|||
'character-groups': GroupsView,
|
||||
'character-infotags': InfotagsView,
|
||||
'character-images': ImagesView,
|
||||
'character-kinks': CharacterKinksView
|
||||
'character-kinks': CharacterKinksView,
|
||||
'match-report': MatchReportView
|
||||
}
|
||||
})
|
||||
export default class CharacterPage extends Vue {
|
||||
|
@ -147,9 +150,9 @@
|
|||
return this.load();
|
||||
}
|
||||
|
||||
|
||||
async load(mustLoad = true) {
|
||||
this.loading = true;
|
||||
this.error = '';
|
||||
|
||||
try {
|
||||
const due: Promise<any>[] = [];
|
||||
|
@ -173,7 +176,6 @@
|
|||
this.loading = false;
|
||||
}
|
||||
|
||||
|
||||
memo(memo: {id: number, memo: string}): void {
|
||||
Vue.set(this.character!, 'memo', memo);
|
||||
}
|
||||
|
@ -182,7 +184,6 @@
|
|||
Vue.set(this.character!, 'bookmarked', state);
|
||||
}
|
||||
|
||||
|
||||
protected async loadSelfCharacter(): Promise<Character> {
|
||||
// console.log('SELF');
|
||||
|
||||
|
@ -197,10 +198,9 @@
|
|||
return this.selfCharacter;
|
||||
}
|
||||
|
||||
|
||||
private async _getCharacter(): Promise<void> {
|
||||
this.error = '';
|
||||
this.character = undefined;
|
||||
|
||||
if(this.name === undefined || this.name.length === 0)
|
||||
return;
|
||||
|
||||
|
@ -218,8 +218,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const matcher = new Matcher(this.selfCharacter.character, this.character.character);
|
||||
this.characterMatch = matcher.match();
|
||||
this.characterMatch = Matcher.generateReport(this.selfCharacter.character, this.character.character);
|
||||
|
||||
console.log('Match', this.selfCharacter.character.name, this.character.character.name, this.characterMatch);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -445,23 +446,123 @@
|
|||
|
||||
|
||||
.infotag {
|
||||
&.match-score {
|
||||
padding-top: 2px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
margin-left: -4px;
|
||||
margin-right: -4px;
|
||||
border-radius: 2px;
|
||||
padding-bottom: 2px;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.infotag-value {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.match {
|
||||
background-color: green;
|
||||
background-color: rgba(0, 255, 0, 0.5);
|
||||
border: solid 1px rgba(0, 255, 0, 0.15);
|
||||
}
|
||||
|
||||
&.mismatch {
|
||||
background-color: red;
|
||||
background-color: rgba(255, 0, 0, 0.6);
|
||||
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
|
||||
&.weakMatch {
|
||||
background-color: rgba(0, 162, 0, 0.6);
|
||||
&.weak-match {
|
||||
background-color: rgba(0, 162, 0, 0.35);
|
||||
border: 1px solid rgba(0, 162, 0, 0.15);
|
||||
}
|
||||
|
||||
|
||||
&.weakMismatch {
|
||||
background-color: rgba(255, 96, 0, 0.6);
|
||||
&.weak-mismatch {
|
||||
background-color: rgba(255, 225, 0, 0.6);
|
||||
border: 1px solid rgba(255, 225, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.match-report {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
/* width: 100%; */
|
||||
margin-top: -1.2rem;
|
||||
margin-left: -1.2rem;
|
||||
margin-right: -1.2rem;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0.5rem;
|
||||
max-width: 25rem;
|
||||
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.scores {
|
||||
float: left;
|
||||
flex: 1;
|
||||
margin-right: 1rem;
|
||||
max-width: 25rem;
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
padding-left: 0.5rem;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.match-score {
|
||||
font-size: 0.85rem;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 4px;
|
||||
padding: 2px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
|
||||
span {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.match {
|
||||
background-color: rgba(0, 255, 0, 0.5);
|
||||
border: solid 1px rgba(0, 255, 0, 0.15);
|
||||
}
|
||||
|
||||
&.mismatch {
|
||||
background-color: rgba(255, 0, 0, 0.6);
|
||||
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
|
||||
&.weak-match {
|
||||
background-color: rgba(0, 162, 0, 0.35);
|
||||
border: 1px solid rgba(0, 162, 0, 0.15);
|
||||
}
|
||||
|
||||
|
||||
&.weak-mismatch {
|
||||
background-color: rgba(255, 225, 0, 0.6);
|
||||
border: 1px solid rgba(255, 225, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vs {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
text-align: center;
|
||||
font-size: 5rem;
|
||||
line-height: 0;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
font-style: italic;
|
||||
font-family: 'Times New Roman', Georgia, serif;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -13,7 +13,7 @@
|
|||
import { DisplayInfotag } from './interfaces';
|
||||
// import { Character as CharacterInfo } from '../../interfaces';
|
||||
import {Store} from './data_store';
|
||||
import { MatchReport, TagId } from './matcher';
|
||||
import { MatchReport, Score, TagId } from './matcher';
|
||||
|
||||
|
||||
@Component
|
||||
|
@ -31,29 +31,36 @@
|
|||
infotag: true,
|
||||
};
|
||||
|
||||
console.log(`Infotag ${this.infotag.id}: ${this.label}`);
|
||||
// console.log(`Infotag ${this.infotag.id}: ${this.label}`);
|
||||
const id = this.infotag.id;
|
||||
|
||||
if ((this.characterMatch) && (this.infotag.id in this.characterMatch)) {
|
||||
const n = this.characterMatch[this.infotag.id];
|
||||
if (this.characterMatch) {
|
||||
const scores = this.theirInterestIsRelevant(id)
|
||||
? this.characterMatch.them.scores
|
||||
: (this.yourInterestIsRelevant(id) ? this.characterMatch.you.scores : null);
|
||||
|
||||
console.log(`Found match [${this.infotag.id} === ${TagId[this.infotag.id]}]: ${n}`);
|
||||
if (scores) {
|
||||
const score = scores[id] as Score;
|
||||
|
||||
if (n >= 1)
|
||||
styles.match = true;
|
||||
else if(n >= 0.5)
|
||||
styles.weakMatch = true;
|
||||
else if(n === 0)
|
||||
styles.neutral = true;
|
||||
else if(n <= -1)
|
||||
styles.mismatch = true;
|
||||
else if(n <= -0.5)
|
||||
styles.weakMismatch = true;
|
||||
styles[score.getRecommendedClass()] = true;
|
||||
styles['match-score'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
|
||||
theirInterestIsRelevant(id: number): boolean {
|
||||
return ((id === TagId.FurryPreference) || (id === TagId.Orientation));
|
||||
}
|
||||
|
||||
|
||||
yourInterestIsRelevant(id: number): boolean {
|
||||
return ((id === TagId.Gender) || (id === TagId.Age) || (id === TagId.Species))
|
||||
}
|
||||
|
||||
|
||||
get label(): string {
|
||||
const infotag = Store.kinks.infotags[this.infotag.id];
|
||||
if(typeof infotag === 'undefined')
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<div id="match-report" :class="{'match-report': true, minimized: minimized}" v-if="(haveScores(characterMatch.you) || haveScores(characterMatch.them))">
|
||||
<a @click="toggleMinimize()"><i :class="{fa: true, 'fa-plus': minimized, 'fa-minus': !minimized}"></i></a>
|
||||
|
||||
<div v-if="haveScores(characterMatch.you)" class="scores you">
|
||||
<h3>{{characterMatch.you.you.name}}</h3>
|
||||
|
||||
<ul>
|
||||
<li v-for="score in getScores(characterMatch.you)" v-if="shouldShowScore(score)" :class="getScoreClass(score)" v-html="score.description"></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="vs">
|
||||
vs.
|
||||
</div>
|
||||
|
||||
<div v-if="haveScores(characterMatch.them)" class="scores them">
|
||||
<h3>{{characterMatch.them.you.name}}</h3>
|
||||
|
||||
<ul>
|
||||
<li v-for="score in getScores(characterMatch.them)" v-if="shouldShowScore(score)" :class="getScoreClass(score)" v-html="score.description"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop } from '@f-list/vue-ts';
|
||||
import Vue from 'vue';
|
||||
import { MatchReport, MatchResult, Score, Scoring } from './matcher';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
|
||||
@Component
|
||||
export default class MatchReportView extends Vue {
|
||||
@Prop({required: true})
|
||||
readonly characterMatch!: MatchReport;
|
||||
|
||||
minimized = false;
|
||||
|
||||
getScoreClass(score: Score) {
|
||||
const classes: any = {};
|
||||
|
||||
classes[score.getRecommendedClass()] = true;
|
||||
classes['match-score'] = true;
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
haveScores(result: MatchResult): boolean {
|
||||
return !_.every(
|
||||
result.scores,
|
||||
(s: Score) => (s.score === Scoring.NEUTRAL)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
shouldShowScore(score: Score) {
|
||||
return (score.score !== Scoring.NEUTRAL);
|
||||
}
|
||||
|
||||
|
||||
getScores(result: MatchResult): Score[] {
|
||||
return _.map(result.scores, (s: Score) => (s));
|
||||
}
|
||||
|
||||
|
||||
toggleMinimize() {
|
||||
this.minimized = !this.minimized;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
|
@ -1,5 +1,7 @@
|
|||
import * as _ from 'lodash';
|
||||
import { Character } from '../../interfaces';
|
||||
import { Character, CharacterInfotag } from '../../interfaces';
|
||||
|
||||
/* eslint-disable no-null-keyword */
|
||||
|
||||
export enum TagId {
|
||||
Age = 1,
|
||||
|
@ -39,7 +41,6 @@ export enum Orientation {
|
|||
BiCurious = 128
|
||||
}
|
||||
|
||||
|
||||
export enum BodyType {
|
||||
Anthro = 122,
|
||||
Feral = 121,
|
||||
|
@ -54,28 +55,10 @@ export enum BodyType {
|
|||
export enum KinkPreference {
|
||||
Favorite = 1,
|
||||
Yes = 0.5,
|
||||
Maybe = 0,
|
||||
Maybe = -0.5,
|
||||
No = -1
|
||||
}
|
||||
|
||||
type ScoringCallback = (you: Character, them: Character) => number;
|
||||
|
||||
interface CompatibilityCollection {
|
||||
[key: number]: ScoringCallback;
|
||||
}
|
||||
|
||||
const orientationCompatibility: CompatibilityCollection = {
|
||||
[Orientation.Straight]: (you: Character, them: Character) => Matcher.isCis(you, them) ? (Matcher.isSameSexCis(you, them) ? -1 : 1) : 0,
|
||||
[Orientation.Gay]: (you: Character, them: Character) => Matcher.isCis(you, them) ? (Matcher.isSameSexCis(you, them) ? 1 : -1) : 0,
|
||||
[Orientation.Bisexual]: (you: Character) => Matcher.isGenderedCis(you) ? 1 : 0,
|
||||
[Orientation.Asexual]: () => 0,
|
||||
[Orientation.Unsure]: () => 0,
|
||||
[Orientation.BiMalePreference]: (you: Character, them: Character) => Matcher.isCis(you, them) ? (Matcher.isMaleCis(you) ? 1 : 0.5) : 0,
|
||||
[Orientation.BiFemalePreference]: (you: Character, them: Character) => Matcher.isCis(you, them) ? (Matcher.isFemaleCis(you) ? 1 : 0.5) : 0,
|
||||
[Orientation.Pansexual]: () => 1,
|
||||
[Orientation.BiCurious]: (you: Character, them: Character) => Matcher.isCis(you, them) ? (Matcher.isSameSexCis(you, them) ? 0.5 : Matcher.isGenderedCis(you) ? 1 : 0) : 0
|
||||
};
|
||||
|
||||
enum Kink {
|
||||
Females = 554,
|
||||
MaleHerms = 552,
|
||||
|
@ -91,9 +74,10 @@ enum Kink {
|
|||
UnderageCharacters = 207,
|
||||
|
||||
AnthroCharacters = 587,
|
||||
Humans = 609
|
||||
}
|
||||
Humans = 609,
|
||||
|
||||
Mammals = 224
|
||||
}
|
||||
|
||||
enum FurryPreference {
|
||||
FurriesOnly = 39,
|
||||
|
@ -118,11 +102,10 @@ const genderKinkMapping: GenderKinkIdMap = {
|
|||
[Gender.Transgender]: Kink.Transgenders
|
||||
};
|
||||
|
||||
|
||||
// if no species and 'no furry chareacters', === human
|
||||
// if no species and dislike 'antho characters' === human
|
||||
|
||||
enum Species {
|
||||
enum Species {
|
||||
Human = 609,
|
||||
Equine = 236,
|
||||
Feline = 212,
|
||||
|
@ -138,24 +121,34 @@ const genderKinkMapping: GenderKinkIdMap = {
|
|||
Procyon = 325,
|
||||
Rodent = 283,
|
||||
Ursine = 326,
|
||||
MarineMammal,
|
||||
MarineMammal = 309,
|
||||
Primate = 613,
|
||||
Elf = 611,
|
||||
Orc = 615,
|
||||
Fish = 608,
|
||||
Reptile = 225,
|
||||
Anthro = 587,
|
||||
Minotaur = 121212
|
||||
Minotaur = 12121212
|
||||
}
|
||||
|
||||
const nonAnthroSpecies = [Species.Human, Species.Elf, Species.Orc];
|
||||
|
||||
// const mammalSpecies = [Species.Human, Species.Equine, Species.Feline, Species.Canine, Species.Vulpine, Species.Cervine, Species.Lapine, Species.Musteline, Species.Rodent, Species.Ursine, Species.MarineMammal, Species.Primate, Species.Elf, Species.Orc, Species.Anthro, Species.Minotaur];
|
||||
const mammalSpecies = [Species.Equine, Species.Feline, Species.Canine, Species.Vulpine, Species.Cervine, Species.Lapine, Species.Musteline, Species.Rodent, Species.Ursine, Species.MarineMammal, Species.Primate, Species.Elf, Species.Orc, Species.Anthro, Species.Minotaur];
|
||||
|
||||
interface SpeciesMap {
|
||||
[key: number]: string[]
|
||||
}
|
||||
|
||||
interface SpeciesStrMap {
|
||||
[key: number]: string;
|
||||
}
|
||||
|
||||
const speciesNames: SpeciesStrMap = {
|
||||
[Species.MarineMammal]: 'marine mammals',
|
||||
[Species.Elf]: 'elves',
|
||||
[Species.Fish]: 'fishes'
|
||||
};
|
||||
|
||||
const speciesMapping: SpeciesMap = {
|
||||
[Species.Human]: ['human', 'humanoid', 'angel', 'android'],
|
||||
[Species.Equine]: ['horse', 'stallion', 'mare', 'filly', 'equine', 'shire', 'donkey', 'mule', 'zebra', 'centaur', 'pony' ],
|
||||
|
@ -180,7 +173,7 @@ const speciesMapping: SpeciesMap = {
|
|||
[Species.Reptile]: ['chameleon', 'anole', 'alligator', 'snake', 'crocodile', 'lizard'],
|
||||
[Species.Anthro]: ['anthro', 'anthropomorphic'],
|
||||
[Species.Minotaur]: ['minotaur']
|
||||
}
|
||||
};
|
||||
|
||||
interface KinkPreferenceMap {
|
||||
[key: string]: KinkPreference;
|
||||
|
@ -194,9 +187,76 @@ const kinkMapping: KinkPreferenceMap = {
|
|||
};
|
||||
|
||||
export interface MatchReport {
|
||||
[key: number]: number;
|
||||
you: MatchResult;
|
||||
them: MatchResult;
|
||||
}
|
||||
|
||||
export interface MatchResultCharacterInfo {
|
||||
species: Species | null;
|
||||
gender: Gender | null;
|
||||
orientation: Orientation | null;
|
||||
}
|
||||
|
||||
export interface MatchResultScores {
|
||||
[key: number]: Score;
|
||||
[TagId.Orientation]: Score;
|
||||
[TagId.Gender]: Score;
|
||||
[TagId.Age]: Score;
|
||||
[TagId.FurryPreference]: Score;
|
||||
[TagId.Species]: Score;
|
||||
}
|
||||
|
||||
export interface MatchResult {
|
||||
you: Character,
|
||||
them: Character,
|
||||
scores: MatchResultScores;
|
||||
info: MatchResultCharacterInfo;
|
||||
}
|
||||
|
||||
export enum Scoring {
|
||||
MATCH = 1,
|
||||
WEAK_MATCH = 0.5,
|
||||
NEUTRAL = 0,
|
||||
WEAK_MISMATCH = 0.5,
|
||||
MISMATCH = -1
|
||||
}
|
||||
|
||||
export interface ScoreClassMap {
|
||||
[key: number]: string;
|
||||
}
|
||||
|
||||
const scoreClasses: ScoreClassMap = {
|
||||
[Scoring.MATCH]: 'match',
|
||||
[Scoring.WEAK_MATCH]: 'weak-match',
|
||||
[Scoring.NEUTRAL]: 'neutral',
|
||||
[Scoring.WEAK_MISMATCH]: 'weak-mismatch',
|
||||
[Scoring.MISMATCH]: 'mismatch'
|
||||
};
|
||||
|
||||
export class Score {
|
||||
readonly score: Scoring;
|
||||
readonly description: string;
|
||||
|
||||
constructor(score: Scoring, description: string = '') {
|
||||
if ((score !== Scoring.NEUTRAL) && (description === ''))
|
||||
throw new Error('Description must be provided if score is not neutral');
|
||||
|
||||
this.score = score;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
getRecommendedClass(): string {
|
||||
return scoreClasses[this.score];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Answers the question: What YOU think about THEM
|
||||
* Never what THEY think about YOU
|
||||
*
|
||||
* So, when comparing two characters, you have to run it twice (you, them / them, you)
|
||||
* to get the full picture
|
||||
*/
|
||||
export class Matcher {
|
||||
you: Character;
|
||||
them: Character;
|
||||
|
@ -206,350 +266,300 @@ export class Matcher {
|
|||
this.them = them;
|
||||
}
|
||||
|
||||
match(): MatchReport {
|
||||
static generateReport(you: Character, them: Character): MatchReport {
|
||||
const youThem = new Matcher(you, them);
|
||||
const themYou = new Matcher(them, you);
|
||||
|
||||
return {
|
||||
[TagId.Orientation]: this.resolveScore(TagId.Orientation, orientationCompatibility),
|
||||
[TagId.Gender]: this.resolveGenderScore(),
|
||||
[TagId.Age]: this.resolveAgeScore(),
|
||||
[TagId.FurryPreference]: this.resolveFurryScore(),
|
||||
[TagId.Species]: this.resolveSpeciesScore()
|
||||
you: youThem.match(),
|
||||
them: themYou.match()
|
||||
};
|
||||
}
|
||||
|
||||
match(): MatchResult {
|
||||
return {
|
||||
you: this.you,
|
||||
them: this.them,
|
||||
|
||||
scores: {
|
||||
[TagId.Orientation]: this.resolveOrientationScore(),
|
||||
[TagId.Gender]: this.resolveGenderScore(),
|
||||
[TagId.Age]: this.resolveAgeScore(),
|
||||
[TagId.FurryPreference]: this.resolveFurryPairingsScore(),
|
||||
[TagId.Species]: this.resolveSpeciesScore()
|
||||
},
|
||||
|
||||
info: {
|
||||
species: Matcher.species(this.you),
|
||||
gender: Matcher.getTagValueList(TagId.Gender, this.you),
|
||||
orientation: Matcher.getTagValueList(TagId.Orientation, this.you),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private resolveScore(tagId: number, compatibilityMap: any, you: Character = this.you, them: Character = this.them): number {
|
||||
const v = Matcher.getTagValueList(tagId, this.them);
|
||||
|
||||
if ((!v) || (!(v in compatibilityMap)))
|
||||
return 0;
|
||||
|
||||
return compatibilityMap[v](you, them);
|
||||
}
|
||||
|
||||
|
||||
private resolveSpeciesScore() {
|
||||
private resolveOrientationScore(): Score {
|
||||
const you = this.you;
|
||||
const them = this.them;
|
||||
|
||||
const yourSpecies = Matcher.species(you);
|
||||
const yourGender = Matcher.getTagValueList(TagId.Gender, you);
|
||||
const theirGender = Matcher.getTagValueList(TagId.Gender, them);
|
||||
const yourOrientation = Matcher.getTagValueList(TagId.Orientation, you);
|
||||
|
||||
if ((yourGender === null) || (theirGender === null) || (yourOrientation === null))
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
|
||||
// Question: If someone identifies themselves as 'straight cuntboy', how should they be matched? like a straight female?
|
||||
|
||||
// CIS
|
||||
if (Matcher.isCisGender(yourGender)) {
|
||||
if (yourGender === theirGender) {
|
||||
// same sex CIS
|
||||
if (yourOrientation === Orientation.Straight)
|
||||
return new Score(Scoring.MISMATCH, 'No <span>same sex</span>');
|
||||
|
||||
if (
|
||||
(yourOrientation === Orientation.Gay)
|
||||
|| (yourOrientation === Orientation.Bisexual)
|
||||
|| (yourOrientation === Orientation.Pansexual)
|
||||
|| ((yourOrientation === Orientation.BiFemalePreference) && (theirGender === Gender.Female))
|
||||
|| ((yourOrientation === Orientation.BiMalePreference) && (theirGender === Gender.Male))
|
||||
)
|
||||
return new Score(Scoring.MATCH, 'Loves <span>same sex</span>');
|
||||
|
||||
if (
|
||||
(yourOrientation === Orientation.BiCurious)
|
||||
|| ((yourOrientation === Orientation.BiFemalePreference) && (theirGender === Gender.Male))
|
||||
|| ((yourOrientation === Orientation.BiMalePreference) && (theirGender === Gender.Female))
|
||||
)
|
||||
return new Score(Scoring.WEAK_MATCH, 'Likes <span>same sex</span>');
|
||||
} else if (Matcher.isCisGender(theirGender)) {
|
||||
// straight CIS
|
||||
if (yourOrientation === Orientation.Gay)
|
||||
return new Score(Scoring.MISMATCH, 'No <span>opposite sex</span>');
|
||||
|
||||
if (
|
||||
(yourOrientation === Orientation.Straight)
|
||||
|| (yourOrientation === Orientation.Bisexual)
|
||||
|| (yourOrientation === Orientation.BiCurious)
|
||||
|| (yourOrientation === Orientation.Pansexual)
|
||||
|| ((yourOrientation === Orientation.BiFemalePreference) && (theirGender === Gender.Female))
|
||||
|| ((yourOrientation === Orientation.BiMalePreference) && (theirGender === Gender.Male))
|
||||
)
|
||||
return new Score(Scoring.MATCH, 'Loves <span>opposite sex</span>');
|
||||
|
||||
if (
|
||||
((yourOrientation === Orientation.BiFemalePreference) && (theirGender === Gender.Male))
|
||||
|| ((yourOrientation === Orientation.BiMalePreference) && (theirGender === Gender.Female))
|
||||
)
|
||||
return new Score(Scoring.WEAK_MATCH, 'Likes <span>opposite sex</span>');
|
||||
}
|
||||
}
|
||||
|
||||
// Can't do anything with Gender.None
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
}
|
||||
|
||||
private formatKinkScore(score: KinkPreference, description: string): Score {
|
||||
if (score === KinkPreference.No)
|
||||
return new Score(Scoring.MISMATCH, `No <span>${description}</span>`);
|
||||
|
||||
if (score === KinkPreference.Maybe)
|
||||
return new Score(Scoring.WEAK_MISMATCH, `Undecided on <span>${description}</span>`);
|
||||
|
||||
if (score === KinkPreference.Yes)
|
||||
return new Score(Scoring.WEAK_MATCH, `Likes <span>${description}</span>`);
|
||||
|
||||
if (score === KinkPreference.Favorite)
|
||||
return new Score(Scoring.MATCH, `Loves <span>${description}</span>`);
|
||||
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
}
|
||||
|
||||
private resolveSpeciesScore(): Score {
|
||||
const you = this.you;
|
||||
const them = this.them;
|
||||
const theirSpecies = Matcher.species(them);
|
||||
|
||||
if (
|
||||
((yourSpecies !== null) && (Matcher.hatesSpecies(them, yourSpecies))) ||
|
||||
((theirSpecies !== null) && (Matcher.hatesSpecies(you, theirSpecies)))
|
||||
) {
|
||||
return -1;
|
||||
if (theirSpecies === null)
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
|
||||
const speciesScore = Matcher.getKinkSpeciesPreference(you, theirSpecies);
|
||||
|
||||
if (speciesScore !== null) {
|
||||
const speciesName = speciesNames[theirSpecies] || `${Species[theirSpecies].toLowerCase()}s`;
|
||||
|
||||
return this.formatKinkScore(speciesScore, speciesName);
|
||||
}
|
||||
|
||||
if (
|
||||
((yourSpecies !== null) && (Matcher.maybeSpecies(them, yourSpecies))) ||
|
||||
((theirSpecies !== null) && (Matcher.maybeSpecies(you, theirSpecies)))
|
||||
) {
|
||||
return -0.5;
|
||||
if (Matcher.isAnthro(them)) {
|
||||
const anthroScore = Matcher.getKinkPreference(them, Kink.AnthroCharacters);
|
||||
|
||||
if (anthroScore !== null)
|
||||
return this.formatKinkScore(anthroScore, 'anthros');
|
||||
}
|
||||
|
||||
if (
|
||||
((yourSpecies !== null) && (Matcher.likesSpecies(them, yourSpecies))) ||
|
||||
((theirSpecies !== null) && (Matcher.likesSpecies(you, theirSpecies)))
|
||||
) {
|
||||
return 1;
|
||||
if (Matcher.isMammal(them)) {
|
||||
const mammalScore = Matcher.getKinkPreference(them, Kink.Mammals);
|
||||
|
||||
if (mammalScore !== null)
|
||||
return this.formatKinkScore(mammalScore, 'mammals');
|
||||
}
|
||||
|
||||
return 0;
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
}
|
||||
|
||||
formatScoring(score: Scoring, description: string): Score {
|
||||
let type = '';
|
||||
|
||||
private resolveFurryScore() {
|
||||
switch (score) {
|
||||
case Scoring.MISMATCH:
|
||||
type = 'No';
|
||||
break;
|
||||
|
||||
case Scoring.WEAK_MISMATCH:
|
||||
type = 'Undecided on';
|
||||
break;
|
||||
|
||||
case Scoring.WEAK_MATCH:
|
||||
type = 'Likes';
|
||||
break;
|
||||
|
||||
case Scoring.MATCH:
|
||||
type = 'Loves';
|
||||
break;
|
||||
}
|
||||
|
||||
return new Score(score, `${type} <span>${description}</span>`);
|
||||
}
|
||||
|
||||
private resolveFurryPairingsScore(): Score {
|
||||
const you = this.you;
|
||||
const them = this.them;
|
||||
|
||||
const youAreAnthro = Matcher.isAnthro(you);
|
||||
const theyAreAnthro = Matcher.isAnthro(them);
|
||||
|
||||
const youAreHuman = Matcher.isHuman(you);
|
||||
const theyAreHuman = Matcher.isHuman(them);
|
||||
|
||||
const yourScore = theyAreAnthro ? Matcher.furryLikeabilityScore(you) : theyAreHuman ? Matcher.humanLikeabilityScore(you) : 0;
|
||||
const theirScore = youAreAnthro ? Matcher.furryLikeabilityScore(them) : youAreHuman ? Matcher.humanLikeabilityScore(them) : 0;
|
||||
const score = theyAreAnthro
|
||||
? Matcher.furryLikeabilityScore(you)
|
||||
: (theyAreHuman ? Matcher.humanLikeabilityScore(you) : Scoring.NEUTRAL);
|
||||
|
||||
return Math.min(yourScore || 0, theirScore || 0);
|
||||
return this.formatScoring(score, theyAreAnthro ? 'furry pairings' : theyAreHuman ? 'human pairings' : '');
|
||||
}
|
||||
|
||||
|
||||
static furryLikeabilityScore(c: Character): number | null {
|
||||
const anthroKink = Matcher.getKinkPreference(c, Kink.AnthroCharacters);
|
||||
|
||||
if ((anthroKink === KinkPreference.Yes) || (anthroKink === KinkPreference.Favorite)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (anthroKink === KinkPreference.Maybe) {
|
||||
return -0.5;
|
||||
}
|
||||
|
||||
if (anthroKink === KinkPreference.No) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static furryLikeabilityScore(c: Character): Scoring {
|
||||
const furryPreference = Matcher.getTagValueList(TagId.FurryPreference, c);
|
||||
|
||||
if (
|
||||
(furryPreference === FurryPreference.FursAndHumans) ||
|
||||
(furryPreference === FurryPreference.FurriesPreferredHumansOk) ||
|
||||
(furryPreference === FurryPreference.FurriesOnly)
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
)
|
||||
return Scoring.MATCH;
|
||||
|
||||
if (furryPreference === FurryPreference.HumansPreferredFurriesOk) {
|
||||
return 0.5;
|
||||
}
|
||||
if (furryPreference === FurryPreference.HumansPreferredFurriesOk)
|
||||
return Scoring.WEAK_MATCH;
|
||||
|
||||
if (furryPreference === FurryPreference.HumansOnly) {
|
||||
return -1;
|
||||
}
|
||||
if (furryPreference === FurryPreference.HumansOnly)
|
||||
return Scoring.MISMATCH;
|
||||
|
||||
return 0;
|
||||
return Scoring.NEUTRAL;
|
||||
}
|
||||
|
||||
|
||||
static humanLikeabilityScore(c: Character): number | null {
|
||||
const humanKink = Matcher.getKinkPreference(c, Kink.Humans);
|
||||
|
||||
if ((humanKink === KinkPreference.Yes) || (humanKink === KinkPreference.Favorite)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (humanKink === KinkPreference.Maybe) {
|
||||
return -0.5;
|
||||
}
|
||||
|
||||
if (humanKink === KinkPreference.No) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static humanLikeabilityScore(c: Character): Scoring {
|
||||
const humanPreference = Matcher.getTagValueList(TagId.FurryPreference, c);
|
||||
|
||||
if (
|
||||
(humanPreference === FurryPreference.FursAndHumans) ||
|
||||
(humanPreference === FurryPreference.HumansPreferredFurriesOk) ||
|
||||
(humanPreference === FurryPreference.HumansOnly)
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
(humanPreference === FurryPreference.FursAndHumans)
|
||||
|| (humanPreference === FurryPreference.HumansPreferredFurriesOk)
|
||||
|| (humanPreference === FurryPreference.HumansOnly)
|
||||
)
|
||||
return Scoring.MATCH;
|
||||
|
||||
if (humanPreference === FurryPreference.FurriesPreferredHumansOk) {
|
||||
return 0.5;
|
||||
}
|
||||
if (humanPreference === FurryPreference.FurriesPreferredHumansOk)
|
||||
return Scoring.WEAK_MATCH;
|
||||
|
||||
if (humanPreference === FurryPreference.FurriesOnly) {
|
||||
return -1;
|
||||
}
|
||||
if (humanPreference === FurryPreference.FurriesOnly)
|
||||
return Scoring.MISMATCH;
|
||||
|
||||
return 0;
|
||||
return Scoring.NEUTRAL;
|
||||
}
|
||||
|
||||
|
||||
static likesFurs(c: Character) {
|
||||
const score = this.furryLikeabilityScore(c);
|
||||
|
||||
return (score !== null) ? (score > 0) : false;
|
||||
}
|
||||
|
||||
static hatesFurs(c: Character) {
|
||||
const score = this.furryLikeabilityScore(c);
|
||||
|
||||
return (score !== null) ? (score < 0) : false;
|
||||
}
|
||||
|
||||
|
||||
static likesHumans(c: Character) {
|
||||
const score = this.humanLikeabilityScore(c);
|
||||
|
||||
return (score !== null) ? (score > 0) : false;
|
||||
}
|
||||
|
||||
|
||||
static hatesHumans(c: Character) {
|
||||
const score = this.humanLikeabilityScore(c);
|
||||
|
||||
return (score !== null) ? (score < 0) : false;
|
||||
}
|
||||
|
||||
|
||||
private resolveAgeScore(): number {
|
||||
private resolveAgeScore(): Score {
|
||||
const you = this.you;
|
||||
const them = this.them;
|
||||
|
||||
const yourAgeTag = Matcher.getTagValue(TagId.Age, you);
|
||||
const theirAgeTag = Matcher.getTagValue(TagId.Age, them);
|
||||
|
||||
if ((!yourAgeTag) || (!theirAgeTag)) {
|
||||
return 0;
|
||||
}
|
||||
if (!theirAgeTag)
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
|
||||
if ((!yourAgeTag.string) || (!theirAgeTag.string)) {
|
||||
return 0;
|
||||
}
|
||||
if (!theirAgeTag.string)
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
|
||||
const yourAge = parseInt(yourAgeTag.string, 10);
|
||||
const theirAge = parseInt(theirAgeTag.string, 10);
|
||||
|
||||
if (
|
||||
((theirAge < 16) && (Matcher.hates(you, Kink.Ageplay))) ||
|
||||
((yourAge < 16) && (Matcher.hates(them, Kink.Ageplay))) ||
|
||||
((theirAge < 16) && (Matcher.has(you, Kink.Ageplay) === false)) ||
|
||||
((yourAge < 16) && (Matcher.has(them, Kink.Ageplay) === false)) ||
|
||||
((yourAge < theirAge) && (Matcher.hates(you, Kink.OlderCharacters))) ||
|
||||
((yourAge > theirAge) && (Matcher.hates(them, Kink.OlderCharacters))) ||
|
||||
((yourAge > theirAge) && (Matcher.hates(you, Kink.YoungerCharacters))) ||
|
||||
((yourAge < theirAge) && (Matcher.hates(them, Kink.YoungerCharacters))) ||
|
||||
((theirAge < 18) && (Matcher.hates(you, Kink.UnderageCharacters))) ||
|
||||
((yourAge < 18) && (Matcher.hates(them, Kink.UnderageCharacters)))
|
||||
)
|
||||
return -1;
|
||||
const ageplayScore = Matcher.getKinkPreference(you, Kink.Ageplay);
|
||||
const underageScore = Matcher.getKinkPreference(you, Kink.UnderageCharacters);
|
||||
|
||||
if (
|
||||
((theirAge < 18) && (Matcher.likes(you, Kink.UnderageCharacters))) ||
|
||||
((yourAge < 18) && (Matcher.likes(them, Kink.UnderageCharacters))) ||
|
||||
((yourAge > theirAge) && (Matcher.likes(you, Kink.YoungerCharacters))) ||
|
||||
((yourAge < theirAge) && (Matcher.likes(them, Kink.YoungerCharacters))) ||
|
||||
((yourAge < theirAge) && (Matcher.likes(you, Kink.OlderCharacters))) ||
|
||||
((yourAge > theirAge) && (Matcher.likes(them, Kink.OlderCharacters))) ||
|
||||
((theirAge < 16) && (Matcher.likes(you, Kink.Ageplay))) ||
|
||||
((yourAge < 16) && (Matcher.likes(them, Kink.Ageplay)))
|
||||
)
|
||||
return 1;
|
||||
if ((theirAge < 16) && (ageplayScore !== null))
|
||||
return this.formatKinkScore(ageplayScore, `ages of ${theirAge}`);
|
||||
|
||||
return 0;
|
||||
if ((theirAge < 16) && (ageplayScore === null))
|
||||
return this.formatKinkScore(KinkPreference.No, `ages of ${theirAge}`);
|
||||
|
||||
if ((theirAge < 18) && (underageScore !== null))
|
||||
return this.formatKinkScore(underageScore, `ages of ${theirAge}`);
|
||||
|
||||
if ((yourAgeTag) && (yourAgeTag.string)) {
|
||||
const olderCharactersScore = Matcher.getKinkPreference(you, Kink.OlderCharacters);
|
||||
const youngerCharactersScore = Matcher.getKinkPreference(you, Kink.YoungerCharacters);
|
||||
|
||||
const yourAge = parseInt(yourAgeTag.string, 10);
|
||||
|
||||
if ((yourAge < theirAge) && (olderCharactersScore !== null))
|
||||
return this.formatKinkScore(olderCharactersScore, 'older characters');
|
||||
|
||||
if ((yourAge > theirAge) && (youngerCharactersScore !== null))
|
||||
return this.formatKinkScore(youngerCharactersScore, 'younger characters');
|
||||
}
|
||||
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
}
|
||||
|
||||
private resolveGenderScore() {
|
||||
private resolveGenderScore(): Score {
|
||||
const you = this.you;
|
||||
const them = this.them;
|
||||
|
||||
const yourGender = Matcher.getTagValueList(TagId.Gender, you);
|
||||
const theirGender = Matcher.getTagValueList(TagId.Gender, them);
|
||||
|
||||
const yourGenderScore = Matcher.genderLikeabilityScore(them, yourGender);
|
||||
const theirGenderScore = Matcher.genderLikeabilityScore(you, theirGender);
|
||||
if (theirGender === null)
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
|
||||
const yourFinalScore = (yourGenderScore !== null) ? yourGenderScore : this.resolveScore(TagId.Orientation, orientationCompatibility, you, them);
|
||||
const theirFinalScore = (theirGenderScore !== null) ? theirGenderScore : this.resolveScore(TagId.Orientation, orientationCompatibility, them, you);
|
||||
const genderName = `${Gender[theirGender].toLowerCase()}s`;
|
||||
const genderKinkScore = Matcher.getKinkGenderPreference(you, theirGender);
|
||||
|
||||
return Math.min(yourFinalScore, theirFinalScore);
|
||||
if (genderKinkScore !== null)
|
||||
return this.formatKinkScore(genderKinkScore, genderName);
|
||||
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
}
|
||||
|
||||
static getTagValue(tagId: number, c: Character) {
|
||||
static getTagValue(tagId: number, c: Character): CharacterInfotag | undefined {
|
||||
return c.infotags[tagId];
|
||||
}
|
||||
|
||||
static getTagValueList(tagId: number, c: Character): number | undefined {
|
||||
static getTagValueList(tagId: number, c: Character): number | null {
|
||||
const t = this.getTagValue(tagId, c);
|
||||
|
||||
if ((!t) || (!t.list)) {
|
||||
return;
|
||||
}
|
||||
if ((!t) || (!t.list))
|
||||
return null;
|
||||
|
||||
return t.list;
|
||||
}
|
||||
|
||||
// Considers males and females only
|
||||
static isSameSexCis(a: Character, b: Character): boolean {
|
||||
const aGender = this.getTagValueList(TagId.Gender, a);
|
||||
const bGender = this.getTagValueList(TagId.Gender, b);
|
||||
|
||||
if ((aGender !== Gender.Male) && (aGender !== Gender.Female)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((aGender !== undefined) && (aGender === bGender));
|
||||
}
|
||||
|
||||
// Considers
|
||||
static isGenderedCis(c: Character): boolean {
|
||||
const gender = this.getTagValueList(TagId.Gender, c);
|
||||
|
||||
return ((!!gender) && (gender !== Gender.None));
|
||||
}
|
||||
|
||||
static isMaleCis(c: Character): boolean {
|
||||
const gender = this.getTagValueList(TagId.Gender, c);
|
||||
|
||||
return (gender === Gender.Male);
|
||||
}
|
||||
|
||||
static isFemaleCis(c: Character): boolean {
|
||||
const gender = this.getTagValueList(TagId.Gender, c);
|
||||
|
||||
return (gender === Gender.Female);
|
||||
}
|
||||
|
||||
static isCis(...characters: Character[]): boolean {
|
||||
return _.every(characters, (c: Character) => ((Matcher.isMaleCis(c)) || (Matcher.isFemaleCis(c))));
|
||||
}
|
||||
|
||||
|
||||
static genderLikeabilityScore(c: Character, gender?: Gender): number | null {
|
||||
if (gender === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const byKink = Matcher.getKinkGenderPreference(c, gender);
|
||||
|
||||
if (byKink !== null) {
|
||||
if ((byKink === KinkPreference.Yes) || (byKink === KinkPreference.Favorite)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (byKink === KinkPreference.Maybe) {
|
||||
return -0.5;
|
||||
}
|
||||
|
||||
if (byKink === KinkPreference.No) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isCis(c)) {
|
||||
if ((gender !== Gender.Female) && (gender !== Gender.Male)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static likesGender(c: Character, gender: Gender): boolean | null {
|
||||
const byKink = Matcher.getKinkGenderPreference(c, gender);
|
||||
|
||||
if (byKink !== null)
|
||||
return ((byKink === KinkPreference.Yes) || (byKink === KinkPreference.Favorite));
|
||||
|
||||
if ((Matcher.isCis(c)) && ((gender === Gender.Male) || (gender === Gender.Female)))
|
||||
return gender !== this.getTagValueList(TagId.Gender, c);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static dislikesGender(c: Character, gender: Gender): boolean | null {
|
||||
const byKink = Matcher.getKinkGenderPreference(c, gender);
|
||||
|
||||
if (byKink !== null)
|
||||
return (byKink === KinkPreference.No);
|
||||
|
||||
if ((Matcher.isCis(c)) && ((gender === Gender.Male) || (gender === Gender.Female)))
|
||||
return gender === this.getTagValueList(TagId.Gender, c);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static maybeGender(c: Character, gender: Gender): boolean | null {
|
||||
const byKink = Matcher.getKinkGenderPreference(c, gender);
|
||||
|
||||
if (byKink !== null)
|
||||
return (byKink === KinkPreference.Maybe);
|
||||
|
||||
return null;
|
||||
static isCisGender(...genders: Gender[]): boolean {
|
||||
return _.every(genders, (g: Gender) => ((g === Gender.Female) || (g === Gender.Male)));
|
||||
}
|
||||
|
||||
static getKinkPreference(c: Character, kinkId: number): KinkPreference | null {
|
||||
|
@ -570,74 +580,40 @@ export class Matcher {
|
|||
return this.getKinkPreference(c, species);
|
||||
}
|
||||
|
||||
static likesSpecies(c: Character, species: Species): boolean | null {
|
||||
const byKink = Matcher.getKinkSpeciesPreference(c, species);
|
||||
|
||||
if (byKink !== null)
|
||||
return ((byKink === KinkPreference.Yes) || (byKink === KinkPreference.Favorite));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static maybeSpecies(c: Character, species: Species): boolean | null {
|
||||
const byKink = Matcher.getKinkSpeciesPreference(c, species);
|
||||
|
||||
if (byKink !== null)
|
||||
return (byKink === KinkPreference.Maybe);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static hatesSpecies(c: Character, species: Species): boolean | null {
|
||||
const byKink = Matcher.getKinkSpeciesPreference(c, species);
|
||||
|
||||
if (byKink !== null)
|
||||
return (byKink === KinkPreference.No);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static likes(c: Character, kinkId: Kink): boolean {
|
||||
const r = Matcher.getKinkPreference(c, kinkId);
|
||||
|
||||
return ((r === KinkPreference.Favorite) || (r === KinkPreference.Yes));
|
||||
|
||||
}
|
||||
|
||||
static hates(c: Character, kinkId: Kink): boolean {
|
||||
const r = Matcher.getKinkPreference(c, kinkId);
|
||||
|
||||
return (r === KinkPreference.No);
|
||||
|
||||
}
|
||||
|
||||
static has(c: Character, kinkId: Kink): boolean {
|
||||
const r = Matcher.getKinkPreference(c, kinkId);
|
||||
|
||||
return (r !== null);
|
||||
}
|
||||
|
||||
static isMammal(c: Character): boolean | null {
|
||||
const species = Matcher.species(c);
|
||||
|
||||
if (species === null)
|
||||
return null;
|
||||
|
||||
return (mammalSpecies.indexOf(species) >= 0);
|
||||
}
|
||||
|
||||
static isAnthro(c: Character): boolean | null {
|
||||
const bodyTypeId = this.getTagValueList(TagId.BodyType, c);
|
||||
|
||||
if (bodyTypeId === BodyType.Anthro) {
|
||||
if (bodyTypeId === BodyType.Anthro)
|
||||
return true;
|
||||
}
|
||||
|
||||
const speciesId = this.species(c);
|
||||
|
||||
if (!speciesId)
|
||||
return null;
|
||||
|
||||
return (nonAnthroSpecies.indexOf(parseInt(`${speciesId}`, 10)) < 0);
|
||||
return (nonAnthroSpecies.indexOf(speciesId) < 0);
|
||||
}
|
||||
|
||||
static isHuman(c: Character): boolean | null {
|
||||
const bodyTypeId = this.getTagValueList(TagId.BodyType, c);
|
||||
|
||||
if (bodyTypeId === BodyType.Human) {
|
||||
if (bodyTypeId === BodyType.Human)
|
||||
return true;
|
||||
}
|
||||
|
||||
const speciesId = this.species(c);
|
||||
|
||||
|
@ -650,9 +626,8 @@ export class Matcher {
|
|||
|
||||
const mySpecies = this.getTagValue(TagId.Species, c);
|
||||
|
||||
if ((!mySpecies) || (!mySpecies.string)) {
|
||||
if ((!mySpecies) || (!mySpecies.string))
|
||||
return Species.Human; // best guess
|
||||
}
|
||||
|
||||
const finalSpecies = mySpecies.string.toLowerCase();
|
||||
|
||||
|
@ -671,6 +646,6 @@ export class Matcher {
|
|||
}
|
||||
);
|
||||
|
||||
return foundSpeciesId;
|
||||
return (foundSpeciesId === null) ? null : parseInt(foundSpeciesId, 10);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue