XP system
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								src/art/pickups/chest.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/art/pickups/chest.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 426 B | 
							
								
								
									
										
											BIN
										
									
								
								src/art/pickups/resources.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/art/pickups/resources.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 418 B | 
| @@ -2,6 +2,9 @@ | ||||
| export type Stat = "AGI" | "INT" | "CHA" | "PSI"; | ||||
| export const ALL_STATS: Array<Stat> = ["AGI", "INT", "CHA", "PSI"]; | ||||
|  | ||||
| export type Resource = "EXP"; | ||||
| export const ALL_RESOURCES: Array<Resource> = ["EXP"] | ||||
|  | ||||
| export type SkillGoverning = { | ||||
|   stats: Stat[], underTarget: number, target: number, cost: number, note: string | ||||
| }; | ||||
|   | ||||
| @@ -24,7 +24,7 @@ export class Hud { | ||||
|       y += 16; | ||||
|     } | ||||
|     D.drawText("EXP", new Point(0, 128), FG_BOLD); | ||||
|     D.drawText("0", new Point(32, 128), FG_TEXT); | ||||
|     D.drawText(`${prog.getExperience()}`, new Point(32, 128), FG_TEXT); | ||||
|     D.drawText("BLD", new Point(0, 144), FG_BOLD); | ||||
|     D.drawText(`${prog.getBlood()}cc`, new Point(32, 144), FG_TEXT); | ||||
|   } | ||||
|   | ||||
| @@ -1,14 +1,15 @@ | ||||
| import {Grid, Point, Rect, Size} from "./engine/datatypes.ts"; | ||||
| import {ConceptualCell, maps} from "./maps.ts"; | ||||
| import {ALL_STATS, Stat} from "./datatypes.ts"; | ||||
| import {ALL_STATS, Resource, Stat} from "./datatypes.ts"; | ||||
| import {DrawPile} from "./drawpile.ts"; | ||||
| import {D} from "./engine/public.ts"; | ||||
| import {sprDrips, sprRaccoonWalking, sprStatPickup} from "./sprites.ts"; | ||||
| import {sprDrips, sprRaccoonWalking, sprResourcePickup, sprStatPickup} from "./sprites.ts"; | ||||
| import {BG_INSET, FG_TEXT} from "./colors.ts"; | ||||
| import {getPlayerProgress} from "./playerprogress.ts"; | ||||
|  | ||||
| export type MapCellContent = | ||||
|   {type: "statPickup", stat: Stat} | | ||||
|   {type: "resourcePickup", resource: Resource} | | ||||
|   {type: "stairs"} | | ||||
|   {type: "empty"} | | ||||
|   {type: "block"} | ||||
| @@ -112,9 +113,13 @@ export class HuntMode { | ||||
|     let gsp = (): MapCellContent => { | ||||
|       return {type: "statPickup", stat: choose(ALL_STATS)} | ||||
|     }; | ||||
|     let exp = (): MapCellContent => { | ||||
|       return {type: "resourcePickup", resource: "EXP"} | ||||
|     } | ||||
|     // TODO: Other objects? | ||||
|     return choose([ | ||||
|       gsp, gsp, gsp, gsp | ||||
|       gsp, gsp, gsp, gsp, | ||||
|       exp, | ||||
|     ])(); | ||||
|   } | ||||
|  | ||||
| @@ -142,17 +147,31 @@ export class HuntMode { | ||||
|  | ||||
|   #collectResources() { | ||||
|     let present = this.cells.get(this.player); | ||||
|  | ||||
|     if (present.content.type == "statPickup") { | ||||
|       let stat = present.content.stat; | ||||
|       let amount = 1; | ||||
|       present.content = {type: "empty"}; | ||||
|       getPlayerProgress().add(stat, amount); | ||||
|     } | ||||
|  | ||||
|     if (present.content.type == "resourcePickup") { | ||||
|       let resource = present.content.resource; | ||||
|       switch(resource) { | ||||
|         case "EXP": | ||||
|           getPlayerProgress().addExperience(25); | ||||
|           break; | ||||
|         default: | ||||
|           throw `not sure how to add ${resource}` | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     present.content = {type: "empty"}; | ||||
|   } | ||||
|  | ||||
|   #computeCostToMoveTo(mapPosition: Point): number | null { | ||||
|     let present = this.cells.get(mapPosition); | ||||
|     if (present.content.type == "statPickup") { | ||||
|     if (present.content.type == "statPickup" || present.content.type == "resourcePickup") { | ||||
|       return 100; | ||||
|     } | ||||
|     if (present.content.type == "empty") { | ||||
| @@ -267,6 +286,20 @@ export class HuntMode { | ||||
|         ) | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|     if (cellData.content.type == "resourcePickup" && cellData.content.resource == "EXP") { | ||||
|       this.drawpile.add(inAir, () => { | ||||
|         D.drawSprite( | ||||
|           sprResourcePickup, | ||||
|           cellOffset.offset(new Point(0, -16 * 3)), | ||||
|           0, | ||||
|           { | ||||
|             xScale: 3, | ||||
|             yScale: 3, | ||||
|           } | ||||
|         ); | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   #drawPlayer(globalOffset: Point) { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import {getSkills} from "./skills.ts"; | ||||
|  | ||||
| export class PlayerProgress { | ||||
|   #stats: Record<Stat, number> | ||||
|   #exp: number; | ||||
|   #blood: number | ||||
|   #skillsLearned: number[]  // use the raw ID representation for indexOf | ||||
|   #untrimmedSkillsAvailable: Skill[] | ||||
| @@ -14,6 +15,7 @@ export class PlayerProgress { | ||||
|       CHA: 10, | ||||
|       PSI: 10, | ||||
|     }; | ||||
|     this.#exp = 0; | ||||
|     this.#blood = 0; | ||||
|     this.#skillsLearned = []; | ||||
|     this.#untrimmedSkillsAvailable = [] | ||||
| @@ -82,6 +84,21 @@ export class PlayerProgress { | ||||
|     this.#stats[stat] += amount; | ||||
|   } | ||||
|  | ||||
|   addExperience(amt: number) { | ||||
|     this.#exp += amt; | ||||
|   } | ||||
|  | ||||
|   getExperience(): number { | ||||
|     return this.#exp | ||||
|   } | ||||
|  | ||||
|   spendExperience(cost: number) { | ||||
|     if (this.#exp < cost) { | ||||
|       throw `can't spend ${cost}` | ||||
|     } | ||||
|     this.#exp -= cost; | ||||
|   } | ||||
|  | ||||
|   getStat(stat: Stat): number { | ||||
|     return this.#stats[stat] | ||||
|   } | ||||
| @@ -97,9 +114,6 @@ export class PlayerProgress { | ||||
|   getAvailableSkills(): Skill[] { | ||||
|     // Sort by cost, then by name, then trim down to first 6 | ||||
|     let skillsAvailable = [...this.#untrimmedSkillsAvailable]; | ||||
|     skillsAvailable.sort((a, b) => { | ||||
|       return getSkills().computeCost(a) - getSkills().computeCost(b) | ||||
|     }); | ||||
|     skillsAvailable.sort((a, b) => { | ||||
|       let name1 = getSkills().get(a).profile.name; | ||||
|       let name2 = getSkills().get(b).profile.name; | ||||
| @@ -108,8 +122,12 @@ export class PlayerProgress { | ||||
|       if (name1 > name2) { return 1; } | ||||
|       return 0; | ||||
|     }); | ||||
|     skillsAvailable.sort((a, b) => { | ||||
|       return getSkills().computeCost(a) - getSkills().computeCost(b) | ||||
|     }); | ||||
|     return skillsAvailable.slice(0, 6) | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| let active: PlayerProgress = new PlayerProgress(); | ||||
|   | ||||
| @@ -53,7 +53,6 @@ function geomInterpolate( | ||||
|   if (x >= highIn) { return lowOut; } | ||||
|  | ||||
|   const proportion = 1.0 - (x - lowIn) / (highIn - lowIn); | ||||
|   console.log(`proportion: ${x} ${proportion}`) | ||||
|   return lowOut * Math.pow(highOut / lowOut, proportion) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -89,6 +89,7 @@ export class SkillsModal { | ||||
|     let selection = this.#skillSelection; | ||||
|     if (selection != null) { | ||||
|       let data = getSkills().get(selection); | ||||
|       let cost = getSkills().computeCost(selection); | ||||
|       let size = this.#size; | ||||
|       let remainingWidth = size.w - 160; | ||||
|  | ||||
| @@ -99,8 +100,14 @@ export class SkillsModal { | ||||
|  | ||||
|       // add learn button | ||||
|       let drawButtonRect = new Rect(new Point(160, 96), new Size(remainingWidth, 32)) | ||||
|       let canAfford = getPlayerProgress().getExperience() >= cost; | ||||
|       let caption = `Learn ${data.profile.name}` | ||||
|       addButton(this.#drawpile, caption, drawButtonRect, true, () => { | ||||
|       if (!canAfford) { | ||||
|         caption = `Can't Afford`; | ||||
|       } | ||||
|  | ||||
|       addButton(this.#drawpile, caption, drawButtonRect, canAfford, () => { | ||||
|         getPlayerProgress().spendExperience(cost); | ||||
|         getPlayerProgress().learnSkill(selection); | ||||
|       }) | ||||
|     } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import imgSnake from "./art/characters/snake.png"; | ||||
|  */ | ||||
| import imgRaccoon from "./art/characters/raccoon.png"; | ||||
| import imgRaccoonWalking from "./art/characters/raccoon_walking.png"; | ||||
| import imgResourcePickup from "./art/pickups/resources.png"; | ||||
| import imgStatPickup from "./art/pickups/stats.png"; | ||||
| import imgDrips from "./art/tilesets/drips.png"; | ||||
| import {Point, Size} from "./engine/datatypes.ts"; | ||||
| @@ -28,6 +29,10 @@ export let sprRaccoonWalking = new Sprite( | ||||
|   new Size(64, 64), new Point(32, 32), new Size(8, 1), | ||||
|   8 | ||||
| ); | ||||
| export let sprResourcePickup = new Sprite( | ||||
|   imgResourcePickup, new Size(32, 32), new Point(16, 16), | ||||
|   new Size(1, 1), 1 | ||||
| ); | ||||
|  | ||||
| export let sprStatPickup = new Sprite( | ||||
|   imgStatPickup, new Size(32, 32), new Point(16, 16), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user