extends CharacterBody2D class_name Cow signal moved var interactionsInRange = [] var targetInteraction var interactionTrigger var cowState = "Idle" var currentInteractingItem var currentInteractingGroundItem var interactingSpeed var currentInteractingBuildingZone var interactionTimer = 0 var interactionState = "none" var lastInteractionCheckThreshold = 100 var movementTarget:Vector2 var movementThreshold = 0.1 var moveSpeed:int = 200 var fastWalking = false var swimmingZones = [] var soakTimer = 2 var facingLeft:bool = true var defaultVisiblesPosition var lastPosition var pointsForXpDrop = 100 var movementXpProgress = 0 var movementXpAmount = 5 var timeMovedMultiplier = 10 var distanceMovedMultiplier = 0.1 var maxMovementThresholdForXP = 50 var wisdom = [] var wisdomDelays = [] var wisdomTimer = 0 var wisdomIndex = 0 var rng = RandomNumberGenerator.new() func _ready(): defaultVisiblesPosition = %Visuals.position fastWalking = false movementTarget = position lastPosition = position face_direction(false) func _process(delta): if !cowState == "Riding": if targetInteraction != null: if target_interaction_range_check(): movementTarget = global_position else: movement(delta) else: movement(delta) if cowState == "Drinking": drinking(delta) if cowState == "Weaving": weaving(delta) if cowState == "Building": building(delta) if cowState == "Playing": playing(delta) if cowState == "Demolishing": demolishing(delta) if interactionTimer > 0: interactionTimer -= delta if interactionTimer <= 0: if cowState == "Eating": if currentInteractingItem.get_name(false).contains("Brass Key"): juice_consultant_location_wisdom() LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "ate") InventoryManager.remove_item_from_inventory(currentInteractingItem) AchievementManager.eat_achievement_checks(currentInteractingItem) if currentInteractingItem.get_edibility() >= 125: AchievementManager.complete_achievement("Delicious Delicacy") stop_eating() change_state("Idle") if wisdomTimer > 0: wisdomTimer -= delta if wisdomTimer <= 0: MessageManager.addMessage(wisdom[wisdomIndex], GameVariables.player, "Cow", Color.YELLOW) wisdomIndex += 1 if wisdomIndex < wisdom.size(): wisdomTimer = wisdomDelays[wisdomIndex - 1] func juice_consultant_location_wisdom(): get_tree().get_root().get_node("MainGame/PuzzleCompleteAudio").play() wisdomIndex = 0 wisdomTimer = 0.1 wisdom = ["Upon a circle ever spinning", "I must board a creature ever buzzing", "Upon them I must shout with glee:", "Yippee!"] wisdomDelays = [4.1, 4.1, 4.1] SaveManager.set_save_value("juiceKnowledgeObtained", true) func change_state(targetState): if cowState == "Drinking": stop_drinking() if cowState == "Eating": stop_eating() if cowState == "Playing": stop_playing() if cowState == "Beholding": stop_beholding() if cowState == "Weaving": stop_weaving() if cowState == "Building": stop_building() if cowState == "Demolishing": stop_demolishing() cowState = targetState if cowState == "Idle": play_animation("Idle") func reset_visuals_pos(): %Visuals.position = defaultVisiblesPosition func set_visuals_pos(newPosition): %Visuals.position = newPosition func add_swimming_area(swimmingArea): swimmingZones.append(swimmingArea) func remove_swimming_area(swimmingArea): swimmingZones.erase(swimmingArea) func clear_swimming_areas(): swimmingZones = [] soakTimer = 0.2 %Waves.visible = false moveSpeed = 200 func playing(delta): if currentInteractingItem.get_name(false) == "DIY Excavation": if %Toy.frame >= 2 and interactionState == "started": interactionState = "boneShown" InventoryManager.remove_item_from_inventory(currentInteractingItem) var boneReward = BoneGenerator.get_a_bone() InventoryManager.add_item_to_inventory(boneReward) var xpReward = BoneGenerator.get_xp_reward_for_bone(boneReward) LevelManager.add_XP("gaming", xpReward) %Bone.visible = true %Bone.texture = boneReward.get_sprite() if %Toy.frame >= 5 and interactionState == "boneShown": interactionState = "done" %Toy.pause() func behold_item(item): change_state("Beholding") play_animation("Playing") %BeheldItem.visible = true currentInteractingItem = item var itemAnimation:SpriteFrames = SpriteFrames.new() itemAnimation.add_frame("default", item.get_sprite()) %BeheldItem.sprite_frames = itemAnimation %BeheldItem.frame = 0 AchievementManager.behold_achievement_checks(item) LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "beholded") GlobalEvents.itemBeheld.emit(item) func stop_beholding(): %BeheldItem.visible = false func play_item(item): if item.get_name(false) == "Ball": var newBall = preload("res://Objects/Beach/Ball/Ball.tscn").instantiate() newBall.global_position = global_position + Vector2(rng.randf_range(-50, 50), rng.randf_range(-5, 5)) LocationManager.currentLocation.add_child(newBall) AchievementManager.play_achievement_checks(item) LevelManager.get_skill("appreciating").experience_item(item, "played") GlobalEvents.itemPlayedWith.emit(item) InventoryManager.remove_item_from_inventory(item) return change_state("Playing") play_animation("Playing") %Toy.visible = true currentInteractingItem = item interactionState = "started" var itemAnimation:SpriteFrames = SpriteFrames.new() for additionalSprite in item.get_additional_sprites(): itemAnimation.add_frame("default", additionalSprite) %Toy.sprite_frames = itemAnimation %Toy.frame = 0 %Toy.play() AchievementManager.play_achievement_checks(item) LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "played") GlobalEvents.itemPlayedWith.emit(item) func stop_playing(): %Toy.visible = false %Bone.visible = false func eat_item(item): play_animation("Eat") change_state("Eating") %Food.visible = true %Food.texture = item.get_sprite() currentInteractingItem = item interactionTimer = 1.5 func stop_eating(): %Food.visible = false func demolish(buildingZone): change_state("Demolishing") play_animation("Idle") currentInteractingBuildingZone = buildingZone var demolishingBar:ProgressBar = %DemolishingBar demolishingBar.visible = true demolishingBar.value = 0 interactingSpeed = buildingZone.get_demolishing_speed() func demolishing(delta): %DemolishingBar.value += interactingSpeed * delta if %DemolishingBar.value >= 100: %DemolishingBar.value = 0 currentInteractingBuildingZone.demolished() change_state("Idle") func stop_demolishing(): %DemolishingBar.visible = false func build(item, buildingZone): change_state("Building") play_animation("Idle") currentInteractingItem = item currentInteractingBuildingZone = buildingZone var buildingBar:ProgressBar = %BuildingBar buildingBar.visible = true buildingBar.value = 0 var itemColor = SpriteGeneration.get_average_color(item.get_sprite().get_image(), [Color.BLACK]) var buildingBarStyleBox:StyleBoxFlat = StyleBoxFlat.new() buildingBarStyleBox.set_border_width_all(2) buildingBarStyleBox.set_corner_radius_all(6) buildingBarStyleBox.border_color = Color.TRANSPARENT buildingBarStyleBox.bg_color = itemColor buildingBarStyleBox.anti_aliasing = false buildingBar.set("theme_override_styles/fill", buildingBarStyleBox) interactingSpeed = LevelManager.get_skill("building").get_building_speed(item) lastInteractionCheckThreshold = rng.randi_range(20, 80) func stop_building(): %BuildingBar.visible = false func building(delta): %BuildingBar.value += interactingSpeed * delta if !InventoryManager.check_if_in_inventory(currentInteractingItem): change_state("Idle") var itemName = currentInteractingItem.get_name() MessageManager.addMessage("i need more " + itemName, GameVariables.player, "Cow", Color.YELLOW) return if %BuildingBar.value >= 100: InventoryManager.spend_item(currentInteractingItem) %BuildingBar.value = 0 lastInteractionCheckThreshold = rng.randi_range(20, 80) if !currentInteractingBuildingZone.stage_complete(): change_state("Idle") elif %BuildingBar.value >= lastInteractionCheckThreshold: var successChance = currentInteractingBuildingZone.get_success_chance(currentInteractingItem) if rng.randi_range(0, 100) > successChance: MessageManager.addMessage("dam", GameVariables.player, "Cow", Color.YELLOW) %BuildingBar.value = 0 lastInteractionCheckThreshold = rng.randi_range(20, 80) InventoryManager.spend_item(currentInteractingItem) LevelManager.add_XP("building", 1) else: lastInteractionCheckThreshold = 200 func weave_item(item): change_state("Weaving") play_animation("Idle") currentInteractingItem = item var weavingBar:ProgressBar = %WeavingBar weavingBar.visible = true weavingBar.value = 0 var basketColor = SpriteGeneration.get_average_color(item.get_sprite().get_image(), [Color.BLACK]) var weavingBarStyleBox:StyleBoxFlat = StyleBoxFlat.new() weavingBarStyleBox.set_border_width_all(2) weavingBarStyleBox.set_corner_radius_all(6) weavingBarStyleBox.border_color = Color.TRANSPARENT weavingBarStyleBox.bg_color = basketColor weavingBarStyleBox.anti_aliasing = false weavingBar.set("theme_override_styles/fill", weavingBarStyleBox) interactingSpeed = LevelManager.get_skill("basketWeaving").get_basketing_speed(item) lastInteractionCheckThreshold = 0 func stop_weaving(): %WeavingBar.visible = false if %WeavingBar.value >= 50 and %WeavingBar.value < 100: currentInteractingItem.set_modification(Item.modifications.Knotted) currentInteractingGroundItem.set_item(currentInteractingItem) LevelManager.add_XP("basketWeaving", LevelManager.get_skill("basketWeaving").get_failed_item_xp(currentInteractingItem)) func drink_juice(item): play_animation("Drink") change_state("Drinking") %Juice.visible = true %Juice.texture = item.get_sprite() currentInteractingItem = item var juiceBar:ProgressBar = %JuiceBar var juiceColor = SpriteGeneration.get_average_color(%Juice.texture.get_image(), [Color.BLACK]) var juiceBarStyleBox:StyleBoxFlat = StyleBoxFlat.new() juiceBarStyleBox.set_border_width_all(2) juiceBarStyleBox.set_corner_radius_all(6) juiceBarStyleBox.border_color = Color.TRANSPARENT juiceBarStyleBox.bg_color = juiceColor juiceBarStyleBox.anti_aliasing = false juiceBar.set("theme_override_styles/fill", juiceBarStyleBox) %JuiceBar.value = 100 %JuiceBar.visible = true %JuiceParticles.emitting = true %JuiceParticles.visible = true %JuiceParticles.position.x = 65 %JuiceParticles.color = juiceColor interactingSpeed = LevelManager.get_skill("juiceDrinking").get_drink_speed(item) lastInteractionCheckThreshold = 100 func stop_drinking(): %Juice.visible = false %JuiceBar.visible = false %JuiceParticles.emitting = false %JuiceParticles.visible = false %JuiceParticles.restart() func drinking(delta): %JuiceBar.value -= interactingSpeed * delta %JuiceParticles.position.x = 57 - (130*((100 - %JuiceBar.value)*0.01)) if %JuiceBar.value <= 0: if currentInteractingItem.get_name(false).contains("Brass Key"): juice_consultant_location_wisdom() InventoryManager.remove_item_from_inventory(currentInteractingItem) if currentInteractingItem.get_name(false) == "Green Soda": var newItem = preload("res://Items/Foods/Liquids/GreenSodaCan.gd").new() InventoryManager.add_item_to_inventory(newItem) elif currentInteractingItem.get_name(false) == "Blue Soda": var newItem = preload("res://Items/Foods/Liquids/BlueSodaCan.gd").new() InventoryManager.add_item_to_inventory(newItem) elif currentInteractingItem.get_name(false).contains("Brass Key"): juice_consultant_location_wisdom() AchievementManager.drink_achievement_checks(currentInteractingItem) LevelManager.add_XP("juiceDrinking", LevelManager.get_skill("juiceDrinking").get_item_xp(currentInteractingItem)) LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "drank") change_state("Idle") elif %JuiceBar.value <= (lastInteractionCheckThreshold - 20): var blehChance = LevelManager.get_skill("juiceDrinking").get_bleh_chance(currentInteractingItem) if rng.randi_range(0, 100) <= blehChance: MessageManager.addMessage("bleh", GameVariables.player, "Cow", Color.YELLOW) change_state("Idle") lastInteractionCheckThreshold -= 20 func weaving(delta): %WeavingBar.value += interactingSpeed * delta if %WeavingBar.value >= 100: GlobalEvents.itemWeaved.emit(currentInteractingItem) var newBasket = BasketGenerator.generate_basket(currentInteractingItem) currentInteractingGroundItem.set_item(newBasket) LevelManager.add_XP("basketWeaving", LevelManager.get_skill("basketWeaving").get_item_xp(currentInteractingItem)) LevelManager.get_skill("appreciating").experience_item(newBasket, "wove") change_state("Idle") elif %WeavingBar.value >= (lastInteractionCheckThreshold + 20): var failChance = LevelManager.get_skill("basketWeaving").get_fail_chance(currentInteractingItem) if rng.randi_range(0, 100) <= failChance: MessageManager.addMessage("oh deer", GameVariables.player, "Cow", Color.YELLOW) change_state("Idle") lastInteractionCheckThreshold += 20 func set_target_position(targetPos): movementTarget = targetPos if movementTarget.x != global_position.x: if movementTarget.x > global_position.x: face_direction(false) else: face_direction(true) moved.emit() func movement(delta): if swimmingZones.size() > 0: soakTimer -= delta if soakTimer <= 0: soakTimer = 2 InventoryManager.soak_player_inventory() if !%Waves.visible: %Waves.visible = true $Splash.play() %WaterSpray.emitting = true var mainSwimmingZone = swimmingZones[0] for zone in swimmingZones: if zone.swimmingSpeed <= mainSwimmingZone.swimmingSpeed: mainSwimmingZone = zone %Waves.self_modulate = mainSwimmingZone.liquidColor moveSpeed = mainSwimmingZone.swimmingSpeed var swimmingLevel = LevelManager.get_skill("swimming").currentLevel moveSpeed = mainSwimmingZone.swimmingSpeed * (1 + (0.015 * swimmingLevel)) else: soakTimer = 0.2 %Waves.visible = false moveSpeed = 200 if fastWalking: moveSpeed += 40 moveSpeed += LevelManager.get_skill("fastWalking").currentLevel * 1.5 var distanceToTarget = global_position.distance_to(movementTarget) if distanceToTarget > movementThreshold: handle_movement_xp(delta, (lastPosition - position).length()) lastPosition = position var movementVector = global_position.move_toward(movementTarget, moveSpeed*delta) - global_position velocity = movementVector var collision = move_and_collide(velocity) if collision: velocity = velocity.slide(collision.get_normal()) handle_collision(collision) play_animation("Walk") change_state("Walking") elif cowState == "Walking": global_position = movementTarget play_animation("Idle") change_state("Idle") func handle_collision(collision:KinematicCollision2D): var collider = collision.get_collider() if collider is NoSwimBlocker: collider.cow_collided() func handle_movement_xp(time, distance): if distance > maxMovementThresholdForXP: return var xpToEarn = 0 movementXpProgress += (time * timeMovedMultiplier) movementXpProgress += (distance * distanceMovedMultiplier) while movementXpProgress >= pointsForXpDrop: if swimmingZones.size() > 0: var mainSwimmingZone = swimmingZones[0] for zone in swimmingZones: if zone.swimmingSpeed <= mainSwimmingZone.swimmingSpeed: mainSwimmingZone = zone xpToEarn += mainSwimmingZone.swimmingXp else: xpToEarn += movementXpAmount movementXpProgress -= pointsForXpDrop if xpToEarn > 0: if swimmingZones.size() > 0: LevelManager.add_XP("swimming", xpToEarn) elif fastWalking: LevelManager.add_XP("fastWalking", xpToEarn) else: LevelManager.add_XP("walking", xpToEarn) func interact(interactionObj, interactionFunction, interactionPosition): targetInteraction = interactionObj interactionTrigger = interactionFunction set_target_position(interactionPosition) func target_interaction_range_check(): if targetInteraction in interactionsInRange: interactionTrigger.call() targetInteraction = null return true return false func _on_interaction_area_area_entered(area): if area.get_parent() is Interaction: interactionsInRange.append(area.get_parent()) func _on_interaction_area_area_exited(area): if area.get_parent() is Interaction: if area.get_parent() in interactionsInRange: interactionsInRange.erase(area.get_parent()) func face_direction(left:bool = true): if left: if !facingLeft: facingLeft = true %Cow.flip_h = false %Cow.position.x -= 37 %Juice.position.x = -74 %Toy.flip_h = false %Toy.position.x = -72 %Bone.flip_h = false %Bone.position.x = -72 %Food.flip_h = false %Food.position.x = -74 %BeheldItem.position.x = -69 else: if facingLeft: facingLeft = false %Cow.flip_h = true %Cow.position.x += 37 %Juice.position.x = 74 %Toy.flip_h = true %Toy.position.x = 72 %Bone.flip_h = true %Bone.position.x = 72 %Food.flip_h = true %Food.position.x = 74 %BeheldItem.position.x = 69 func play_animation(animationName): %Cow.play(animationName) func _on_cow_animation_finished(): play_animation("Idle")