rival.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. //
  2. // rival object, generally your oponent in combat, but can also be used as in intermediate object when
  3. // reviewing your clan or meeting other people
  4. /*jshint multistr:true*/
  5. var rival;
  6. // Functions
  7. function EncounterNamedRival(currentRival)
  8. {
  9. // Standard Victory/Defeat/Tells for Generic man
  10. console.log(currentRival);
  11. if(typeof currentRival !=="undefined"){
  12. rival=currentRival;
  13. }
  14. console.log(rival);
  15. rival.Victory = RivalVictory;
  16. rival.Defeat = RivalDefeat;
  17. rival.getTell = RivalGetTell;
  18. rival.spendExperience = RivalSpendExperience;
  19. rival.determineAttackTrait = RivalDetermineAttackTrait;
  20. rival.goods += getRandomInt(3, 10);
  21. rival.spendExperience();
  22. rival.experience = 0;
  23. }
  24. function updateRival()
  25. {
  26. rival.Mods.breasts = player.Mods.breasts;
  27. rival.Mods.amazon = player.Mods.amazon;
  28. rival.Mods.cock = player.Mods.futa;
  29. rival.capTraits();
  30. rival.calcPhysique();
  31. }
  32. // Reset to a average person, with stats all in the center, no bars shown
  33. function resetRival()
  34. {
  35. rival = new Avatar(50, 50, 50, 50, 50);
  36. redraw();
  37. }
  38. // Generic Man
  39. // Create
  40. function createRival(exp)
  41. {
  42. // Stats
  43. var femininity = getRandomInt(15, 35) - (exp / 5); // 15-35 median for stats
  44. if (femininity < 6) femininity = 6;
  45. var minTrait = femininity - 10;
  46. var maxTrait = femininity + 10;
  47. rival = new Avatar(getRandomInt(minTrait, maxTrait), getRandomInt(minTrait, maxTrait), getRandomInt(minTrait, maxTrait), getRandomInt(minTrait, maxTrait), getRandomInt(minTrait, maxTrait));
  48. // Standard Victory/Defeat/Tells for Generic man
  49. rival.Victory = RivalVictory;
  50. rival.Defeat = RivalDefeat;
  51. rival.getTell = RivalGetTell;
  52. rival.spendExperience = RivalSpendExperience;
  53. rival.determineAttackTrait = RivalDetermineAttackTrait;
  54. rival.experience = exp;
  55. rival.goods = getRandomInt(3, 10);
  56. // Can they be futa, yes if the player is or any of their women
  57. var iFuta = player.futa;
  58. $.each(player.women, function( index, value ) {
  59. iFuta += player.women[index].isFutanari() ? 1 : 0;
  60. });
  61. rival.futa = iFuta > 0 && Math.random() < 0.2 ? player.futa : 0;
  62. rival.name = rival.isFemale() || rival.futa > 0 ? "Rival woman" : "Rival man"; // Generic man
  63. rival.spendExperience();
  64. rival.experience = 0;
  65. }
  66. // allocate experience
  67. function RivalSpendExperience()
  68. {
  69. if (rival.experience === 0) return;
  70. // Ranks
  71. var ranks = rival.experience / 5;
  72. // divide ranks up
  73. // Perception 20%
  74. var used = 0;
  75. var val = Math.floor(ranks / 5);
  76. if (val > ((player.Mods.perception / 5) - 1)) val = (player.Mods.perception / 5) - 1;
  77. if (val > 0) {
  78. rival.Mods.perception += val * 5;
  79. used += val;
  80. }
  81. // Changra 20%
  82. val = Math.floor(ranks / 5);
  83. if (val > 0) {
  84. rival.Mods.changra += val * 5;
  85. used += val;
  86. }
  87. // Iron will
  88. if ((ranks - used) > 3) {
  89. rival.Mods.ironwill++;
  90. used++;
  91. }
  92. // Divide remaining between push and resist
  93. for (var i = ranks - used; i > 0; i--) {
  94. // TODO respect desires
  95. var trait = AVATAR_TRAITS[getRandomInt(1, 5)];
  96. if (getRandomInt(1, 100) < 50) rival.Mods["push" + trait] += 2;
  97. else rival.Mods["resist" + trait] += 1;
  98. used++;
  99. }
  100. }
  101. // You beat them
  102. function RivalVictory()
  103. {
  104. updateRival();
  105. // remove from runaway list
  106. for (var index = 0; index < runaways.length; index++) {
  107. if (runaways[index] === rival) {
  108. runaways.splice(index, 1);
  109. break;
  110. }
  111. }
  112. redraw();
  113. var nm = rival.name == "Rival man" || rival.name == "Rival woman" ? getUnusedFemaleName() : rival.name;
  114. $("#output").html(
  115. "<h1>You Howl!</h1>\
  116. <p>And unleash your spirit Changra. The air smell of burning and lightning, and then your rival crumble, weeping like woman. Her Changra burned away. She yours, and soon she forget how to be what she was. You take what <i>she</i> was carrying from their hunt.</p>\
  117. <p>As she quiver and snivel, you must decide on name for her.</p>\
  118. <input id='woman_name' value='" + nm + "'>\
  119. <button id='name_woman' class='btn'>Give Name</button>\
  120. <button id='reject_woman' class='btn'>Reject Woman</button>\
  121. ");
  122. $('#woman_name').click(function() {
  123. $("#woman_name").focus();
  124. });
  125. $("#name_woman").click(function() {
  126. rival.name = $("#woman_name").val().length > 0 ? $("#woman_name").val() : getUnusedFemaleName();
  127. rival.femaleName=rival.name;
  128. var bAlready = false;
  129. for (var index = 0; index < runaways.length; index++) {
  130. if (player.women[index] === rival) {
  131. bAlready = true;
  132. break;
  133. }
  134. }
  135. if (!bAlready) player.women.push(rival);
  136. player.experience += minValue(Math.floor(rival.femininity() / 3), 15);
  137. player.goods += rival.goods;
  138. rival.goods = 0;
  139. rival.round = player.round; // day captured
  140. EndRound();
  141. });
  142. $("#reject_woman").click(function() {
  143. player.experience += minValue(Math.floor(rival.femininity() / 3), 15);
  144. player.goods += rival.goods;
  145. EndRound(Message(NextWindow, "You no want this weakling and leave her to be claimed by another."));
  146. });
  147. }
  148. // You lost
  149. function RivalDefeat()
  150. {
  151. var rivalhis = rival.hisher;
  152. var rivalhim = rival.himher;
  153. var fates = [];
  154. if (player.submissiveness > 75) {
  155. fates.push("meekly obeying " + rivalhis + " wishes");
  156. }
  157. if (player.domesticity > 75) {
  158. fates.push("spending your days tending to " + rivalhis + " household");
  159. }
  160. if (player.allure > 75) {
  161. fates.push("spreading your legs for " + rivalhim + " every night");
  162. }
  163. if (player.maternalism > 75) {
  164. fates.push("bearing " + rivalhim + " healthy sons");
  165. }
  166. if (fates.length === 0) {
  167. fates.push("sneaking away, though. You not man, but you refuse to be woman of this one");
  168. }
  169. var fate = toCommaSeperatedList(fates);
  170. var rivalhe = rival.heshe;
  171. var playerFemaleName = randomFemaleName();
  172. var rivalmanlwr = rival.name == "Rival man" || rival.name == "Rival woman" ? rival.name.toLowerCase() : rival.name;
  173. fate = "<p>With mighty howl, " + rivalmanlwr + " stomp and point palm at you, " + rivalhis + " Changra surge into you, and your Changra evaporate like mist in sunlight. You collapse at " + rivalmanlwr + "'s feet, and he stare down as you pant and try collect your Changra. Finally " + rivalhe + " laugh and offer you hand.</p>\
  174. <p>'You have no Changra,' " + rivalhe + " say, pulling you up. 'You womanfolk. You mine now, and you be called "+playerFemaleName+".'</p>\
  175. <p>You very confused, and you follow " + rivalhim + " back to clan. You struggle remember what was to be man, but those thoughts become strange to you, until finally all you know is to be woman.</p>\
  176. <p>" + rival.name + " in your thoughts always now. Soon, you " + fate + ".</p>";
  177. if (fates.length === 0) {
  178. // Escape, not feminine enough
  179. Message(NextWindow, fate);
  180. return false;
  181. }
  182. // Captured
  183. $(".stats").hide();
  184. $("#output").html("<div id='message'>" + fate + "</div>\
  185. <div id='end_buttons' class='push--top'></div>\
  186. ");
  187. // add choices
  188. $("#end_buttons").append("<button id='end_button_submit' class='btn btn-woman push--right' title='Submit'>Submit</button>");
  189. $("#end_button_submit").click(
  190. function(){
  191. Message("location.reload();", "You give up and submit to your man");
  192. }
  193. );
  194. $("#end_buttons").append("<button id='end_button_pretend' class='btn btn-woman' title='Pretend'>Pretend Submit</button>");
  195. $("#end_button_pretend").click(playerFemaleName,
  196. function(evt){
  197. camp="captured";
  198. makeLeader(player,rival,false,evt.data);
  199. /*leader=rival;
  200. leader.women=[player];//todo: generate some women for him, maybe?
  201. if(player===leader){//otherwise we lose male name forever if captured twice
  202. player.oldName=player.name;
  203. }
  204. player.name=evt.data;*/
  205. //player.women.push(rival);//we need to do this so saves work. Fixed now with new save system, but maybe keep?
  206. rival.name=randomMaleName();
  207. rival.maleName=rival.name;
  208. player.dysphoria=3*player.masculinity()+20*player.Mods.ironwill;
  209. rival.rest();
  210. /*$.each(AVATAR_TRAITS, function(index, trait) {
  211. player.natural[trait] = player[trait];
  212. });*///removed rest step if not leader. should no longer revert without intervention.
  213. EndRound(Message(NextWindow,"He bring you back to camp as his woman, but you only pretending."));
  214. }
  215. );
  216. if (player.Mods.ironwill > 0) {
  217. $("#end_buttons").append("<button id='end_button_resist' class='btn btn-woman push--right' title='Resist'>Resist</button>");
  218. $("#end_button_resist").click(
  219. function() {
  220. player.Mods.changra -= 5;
  221. EndRound(Message(NextWindow, "You resist you desire for the " + rivalmanlwr + " and run away, you weaker for this"));
  222. }
  223. );
  224. } else $("#end_buttons").append("<p><b>You not strong in will enough to do anything else.</b></p>");
  225. return true;
  226. }
  227. // The tells they give off
  228. function RivalGetTell(action) {
  229. var pushDescription = getRandomElem([
  230. "pound chest.",
  231. "yell powerful.",
  232. "bellow laugh.",
  233. "flare nostrils like dragon.",
  234. "stomp ground"
  235. ]);
  236. var drainDescription = getRandomElem([
  237. "close eyes and hum to self.",
  238. "quiet and focus.",
  239. "whisper to self.",
  240. "close eyes and breathe deep.",
  241. "focused and very still."
  242. ]);
  243. var reflectDescription = getRandomElem([
  244. "plant feet in ground and stare at you defiant.",
  245. "cross arms over chest.",
  246. "step back, arms crossed in front of face.",
  247. "crouch low, arms crossed in front of face.",
  248. "crouched and very still."
  249. ]);
  250. var restDescription = getRandomElem([
  251. "breathe deep.",
  252. "panting.",
  253. "look pale.",
  254. "wipe sweat face.",
  255. "very still."
  256. ]);
  257. var hesitateDescription = getRandomElem([
  258. "look uncertain.",
  259. "look confused.",
  260. "bite lip.",
  261. "look at ground.",
  262. "chew lip."
  263. ]);
  264. switch(action) {
  265. case "push": return rival.name + " " + pushDescription;
  266. case "drain": return rival.name + " " + drainDescription;
  267. case "reflect": return rival.name + " " + reflectDescription;
  268. case "rest": return rival.name + " " + restDescription;
  269. case "hesitate": return rival.name + " " + hesitateDescription;
  270. }
  271. return "";
  272. }
  273. function RivalDetermineAttackTrait(avatar, opponent, action) {
  274. var viableTraits = [];
  275. $.each(AVATAR_TRAITS, function(index, trait) {
  276. if (opponent[trait] < 100) {
  277. viableTraits.push(trait);
  278. }
  279. });
  280. var desiredTraits = [];
  281. $.each(viableTraits, function(index, trait) {
  282. var defensiveIncentive;
  283. if (action === "push" && avatar[trait] < 50) defensiveIncentive = 0;
  284. else defensiveIncentive = (avatar[trait] / 100) * avatar.defensiveness;
  285. var offensiveIncentive;
  286. if (action === "drain" && opponent[trait] > 50) offensiveIncentive = 0;
  287. else offensiveIncentive = ((avatar.desires[trait] - opponent[trait]) / 50) * avatar.offensiveness;
  288. desiredTraits.push({"trait": trait, "desire": offensiveIncentive + defensiveIncentive + getRandomInt(0, avatar.unpredictability * 2)});
  289. });
  290. desiredTraits = desiredTraits.sort(function(a,b) {
  291. return b.desire - a.desire;
  292. });
  293. if (desiredTraits.length > 0) return desiredTraits[0].trait;
  294. return "submissiveness";
  295. };